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

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

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

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

@ -16,97 +16,90 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1087460
// Test callback for custom element when used after registration.
var createdCallbackCount = 0;
var attachedCallbackCount = 0;
var detachedCallbackCount = 0;
var connectedCallbackCount = 0;
var disconnectedCallbackCount = 0;
var attributeChangedCallbackCount = 0;
var p1 = Object.create(HTMLElement.prototype);
class Foo extends HTMLElement
{
connectedCallback() {
connectedCallbackCount++;
}
p1.createdCallback = function() {
createdCallbackCount++;
};
disconnectedCallback() {
disconnectedCallbackCount++;
}
p1.attachedCallback = function() {
attachedCallbackCount++;
};
attributeChangedCallback(aName, aOldValue, aNewValue) {
attributeChangedCallbackCount++;
}
p1.detachedCallback = function() {
detachedCallbackCount++;
};
static get observedAttributes() {
return ["data-foo"];
}
}
p1.attributeChangedCallback = function(name, oldValue, newValue) {
attributeChangedCallbackCount++;
};
document.registerElement("x-foo", { prototype: p1 });
customElements.define("x-foo", Foo);
var container = document.getElementById("container");
var shadow = container.createShadowRoot();
is(createdCallbackCount, 0, "createdCallback should not be called more than once in this test.");
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.");
customElem.setAttribute("data-foo", "bar");
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);
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);
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.
createdCallbackCount = 0;
attachedCallbackCount = 0;
detachedCallbackCount = 0;
connectedCallbackCount = 0;
disconnectedCallbackCount = 0;
attributeChangedCallbackCount = 0;
shadow.innerHTML = "<x-foo></x-foo>";
is(createdCallbackCount, 1, "createdCallback should be called after creating a custom element.");
is(attachedCallbackCount, 1, "attachedCallback should be called after creating an element in the composed document.");
is(connectedCallbackCount, 1, "connectedCallback should be called after creating an element in the composed document.");
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.
createdCallbackCount = 0;
attachedCallbackCount = 0;
detachedCallbackCount = 0;
connectedCallbackCount = 0;
disconnectedCallbackCount = 0;
attributeChangedCallbackCount = 0;
var host = document.createElement("div");
shadow = host.createShadowRoot();
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);
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);
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);
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);
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);
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.
createdCallbackCount = 0;
attachedCallbackCount = 0;
detachedCallbackCount = 0;
connectedCallbackCount = 0;
disconnectedCallbackCount = 0;
attributeChangedCallbackCount = 0;
shadow = container.shadowRoot;
@ -114,17 +107,12 @@ shadow.innerHTML = "<x-bar></x-bar>";
var p2 = Object.create(HTMLElement.prototype);
p2.createdCallback = function() {
createdCallbackCount++;
};
p2.attachedCallback = function() {
attachedCallbackCount++;
p2.connectedCallback = function() {
connectedCallbackCount++;
};
document.registerElement("x-bar", { prototype: p2 });
is(createdCallbackCount, 1, "createdCallback should be called after registering element.");
is(attachedCallbackCount, 1, "attachedCallback should be called after upgrading element in composed document.");
is(connectedCallbackCount, 1, "connectedCallback should be called after upgrading element in composed document.");
</script>

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

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