dom/tests/mochitest/webcomponents/test_document_register_lifecycle.html

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

michael@0 1 <!DOCTYPE HTML>
michael@0 2 <html>
michael@0 3 <!--
michael@0 4 https://bugzilla.mozilla.org/show_bug.cgi?id=783129
michael@0 5 -->
michael@0 6 <head>
michael@0 7 <title>Test for document.registerElement lifecycle callback</title>
michael@0 8 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
michael@0 9 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
michael@0 10 </head>
michael@0 11 <body>
michael@0 12 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
michael@0 13 <div id="container">
michael@0 14 <x-hello id="hello"></x-hello>
michael@0 15 <button id="extbutton" is="x-button"></button>
michael@0 16 </div>
michael@0 17 <script>
michael@0 18
michael@0 19 var container = document.getElementById("container");
michael@0 20
michael@0 21 // Tests callbacks after registering element type that is already in the document.
michael@0 22 // create element in document -> register -> remove from document
michael@0 23 function testRegisterUnresolved() {
michael@0 24 var helloElem = document.getElementById("hello");
michael@0 25
michael@0 26 var createdCallbackCalled = false;
michael@0 27 var attachedCallbackCalled = false;
michael@0 28 var detachedCallbackCalled = false;
michael@0 29
michael@0 30 var p = Object.create(HTMLElement.prototype);
michael@0 31 p.createdCallback = function() {
michael@0 32 is(helloElem.__proto__, p, "Prototype should be adjusted just prior to invoking the created callback.");
michael@0 33 is(createdCallbackCalled, false, "Created callback should only be called once in this tests.");
michael@0 34 is(this, helloElem, "The 'this' value should be the custom element.");
michael@0 35 createdCallbackCalled = true;
michael@0 36 };
michael@0 37
michael@0 38 p.attachedCallback = function() {
michael@0 39 is(createdCallbackCalled, true, "Created callback should be called before attached");
michael@0 40 is(attachedCallbackCalled, false, "attached callback should only be called once in this test.");
michael@0 41 is(this, helloElem, "The 'this' value should be the custom element.");
michael@0 42 attachedCallbackCalled = true;
michael@0 43 };
michael@0 44
michael@0 45 p.detachedCallback = function() {
michael@0 46 is(attachedCallbackCalled, true, "attached callback should be called before detached");
michael@0 47 is(detachedCallbackCalled, false, "detached callback should only be called once in this test.");
michael@0 48 detachedCallbackCalled = true;
michael@0 49 is(this, helloElem, "The 'this' value should be the custom element.");
michael@0 50 runNextTest();
michael@0 51 };
michael@0 52
michael@0 53 p.attributeChangedCallback = function(name, oldValue, newValue) {
michael@0 54 ok(false, "attributeChanged callback should never be called in this test.");
michael@0 55 };
michael@0 56
michael@0 57 document.registerElement("x-hello", { prototype: p });
michael@0 58 is(createdCallbackCalled, true, "created callback should be called when control returns to script from user agent code");
michael@0 59
michael@0 60 // Remove element from document to trigger detached callback.
michael@0 61 container.removeChild(helloElem);
michael@0 62 }
michael@0 63
michael@0 64 // Tests callbacks after registering an extended element type that is already in the document.
michael@0 65 // create element in document -> register -> remove from document
michael@0 66 function testRegisterUnresolvedExtended() {
michael@0 67 var buttonElem = document.getElementById("extbutton");
michael@0 68
michael@0 69 var createdCallbackCalled = false;
michael@0 70 var attachedCallbackCalled = false;
michael@0 71 var detachedCallbackCalled = false;
michael@0 72
michael@0 73 var p = Object.create(HTMLButtonElement.prototype);
michael@0 74 p.createdCallback = function() {
michael@0 75 is(buttonElem.__proto__, p, "Prototype should be adjusted just prior to invoking the created callback.");
michael@0 76 is(createdCallbackCalled, false, "Created callback should only be called once in this tests.");
michael@0 77 is(this, buttonElem, "The 'this' value should be the custom element.");
michael@0 78 createdCallbackCalled = true;
michael@0 79 };
michael@0 80
michael@0 81 p.attachedCallback = function() {
michael@0 82 is(createdCallbackCalled, true, "Created callback should be called before attached");
michael@0 83 is(attachedCallbackCalled, false, "attached callback should only be called once in this test.");
michael@0 84 is(this, buttonElem, "The 'this' value should be the custom element.");
michael@0 85 attachedCallbackCalled = true;
michael@0 86 };
michael@0 87
michael@0 88 p.detachedCallback = function() {
michael@0 89 is(attachedCallbackCalled, true, "attached callback should be called before detached");
michael@0 90 is(detachedCallbackCalled, false, "detached callback should only be called once in this test.");
michael@0 91 detachedCallbackCalled = true;
michael@0 92 is(this, buttonElem, "The 'this' value should be the custom element.");
michael@0 93 runNextTest();
michael@0 94 };
michael@0 95
michael@0 96 p.attributeChangedCallback = function(name, oldValue, newValue) {
michael@0 97 ok(false, "attributeChanged callback should never be called in this test.");
michael@0 98 };
michael@0 99
michael@0 100 document.registerElement("x-button", { prototype: p, extends: "button" });
michael@0 101 is(createdCallbackCalled, true, "created callback should be called when control returns to script from user agent code");
michael@0 102
michael@0 103 // Remove element from document to trigger detached callback.
michael@0 104 container.removeChild(buttonElem);
michael@0 105 }
michael@0 106
michael@0 107 function testInnerHTML() {
michael@0 108 var createdCallbackCalled = false;
michael@0 109
michael@0 110 var p = Object.create(HTMLElement.prototype);
michael@0 111 p.createdCallback = function() {
michael@0 112 is(createdCallbackCalled, false, "created callback should only be called once in this test.");
michael@0 113 createdCallbackCalled = true;
michael@0 114 };
michael@0 115
michael@0 116 document.registerElement("x-inner-html", { prototype: p });
michael@0 117 var div = document.createElement(div);
michael@0 118 div.innerHTML = '<x-inner-html></x-inner-html>';
michael@0 119 is(createdCallbackCalled, true, "created callback should be called after setting innerHTML.");
michael@0 120 runNextTest();
michael@0 121 }
michael@0 122
michael@0 123 function testInnerHTMLExtended() {
michael@0 124 var createdCallbackCalled = false;
michael@0 125
michael@0 126 var p = Object.create(HTMLButtonElement.prototype);
michael@0 127 p.createdCallback = function() {
michael@0 128 is(createdCallbackCalled, false, "created callback should only be called once in this test.");
michael@0 129 createdCallbackCalled = true;
michael@0 130 };
michael@0 131
michael@0 132 document.registerElement("x-inner-html-extended", { prototype: p, extends: "button" });
michael@0 133 var div = document.createElement(div);
michael@0 134 div.innerHTML = '<button is="x-inner-html-extended"></button>';
michael@0 135 is(createdCallbackCalled, true, "created callback should be called after setting innerHTML.");
michael@0 136 runNextTest();
michael@0 137 }
michael@0 138
michael@0 139 function testInnerHTMLUpgrade() {
michael@0 140 var createdCallbackCalled = false;
michael@0 141
michael@0 142 var div = document.createElement(div);
michael@0 143 div.innerHTML = '<x-inner-html-upgrade></x-inner-html-upgrade>';
michael@0 144
michael@0 145 var p = Object.create(HTMLElement.prototype);
michael@0 146 p.createdCallback = function() {
michael@0 147 is(createdCallbackCalled, false, "created callback should only be called once in this test.");
michael@0 148 createdCallbackCalled = true;
michael@0 149 };
michael@0 150
michael@0 151 document.registerElement("x-inner-html-upgrade", { prototype: p });
michael@0 152 is(createdCallbackCalled, true, "created callback should be called after registering.");
michael@0 153 runNextTest();
michael@0 154 }
michael@0 155
michael@0 156 function testInnerHTMLExtendedUpgrade() {
michael@0 157 var createdCallbackCalled = false;
michael@0 158
michael@0 159 var div = document.createElement(div);
michael@0 160 div.innerHTML = '<button is="x-inner-html-extended-upgrade"></button>';
michael@0 161
michael@0 162 var p = Object.create(HTMLButtonElement.prototype);
michael@0 163 p.createdCallback = function() {
michael@0 164 is(createdCallbackCalled, false, "created callback should only be called once in this test.");
michael@0 165 createdCallbackCalled = true;
michael@0 166 };
michael@0 167
michael@0 168 document.registerElement("x-inner-html-extended-upgrade", { prototype: p, extends: "button" });
michael@0 169 is(createdCallbackCalled, true, "created callback should be called after registering.");
michael@0 170 runNextTest();
michael@0 171 }
michael@0 172
michael@0 173 // Test callback when creating element after registering an element type.
michael@0 174 // register -> create element -> insert into document -> remove from document
michael@0 175 function testRegisterResolved() {
michael@0 176 var createdCallbackCalled = false;
michael@0 177 var attachedCallbackCalled = false;
michael@0 178 var detachedCallbackCalled = false;
michael@0 179
michael@0 180 var createdCallbackThis;
michael@0 181
michael@0 182 var p = Object.create(HTMLElement.prototype);
michael@0 183 p.createdCallback = function() {
michael@0 184 is(createdCallbackCalled, false, "Created callback should only be called once in this test.");
michael@0 185 createdCallbackThis = this;
michael@0 186 createdCallbackCalled = true;
michael@0 187 };
michael@0 188
michael@0 189 p.attachedCallback = function() {
michael@0 190 is(createdCallbackCalled, true, "created callback should be called before attached callback.");
michael@0 191 is(attachedCallbackCalled, false, "attached callback should only be called on in this test.");
michael@0 192 is(this, createdElement, "The 'this' value should be the custom element.");
michael@0 193 attachedCallbackCalled = true;
michael@0 194 };
michael@0 195
michael@0 196 p.detachedCallback = function() {
michael@0 197 is(attachedCallbackCalled, true, "attached callback should be called before detached");
michael@0 198 is(detachedCallbackCalled, false, "detached callback should only be called once in this test.");
michael@0 199 is(this, createdElement, "The 'this' value should be the custom element.");
michael@0 200 detachedCallbackCalled = true;
michael@0 201 runNextTest();
michael@0 202 };
michael@0 203
michael@0 204 p.attributeChangedCallback = function() {
michael@0 205 ok(false, "attributeChanged callback should never be called in this test.");
michael@0 206 };
michael@0 207
michael@0 208 document.registerElement("x-resolved", { prototype: p });
michael@0 209 is(createdCallbackCalled, false, "Created callback should not be called when custom element instance has not been created.");
michael@0 210
michael@0 211 var createdElement = document.createElement("x-resolved");
michael@0 212 is(createdCallbackThis, createdElement, "The 'this' value in the created callback should be the custom element.");
michael@0 213 is(createdElement.__proto__, p, "Prototype of custom element should be the registered prototype.");
michael@0 214
michael@0 215 // Insert element into document to trigger attached callback.
michael@0 216 container.appendChild(createdElement);
michael@0 217
michael@0 218 // Remove element from document to trigger detached callback.
michael@0 219 container.removeChild(createdElement);
michael@0 220 }
michael@0 221
michael@0 222 // Callbacks should always be the same ones when registered.
michael@0 223 function testChangingCallback() {
michael@0 224 var p = Object.create(HTMLElement.prototype);
michael@0 225 var callbackCalled = false;
michael@0 226 p.attributeChangedCallback = function(name, oldValue, newValue) {
michael@0 227 is(callbackCalled, false, "Callback should only be called once in this test.");
michael@0 228 callbackCalled = true;
michael@0 229 runNextTest();
michael@0 230 };
michael@0 231
michael@0 232 document.registerElement("x-test-callback", { prototype: p });
michael@0 233
michael@0 234 p.attributeChangedCallback = function(name, oldValue, newValue) {
michael@0 235 ok(false, "Only callbacks at registration should be called.");
michael@0 236 };
michael@0 237
michael@0 238 var elem = document.createElement("x-test-callback");
michael@0 239 elem.setAttribute("foo", "bar");
michael@0 240 }
michael@0 241
michael@0 242 function testAttributeChanged() {
michael@0 243 var createdCallbackCalled = false;
michael@0 244
michael@0 245 var createdElement;
michael@0 246 var createdCallbackThis;
michael@0 247
michael@0 248 var p = Object.create(HTMLElement.prototype);
michael@0 249 p.createdCallback = function() {
michael@0 250 is(createdCallbackCalled, false, "Created callback should only be called once in this test.");
michael@0 251 createdCallbackThis = this;
michael@0 252 createdCallbackCalled = true;
michael@0 253 };
michael@0 254
michael@0 255 // Sequence of callback arguments that we expect from attribute changed callback
michael@0 256 // after changing attributes values in a specific order.
michael@0 257 var expectedCallbackArguments = [
michael@0 258 // [oldValue, newValue]
michael@0 259 [null, "newvalue"], // Setting the attribute value to "newvalue"
michael@0 260 ["newvalue", "nextvalue"], // Changing the attribute value from "newvalue" to "nextvalue"
michael@0 261 ["nextvalue", ""], // Changing the attribute value from "nextvalue" to empty string
michael@0 262 ["", null], // Removing the attribute.
michael@0 263 ];
michael@0 264
michael@0 265 p.attributeChangedCallback = function(name, oldValue, newValue) {
michael@0 266 is(createdCallbackCalled, true, "created callback should be called before attribute changed.");
michael@0 267 is(this, createdElement, "The 'this' value should be the custom element.");
michael@0 268 ok(expectedCallbackArguments.length > 0, "Attribute changed callback should not be called more than expected.");
michael@0 269
michael@0 270 is(name, "changeme", "name arugment in attribute changed callback should be the name of the changed attribute.");
michael@0 271
michael@0 272 var expectedArgs = expectedCallbackArguments.shift();
michael@0 273 is(oldValue, expectedArgs[0], "The old value argument should match the expected value.");
michael@0 274 is(newValue, expectedArgs[1], "The new value argument should match the expected value.");
michael@0 275
michael@0 276 if (expectedCallbackArguments.length === 0) {
michael@0 277 // Done with the attribute changed callback test.
michael@0 278 runNextTest();
michael@0 279 }
michael@0 280 };
michael@0 281
michael@0 282 document.registerElement("x-attrchange", { prototype: p });
michael@0 283
michael@0 284 var createdElement = document.createElement("x-attrchange");
michael@0 285 is(createdCallbackThis, createdElement, "The 'this' value in the created callback should be the custom element.");
michael@0 286 createdElement.setAttribute("changeme", "newvalue");
michael@0 287 createdElement.setAttribute("changeme", "nextvalue");
michael@0 288 createdElement.setAttribute("changeme", "");
michael@0 289 createdElement.removeAttribute("changeme");
michael@0 290 }
michael@0 291
michael@0 292 function testAttributeChangedExtended() {
michael@0 293 var p = Object.create(HTMLButtonElement.prototype);
michael@0 294 var callbackCalled = false;
michael@0 295 p.attributeChangedCallback = function(name, oldValue, newValue) {
michael@0 296 is(callbackCalled, false, "Callback should only be called once in this test.");
michael@0 297 callbackCalled = true;
michael@0 298 runNextTest();
michael@0 299 };
michael@0 300
michael@0 301 document.registerElement("x-extended-attribute-change", { prototype: p, extends: "button" });
michael@0 302
michael@0 303 var elem = document.createElement("button", "x-extended-attribute-change");
michael@0 304 elem.setAttribute("foo", "bar");
michael@0 305 }
michael@0 306
michael@0 307 // Creates a custom element that is an upgrade candidate (no registration)
michael@0 308 // and mutate the element in ways that would call callbacks for registered
michael@0 309 // elements.
michael@0 310 function testUpgradeCandidate() {
michael@0 311 var createdElement = document.createElement("x-upgrade-candidate");
michael@0 312 container.appendChild(createdElement);
michael@0 313 createdElement.setAttribute("foo", "bar");
michael@0 314 container.removeChild(createdElement);
michael@0 315 ok(true, "Nothing bad should happen when trying to mutating upgrade candidates.");
michael@0 316 runNextTest();
michael@0 317 }
michael@0 318
michael@0 319 function testNotInDocEnterLeave() {
michael@0 320 var p = Object.create(HTMLElement.prototype);
michael@0 321
michael@0 322 p.attached = function() {
michael@0 323 ok(false, "attached should not be called when not entering the document.");
michael@0 324 };
michael@0 325
michael@0 326 p.detached = function() {
michael@0 327 ok(false, "leaveView should not be called when not leaving the document.");
michael@0 328 };
michael@0 329
michael@0 330 var createdElement = document.createElement("x-destined-for-fragment");
michael@0 331
michael@0 332 document.registerElement("x-destined-for-fragment", { prototype: p });
michael@0 333
michael@0 334 var fragment = new DocumentFragment();
michael@0 335 fragment.appendChild(createdElement);
michael@0 336 fragment.removeChild(createdElement);
michael@0 337
michael@0 338 var divNotInDoc = document.createElement("div");
michael@0 339 divNotInDoc.appendChild(createdElement);
michael@0 340 divNotInDoc.removeChild(createdElement);
michael@0 341
michael@0 342 runNextTest();
michael@0 343 }
michael@0 344
michael@0 345 function testEnterLeaveView() {
michael@0 346 var attachedCallbackCalled = false;
michael@0 347 var detachedCallbackCalled = false;
michael@0 348
michael@0 349 var p = Object.create(HTMLElement.prototype);
michael@0 350 p.attachedCallback = function() {
michael@0 351 is(attachedCallbackCalled, false, "attached callback should only be called on in this test.");
michael@0 352 attachedCallbackCalled = true;
michael@0 353 };
michael@0 354
michael@0 355 p.detachedCallback = function() {
michael@0 356 is(attachedCallbackCalled, true, "attached callback should be called before detached");
michael@0 357 is(detachedCallbackCalled, false, "detached callback should only be called once in this test.");
michael@0 358 detachedCallbackCalled = true;
michael@0 359 runNextTest();
michael@0 360 };
michael@0 361
michael@0 362 var div = document.createElement("div");
michael@0 363 document.registerElement("x-element-in-div", { prototype: p });
michael@0 364 var customElement = document.createElement("x-element-in-div");
michael@0 365 div.appendChild(customElement);
michael@0 366 is(attachedCallbackCalled, false, "Appending a custom element to a node that is not in the document should not call the attached callback.");
michael@0 367
michael@0 368 container.appendChild(div);
michael@0 369 container.removeChild(div);
michael@0 370 }
michael@0 371
michael@0 372 var testFunctions = [
michael@0 373 testRegisterUnresolved,
michael@0 374 testRegisterUnresolvedExtended,
michael@0 375 testInnerHTML,
michael@0 376 testInnerHTMLExtended,
michael@0 377 testInnerHTMLUpgrade,
michael@0 378 testInnerHTMLExtendedUpgrade,
michael@0 379 testRegisterResolved,
michael@0 380 testAttributeChanged,
michael@0 381 testAttributeChangedExtended,
michael@0 382 testUpgradeCandidate,
michael@0 383 testChangingCallback,
michael@0 384 testNotInDocEnterLeave,
michael@0 385 testEnterLeaveView,
michael@0 386 SimpleTest.finish
michael@0 387 ];
michael@0 388
michael@0 389 function runNextTest() {
michael@0 390 if (testFunctions.length > 0) {
michael@0 391 var nextTestFunction = testFunctions.shift();
michael@0 392 nextTestFunction();
michael@0 393 }
michael@0 394 }
michael@0 395
michael@0 396 SimpleTest.waitForExplicitFinish();
michael@0 397
michael@0 398 runNextTest();
michael@0 399
michael@0 400 </script>
michael@0 401 </body>
michael@0 402 </html>

mercurial