Update web-platform-tests to revision 0d318188757a9c996e20b82db201fd04de5aa255

This commit is contained in:
James Graham 2015-03-27 09:15:38 +00:00
parent b2a5225831
commit 1a81b18b9f
12321 changed files with 544385 additions and 6 deletions

View file

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html>
<head>
<title>Invoke CALLBACK with ELEMENT as callback this value</title>
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
<meta name="assert" content="Invoke CALLBACK with ELEMENT as callback this value">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#enqueuing-and-invoking-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-a', {prototype: proto});
var customElement = new GeneratedConstructor();
doc.body.innerHTML = '<x-a id="x-a"></x-a>';
assert_equals(doc.querySelector('#x-a'), proto.createdCallbackThis,
'\'this\' value of the created callback should be the custom element');
}, 'Test \'this\' value inside created callback.');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
assert_equals(doc.querySelector('#x-element'), proto.attachedCallbackThis,
'\'this\' value of the attached callback should be the custom element');
}, 'Test \'this\' value inside attached callback.');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
doc.body.removeChild(customElement);
assert_equals(customElement, proto.detachedCallbackThis,
'\'this\' value of the detached callback should be the custom element');
}, 'Test \'this\' value inside detached callback.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-b', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass');
assert_equals(customElement, proto.attributeChangedCallbackThis,
'\'this\' value of the attributeChanged callback should be the custom element');
}, 'Test \'this\' value inside attributeChanged callback.');
</script>
</body>
</html>

View file

@ -0,0 +1,160 @@
<!DOCTYPE html>
<html>
<head>
<title>Attached callback of a custom element should be called if element is moved</title>
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="assert" content="attached callback ... must be enqueued whenever custom element is inserted into a document and this document has a browsing context.">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-a', {prototype: proto});
var customElement = doc.createElement('x-a');
doc.body.appendChild(customElement);
assert_equals(proto.attachedCallbackCalledCounter, 0, 'Callback attached ' +
'should not be called in documents that do not have a browsing context');
var divElement = doc.createElement('div');
doc.body.appendChild(divElement);
divElement.appendChild(customElement);
assert_equals(proto.attachedCallbackCalledCounter, 0, 'Callback attached ' +
'should not be called in documents that do not have a browsing context');
}, 'Test attached callback if moving custom element inside document ' +
'without browsing context');
testInIFrame('../../resources/blank.html', function(docWithBrowsingContext) {
var docNoBrowsingContext = newHTMLDocument();
var proto1 = newHTMLElementPrototype();
docNoBrowsingContext.registerElement('x-b', {prototype: proto1});
var customElement = docNoBrowsingContext.createElement('x-b');
docNoBrowsingContext.body.appendChild(customElement);
assert_equals(proto1.attachedCallbackCalledCounter, 0,
'Callback attached should not be called ' +
'in documents that do not have a browsing context');
var proto2 = newHTMLElementPrototype();
docWithBrowsingContext.registerElement('x-b', {prototype: proto2});
docWithBrowsingContext.body.appendChild(customElement);
assert_equals(proto1.attachedCallbackCalledCounter, 1,
'Callback attached should be called in documents with browsing context');
assert_equals(proto2.attachedCallbackCalledCounter, 0,
'Callback attached, defined in receiving document, should not be called');
}, 'Test attached callback if moving custom element from ' +
'document without browsing context to document with browsing context');
testInIFrame('../../resources/blank.html', function(docWithBrowsingContext) {
var proto1 = newHTMLElementPrototype();
docWithBrowsingContext.registerElement('x-c', {prototype: proto1});
var customElement = docWithBrowsingContext.createElement('x-c');
docWithBrowsingContext.body.appendChild(customElement);
assert_equals(proto1.attachedCallbackCalledCounter, 1,
'Callback attached should be called in documents with browsing context');
var docNoBrowsingContext = newHTMLDocument();
var proto2 = newHTMLElementPrototype();
docNoBrowsingContext.registerElement('x-c', {prototype: proto2});
docNoBrowsingContext.body.appendChild(customElement);
assert_equals(proto1.attachedCallbackCalledCounter, 1, 'Callback attached should not be called ' +
'in documents that do not have a browsing context');
assert_equals(proto2.attachedCallbackCalledCounter, 0,
'Callback attached, defined in receiving document, should not be called');
}, 'Test attached callback if moving custom element from ' +
'document with browsing context to document without browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-d', {prototype: proto});
var customElement = doc.createElement('x-d');
doc.body.appendChild(customElement);
assert_equals(proto.attachedCallbackCalledCounter, 1,
'Callback attached should be called in documents with browsing context');
var divElement = doc.createElement('div');
doc.body.appendChild(divElement);
divElement.appendChild(customElement);
assert_equals(proto.attachedCallbackCalledCounter, 2,
'Callback attached should be called in documents with browsing context');
}, 'Test attached callback if moving custom element inside document ' +
'with browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-e', {prototype: proto});
var customElement = doc.createElement('x-e');
doc.body.appendChild(customElement);
assert_equals(proto.attachedCallbackCalledCounter, 1,
'Callback attached should be called in documents with browsing context');
var divElement = doc.createElement('div');
divElement.appendChild(customElement);
assert_equals(proto.attachedCallbackCalledCounter, 1,
'Callback attached should not be called if element is not appended to the document');
doc.body.appendChild(divElement);
assert_equals(proto.attachedCallbackCalledCounter, 2,
'Callback attached should be called in documents with browsing context');
}, 'Test attached callback if indirectly moving custom element inside document ' +
'with browsing context');
var moveTest = async_test('Test attached callback if moving custom element from ' +
'document with browsing context to document with browsing context');
moveTest.step(function() {
var iframe1 = newIFrame('../../resources/blank.html');
iframe1.onload = moveTest.step_func(function() {
var doc1 = iframe1.contentDocument;
// register custom element type
var proto1 = newHTMLElementPrototype();
doc1.registerElement('x-f', {prototype: proto1});
// create custom element
var customElement = doc1.createElement('x-f');
doc1.body.appendChild(customElement);
assert_equals(proto1.attachedCallbackCalledCounter, 1,
'Callback attached should be called in documents with browsing context');
// create second iframe
var iframe2 = newIFrame('../../resources/x-element.html');
iframe2.onload = moveTest.step_func(function() {
var doc2 = iframe2.contentDocument;
// register custom element type
var proto2 = newHTMLElementPrototype();
doc2.registerElement('x-f', {prototype: proto2});
// move element
doc2.body.appendChild(customElement);
assert_equals(proto1.attachedCallbackCalledCounter, 2,
'Callback attached should be called in documents with browsing context');
assert_equals(proto2.attachedCallbackCalledCounter, 0,
'Callback attached, defined in receiving document, should not be called');
// test clean up
iframe1.remove();
iframe2.remove();
moveTest.done();
});
});
});
</script>
</body>
</html>

View file

@ -0,0 +1,117 @@
<!DOCTYPE html>
<html>
<head>
<title>Attached callback of a custom element should be called </title>
<meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
<meta name="assert" content="attached callback ... must be enqueued whenever custom element is inserted into a document and this document has a browsing context.">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-a', {prototype: proto});
var customElement = new GeneratedConstructor();
assert_equals(proto.attachedCallbackCalledCounter, 0, 'Callback attached ' +
'should not be called in documents that do not have a browsing context');
}, 'Test attached callback if custom element is instantiated via constructor. ' +
'Document has no browsing context');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-b', {prototype: proto});
doc.body.innerHTML = '<x-b></x-b>';
assert_equals(proto.attachedCallbackCalledCounter, 0, 'Callback attached ' +
'should not be called in documents that do not have a browsing context');
}, 'Test attached callback if custom element is created via innerHTML property. ' +
'Document has no browsing context');
test(function() {
var doc = newHTMLDocument();
doc.body.innerHTML = '<x-c></x-c>';
var proto = newHTMLElementPrototype();
doc.registerElement('x-c', {prototype: proto});
assert_equals(proto.attachedCallbackCalledCounter, 0, 'Callback attached ' +
'should not be called in documents that do not have a browsing context');
}, 'Test attached callback if custom element is created via innerHTML property before ' +
'registration. Document has no browsing context');
test(function() {
var doc = newHTMLDocument();
doc.body.innerHTML = '<x-d id="x-d"></x-d>';
var customElement = doc.querySelector('#x-d');
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-d', {prototype: proto});
customElement.constructor.prototype = proto;
assert_equals(proto.attachedCallbackCalledCounter, 0, 'Callback attached should ' +
'not be called for unregistered custom element in document without browsing context');
}, 'Test attached callback if custom element is unregistered');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
assert_equals(proto.attachedCallbackCalledCounter, 1, 'Callback attached should be ' +
'called in documents with browsing context');
}, 'Test attached callback. Document has browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var x = doc.createElement('x-element');
assert_equals(proto.attachedCallbackCalledCounter, 0, 'Callback attached should not ' +
'be called before element is added to document with browsing context');
doc.body.appendChild(x);
assert_equals(proto.attachedCallbackCalledCounter, 1, 'Callback attached should be called ' +
'in documents with browsing context');
}, 'Test attached callback. Registered element is created via document.createElement(). ' +
'Document has browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
var x = doc.createElement('x-element');
doc.body.appendChild(x);
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
assert_equals(proto.attachedCallbackCalledCounter, 1, 'Callback attached should ' +
'be called in documents with browsing context');
}, 'Test attached callback. Unregistered element is created via document.createElement(). ' +
'Document has browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
doc.body.innerHTML = '<x-element></x-element>';
assert_equals(proto.attachedCallbackCalledCounter, 1, 'Callback attached should ' +
'be called in documents with browsing context');
}, 'Test attached callback. Registered element is created via innerHTML property. ' +
'Document has browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
doc.body.innerHTML = '<x-element></x-element>';
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
assert_equals(proto.attachedCallbackCalledCounter, 1, 'Callback attached should ' +
'be called in documents with browsing context');
}, 'Test attached callback. Unresolved element is created via innerHTML property. ' +
'Document has browsing context');
</script>
</body>
</html>

View file

@ -0,0 +1,230 @@
<!DOCTYPE html>
<html>
<head>
<title>Test attributeChanged callback is called if custom element attribute value is changed</title>
<meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="assert" content="attributeChanged callback must be enqueued whenever custom element's attribute is added, changed or removed">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-a', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass');
proto.attributeChangedCallbackCalledCounter = 0;
customElement.setAttribute('class', 'someClass2');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is changed by method ' +
'setAttribute(). The custom element is created via constructor');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-b', {prototype: proto});
doc.body.innerHTML = '<x-b id="x-b" class="oldValue"></x-b>';
var customElement = doc.querySelector('#x-b');
customElement.setAttribute('class', 'newValue');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'oldValue', 'newValue'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is changed by method ' +
'setAttribute(). The custom element is created via innerHTML property');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-c', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass');
proto.attributeChangedCallbackCalledCounter = 0;
customElement.classList.add('someClass3');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is changed by method ' +
'classList.add(). The custom element is created via constructor');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-d', {prototype: proto});
doc.body.innerHTML = '<x-d id="x-d" class="oldValue"></x-d>';
var customElement = doc.querySelector('#x-d');
customElement.classList.add('newestValue');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'oldValue', 'oldValue newestValue'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is changed by method ' +
'classList.add(). The custom element is created via innerHTML property');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-e', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass');
proto.attributeChangedCallbackCalledCounter = 0;
customElement.id = 'someId';
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is changed as property. ' +
'The custom element is created via constructor');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-f', {prototype: proto});
doc.body.innerHTML = '<x-f id="x-f" class="oldValue"></x-f>';
var customElement = doc.querySelector('#x-f');
customElement.className = 'lastValue';
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'oldValue', 'lastValue'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is changed as property. ' +
'The custom element is created via innerHTML property');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-g', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass someSuperClass');
proto.attributeChangedCallbackCalledCounter = 0;
customElement.classList.toggle('someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is changed by classList.toggle(). ' +
'The custom element is created via constructor');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-h', {prototype: proto});
doc.body.innerHTML = '<x-h id="x-h" class="oldValue lastValue"></x-h>';
var customElement = doc.querySelector('#x-h');
customElement.classList.toggle('lastValue');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'oldValue lastValue', 'oldValue'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is changed by classList.toggle(). ' +
'The custom element is created via innerHTML property');
test(function() {
var doc = newHTMLDocument();
doc.body.innerHTML = '<x-i id="x-i" class="oldValue"></x-i>';
var customElement = doc.querySelector('#x-i');
customElement.setAttribute('class', 'newValue');
customElement.setAttribute('class', 'newestValue');
var proto = newHTMLElementPrototype();
doc.registerElement('x-i', {prototype: proto});
assert_equals(proto.attributeChangedCallbackCalledCounter, 0,
'Callback attributeChanged should not be called');
customElement.setAttribute('class', 'rightValue');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should not be called');
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'newestValue', 'rightValue'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback is not called if custom element is not registered');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
customElement.setAttribute('class', 'firstValue');
customElement.setAttribute('class', 'secondValue');
assert_equals(proto.attributeChangedCallbackCalledCounter, 2, 'Callback ' +
'attributeChanged should be called after call to setAttribute()');
customElement.classList.add('someClass3');
assert_equals(proto.attributeChangedCallbackCalledCounter, 3, 'Callback ' +
'attributeChanged should be called after call to classList.add()');
customElement.id = 'someId';
assert_equals(proto.attributeChangedCallbackCalledCounter, 4, 'Callback ' +
'attributeChanged should be called after changing attribute as property');
}, 'Test attributeChanged callback is called if attribute value is changed. ' +
'The document has browsing context');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
customElement.setAttribute('class', 'firstValue');
customElement.setAttribute('class', 'secondValue');
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'firstValue', 'secondValue'],
'Unexpected callback attributeChanged arguments after call to setAttribute()');
customElement.classList.add('newestValue');
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'secondValue', 'secondValue newestValue'],
'Unexpected callback attributeChanged arguments after call to classList.add()');
customElement.className = 'lastValue';
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'secondValue newestValue', 'lastValue'],
'Unexpected callback attributeChanged arguments after changing attribute as property');
}, 'Test attributeChanged callback arguments if attribute value is changed. ' +
'The document has browsing context');
testInIFrame('../../resources/x-element.html', function(doc) {
var customElement = doc.querySelector('#x-element');
customElement.setAttribute('class', 'firstValue');
customElement.setAttribute('class', 'secondValue');
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
customElement.setAttribute('class', 'thirdValue');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'secondValue', 'thirdValue'],
'Unexpected callback attributeChanged arguments after setAttribute() call');
}, 'Test attributeChanged callback is not called if custom element is not registered. ' +
'The document has browsing context');
</script>
</body>
</html>

View file

@ -0,0 +1,167 @@
<!DOCTYPE html>
<html>
<head>
<title>Test attribute removing to check attributeChanged callback of a custom element</title>
<meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
<meta name="assert" content="attributeChanged callback must be enqueued whenever custom element's attribute is removed">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-a', {prototype: proto});
var customElement = new GeneratedConstructor();
//attributeChangedCallback should be called the first time here
customElement.setAttribute('class', 'someClass');
//attributeChangedCallback should be called the second time here
customElement.removeAttribute('class');
assert_equals(proto.attributeChangedCallbackCalledCounter, 2, 'Callback attributeChanged should be called ' +
'after setAttribute() and removeAttribute() calls');
}, 'Test attributeChanged callback if attribute is removed. ' +
'The custom element created via constructor');
test(function() {
var doc = newHTMLDocument();
HTML5_ELEMENTS.forEach(function(element) {
var obj = doc.createElement(element);
var proto = newCustomElementPrototype(obj.constructor.prototype);
var GeneratedConstructor = doc.registerElement('x-' + element + '-' + element + '-1', {
prototype: proto,
extends: element
});
var customElement = new GeneratedConstructor();
//attributeChangedCallback should be called the first time here
customElement.setAttribute('class', 'someClass');
//attributeChangedCallback should be called the second time here
customElement.removeAttribute('class');
assert_equals(proto.attributeChangedCallbackCalledCounter, 2,
'Callback attributeChanged should be called ' +
'after setAttribute() and removeAttribute() calls for "' + element + '"');
});
}, 'Test attributeChanged callback if attribute is removed. ' +
'The custom element created via constructor and extends HTML element');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-b', {prototype: proto});
doc.body.innerHTML = '<x-b id="x-b" class="theClass"></x-b>';
var customElement = doc.querySelector('#x-b');
customElement.removeAttribute('class');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called ' +
'after removeAttribute() call');
}, 'Test attributeChanged callback if attribute is removed. ' +
'The custom element created via innerHTML property');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-c', {prototype: proto});
doc.body.innerHTML = '<x-c id="x-c" class="theClass"></x-c>';
var customElement = doc.querySelector('#x-c');
customElement.removeAttribute('class');
assert_equals(proto.attributeChangedCallbackArgs[2], null,
'Removing an attribute should invoke ' +
'the attributeChanged callback with a null new value');
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'theClass', null],
'Unexpected attributeChanged callback arguments');
}, 'Test attributeChanged callback arguments if attribute is removed. ' +
'The custom element created via innerHTML property');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.body.innerHTML = '<x-d id="x-d" class="theClass"></x-d>';
var customElement = doc.querySelector('#x-d');
// this should not call or enqueue attributeChangedCallback
customElement.setAttribute('class', 'someClass');
// this one should not too
customElement.removeAttribute('class');
assert_equals(proto.attributeChangedCallbackCalledCounter, 0,
'Callback attributeChanged should not be called');
doc.registerElement('x-d', {prototype: proto});
// this call invokes attributeChangedCallback
customElement.setAttribute('name', 'someName');
// and this one
customElement.removeAttribute('name');
assert_equals(proto.attributeChangedCallbackCalledCounter, 2,
'Callback attributeChanged should be called ' +
'after setAttribute() and removeAttribute() calls');
}, 'Test attributeChanged callback is not called if attribute is removed. ' +
'The custom element created via innerHTML property and unresolved at first');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
customElement.setAttribute('class', 'someClass');
customElement.removeAttribute('class');
assert_equals(proto.attributeChangedCallbackCalledCounter, 2,
'Callback attributeChanged should be called ' +
'after setAttribute() and removeAttribute() calls');
}, 'Test attributeChanged callback is called if attribute is removed. ' +
'The custom element created via constructor and the document has browsing context');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
doc.body.innerHTML = '<x-element id="x-element" class="theClass"></x-element>';
var customElement = doc.querySelector('#x-element');
customElement.removeAttribute('class');
assert_equals(proto.attributeChangedCallbackArgs[2], null,
'Removing an attribute should invoke ' +
'the attributeChanged callback with a null new value');
assert_array_equals(proto.attributeChangedCallbackArgs,
['class', 'theClass', null],
'Unexpected attributeChanged callback arguments');
}, 'Test attributeChanged callback arguments if attribute is removed. ' +
'The custom element created via innerHTML property and the document has browsing context');
testInIFrame('../../resources/x-element.html', function(doc) {
var customElement = doc.querySelector('#x-element');
// this should not call or enqueue attributeChangedCallback
customElement.setAttribute('name', 'someName');
// this one too
customElement.removeAttribute('name');
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
assert_equals(proto.attributeChangedCallbackCalledCounter, 0,
'Callback attributeChanged should not be called');
// this call invokes attributeChangedCallback
customElement.setAttribute('class', 'someClass');
// this call invokes attributeChangedCallback at second time
customElement.removeAttribute('class');
assert_equals(proto.attributeChangedCallbackCalledCounter, 2,
'Callback attributeChanged should be called ' +
'after setAttribute() and removeAttribute() calls');
}, 'Test attributeChanged callback if attribute is removed. ' +
'The custom element created via innerHTML property and unresolved at first. ' +
'The document has browsing context');
</script>
</body>
</html>

View file

@ -0,0 +1,339 @@
<!DOCTYPE html>
<html>
<head>
<title>Test attributeChanged callback is called if custom element attribute value is set</title>
<meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="assert" content="attributeChanged callback ... must be enqueued whenever custom element's attribute is added, changed or removed.">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-a', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is set by method ' +
'setAttribute(). The custom element is created via constructor.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-b', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass');
assert_array_equals(proto.attributeChangedCallbackArgs, ['class', null, 'someClass'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is set by method ' +
'setAttribute(). The custom element is created via constructor.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-c', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.classList.add('someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is set by method ' +
'classList.add(). The custom element is created via constructor.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-d', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.classList.add('someClass');
assert_array_equals(proto.attributeChangedCallbackArgs, ['class', null, 'someClass'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is set by method ' +
'classList.add(). The custom element is created via constructor.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-e', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.classList.toggle('someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is set by method ' +
'classList.toggle(). The custom element is created via constructor.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-f', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.classList.toggle('someClass');
assert_array_equals(proto.attributeChangedCallbackArgs, ['class', null, 'someClass'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is set by method ' +
'classList.toggle(). The custom element is created via constructor.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-g', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.className = 'someClass';
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is set as property. ' +
'The custom element is created via constructor.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-h', {prototype: proto});
var customElement = new GeneratedConstructor();
customElement.className = 'someClass';
assert_array_equals(proto.attributeChangedCallbackArgs, ['class', null, 'someClass'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is set as property. '+
'The custom element is created via constructor.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-i', {prototype: proto});
doc.body.innerHTML = '<x-i id="x-i" class="theClass"></x-i>';
assert_equals(proto.attributeChangedCallbackCalledCounter, 0,
'Callback attributeChanged should not be called');
}, 'Test attributeChanged callback is not called if attribute value is specified in HTML. '+
'The custom element is created via innerHTML property.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-j', {prototype: proto});
doc.body.innerHTML = '<x-j id="x-j" class="theClass"></x-j>';
var customElement = doc.querySelector('#x-j');
customElement.setAttribute('class', 'someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is set by method setAttribute(). '+
'The custom element is created via innerHTML property.');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-k', {prototype: proto});
doc.body.innerHTML = '<x-k id="x-k"></x-k>';
var customElement = doc.querySelector('#x-k');
customElement.setAttribute('class', 'someClass');
assert_array_equals(proto.attributeChangedCallbackArgs, ['class', null, 'someClass'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is set by method setAttribute(). '+
'The custom element is created via innerHTML property.');
test(function() {
var doc = newHTMLDocument();
doc.body.innerHTML = '<x-l id="x-l"></x-l>';
var customElement = doc.querySelector('#x-l');
// this call shouldn't invoke or enqueue the callback
customElement.setAttribute('class', 'someClass');
var proto = newHTMLElementPrototype();
doc.registerElement('x-l', {prototype: proto});
assert_equals(proto.attributeChangedCallbackCalledCounter, 0,
'Callback attributeChanged should not be called');
// this one should
customElement.setAttribute('class', 'someClass2');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is not called if attribute value of unresolved element '+
'is set by method setAttribute().');
test(function() {
var doc = newHTMLDocument();
HTML5_ELEMENTS.forEach(function(element) {
var obj = doc.createElement(element);
var proto = newCustomElementPrototype(obj.constructor.prototype);
var GeneratedConstructor = doc.registerElement('x-' + element + '-' + element + '-1', {
prototype: proto,
extends: element
});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
});
}, 'Test attributeChanged callback of the custom element that extends some HTML element. ' +
'Test that the callback is called');
test(function() {
var doc = newHTMLDocument();
HTML5_ELEMENTS.forEach(function(element) {
var obj = doc.createElement(element);
var proto = newCustomElementPrototype(obj.constructor.prototype);
var GeneratedConstructor = doc.registerElement('x-' + element + '-' + element + '-1-1', {
prototype: proto,
extends: element
});
var customElement = new GeneratedConstructor();
customElement.classList.add('someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
});
}, 'Test attributeChanged callback is called if attribute is set by method classList.add(). '+
'The custom element extends some HTML element.');
test(function() {
var doc = newHTMLDocument();
HTML5_ELEMENTS.forEach(function(element) {
var obj = doc.createElement(element);
var proto = newCustomElementPrototype(obj.constructor.prototype);
var GeneratedConstructor = doc.registerElement('x-' + element + '-' + element + '-2', {
prototype: proto,
extends: element
});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass');
assert_array_equals(proto.attributeChangedCallbackArgs, ['class', null, 'someClass'],
'Unexpected callback attributeChanged arguments');
});
}, 'Test attributeChanged callback arguments if attribute value is set by method setAttribute(). '+
'The custom element extends some HTML element.');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
customElement.setAttribute('class', 'someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is set by method setAttribute(). '+
'The document has browsing context.');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
customElement.setAttribute('class', 'someClass');
assert_array_equals(proto.attributeChangedCallbackArgs, ['class', null, 'someClass'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is set by method setAttribute(). '+
'The document has browsing context.');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
customElement.classList.add('someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is called if attribute value is set by method classList.add(). '+
'The document has browsing context.');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
customElement.classList.add('someClass');
assert_array_equals(proto.attributeChangedCallbackArgs, ['class', null, 'someClass'],
'Unexpected callback attributeChanged arguments');
}, 'Test attributeChanged callback arguments if attribute value is set by method classList.add(). '+
'The document has browsing context.');
testInIFrame('../../resources/x-element.html', function(doc) {
var customElement = doc.querySelector('#x-element');
// this call shouldn't invoke or enqueue the callback
customElement.setAttribute('name', 'someName');
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
assert_equals(proto.attributeChangedCallbackCalledCounter, 0,
'Callback attributeChanged should not be called');
// this one should
customElement.setAttribute('class', 'someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
}, 'Test attributeChanged callback is not called if attribute value of unresolved element '+
'is set by method setAttribute(). The document has browsing context.');
testInIFrame('../../resources/x-element.html', function(doc) {
HTML5_ELEMENTS.forEach(function(element) {
var obj = doc.createElement(element);
var proto = newCustomElementPrototype(obj.constructor.prototype);
var GeneratedConstructor = doc.registerElement('x-' + element + '-' + element + '-1', {
prototype: proto,
extends: element
});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass');
assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
'Callback attributeChanged should be called');
});
}, 'Test attributeChanged callback is called if attribute value is set by method setAttribute(). '+
'The document has browsing context. The custom element extends some HTML element.');
testInIFrame('../../resources/x-element.html', function(doc) {
HTML5_ELEMENTS.forEach(function(element) {
var obj = doc.createElement(element);
var proto = newCustomElementPrototype(obj.constructor.prototype);
var GeneratedConstructor = doc.registerElement('x-' + element + '-' + element + '-2', {
prototype: proto,
extends: element
});
var customElement = new GeneratedConstructor();
customElement.setAttribute('class', 'someClass');
assert_array_equals(proto.attributeChangedCallbackArgs, ['class', null, 'someClass'],
'Unexpected callback attributeChanged arguments');
});
}, 'Test attributeChanged callback arguments if attribute value is set by method setAttribute(). '+
'The document has browsing context. The custom element extends some HTML element.');
</script>
</body>
</html>

View file

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html>
<head>
<title>The custom element prototype must be set just prior to invoking created callback</title>
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
<meta name="assert" content="The custom element prototype must be set just prior to invoking callback.">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.body.innerHTML = '<x-a></x-a>';
doc.registerElement('x-a', {prototype: proto});
assert_equals(proto.createdCallbackThis.constructor.prototype, proto,
'The custom element prototype is incorrect inside created callback');
}, 'Test custom element prototype inside created callback when custom element is created ' +
'in HTML before registration of a custom element');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-b', {prototype: proto});
doc.body.innerHTML = '<x-b></x-b>';
assert_equals(proto.createdCallbackThis.constructor.prototype, proto,
'The custom element prototype is incorrect inside created callback');
}, 'Test custom element prototype inside created callback when custom element is created ' +
'in HTML after registration of a custom element');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var customElement = doc.createElement('x-c');
doc.body.appendChild(customElement);
doc.registerElement('x-c', {prototype: proto});
assert_equals(proto.createdCallbackThis.constructor.prototype, proto,
'The custom element prototype is incorrect inside created callback');
}, 'Test custom element prototype inside created callback when custom element is created ' +
'via document.createElement() before registration of a custom element');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-d', {prototype: proto});
var customElement = doc.createElement('x-d');
doc.body.appendChild(customElement);
assert_equals(proto.createdCallbackThis.constructor.prototype, proto,
'The custom element prototype is incorrect inside created callback');
}, 'Test custom element prototype inside created callback when custom element is created ' +
'via document.createElement() after registration of a custom element');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-e', {prototype: proto});
var customElement = new GeneratedConstructor();
assert_equals(proto.createdCallbackThis.constructor.prototype, proto,
'The custom element prototype is incorrect inside created callback');
}, 'Test custom element prototype inside created callback when custom element is created ' +
'via constructor returned by method registerElement');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
assert_equals(proto.createdCallbackThis.constructor.prototype, proto,
'The custom element prototype is incorrect inside created callback');
}, 'Test custom element prototype inside created callback when custom element is created ' +
'by UA parser before registration of a custom element');
</script>
</body>
</html>

View file

@ -0,0 +1,243 @@
<!DOCTYPE html>
<html>
<head>
<title>All other callbacks must not be enqueued until after the created callback's invocation had started</title>
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
<meta name="assert" content="All other callbacks must not be enqueued until after the created callback's invocation had started.">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
function newPrototypeWithCallbackLog() {
var proto = Object.create(HTMLElement.prototype);
proto.callbackLog = [];
proto.createdCallback = function() {
proto.callbackLog.push('created');
};
proto.attachedCallback = function() {
proto.callbackLog.push('attached');
};
proto.attributeChangedCallback = function() {
proto.callbackLog.push('attributeChanged');
};
proto.detachedCallback = function() {
proto.callbackLog.push('detached');
};
return proto;
}
testInIFrame('../../resources/blank.html', function(doc) {
var proto = newPrototypeWithCallbackLog();
doc.registerElement('x-a', {prototype: proto});
doc.body.innerHTML = '<x-a></x-a>';
assert_equals(proto.callbackLog[0], 'created', 'The callback ' +
proto.callbackLog[0] + ' should be enqueued after created callback');
assert_in_array('attached', proto.callbackLog, 'The callback ' +
'attached should be called');
}, 'Test attached callback is enqueued after created callback');
testInIFrame('../../resources/blank.html', function(doc) {
var proto = newPrototypeWithCallbackLog();
doc.registerElement('x-b', {prototype: proto});
doc.body.innerHTML = '<x-b id="x-b"></x-b>';
var customElement = doc.querySelector('#x-b');
customElement.setAttribute('key', 'value');
assert_equals(proto.callbackLog[0], 'created', 'The callback ' +
proto.callbackLog[0] + ' should not be enqueued before created callback');
assert_in_array('attributeChanged', proto.callbackLog,
'The callback attributeChanged should be called');
}, 'Test attributeChanged callback is enqueued after created callback. ' +
'Document has browsing context');
test(function() {
var doc = newHTMLDocument();
var proto = newPrototypeWithCallbackLog();
doc.registerElement('x-c', {prototype: proto});
doc.body.innerHTML = '<x-c id="x-c"></x-c>';
var customElement = doc.querySelector('#x-c');
customElement.setAttribute('key', 'value');
assert_equals(proto.callbackLog[0], 'created', 'The callback ' +
proto.callbackLog[0] + ' should not be enqueued before created callback');
assert_in_array('attributeChanged', proto.callbackLog,
'The callback attributeChanged should be called');
}, 'Test attributeChanged callback is enqueued after created callback. ' +
'Document has no browsing context');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newPrototypeWithCallbackLog();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
doc.body.removeChild(customElement);
assert_equals(proto.callbackLog[0], 'created', 'The callback ' +
proto.callbackLog[0] + ' should not be enqueued before created callback');
assert_in_array('detached', proto.callbackLog,
'The callback detached should be called');
}, 'Test detached callback is enqueued after created callback.');
test(function() {
var doc = newHTMLDocument();
var proto1 = newPrototypeWithCallbackLog();
proto1.createdCallback = function() {
proto1.callbackLog.push('created');
var xe = doc.querySelector('#x-e');
xe.setAttribute('key', 'value');
};
var proto2 = newPrototypeWithCallbackLog();
doc.registerElement('x-d', {prototype: proto1});
doc.registerElement('x-e', {prototype: proto2});
doc.body.innerHTML = '<x-d><x-e id="x-e"></x-e></x-d>';
assert_array_equals(proto2.callbackLog, ['created'],
'attributeChanged callback should not be enqueued before created callback');
}, 'Test attributeChanged callback is not enqueued before created callback started. ' +
'Document has no browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
var proto1 = newPrototypeWithCallbackLog();
proto1.createdCallback = function() {
proto1.callbackLog.push('created');
var xe = doc.querySelector('#x-g');
xe.setAttribute('key', 'value');
};
var proto2 = newPrototypeWithCallbackLog();
doc.registerElement('x-f', {prototype: proto1});
doc.registerElement('x-g', {prototype: proto2});
doc.body.innerHTML = '<x-f><x-g id="x-g"></x-g></x-f>';
assert_array_equals(proto2.callbackLog, ['created', 'attached'],
'attributeChanged callback should not be called before created callback started');
}, 'Test attributeChanged callback is not enqueued before created callback started. ' +
'Document has browsing context');
test(function() {
var doc = newHTMLDocument();
var proto = newPrototypeWithCallbackLog();
proto.createdCallback = function() {
proto.callbackLog.push('created');
this.setAttribute('key', 'value');
};
doc.registerElement('x-h', {prototype: proto});
doc.body.innerHTML = '<x-h></x-h>';
assert_array_equals(proto.callbackLog, ['created', 'attributeChanged'],
'attributeChanged callback should be enqueued after created callback');
}, 'Test attributeChanged callback is enqueued after created callback started. ' +
'Document has no browsing context');
testInIFrame('../../resources/blank.html', function(docWithBrowsingContext) {
var docNoBrowsingContext = newHTMLDocument();
var proto1 = newPrototypeWithCallbackLog();
var proto2 = newPrototypeWithCallbackLog();
proto1.createdCallback = function() {
proto1.callbackLog.push('created');
var xk = docNoBrowsingContext.querySelector('#x-k');
assert_equals(proto2.callbackLog.length, 0, 'Created callback for x-k ' +
'should not be called before created callback for x-i');
docWithBrowsingContext.body.appendChild(xk);
};
docNoBrowsingContext.registerElement('x-i', {prototype: proto1});
docNoBrowsingContext.registerElement('x-k', {prototype: proto2});
docNoBrowsingContext.body.innerHTML = '<x-i><x-k id="x-k"></x-k></x-i>';
// Though at the moment of inserting <x-k> into docWithBrowsingContext
// created callback is not called for <x-k> yet, attached calback is enqueued
// anyway. Because specification for setting custom element prototype algorithm reads:
// ....
// 3. If ELEMENT is in a document and this document has a browsing context:
// 1. Enqueue attached callback for ELEMENT
//
// Changes in the specification will follow, to reflect this exceptional case.
assert_array_equals(proto2.callbackLog, ['created', 'attached'],
'attached callback should be enqueued when custom element prototype is set');
}, 'Test attached callback is enqueued after created callback, but before created callback had started');
testInIFrame('../../resources/blank.html', function(docWithBrowsingContext) {
var docNoBrowsingContext = newHTMLDocument();
var proto = newPrototypeWithCallbackLog();
proto.createdCallback = function() {
proto.callbackLog.push('created');
docWithBrowsingContext.body.appendChild(this);
};
docNoBrowsingContext.registerElement('x-l', {prototype: proto});
docNoBrowsingContext.body.innerHTML = '<x-l></x-l>';
assert_array_equals(proto.callbackLog, ['created', 'attached'],
'attached callback should be enqueued after created callback had started');
}, 'Test attached callback is enqueued after created callback had started');
testInIFrame('../../resources/blank.html', function(doc) {
var proto1 = newPrototypeWithCallbackLog();
var proto2 = newPrototypeWithCallbackLog();
proto1.createdCallback = function() {
proto1.callbackLog.push('created');
var xn = doc.querySelector('#x-n');
assert_equals(proto2.callbackLog.length, 0, 'Created callback for x-n ' +
'should not be called before created callback for x-m');
this.removeChild(xn);
};
doc.registerElement('x-m', {prototype: proto1});
doc.registerElement('x-n', {prototype: proto2});
doc.body.innerHTML = '<x-m><x-n id="x-n"></x-n></x-m>';
assert_array_equals(proto2.callbackLog, ['created'],
'detached callback should not be enqueued before created callback had started');
}, 'Test detached callback is not enqueued before created callback had started');
testInIFrame('../../resources/blank.html', function(doc) {
var proto = newPrototypeWithCallbackLog();
proto.createdCallback = function() {
proto.callbackLog.push('created');
this.remove();
};
doc.registerElement('x-o', {prototype: proto});
doc.body.innerHTML = '<x-o></x-o>';
assert_array_equals(proto.callbackLog, ['created', 'attached', 'detached'],
'detached callback should be enqueued after created callback had started');
}, 'Test detached callback is enqueued after created callback had started');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newPrototypeWithCallbackLog();
doc.registerElement('x-element', {prototype: proto});
// Though at the moment of inserting <x-element> into the document
// created callback is not called for <x-element> yet, attached calback is enqueued
// anyway. Because specification for setting custom element prototype algorithm reads:
// ....
// 3. If ELEMENT is in a document and this document has a browsing context:
// 1. Enqueue attached callback for ELEMENT
//
// Changes in the specification will follow, to reflect this exceptional case.
assert_array_equals(proto.callbackLog, ['created', 'attached'],
'attached callback should be enqueued when custom element prototype is set');
}, 'Test attached callback is enqueued after created callback after registration ' +
'of custom element type');
</script>
</body>
</html>

View file

@ -0,0 +1,168 @@
<!DOCTYPE html>
<html>
<head>
<title>Created callback of a custom element should be invoked after custom element instance is created and its definition is registered</title>
<meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="assert" content="CREATED callback is invoked after custom element instance is created and its definition is registered">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-a', {prototype: proto});
assert_equals(proto.createdCallbackCalledCounter, 0,
'Callback created should not be called before element instance was created');
var customElement = new GeneratedConstructor();
assert_equals(proto.createdCallbackCalledCounter, 1,
'Callback created should be called after element instance was created');
}, 'Test created callback when custom element is created by constructor');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-b', {prototype: proto});
assert_equals(proto.createdCallbackCalledCounter, 0,
'Callback created should not be called before element instance was created');
doc.body.innerHTML = '<x-b></x-b>';
assert_equals(proto.createdCallbackCalledCounter, 1,
'Callback created should be called after element instance was created');
}, 'Test created callback when custom element is created in HTML');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-c', {prototype: proto});
assert_equals(proto.createdCallbackCalledCounter, 0,
'Callback created should not be called before element instance was created');
doc.body.innerHTML = '<div><x-c></x-c></div>';
assert_equals(proto.createdCallbackCalledCounter, 1,
'Callback created should be called after element instance was created');
}, 'Test created callback when custom element is created in HTML as descendant of ' +
'another element');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-d', {prototype: proto});
assert_equals(proto.createdCallbackCalledCounter, 0,
'Callback created should not be called before element instance was created');
var customElement = doc.createElement('x-d');
assert_equals(proto.createdCallbackCalledCounter, 1,
'Callback created should be called after element instance was created');
}, 'Test created callback when custom element is created by createElement');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.body.innerHTML = '<x-e></x-e>';
doc.registerElement('x-e', {prototype: proto});
assert_equals(proto.createdCallbackCalledCounter, 1,
'Callback created should be called after element instance was created');
}, 'Test created callback when custom element is created in HTML before ' +
'registration of a custom element');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-f', {prototype: proto});
doc.body.innerHTML = '<x-f-unresolved id="x-f-unresolved"></x-f-unresolved>';
assert_equals(proto.createdCallbackCalledCounter, 0,
'Callback created should not be called if custom element is unresolved');
var customElement = doc.querySelector('#x-f-unresolved');
customElement.constructor.prototype = proto;
assert_equals(proto.createdCallbackCalledCounter, 0,
'Created callback should not be called if custom element is unresolved');
}, 'Test created callback if custom element is unresolved.');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
assert_equals(proto.createdCallbackCalledCounter, 1, 'Callback created should be called');
}, 'Test created callback is called after custom element is created and registered. ' +
'Document has browsing context');
testInIFrame('../../resources/register-and-create-custom-element.html', function(doc) {
assert_equals(doc.querySelector('#log').innerText, 'Created callback was called',
'Callback created should be called');
}, 'Test created callback is called after custom element is registered and created. ' +
'Document has browsing context');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var customElement = doc.createElement('x-g');
doc.registerElement('x-g', {prototype: proto});
assert_equals(proto.createdCallbackCalledCounter, 1,
'Callback created should be called after registration of custom element');
}, 'Test created callback when custom element is created by createElement '+
'before registration of a custom element');
test(function(){
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-h', {prototype: proto});
var customElement1 = new GeneratedConstructor();
assert_equals(proto.createdCallbackCalledCounter, 1, 'Callback created should be called');
var customElement2 = doc.createElement('x-h');
assert_equals(proto.createdCallbackCalledCounter, 2,
'Callback created should be called after element instance was created');
doc.body.innerHTML = '<x-h></x-h>';
assert_equals(proto.createdCallbackCalledCounter, 3,
'Callback created should be called after element instance was created');
doc.body.innerHTML = '<div><x-h></x-h></div>';
assert_equals(proto.createdCallbackCalledCounter, 4,
'Callback created should be called after element instance was created');
}, 'Test created callback. Create several custom elements using different ways');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
var GeneratedConstructor = doc.registerElement('x-element', {prototype: proto});
assert_equals(proto.createdCallbackCalledCounter, 1,
'Callback created should be called for custom element in loaded document');
var customElement2 = new GeneratedConstructor();
assert_equals(proto.createdCallbackCalledCounter, 2,
'Callback created should be called after element instance was created');
var customElement3 = doc.createElement('x-element');
assert_equals(proto.createdCallbackCalledCounter, 3,
'Callback created should be called after element instance was created');
doc.body.innerHTML = '<x-element></x-element>';
assert_equals(proto.createdCallbackCalledCounter, 4,
'Callback created should be called after element instance was created');
doc.body.innerHTML = '<div><x-element></x-element></div>';
assert_equals(proto.createdCallbackCalledCounter, 5,
'Callback created should be called after element instance was created');
}, 'Test created callback. Create several custom elements using different ways. ' +
'Document has browsing context');
</script>
</body>
</html>

View file

@ -0,0 +1,131 @@
<!DOCTYPE html>
<html>
<head>
<title>Test detached callback of a custom element when moving custom element between different documents</title>
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="assert" content="detached callback ... must be enqueued whenever custom element is removed from the document and this document has a browsing context.">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-a', {prototype: proto});
var customElement = doc.createElement('x-a');
doc.body.appendChild(customElement);
var divElement = doc.createElement('div');
doc.body.appendChild(divElement);
divElement.appendChild(customElement);
assert_equals(proto.detachedCallbackCalledCounter, 0,
'Callback detached should not be called in document without a browsing context');
}, 'Test detached callback is not called if moving custom element inside document ' +
'without browsing context');
testInIFrame('../../resources/blank.html', function(docWithBrowsingContext) {
var docNoBrowsingContext = newHTMLDocument();
var proto1 = newHTMLElementPrototype();
docNoBrowsingContext.registerElement('x-b', {prototype: proto1});
var customElement = docNoBrowsingContext.createElement('x-b');
docNoBrowsingContext.body.appendChild(customElement);
var proto2 = newHTMLElementPrototype();
docWithBrowsingContext.registerElement('x-b', {prototype: proto2});
docWithBrowsingContext.body.appendChild(customElement);
assert_equals(proto1.detachedCallbackCalledCounter, 0,
'Callback detached should not be called in document without browsing context');
assert_equals(proto2.detachedCallbackCalledCounter, 0,
'Callback detached, defined in receiving document, should not be called');
}, 'Test detached callback is not called if moving custom element from ' +
'document without browsing context to document with browsing context');
testInIFrame('../../resources/blank.html', function(docWithBrowsingContext) {
var proto1 = newHTMLElementPrototype();
docWithBrowsingContext.registerElement('x-c', {prototype: proto1});
var customElement = docWithBrowsingContext.createElement('x-c');
docWithBrowsingContext.body.appendChild(customElement);
var docNoBrowsingContext = newHTMLDocument();
var proto2 = newHTMLElementPrototype();
docNoBrowsingContext.registerElement('x-c', {prototype: proto2});
docNoBrowsingContext.body.appendChild(customElement);
assert_equals(proto1.detachedCallbackCalledCounter, 1,
'Callback detached should be called in documents with browsing context');
assert_equals(proto2.detachedCallbackCalledCounter, 0,
'Callback detached, defined in receiving document, should not be called');
}, 'Test detached callback if moving custom element from ' +
'document with browsing context to document without browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-d', {prototype: proto});
var customElement = doc.createElement('x-d');
doc.body.appendChild(customElement);
var divElement = doc.createElement('div');
doc.body.appendChild(divElement);
divElement.appendChild(customElement);
assert_equals(proto.detachedCallbackCalledCounter, 1,
'Callback detached should be called in documents with browsing context');
}, 'Test detached callback if moving custom element inside document ' +
'with browsing context');
var moveTest = async_test('Test detached callback if moving custom element from ' +
'document with browsing context to document with browsing context');
moveTest.step(function() {
var iframe1 = newIFrame('../../resources/blank.html');
iframe1.onload = moveTest.step_func(function() {
var doc1 = iframe1.contentDocument;
// register custom element type
var proto1 = newHTMLElementPrototype();
doc1.registerElement('x-e', {prototype: proto1});
// create custom element
var customElement = doc1.createElement('x-e');
doc1.body.appendChild(customElement);
assert_equals(proto1.detachedCallbackCalledCounter, 0,
'Callback detached should not be called when element is created');
// create second iframe
var iframe2 = newIFrame('../../resources/x-element.html');
iframe2.onload = moveTest.step_func(function() {
var doc2 = iframe2.contentDocument;
// register custom element type
var proto2 = newHTMLElementPrototype();
doc2.registerElement('x-e', {prototype: proto2});
// move element
doc2.body.appendChild(customElement);
assert_equals(proto1.detachedCallbackCalledCounter, 1,
'Callback detached should be called in documents with browsing context');
assert_equals(proto2.detachedCallbackCalledCounter, 0,
'Callback detached, defined in receiving document, should not be called');
// test clean up
iframe1.remove();
iframe2.remove();
moveTest.done();
});
});
});
</script>
</body>
</html>

View file

@ -0,0 +1,148 @@
<!DOCTYPE html>
<html>
<head>
<title>Detached callback of a custom element should not be called if document has no browsing context</title>
<meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="assert" content="detached callback ... must be enqueued whenever custom element is removed from the document and this document has a browsing context.">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-a', {prototype: proto});
doc.body.innerHTML = '<x-a id="x-a"></x-a>';
var customElement = doc.querySelector('#x-a');
doc.body.removeChild(customElement);
assert_equals(proto.detachedCallbackCalledCounter, 0,
'Callback detached should not be called if the document has no browsing context');
}, 'Test detached callback if custom element is created via innerHTML property. ' +
'Document has no browsing context');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.body.innerHTML = '<x-b id="x-b"></x-b>';
doc.registerElement('x-b', {prototype: proto});
var customElement = doc.querySelector('#x-b');
doc.body.removeChild(customElement);
assert_equals(proto.detachedCallbackCalledCounter, 0,
'Callback detached should not be called if the document has no browsing context');
}, 'Test detached callback if custom element is via innerHTML property before ' +
'registration of a custom element. Document has no browsing context');
test(function() {
var doc = newHTMLDocument();
doc.body.innerHTML = '<x-c id="x-c"></x-c>';
var customElement = doc.querySelector('#x-c');
var proto = newHTMLElementPrototype();
customElement.constructor.prototype = proto;
doc.body.removeChild(customElement);
assert_equals(proto.detachedCallbackCalledCounter, 0,
'Callback detached should not be called if the document has no browsing context');
}, 'Test detached callback if custom element is unregistered. ' +
'Document has no browsing context');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-d', {prototype: proto});
doc.body.innerHTML = '<x-d id="x-d"></x-d>';
doc.body.innerHTML = '';
assert_equals(proto.detachedCallbackCalledCounter, 0,
'Callback detached should not be called if the document has no browsing context');
}, 'Test detached callback if removing custom element via innerHTML property. ' +
'Document has no browsing context');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-e', {prototype: proto});
doc.body.innerHTML = '<div id="customParent"><x-e id="x-e"></x-e></div>';
var parent = doc.querySelector('#customParent');
doc.body.removeChild(parent);
assert_equals(proto.detachedCallbackCalledCounter, 0,
'Callback detached should not be called if the document has no browsing context');
}, 'Test detached callback if removing perent of custom element. ' +
'Document has no browsing context');
test(function() {
var doc = newHTMLDocument();
var proto = newHTMLElementPrototype();
doc.registerElement('x-f', {prototype: proto});
doc.body.innerHTML = '<div><x-f id="x-f"></x-f></div>';
doc.body.innerHTML = '';
assert_equals(proto.detachedCallbackCalledCounter, 0,
'Callback detached should not be called if the document has no browsing context');
}, 'Test detached callback if removing perent of custom element via innerHTML property. ' +
'Document has no browsing context');
var loseBrowsingContextTest = async_test('Test detached callback is not called ' +
'if document lose browsing context and custom element is removed');
loseBrowsingContextTest.step(function() {
var iframe = newIFrame('../../resources/x-element.html');
iframe.onload = loseBrowsingContextTest.step_func(function(){
var doc = iframe.contentDocument;
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
iframe.remove();
customElement.remove();
assert_equals(proto.detachedCallbackCalledCounter, 0,
'Callback detached should not be called if the document has no browsing context');
loseBrowsingContextTest.done();
});
});
var navigateTest = async_test('Test detached callback is not called, ' +
'if document\'s window is navigated to another document and custom element is removed');
navigateTest.step(function() {
var iframe = newIFrame('../../resources/x-element.html');
iframe.onload = navigateTest.step_func(function() {
var doc = iframe.contentDocument;
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
customElement = doc.querySelector('#x-element');
iframe.onload = navigateTest.step_func(function() {
customElement.remove();
assert_equals(proto.detachedCallbackCalledCounter, 0,
'Callback detached should not be called ' +
'if the document has no browsing context');
navigateTest.done();
iframe.remove();
});
iframe.src = '../../resources/blank.html';
});
});
</script>
</body>
</html>

View file

@ -0,0 +1,86 @@
<!DOCTYPE html>
<html>
<head>
<title>Detached callback of a custom element should be called if document has browsing context</title>
<meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="assert" content="detached callback ... must be enqueued whenever custom element is removed from the document and this document has a browsing context.">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
doc.body.removeChild(customElement);
assert_equals(proto.detachedCallbackCalledCounter, 1, 'Callback detached should be ' +
'called if custom element is removed from the document with browsing context');
}, 'Test detached callback is called if custom element is removed by method removeChild() ' +
'from document with browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
doc.body.innerHTML = '<div id="x-a-parent"><x-a id="x-a"></x-a></div>';
var proto = newHTMLElementPrototype();
doc.registerElement('x-a', {prototype: proto});
var div = doc.querySelector('#x-a-parent');
doc.body.removeChild(div);
assert_equals(proto.detachedCallbackCalledCounter, 1, 'Callback detached should be ' +
'called if custom element is removed from the document with browsing context');
}, 'Test detached callback is called if ancestor node of custom element ' +
'is removed by method removeChild() from document with browsing context');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
var customElement = doc.querySelector('#x-element');
var div = doc.createElement('div');
doc.body.replaceChild(div, customElement);
assert_equals(proto.detachedCallbackCalledCounter, 1, 'Callback detached should be ' +
'called if custom element is removed from the document with browsing context');
}, 'Test detached callback is called if custom element is removed by method replaceChild() ' +
'from document with browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-b', {prototype: proto});
doc.body.innerHTML = '<div id="x-b-parent"><x-b id="x-b"></x-b></div>';
var parent = doc.querySelector('#x-b-parent');
var replacement = doc.createElement('div');
doc.body.replaceChild(replacement, parent);
assert_equals(proto.detachedCallbackCalledCounter, 1, 'Callback detached should be ' +
'called if custom element is removed from the document with browsing context');
}, 'Test detached callback is called if ancestor node of custom element ' +
'is removed by method replaceChild() from document with browsing context');
testInIFrame('../../resources/x-element.html', function(doc) {
var proto = newHTMLElementPrototype();
doc.registerElement('x-element', {prototype: proto});
doc.body.innerHTML = '';
assert_equals(proto.detachedCallbackCalledCounter, 1, 'Callback detached should be ' +
'called if custom element is removed from the document with browsing context');
}, 'Test detached callback is called after changing custom element direct parent ' +
'innerHTML property in the document with browsing context');
testInIFrame('../../resources/blank.html', function(doc) {
doc.body.innerHTML = '<div><x-c></x-c></div>';
var proto = newHTMLElementPrototype();
doc.registerElement('x-c', {prototype: proto});
doc.body.innerHTML = '';
assert_equals(proto.detachedCallbackCalledCounter, 1, 'Callback detached should be ' +
'called if custom element is removed from the document with browsing context');
}, 'Test detached callback is called after changing custom element ancestor ' +
'innerHTML property in the document with browsing context');
</script>
</body>
</html>