Bug 1390396 - Reenable mochitests for custom elements lifecycle callbacks; r=smaug

Attribute changed callback now is fired only when the attribute is in observedAttributes list
which is introduced in latest spec, so in this patch, we change the tests for attribute changed
callback to use customElements.define() to register customElements definition instead.

MozReview-Commit-ID: 2s1qj3UsFUS

--HG--
rename : dom/tests/mochitest/webcomponents/test_document_register_lifecycle.html => dom/tests/mochitest/webcomponents/test_custom_element_lifecycle.html
rename : dom/tests/mochitest/webcomponents/test_document_register_stack.html => dom/tests/mochitest/webcomponents/test_custom_element_stack.html
extra : rebase_source : f37c52c8c6ffa80439692d4ba6a8b1a6888e20f2
This commit is contained in:
Edgar Chen 2017-10-03 17:22:58 +08:00
Родитель 3d23b15dec
Коммит 9805853065
6 изменённых файлов: 295 добавлений и 351 удалений

Просмотреть файл

@ -10,14 +10,12 @@ support-files =
[test_content_element.html] [test_content_element.html]
skip-if = true # Triggers assertions about flattened tree inconsistencies and it's going away in bug 1418002. skip-if = true # Triggers assertions about flattened tree inconsistencies and it's going away in bug 1418002.
[test_custom_element_callback_innerhtml.html] [test_custom_element_callback_innerhtml.html]
skip-if = true # disabled - See bug 1390396
[test_custom_element_htmlconstructor.html] [test_custom_element_htmlconstructor.html]
skip-if = os == 'android' # bug 1323645 skip-if = os == 'android' # bug 1323645
support-files = support-files =
htmlconstructor_autonomous_tests.js htmlconstructor_autonomous_tests.js
htmlconstructor_builtin_tests.js htmlconstructor_builtin_tests.js
[test_custom_element_in_shadow.html] [test_custom_element_in_shadow.html]
skip-if = true # disabled - See bug 1390396
[test_custom_element_register_invalid_callbacks.html] [test_custom_element_register_invalid_callbacks.html]
[test_custom_element_throw_on_dynamic_markup_insertion.html] [test_custom_element_throw_on_dynamic_markup_insertion.html]
[test_custom_element_get.html] [test_custom_element_get.html]
@ -26,6 +24,8 @@ skip-if = true # disabled - See bug 1390396
support-files = support-files =
test_upgrade_page.html test_upgrade_page.html
upgrade_tests.js upgrade_tests.js
[test_custom_element_lifecycle.html]
[test_custom_element_stack.html]
[test_nested_content_element.html] [test_nested_content_element.html]
[test_dest_insertion_points.html] [test_dest_insertion_points.html]
[test_fallback_dest_insertion_points.html] [test_fallback_dest_insertion_points.html]
@ -34,11 +34,7 @@ support-files =
[test_document_adoptnode.html] [test_document_adoptnode.html]
[test_document_importnode.html] [test_document_importnode.html]
[test_document_register.html] [test_document_register.html]
[test_document_register_lifecycle.html]
skip-if = true # disabled - See bug 1390396
[test_document_register_parser.html] [test_document_register_parser.html]
[test_document_register_stack.html]
skip-if = true # disabled - See bug 1390396
[test_document_shared_registry.html] [test_document_shared_registry.html]
[test_event_retarget.html] [test_event_retarget.html]
[test_event_stopping.html] [test_event_stopping.html]

Просмотреть файл

@ -4,7 +4,7 @@
https://bugzilla.mozilla.org/show_bug.cgi?id=1102502 https://bugzilla.mozilla.org/show_bug.cgi?id=1102502
--> -->
<head> <head>
<title>Test for attached callback for element created in the document by the parser</title> <title>Test for connected callback for element created in the document by the parser</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head> </head>
@ -20,10 +20,6 @@ var connectedCallbackCount = 0;
var p = Object.create(HTMLElement.prototype); var p = Object.create(HTMLElement.prototype);
p.createdCallback = function() {
ok(true, "createdCallback called.");
};
p.connectedCallback = function() { p.connectedCallback = function() {
ok(true, "connectedCallback should be called when the parser creates an element in the document."); ok(true, "connectedCallback should be called when the parser creates an element in the document.");
connectedCallbackCount++; connectedCallbackCount++;

Просмотреть файл

@ -16,97 +16,90 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1087460
// Test callback for custom element when used after registration. // Test callback for custom element when used after registration.
var createdCallbackCount = 0; var connectedCallbackCount = 0;
var attachedCallbackCount = 0; var disconnectedCallbackCount = 0;
var detachedCallbackCount = 0;
var attributeChangedCallbackCount = 0; var attributeChangedCallbackCount = 0;
var p1 = Object.create(HTMLElement.prototype); class Foo extends HTMLElement
{
connectedCallback() {
connectedCallbackCount++;
}
p1.createdCallback = function() { disconnectedCallback() {
createdCallbackCount++; disconnectedCallbackCount++;
}; }
p1.attachedCallback = function() { attributeChangedCallback(aName, aOldValue, aNewValue) {
attachedCallbackCount++; attributeChangedCallbackCount++;
}; }
p1.detachedCallback = function() { static get observedAttributes() {
detachedCallbackCount++; return ["data-foo"];
}; }
}
p1.attributeChangedCallback = function(name, oldValue, newValue) { customElements.define("x-foo", Foo);
attributeChangedCallbackCount++;
};
document.registerElement("x-foo", { prototype: p1 });
var container = document.getElementById("container"); var container = document.getElementById("container");
var shadow = container.createShadowRoot(); var shadow = container.createShadowRoot();
is(createdCallbackCount, 0, "createdCallback should not be called more than once in this test.");
var customElem = document.createElement("x-foo"); var customElem = document.createElement("x-foo");
is(createdCallbackCount, 1, "createdCallback should be called after creating custom element.");
is(attributeChangedCallbackCount, 0, "attributeChangedCallback should not be called after just creating an element."); is(attributeChangedCallbackCount, 0, "attributeChangedCallback should not be called after just creating an element.");
customElem.setAttribute("data-foo", "bar"); customElem.setAttribute("data-foo", "bar");
is(attributeChangedCallbackCount, 1, "attributeChangedCallback should be called after setting an attribute."); is(attributeChangedCallbackCount, 1, "attributeChangedCallback should be called after setting an attribute.");
is(attachedCallbackCount, 0, "attachedCallback should not be called on an element that is not in a document/composed document."); is(connectedCallbackCount, 0, "connectedCallback should not be called on an element that is not in a document/composed document.");
shadow.appendChild(customElem); shadow.appendChild(customElem);
is(attachedCallbackCount, 1, "attachedCallback should be called after attaching custom element to the composed document."); is(connectedCallbackCount, 1, "connectedCallback should be called after attaching custom element to the composed document.");
is(detachedCallbackCount, 0, "detachedCallback should not be called without detaching custom element."); is(disconnectedCallbackCount, 0, "disconnectedCallback should not be called without detaching custom element.");
shadow.removeChild(customElem); shadow.removeChild(customElem);
is(detachedCallbackCount, 1, "detachedCallback should be called after detaching custom element from the composed document."); is(disconnectedCallbackCount, 1, "disconnectedCallback should be called after detaching custom element from the composed document.");
// Test callback for custom element already in the composed doc when created. // Test callback for custom element already in the composed doc when created.
createdCallbackCount = 0; connectedCallbackCount = 0;
attachedCallbackCount = 0; disconnectedCallbackCount = 0;
detachedCallbackCount = 0;
attributeChangedCallbackCount = 0; attributeChangedCallbackCount = 0;
shadow.innerHTML = "<x-foo></x-foo>"; shadow.innerHTML = "<x-foo></x-foo>";
is(createdCallbackCount, 1, "createdCallback should be called after creating a custom element."); is(connectedCallbackCount, 1, "connectedCallback should be called after creating an element in the composed document.");
is(attachedCallbackCount, 1, "attachedCallback should be called after creating an element in the composed document.");
shadow.innerHTML = ""; shadow.innerHTML = "";
is(detachedCallbackCount, 1, "detachedCallback should be called after detaching custom element from the composed document."); is(disconnectedCallbackCount, 1, "disconnectedCallback should be called after detaching custom element from the composed document.");
// Test callback for custom element in shadow DOM when host attached/detached to/from document. // Test callback for custom element in shadow DOM when host attached/detached to/from document.
createdCallbackCount = 0; connectedCallbackCount = 0;
attachedCallbackCount = 0; disconnectedCallbackCount = 0;
detachedCallbackCount = 0;
attributeChangedCallbackCount = 0; attributeChangedCallbackCount = 0;
var host = document.createElement("div"); var host = document.createElement("div");
shadow = host.createShadowRoot(); shadow = host.createShadowRoot();
customElem = document.createElement("x-foo"); customElem = document.createElement("x-foo");
is(attachedCallbackCount, 0, "attachedCallback should not be called on newly created element."); is(connectedCallbackCount, 0, "connectedCallback should not be called on newly created element.");
shadow.appendChild(customElem); shadow.appendChild(customElem);
is(attachedCallbackCount, 0, "attachedCallback should not be called on attaching to a tree that is not in the composed document."); is(connectedCallbackCount, 0, "connectedCallback should not be called on attaching to a tree that is not in the composed document.");
is(attachedCallbackCount, 0, "detachedCallback should not be called."); is(disconnectedCallbackCount, 0, "disconnectedCallback should not be called.");
shadow.removeChild(customElem); shadow.removeChild(customElem);
is(detachedCallbackCount, 0, "detachedCallback should not be called when detaching from a tree that is not in the composed document."); is(disconnectedCallbackCount, 0, "disconnectedCallback should not be called when detaching from a tree that is not in the composed document.");
shadow.appendChild(customElem); shadow.appendChild(customElem);
is(attachedCallbackCount, 0, "attachedCallback should still not be called after reattaching to a shadow tree that is not in the composed document."); is(connectedCallbackCount, 0, "connectedCallback should still not be called after reattaching to a shadow tree that is not in the composed document.");
container.appendChild(host); container.appendChild(host);
is(attachedCallbackCount, 1, "attachedCallback should be called after host is inserted into document."); is(connectedCallbackCount, 1, "connectedCallback should be called after host is inserted into document.");
container.removeChild(host); container.removeChild(host);
is(detachedCallbackCount, 1, "detachedCallback should be called after host is removed from document."); is(disconnectedCallbackCount, 1, "disconnectedCallback should be called after host is removed from document.");
// Test callback for custom element for upgraded element. // Test callback for custom element for upgraded element.
createdCallbackCount = 0; connectedCallbackCount = 0;
attachedCallbackCount = 0; disconnectedCallbackCount = 0;
detachedCallbackCount = 0;
attributeChangedCallbackCount = 0; attributeChangedCallbackCount = 0;
shadow = container.shadowRoot; shadow = container.shadowRoot;
@ -114,17 +107,12 @@ shadow.innerHTML = "<x-bar></x-bar>";
var p2 = Object.create(HTMLElement.prototype); var p2 = Object.create(HTMLElement.prototype);
p2.createdCallback = function() { p2.connectedCallback = function() {
createdCallbackCount++; connectedCallbackCount++;
};
p2.attachedCallback = function() {
attachedCallbackCount++;
}; };
document.registerElement("x-bar", { prototype: p2 }); document.registerElement("x-bar", { prototype: p2 });
is(createdCallbackCount, 1, "createdCallback should be called after registering element."); is(connectedCallbackCount, 1, "connectedCallback should be called after upgrading element in composed document.");
is(attachedCallbackCount, 1, "attachedCallback should be called after upgrading element in composed document.");
</script> </script>

Просмотреть файл

@ -23,29 +23,20 @@ var container = document.getElementById("container");
function testRegisterUnresolved() { function testRegisterUnresolved() {
var helloElem = document.getElementById("hello"); var helloElem = document.getElementById("hello");
var createdCallbackCalled = false; var connectedCallbackCalled = false;
var attachedCallbackCalled = false; var disconnectedCallbackCalled = false;
var detachedCallbackCalled = false;
var p = Object.create(HTMLElement.prototype); var p = Object.create(HTMLElement.prototype);
p.createdCallback = function() { p.connectedCallback = function() {
is(helloElem.__proto__, p, "Prototype should be adjusted just prior to invoking the created callback."); is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
is(createdCallbackCalled, false, "Created callback should only be called once in this tests.");
is(this, helloElem, "The 'this' value should be the custom element."); is(this, helloElem, "The 'this' value should be the custom element.");
createdCallbackCalled = true; connectedCallbackCalled = true;
}; };
p.attachedCallback = function() { p.disconnectedCallback = function() {
is(createdCallbackCalled, true, "Created callback should be called before attached"); is(connectedCallbackCalled, true, "Connected callback should be called before detached");
is(attachedCallbackCalled, false, "attached callback should only be called once in this test."); is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
is(this, helloElem, "The 'this' value should be the custom element."); disconnectedCallbackCalled = true;
attachedCallbackCalled = true;
};
p.detachedCallback = function() {
is(attachedCallbackCalled, true, "attached callback should be called before detached");
is(detachedCallbackCalled, false, "detached callback should only be called once in this test.");
detachedCallbackCalled = true;
is(this, helloElem, "The 'this' value should be the custom element."); is(this, helloElem, "The 'this' value should be the custom element.");
runNextTest(); runNextTest();
}; };
@ -55,9 +46,8 @@ function testRegisterUnresolved() {
}; };
document.registerElement("x-hello", { prototype: p }); document.registerElement("x-hello", { prototype: p });
is(createdCallbackCalled, true, "created callback should be called when control returns to script from user agent code");
// Remove element from document to trigger detached callback. // Remove element from document to trigger disconnected callback.
container.removeChild(helloElem); container.removeChild(helloElem);
} }
@ -66,29 +56,20 @@ function testRegisterUnresolved() {
function testRegisterUnresolvedExtended() { function testRegisterUnresolvedExtended() {
var buttonElem = document.getElementById("extbutton"); var buttonElem = document.getElementById("extbutton");
var createdCallbackCalled = false; var connectedCallbackCalled = false;
var attachedCallbackCalled = false; var disconnectedCallbackCalled = false;
var detachedCallbackCalled = false;
var p = Object.create(HTMLButtonElement.prototype); var p = Object.create(HTMLButtonElement.prototype);
p.createdCallback = function() { p.connectedCallback = function() {
is(buttonElem.__proto__, p, "Prototype should be adjusted just prior to invoking the created callback."); is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
is(createdCallbackCalled, false, "Created callback should only be called once in this tests.");
is(this, buttonElem, "The 'this' value should be the custom element."); is(this, buttonElem, "The 'this' value should be the custom element.");
createdCallbackCalled = true; connectedCallbackCalled = true;
}; };
p.attachedCallback = function() { p.disconnectedCallback = function() {
is(createdCallbackCalled, true, "Created callback should be called before attached"); is(connectedCallbackCalled, true, "Connected callback should be called before detached");
is(attachedCallbackCalled, false, "attached callback should only be called once in this test."); is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
is(this, buttonElem, "The 'this' value should be the custom element."); disconnectedCallbackCalled = true;
attachedCallbackCalled = true;
};
p.detachedCallback = function() {
is(attachedCallbackCalled, true, "attached callback should be called before detached");
is(detachedCallbackCalled, false, "detached callback should only be called once in this test.");
detachedCallbackCalled = true;
is(this, buttonElem, "The 'this' value should be the custom element."); is(this, buttonElem, "The 'this' value should be the custom element.");
runNextTest(); runNextTest();
}; };
@ -98,106 +79,99 @@ function testRegisterUnresolvedExtended() {
}; };
document.registerElement("x-button", { prototype: p, extends: "button" }); document.registerElement("x-button", { prototype: p, extends: "button" });
is(createdCallbackCalled, true, "created callback should be called when control returns to script from user agent code");
// Remove element from document to trigger detached callback. // Remove element from document to trigger disconnected callback.
container.removeChild(buttonElem); container.removeChild(buttonElem);
} }
function testInnerHTML() { function testInnerHTML() {
var createdCallbackCalled = false; var connectedCallbackCalled = false;
var p = Object.create(HTMLElement.prototype); var p = Object.create(HTMLElement.prototype);
p.createdCallback = function() { p.connectedCallback = function() {
is(createdCallbackCalled, false, "created callback should only be called once in this test."); is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
createdCallbackCalled = true; connectedCallbackCalled = true;
}; };
document.registerElement("x-inner-html", { prototype: p }); document.registerElement("x-inner-html", { prototype: p });
var div = document.createElement(div); var div = document.createElement(div);
document.documentElement.appendChild(div);
div.innerHTML = '<x-inner-html></x-inner-html>'; div.innerHTML = '<x-inner-html></x-inner-html>';
is(createdCallbackCalled, true, "created callback should be called after setting innerHTML."); is(connectedCallbackCalled, true, "Connected callback should be called after setting innerHTML.");
runNextTest(); runNextTest();
} }
function testInnerHTMLExtended() { function testInnerHTMLExtended() {
var createdCallbackCalled = false; var connectedCallbackCalled = false;
var p = Object.create(HTMLButtonElement.prototype); var p = Object.create(HTMLButtonElement.prototype);
p.createdCallback = function() { p.connectedCallback = function() {
is(createdCallbackCalled, false, "created callback should only be called once in this test."); is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
createdCallbackCalled = true; connectedCallbackCalled = true;
}; };
document.registerElement("x-inner-html-extended", { prototype: p, extends: "button" }); document.registerElement("x-inner-html-extended", { prototype: p, extends: "button" });
var div = document.createElement(div); var div = document.createElement(div);
document.documentElement.appendChild(div);
div.innerHTML = '<button is="x-inner-html-extended"></button>'; div.innerHTML = '<button is="x-inner-html-extended"></button>';
is(createdCallbackCalled, true, "created callback should be called after setting innerHTML."); is(connectedCallbackCalled, true, "Connected callback should be called after setting innerHTML.");
runNextTest(); runNextTest();
} }
function testInnerHTMLUpgrade() { function testInnerHTMLUpgrade() {
var createdCallbackCalled = false; var connectedCallbackCalled = false;
var div = document.createElement(div); var div = document.createElement(div);
document.documentElement.appendChild(div);
div.innerHTML = '<x-inner-html-upgrade></x-inner-html-upgrade>'; div.innerHTML = '<x-inner-html-upgrade></x-inner-html-upgrade>';
var p = Object.create(HTMLElement.prototype); var p = Object.create(HTMLElement.prototype);
p.createdCallback = function() { p.connectedCallback = function() {
is(createdCallbackCalled, false, "created callback should only be called once in this test."); is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
createdCallbackCalled = true; connectedCallbackCalled = true;
}; };
document.registerElement("x-inner-html-upgrade", { prototype: p }); document.registerElement("x-inner-html-upgrade", { prototype: p });
is(createdCallbackCalled, true, "created callback should be called after registering."); is(connectedCallbackCalled, true, "Connected callback should be called after registering.");
runNextTest(); runNextTest();
} }
function testInnerHTMLExtendedUpgrade() { function testInnerHTMLExtendedUpgrade() {
var createdCallbackCalled = false; var connectedCallbackCalled = false;
var div = document.createElement(div); var div = document.createElement(div);
document.documentElement.appendChild(div);
div.innerHTML = '<button is="x-inner-html-extended-upgrade"></button>'; div.innerHTML = '<button is="x-inner-html-extended-upgrade"></button>';
var p = Object.create(HTMLButtonElement.prototype); var p = Object.create(HTMLButtonElement.prototype);
p.createdCallback = function() { p.connectedCallback = function() {
is(createdCallbackCalled, false, "created callback should only be called once in this test."); is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
createdCallbackCalled = true; connectedCallbackCalled = true;
}; };
document.registerElement("x-inner-html-extended-upgrade", { prototype: p, extends: "button" }); document.registerElement("x-inner-html-extended-upgrade", { prototype: p, extends: "button" });
is(createdCallbackCalled, true, "created callback should be called after registering."); is(connectedCallbackCalled, true, "Connected callback should be called after registering.");
runNextTest(); runNextTest();
} }
// Test callback when creating element after registering an element type. // Test callback when creating element after registering an element type.
// register -> create element -> insert into document -> remove from document // register -> create element -> insert into document -> remove from document
function testRegisterResolved() { function testRegisterResolved() {
var createdCallbackCalled = false; var connectedCallbackCalled = false;
var attachedCallbackCalled = false; var disconnectedCallbackCalled = false;
var detachedCallbackCalled = false;
var createdCallbackThis;
var p = Object.create(HTMLElement.prototype); var p = Object.create(HTMLElement.prototype);
p.createdCallback = function() { p.connectedCallback = function() {
is(createdCallbackCalled, false, "Created callback should only be called once in this test."); is(connectedCallbackCalled, false, "Connected callback should only be called on in this test.");
createdCallbackThis = this; is(this, createdElement, "The 'this' value should be the custom element.");
createdCallbackCalled = true; connectedCallbackCalled = true;
}; };
p.attachedCallback = function() { p.disconnectedCallback = function() {
is(createdCallbackCalled, true, "created callback should be called before attached callback."); is(connectedCallbackCalled, true, "Connected callback should be called before detached");
is(attachedCallbackCalled, false, "attached callback should only be called on in this test."); is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
is(this, createdElement, "The 'this' value should be the custom element."); is(this, createdElement, "The 'this' value should be the custom element.");
attachedCallbackCalled = true; disconnectedCallbackCalled = true;
};
p.detachedCallback = function() {
is(attachedCallbackCalled, true, "attached callback should be called before detached");
is(detachedCallbackCalled, false, "detached callback should only be called once in this test.");
is(this, createdElement, "The 'this' value should be the custom element.");
detachedCallbackCalled = true;
runNextTest(); runNextTest();
}; };
@ -206,10 +180,8 @@ function testRegisterResolved() {
}; };
document.registerElement("x-resolved", { prototype: p }); document.registerElement("x-resolved", { prototype: p });
is(createdCallbackCalled, false, "Created callback should not be called when custom element instance has not been created.");
var createdElement = document.createElement("x-resolved"); var createdElement = document.createElement("x-resolved");
is(createdCallbackThis, createdElement, "The 'this' value in the created callback should be the custom element.");
is(createdElement.__proto__, p, "Prototype of custom element should be the registered prototype."); is(createdElement.__proto__, p, "Prototype of custom element should be the registered prototype.");
// Insert element into document to trigger attached callback. // Insert element into document to trigger attached callback.
@ -221,37 +193,33 @@ function testRegisterResolved() {
// Callbacks should always be the same ones when registered. // Callbacks should always be the same ones when registered.
function testChangingCallback() { function testChangingCallback() {
var p = Object.create(HTMLElement.prototype);
var callbackCalled = false; var callbackCalled = false;
p.attributeChangedCallback = function(name, oldValue, newValue) {
is(callbackCalled, false, "Callback should only be called once in this test.");
callbackCalled = true;
runNextTest();
};
document.registerElement("x-test-callback", { prototype: p }); class TestCallback extends HTMLElement
{
attributeChangedCallback(aName, aOldValue, aNewValue) {
is(callbackCalled, false, "Callback should only be called once in this test.");
callbackCalled = true;
runNextTest();
}
p.attributeChangedCallback = function(name, oldValue, newValue) { static get observedAttributes() {
return ["data-foo"];
}
}
customElements.define("x-test-callback", TestCallback);
TestCallback.prototype.attributeChangedCallback = function(name, oldValue, newValue) {
ok(false, "Only callbacks at registration should be called."); ok(false, "Only callbacks at registration should be called.");
}; };
var elem = document.createElement("x-test-callback"); var elem = document.createElement("x-test-callback");
elem.setAttribute("foo", "bar"); elem.setAttribute("data-foo", "bar");
} }
function testAttributeChanged() { function testAttributeChanged() {
var createdCallbackCalled = false;
var createdElement; var createdElement;
var createdCallbackThis;
var p = Object.create(HTMLElement.prototype);
p.createdCallback = function() {
is(createdCallbackCalled, false, "Created callback should only be called once in this test.");
createdCallbackThis = this;
createdCallbackCalled = true;
};
// Sequence of callback arguments that we expect from attribute changed callback // Sequence of callback arguments that we expect from attribute changed callback
// after changing attributes values in a specific order. // after changing attributes values in a specific order.
var expectedCallbackArguments = [ var expectedCallbackArguments = [
@ -262,27 +230,32 @@ function testAttributeChanged() {
["", null], // Removing the attribute. ["", null], // Removing the attribute.
]; ];
p.attributeChangedCallback = function(name, oldValue, newValue) { class AttrChange extends HTMLElement
is(createdCallbackCalled, true, "created callback should be called before attribute changed."); {
is(this, createdElement, "The 'this' value should be the custom element."); attributeChangedCallback(name, oldValue, newValue) {
ok(expectedCallbackArguments.length > 0, "Attribute changed callback should not be called more than expected."); is(this, createdElement, "The 'this' value should be the custom element.");
ok(expectedCallbackArguments.length > 0, "Attribute changed callback should not be called more than expected.");
is(name, "changeme", "name arugment in attribute changed callback should be the name of the changed attribute."); is(name, "changeme", "name arugment in attribute changed callback should be the name of the changed attribute.");
var expectedArgs = expectedCallbackArguments.shift(); var expectedArgs = expectedCallbackArguments.shift();
is(oldValue, expectedArgs[0], "The old value argument should match the expected value."); is(oldValue, expectedArgs[0], "The old value argument should match the expected value.");
is(newValue, expectedArgs[1], "The new value argument should match the expected value."); is(newValue, expectedArgs[1], "The new value argument should match the expected value.");
if (expectedCallbackArguments.length === 0) { if (expectedCallbackArguments.length === 0) {
// Done with the attribute changed callback test. // Done with the attribute changed callback test.
runNextTest(); runNextTest();
}
} }
};
document.registerElement("x-attrchange", { prototype: p }); static get observedAttributes() {
return ["changeme"];
}
}
var createdElement = document.createElement("x-attrchange"); customElements.define("x-attrchange", AttrChange);
is(createdCallbackThis, createdElement, "The 'this' value in the created callback should be the custom element.");
createdElement = document.createElement("x-attrchange");
createdElement.setAttribute("changeme", "newvalue"); createdElement.setAttribute("changeme", "newvalue");
createdElement.setAttribute("changeme", "nextvalue"); createdElement.setAttribute("changeme", "nextvalue");
createdElement.setAttribute("changeme", ""); createdElement.setAttribute("changeme", "");
@ -290,18 +263,23 @@ function testAttributeChanged() {
} }
function testAttributeChangedExtended() { function testAttributeChangedExtended() {
var p = Object.create(HTMLButtonElement.prototype); var callbackCalled = false;
var callbackCalled = 0;
p.attributeChangedCallback = function(name, oldValue, newValue) { class ExtnededAttributeChange extends HTMLButtonElement
callbackCalled++; {
if (callbackCalled > 2) { attributeChangedCallback(name, oldValue, newValue) {
is(false, "Got unexpected attribute changed callback."); is(callbackCalled, false, "Callback should only be called once in this test.");
} else if (callbackCalled === 2) { callbackCalled = true;
runNextTest(); runNextTest();
} }
};
document.registerElement("x-extended-attribute-change", { prototype: p, extends: "button" }); static get observedAttributes() {
return ["foo"];
}
}
customElements.define("x-extended-attribute-change", ExtnededAttributeChange,
{ extends: "button" });
var elem = document.createElement("button", {is: "x-extended-attribute-change"}); var elem = document.createElement("button", {is: "x-extended-attribute-change"});
elem.setAttribute("foo", "bar"); elem.setAttribute("foo", "bar");
@ -346,19 +324,19 @@ function testNotInDocEnterLeave() {
} }
function testEnterLeaveView() { function testEnterLeaveView() {
var attachedCallbackCalled = false; var connectedCallbackCalled = false;
var detachedCallbackCalled = false; var disconnectedCallbackCalled = false;
var p = Object.create(HTMLElement.prototype); var p = Object.create(HTMLElement.prototype);
p.attachedCallback = function() { p.connectedCallback = function() {
is(attachedCallbackCalled, false, "attached callback should only be called on in this test."); is(connectedCallbackCalled, false, "Connected callback should only be called on in this test.");
attachedCallbackCalled = true; connectedCallbackCalled = true;
}; };
p.detachedCallback = function() { p.disconnectedCallback = function() {
is(attachedCallbackCalled, true, "attached callback should be called before detached"); is(connectedCallbackCalled, true, "Connected callback should be called before detached");
is(detachedCallbackCalled, false, "detached callback should only be called once in this test."); is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
detachedCallbackCalled = true; disconnectedCallbackCalled = true;
runNextTest(); runNextTest();
}; };
@ -366,7 +344,7 @@ function testEnterLeaveView() {
document.registerElement("x-element-in-div", { prototype: p }); document.registerElement("x-element-in-div", { prototype: p });
var customElement = document.createElement("x-element-in-div"); var customElement = document.createElement("x-element-in-div");
div.appendChild(customElement); div.appendChild(customElement);
is(attachedCallbackCalled, false, "Appending a custom element to a node that is not in the document should not call the attached callback."); is(connectedCallbackCalled, false, "Appending a custom element to a node that is not in the document should not call the connected callback.");
container.appendChild(div); container.appendChild(div);
container.removeChild(div); container.removeChild(div);
@ -392,6 +370,7 @@ var testFunctions = [
function runNextTest() { function runNextTest() {
if (testFunctions.length > 0) { if (testFunctions.length > 0) {
var nextTestFunction = testFunctions.shift(); var nextTestFunction = testFunctions.shift();
info(`Start ${nextTestFunction.name} ...`);
nextTestFunction(); nextTestFunction();
} }
} }

Просмотреть файл

@ -0,0 +1,137 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
-->
<head>
<title>Test for document.registerElement lifecycle callback</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
<div id="container">
</div>
<script>
var container = document.getElementById("container");
function testChangeAttributeInEnteredViewCallback() {
var attributeChangedCallbackCalled = false;
var connectedCallbackCalled = false;
class Two extends HTMLElement
{
connectedCallback() {
is(connectedCallbackCalled, false, "Connected callback should be called only once in this test.");
connectedCallbackCalled = true;
is(attributeChangedCallbackCalled, false, "Attribute changed callback should not be called before changing attribute.");
this.setAttribute("foo", "bar");
is(attributeChangedCallbackCalled, true, "Transition from user-agent implementation to script should result in attribute changed callback being called.");
runNextTest();
}
attributeChangedCallback() {
is(connectedCallbackCalled, true, "Connected callback should have been called prior to attribute changed callback.");
is(attributeChangedCallbackCalled, false, "Attribute changed callback should only be called once in this tests.");
attributeChangedCallbackCalled = true;
}
static get observedAttributes() {
return ["foo"];
}
}
customElements.define("x-two", Two);
var elem = document.createElement("x-two");
var container = document.getElementById("container");
container.appendChild(elem);
}
function testLeaveViewInEnteredViewCallback() {
var p = Object.create(HTMLElement.prototype);
var connectedCallbackCalled = false;
var disconnectedCallbackCalled = false;
var container = document.getElementById("container");
p.connectedCallback = function() {
is(this.parentNode, container, "Parent node should the container in which the node was appended.");
is(connectedCallbackCalled, false, "Connected callback should be called only once in this test.");
connectedCallbackCalled = true;
is(disconnectedCallbackCalled, false, "Disconnected callback should not be called prior to removing element from document.");
container.removeChild(this);
is(disconnectedCallbackCalled, true, "Transition from user-agent implementation to script should run left view callback.");
runNextTest();
};
p.disconnectedCallback = function() {
is(disconnectedCallbackCalled, false, "The disconnected callback should only be called once in this test.");
is(connectedCallbackCalled, true, "The connected callback should be called prior to disconnected callback.");
disconnectedCallbackCalled = true;
};
document.registerElement("x-three", { prototype: p });
var elem = document.createElement("x-three");
container.appendChild(elem);
}
function testStackedAttributeChangedCallback() {
var attributeChangedCallbackCount = 0;
var attributeSequence = ["foo", "bar", "baz"];
class Four extends HTMLElement
{
attributeChangedCallback(attrName, oldValue, newValue) {
if (newValue == "baz") {
return;
}
var nextAttribute = attributeSequence.shift();
ok(true, nextAttribute);
// Setting this attribute will call this function again, when
// control returns to the script, the last attribute in the sequence should
// be set on the element.
this.setAttribute("foo", nextAttribute);
is(this.getAttribute("foo"), "baz", "The last value in the sequence should be the value of the attribute.");
attributeChangedCallbackCount++;
if (attributeChangedCallbackCount == 3) {
runNextTest();
}
}
static get observedAttributes() {
return ["foo"];
}
}
customElements.define("x-four", Four);
var elem = document.createElement("x-four");
elem.setAttribute("foo", "changeme");
}
var testFunctions = [
testChangeAttributeInEnteredViewCallback,
testLeaveViewInEnteredViewCallback,
testStackedAttributeChangedCallback,
SimpleTest.finish
];
function runNextTest() {
if (testFunctions.length > 0) {
var nextTestFunction = testFunctions.shift();
info(`Start ${nextTestFunction.name} ...`);
nextTestFunction();
}
}
SimpleTest.waitForExplicitFinish();
runNextTest();
</script>
</body>
</html>

Просмотреть файл

@ -1,152 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
-->
<head>
<title>Test for document.registerElement lifecycle callback</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
<div id="container">
</div>
<script>
var container = document.getElementById("container");
// Test changing attributes in the created callback on an element
// created after registration.
function testChangeAttributeInCreatedCallback() {
var createdCallbackCalled = false;
var attributeChangedCallbackCalled = false;
var p = Object.create(HTMLElement.prototype);
p.createdCallback = function() {
is(createdCallbackCalled, false, "Created callback should be called before attached callback.");
createdCallbackCalled = true;
is(attributeChangedCallbackCalled, false, "Attribute changed callback should not have been called prior to setting the attribute.");
this.setAttribute("foo", "bar");
is(attributeChangedCallbackCalled, true, "While element is being created, element should be added to the current element callback queue.");
runNextTest();
};
p.attributeChangedCallback = function(name, oldValue, newValue) {
is(createdCallbackCalled, true, "attributeChanged callback should be called after the created callback because it was enqueued during created callback.");
is(attributeChangedCallbackCalled, false, "attributeChanged callback should only be called once in this tests.");
is(newValue, "bar", "The new value should be 'bar'");
attributeChangedCallbackCalled = true;
};
document.registerElement("x-one", { prototype: p });
document.createElement("x-one");
}
function testChangeAttributeInEnteredViewCallback() {
var p = Object.create(HTMLElement.prototype);
var attributeChangedCallbackCalled = false;
var attachedCallbackCalled = false;
p.attachedCallback = function() {
is(attachedCallbackCalled, false, "attached callback should be called only once in this test.");
attachedCallbackCalled = true;
is(attributeChangedCallbackCalled, false, "Attribute changed callback should not be called before changing attribute.");
this.setAttribute("foo", "bar");
is(attributeChangedCallbackCalled, true, "Transition from user-agent implementation to script should result in attribute changed callback being called.");
runNextTest();
};
p.attributeChangedCallback = function() {
is(attachedCallbackCalled, true, "attached callback should have been called prior to attribute changed callback.");
is(attributeChangedCallbackCalled, false, "attributeChanged callback should only be called once in this tests.");
attributeChangedCallbackCalled = true;
};
document.registerElement("x-two", { prototype: p });
var elem = document.createElement("x-two");
var container = document.getElementById("container");
container.appendChild(elem);
}
function testLeaveViewInEnteredViewCallback() {
var p = Object.create(HTMLElement.prototype);
var attachedCallbackCalled = false;
var detachedCallbackCalled = false;
var container = document.getElementById("container");
p.attachedCallback = function() {
is(this.parentNode, container, "Parent node should the container in which the node was appended.");
is(attachedCallbackCalled, false, "attached callback should be called only once in this test.");
attachedCallbackCalled = true;
is(detachedCallbackCalled, false, "detached callback should not be called prior to removing element from document.");
container.removeChild(this);
is(detachedCallbackCalled, true, "Transition from user-agent implementation to script should run left view callback.");
runNextTest();
};
p.detachedCallback = function() {
is(detachedCallbackCalled, false, "The detached callback should only be called once in this test.");
is(attachedCallbackCalled, true, "The attached callback should be called prior to detached callback.");
detachedCallbackCalled = true;
};
document.registerElement("x-three", { prototype: p });
var elem = document.createElement("x-three");
container.appendChild(elem);
}
function testStackedAttributeChangedCallback() {
var p = Object.create(HTMLElement.prototype);
var attributeChangedCallbackCount = 0;
var attributeSequence = ["foo", "bar", "baz"];
p.attributeChangedCallback = function(attrName, oldValue, newValue) {
if (newValue == "baz") {
return;
}
var nextAttribute = attributeSequence.shift();
ok(true, nextAttribute);
// Setting this attribute will call this function again, when
// control returns to the script, the last attribute in the sequence should
// be set on the element.
this.setAttribute("foo", nextAttribute);
is(this.getAttribute("foo"), "baz", "The last value in the sequence should be the value of the attribute.");
attributeChangedCallbackCount++;
if (attributeChangedCallbackCount == 3) {
runNextTest();
}
};
document.registerElement("x-four", { prototype: p });
var elem = document.createElement("x-four");
elem.setAttribute("foo", "changeme");
}
var testFunctions = [
testChangeAttributeInCreatedCallback,
testChangeAttributeInEnteredViewCallback,
testLeaveViewInEnteredViewCallback,
testStackedAttributeChangedCallback,
SimpleTest.finish
];
function runNextTest() {
if (testFunctions.length > 0) {
var nextTestFunction = testFunctions.shift();
nextTestFunction();
}
}
SimpleTest.waitForExplicitFinish();
runNextTest();
</script>
</body>
</html>