4 <title>Test attribute removing to check attributeChanged callback of a custom element</title>
5 <meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
6 <meta name="assert" content="attributeChanged callback must be enqueued whenever custom element's attribute is removed">
7 <link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
8 <script src="../../../../../resources/testharness.js"></script>
9 <script src="../../../../../resources/testharnessreport.js"></script>
10 <script src="../../testcommon.js"></script>
11 <link rel="stylesheet" href="../../../../../resources/testharness.css">
17 var doc = newHTMLDocument();
18 var proto = newHTMLElementPrototype();
19 var GeneratedConstructor = doc.registerElement('x-a', {prototype: proto});
21 var customElement = new GeneratedConstructor();
22 //attributeChangedCallback should be called the first time here
23 customElement.setAttribute('class', 'someClass');
24 //attributeChangedCallback should be called the second time here
25 customElement.removeAttribute('class');
26 assert_equals(proto.attributeChangedCallbackCalledCounter, 2, 'Callback attributeChanged should be called ' +
27 'after setAttribute() and removeAttribute() calls');
28 }, 'Test attributeChanged callback if attribute is removed. ' +
29 'The custom element created via constructor');
33 var doc = newHTMLDocument();
34 HTML5_ELEMENTS.forEach(function(element) {
35 var obj = doc.createElement(element);
36 var proto = newCustomElementPrototype(obj.constructor.prototype);
37 var GeneratedConstructor = doc.registerElement('x-' + element + '-' + element + '-1', {
42 var customElement = new GeneratedConstructor();
43 //attributeChangedCallback should be called the first time here
44 customElement.setAttribute('class', 'someClass');
45 //attributeChangedCallback should be called the second time here
46 customElement.removeAttribute('class');
47 assert_equals(proto.attributeChangedCallbackCalledCounter, 2,
48 'Callback attributeChanged should be called ' +
49 'after setAttribute() and removeAttribute() calls for "' + element + '"');
51 }, 'Test attributeChanged callback if attribute is removed. ' +
52 'The custom element created via constructor and extends HTML element');
56 var doc = newHTMLDocument();
57 var proto = newHTMLElementPrototype();
58 doc.registerElement('x-b', {prototype: proto});
60 doc.body.innerHTML = '<x-b id="x-b" class="theClass"></x-b>';
61 var customElement = doc.querySelector('#x-b');
62 customElement.removeAttribute('class');
63 assert_equals(proto.attributeChangedCallbackCalledCounter, 1,
64 'Callback attributeChanged should be called ' +
65 'after removeAttribute() call');
66 }, 'Test attributeChanged callback if attribute is removed. ' +
67 'The custom element created via innerHTML property');
71 var doc = newHTMLDocument();
72 var proto = newHTMLElementPrototype();
73 doc.registerElement('x-c', {prototype: proto});
75 doc.body.innerHTML = '<x-c id="x-c" class="theClass"></x-c>';
76 var customElement = doc.querySelector('#x-c');
77 customElement.removeAttribute('class');
78 assert_equals(proto.attributeChangedCallbackArgs[2], null,
79 'Removing an attribute should invoke ' +
80 'the attributeChanged callback with a null new value');
81 assert_array_equals(proto.attributeChangedCallbackArgs,
82 ['class', 'theClass', null],
83 'Unexpected attributeChanged callback arguments');
84 }, 'Test attributeChanged callback arguments if attribute is removed. ' +
85 'The custom element created via innerHTML property');
89 var doc = newHTMLDocument();
90 var proto = newHTMLElementPrototype();
92 doc.body.innerHTML = '<x-d id="x-d" class="theClass"></x-d>';
93 var customElement = doc.querySelector('#x-d');
94 // this should not call or enqueue attributeChangedCallback
95 customElement.setAttribute('class', 'someClass');
96 // this one should not too
97 customElement.removeAttribute('class');
98 assert_equals(proto.attributeChangedCallbackCalledCounter, 0,
99 'Callback attributeChanged should not be called');
101 doc.registerElement('x-d', {prototype: proto});
102 // this call invokes attributeChangedCallback
103 customElement.setAttribute('name', 'someName');
105 customElement.removeAttribute('name');
106 assert_equals(proto.attributeChangedCallbackCalledCounter, 2,
107 'Callback attributeChanged should be called ' +
108 'after setAttribute() and removeAttribute() calls');
109 }, 'Test attributeChanged callback is not called if attribute is removed. ' +
110 'The custom element created via innerHTML property and unresolved at first');
113 testInIFrame('../../resources/x-element.html', function(doc) {
114 var proto = newHTMLElementPrototype();
115 doc.registerElement('x-element', {prototype: proto});
117 var customElement = doc.querySelector('#x-element');
118 customElement.setAttribute('class', 'someClass');
119 customElement.removeAttribute('class');
120 assert_equals(proto.attributeChangedCallbackCalledCounter, 2,
121 'Callback attributeChanged should be called ' +
122 'after setAttribute() and removeAttribute() calls');
123 }, 'Test attributeChanged callback is called if attribute is removed. ' +
124 'The custom element created via constructor and the document has browsing context');
127 testInIFrame('../../resources/x-element.html', function(doc) {
128 var proto = newHTMLElementPrototype();
129 doc.registerElement('x-element', {prototype: proto});
131 doc.body.innerHTML = '<x-element id="x-element" class="theClass"></x-element>';
132 var customElement = doc.querySelector('#x-element');
133 customElement.removeAttribute('class');
134 assert_equals(proto.attributeChangedCallbackArgs[2], null,
135 'Removing an attribute should invoke ' +
136 'the attributeChanged callback with a null new value');
137 assert_array_equals(proto.attributeChangedCallbackArgs,
138 ['class', 'theClass', null],
139 'Unexpected attributeChanged callback arguments');
140 }, 'Test attributeChanged callback arguments if attribute is removed. ' +
141 'The custom element created via innerHTML property and the document has browsing context');
144 testInIFrame('../../resources/x-element.html', function(doc) {
145 var customElement = doc.querySelector('#x-element');
146 // this should not call or enqueue attributeChangedCallback
147 customElement.setAttribute('name', 'someName');
149 customElement.removeAttribute('name');
151 var proto = newHTMLElementPrototype();
152 doc.registerElement('x-element', {prototype: proto});
153 assert_equals(proto.attributeChangedCallbackCalledCounter, 0,
154 'Callback attributeChanged should not be called');
155 // this call invokes attributeChangedCallback
156 customElement.setAttribute('class', 'someClass');
157 // this call invokes attributeChangedCallback at second time
158 customElement.removeAttribute('class');
159 assert_equals(proto.attributeChangedCallbackCalledCounter, 2,
160 'Callback attributeChanged should be called ' +
161 'after setAttribute() and removeAttribute() calls');
162 }, 'Test attributeChanged callback if attribute is removed. ' +
163 'The custom element created via innerHTML property and unresolved at first. ' +
164 'The document has browsing context');