Index: third_party/WebKit/LayoutTests/custom-elements/spec/upgrade-element.html |
diff --git a/third_party/WebKit/LayoutTests/custom-elements/spec/upgrade-element.html b/third_party/WebKit/LayoutTests/custom-elements/spec/upgrade-element.html |
index a143b2b151ebf0de5aee3797b74a6d6701460d79..3076a2c7617c3613d8c03ab75b8ba94631569296 100644 |
--- a/third_party/WebKit/LayoutTests/custom-elements/spec/upgrade-element.html |
+++ b/third_party/WebKit/LayoutTests/custom-elements/spec/upgrade-element.html |
@@ -8,62 +8,70 @@ |
<script> |
'use strict' |
-// 6. "attributeChangedCallback" and "connectedCallback" should execute after C and |
-// the rest of the upgrade process finishes. |
+ |
+// 6. If C non-conformantly uses an API decorated with the [CEReactions] extended attribute, |
+// then the reactions enqueued at the beginning of upgrade will execute during this step, |
+// before C finishes and control returns to this algorithm. |
test_with_window((w) => { |
let invocations = []; |
- let changedCallbackArgs; |
+ let changedCallbackArgs = []; |
let a = w.document.createElement('a-a'); |
w.document.body.appendChild(a); |
a.setAttribute('x', '1'); |
class X extends w.HTMLElement { |
constructor() { |
super(); |
+ this.setAttribute('y', '2'); |
invocations.push(['constructor', this]); |
} |
connectedCallback() { invocations.push(['connected', this]); } |
- static get observedAttributes() { return ['x']; } |
+ static get observedAttributes() { return ['x', 'y']; } |
attributeChangedCallback() { |
invocations.push(['attributeChanged', this]); |
- changedCallbackArgs = arguments; |
+ changedCallbackArgs.push(arguments); |
} |
} |
w.customElements.define('a-a', X); |
+ // Unlike calling new, upgrading element with createElement does not set element's state |
+ // to "custom" during HTMLConstructor. Thus, appending attribute after super() |
+ // does not enqueue a callback reaction. |
assert_equals(invocations.length, 3); |
+ assert_equals(changedCallbackArgs.length, 1, 'attributeChangedCallback should only be invoked once'); |
assert_array_equals(invocations[0], ['constructor', a], 'constructor should execute first'); |
- assert_array_equals(invocations[1], ['attributeChanged', a], 'attributeChangedCallback should execute after the constructor'); |
- assert_array_equals(changedCallbackArgs, ['x', null, '1', '']); |
- assert_array_equals(invocations[2], ['connected', a], 'connectedCallback should execute after the constructor'); |
-}, '"connectedCallback", "attributeChangedCallback" reactions should execute after the constructor'); |
+ assert_array_equals(invocations[1], ['attributeChanged', a], 'attributeChangedCallback should execute after constructor'); |
+ assert_array_equals(changedCallbackArgs[0], ['x', null, '1', ''], 'attributeChangedCallback should execute for setAttribute outside of the constructor'); |
+ assert_array_equals(invocations[2], ['connected', a], 'connectedCallback should execute after the constrcutor'); |
+}, 'The constructor non-conformatly uses API decorated with the [CEReactions] when constuctor is invoked during upgrade'); |
-// 6. If C non-conformantly uses an API decorated with the [CEReactions] extended attribute, |
-// then the reactions enqueued at the beginning of upgrade will execute during this step, |
-// before C finishes and control returns to this algorithm. |
+// Step 6 case when constructor is invoked with new |
test_with_window((w) => { |
let invocations = []; |
- let changedCallbackArgs; |
- let a = w.document.createElement('a-a'); |
- w.document.body.appendChild(a); |
+ let changedCallbackArgs = []; |
class X extends w.HTMLElement { |
constructor() { |
super(); |
- this.setAttribute('x', '1'); |
+ this.setAttribute('y', '2'); |
invocations.push(['constructor', this]); |
} |
connectedCallback() { invocations.push(['connected', this]); } |
- static get observedAttributes() { return ['x']; } |
+ static get observedAttributes() { return ['x', 'y']; } |
attributeChangedCallback() { |
invocations.push(['attributeChanged', this]); |
- changedCallbackArgs = arguments; |
+ changedCallbackArgs.push(arguments); |
} |
} |
w.customElements.define('a-a', X); |
+ let a = new X(); |
+ a.setAttribute('x','1'); |
assert_equals(invocations.length, 3); |
- assert_array_equals(invocations[0], ['connected', a], 'connectedCallback executes before the constructor'); |
- assert_array_equals(invocations[1], ['attributeChanged', a], 'attributeChangedCallback executes before the constructor'); |
- assert_array_equals(changedCallbackArgs, ['x', null, '1', '']); |
- assert_array_equals(invocations[2], ['constructor', a], 'constructor executes last'); |
-}, 'The constructor non-conformatly uses API decorated with the [CEReactions]'); |
+ assert_equals(changedCallbackArgs.length, 2, 'attributeChangedCallback should be invoked twice'); |
+ assert_array_equals(invocations[0], ['attributeChanged', a], 'attributeChangedCallback for "a" should execute before the constructor is finished'); |
+ assert_array_equals(invocations[1], ['constructor', a], 'constructor executes second'); |
+ assert_array_equals(invocations[2], ['attributeChanged', a], 'setAttribute outside of the constructorshould be invoked'); |
+ assert_array_equals(changedCallbackArgs[0], ['y', null, '2', '']); |
+ assert_array_equals(changedCallbackArgs[1], ['x', null, '1', '']); |
+}, 'The constructor non-conformatly uses API decorated with the [CEReactions] when consturctor is invoked with new'); |
+ |
// 8. If constructResult is an abrupt completion, then return constructResult |
// (i.e., rethrow the exception). |
@@ -72,14 +80,14 @@ test_with_window((w) => { |
let doc = w.document; |
doc.body.appendChild(doc.createElement('a-a')); |
w.onerror = function (msg, url, lineNo, columnNo, error) { |
- error_log.push(error); |
+ error_log.push(error.name); |
return true; |
}; |
class X extends w.HTMLElement { |
constructor() { |
super(); |
assert_false(this.matches(':defined'), 'calling super() with non-empty construction stack should not define the element'); |
- throw 'constructor throws'; |
+ throw { name: 'constructor throws' }; |
} |
} |
w.customElements.define('a-a', X); |
@@ -91,7 +99,7 @@ test_with_window((w) => { |
test_with_window((w) => { |
let error_log = []; |
w.onerror = function (msg, url, lineNo, columnNo, error) { |
- error_log.push(error); |
+ error_log.push(error.name); |
return true; |
}; |
let a = w.document.createElement('a-a'); |
@@ -104,6 +112,6 @@ test_with_window((w) => { |
} |
w.customElements.define('a-a', X); |
assert_array_equals(error_log, ['InvalidStateError'], 'returning object that is different from element should throw "InvalidStateError"'); |
-}, 'Upgrading an element with invalid constructor'); |
+}, 'Upgrading an element with constructor that returns different object'); |
</script> |
-</body> |
+</body> |