Tests: Import ARIAMixin string attributes CEReactions tests (no code)

This commit is contained in:
sideshowbarker 2024-12-20 21:42:29 +09:00 committed by Tim Flynn
commit e9dedeee34
Notes: github-actions[bot] 2024-12-20 13:17:59 +00:00
5 changed files with 659 additions and 0 deletions

View file

@ -0,0 +1,13 @@
Harness status: OK
Found 8 tests
8 Pass
Pass role on Element must enqueue an attributeChanged reaction when adding role content attribute
Pass role on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaColIndexText on Element must enqueue an attributeChanged reaction when adding aria-colindextext content attribute
Pass ariaColIndexText on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaDescription on Element must enqueue an attributeChanged reaction when adding aria-description content attribute
Pass ariaDescription on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaRowIndexText on Element must enqueue an attributeChanged reaction when adding aria-rowindextext content attribute
Pass ariaRowIndexText on Element must enqueue an attributeChanged reaction when replacing an existing attribute

View file

@ -0,0 +1,85 @@
Harness status: OK
Found 80 tests
80 Pass
Pass ariaAtomic on Element must enqueue an attributeChanged reaction when adding aria-atomic content attribute
Pass ariaAtomic on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaAutoComplete on Element must enqueue an attributeChanged reaction when adding aria-autocomplete content attribute
Pass ariaAutoComplete on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaBrailleLabel on Element must enqueue an attributeChanged reaction when adding aria-braillelabel content attribute
Pass ariaBrailleLabel on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaBrailleRoleDescription on Element must enqueue an attributeChanged reaction when adding aria-brailleroledescription content attribute
Pass ariaBrailleRoleDescription on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaBusy on Element must enqueue an attributeChanged reaction when adding aria-busy content attribute
Pass ariaBusy on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaChecked on Element must enqueue an attributeChanged reaction when adding aria-checked content attribute
Pass ariaChecked on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaColCount on Element must enqueue an attributeChanged reaction when adding aria-colcount content attribute
Pass ariaColCount on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaColIndex on Element must enqueue an attributeChanged reaction when adding aria-colindex content attribute
Pass ariaColIndex on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaColSpan on Element must enqueue an attributeChanged reaction when adding aria-colspan content attribute
Pass ariaColSpan on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaCurrent on Element must enqueue an attributeChanged reaction when adding aria-current content attribute
Pass ariaCurrent on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaDisabled on Element must enqueue an attributeChanged reaction when adding aria-disabled content attribute
Pass ariaDisabled on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaExpanded on Element must enqueue an attributeChanged reaction when adding aria-expanded content attribute
Pass ariaExpanded on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaHasPopup on Element must enqueue an attributeChanged reaction when adding aria-haspopup content attribute
Pass ariaHasPopup on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaHidden on Element must enqueue an attributeChanged reaction when adding aria-hidden content attribute
Pass ariaHidden on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaInvalid on Element must enqueue an attributeChanged reaction when adding aria-invalid content attribute
Pass ariaInvalid on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaKeyShortcuts on Element must enqueue an attributeChanged reaction when adding aria-keyshortcuts content attribute
Pass ariaKeyShortcuts on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaLabel on Element must enqueue an attributeChanged reaction when adding aria-label content attribute
Pass ariaLabel on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaLevel on Element must enqueue an attributeChanged reaction when adding aria-level content attribute
Pass ariaLevel on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaLive on Element must enqueue an attributeChanged reaction when adding aria-live content attribute
Pass ariaLive on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaModal on Element must enqueue an attributeChanged reaction when adding aria-modal content attribute
Pass ariaModal on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaMultiLine on Element must enqueue an attributeChanged reaction when adding aria-multiline content attribute
Pass ariaMultiLine on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaMultiSelectable on Element must enqueue an attributeChanged reaction when adding aria-multiselectable content attribute
Pass ariaMultiSelectable on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaOrientation on Element must enqueue an attributeChanged reaction when adding aria-orientation content attribute
Pass ariaOrientation on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaPlaceholder on Element must enqueue an attributeChanged reaction when adding aria-placeholder content attribute
Pass ariaPlaceholder on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaPosInSet on Element must enqueue an attributeChanged reaction when adding aria-posinset content attribute
Pass ariaPosInSet on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaPressed on Element must enqueue an attributeChanged reaction when adding aria-pressed content attribute
Pass ariaPressed on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaReadOnly on Element must enqueue an attributeChanged reaction when adding aria-readonly content attribute
Pass ariaReadOnly on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaRelevant on Element must enqueue an attributeChanged reaction when adding aria-relevant content attribute
Pass ariaRelevant on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaRequired on Element must enqueue an attributeChanged reaction when adding aria-required content attribute
Pass ariaRequired on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaRoleDescription on Element must enqueue an attributeChanged reaction when adding aria-roledescription content attribute
Pass ariaRoleDescription on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaRowCount on Element must enqueue an attributeChanged reaction when adding aria-rowcount content attribute
Pass ariaRowCount on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaRowIndex on Element must enqueue an attributeChanged reaction when adding aria-rowindex content attribute
Pass ariaRowIndex on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaRowSpan on Element must enqueue an attributeChanged reaction when adding aria-rowspan content attribute
Pass ariaRowSpan on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaSelected on Element must enqueue an attributeChanged reaction when adding aria-selected content attribute
Pass ariaSelected on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaSetSize on Element must enqueue an attributeChanged reaction when adding aria-setsize content attribute
Pass ariaSetSize on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaSort on Element must enqueue an attributeChanged reaction when adding aria-sort content attribute
Pass ariaSort on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaValueMax on Element must enqueue an attributeChanged reaction when adding aria-valuemax content attribute
Pass ariaValueMax on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaValueMin on Element must enqueue an attributeChanged reaction when adding aria-valuemin content attribute
Pass ariaValueMin on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaValueNow on Element must enqueue an attributeChanged reaction when adding aria-valuenow content attribute
Pass ariaValueNow on Element must enqueue an attributeChanged reaction when replacing an existing attribute
Pass ariaValueText on Element must enqueue an attributeChanged reaction when adding aria-valuetext content attribute
Pass ariaValueText on Element must enqueue an attributeChanged reaction when replacing an existing attribute

View file

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html>
<head>
<title>Custom Elements: CEReactions on Element interface</title>
<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
<meta name="assert" content="String attributes of AriaAttributes interface must have CEReactions">
<meta name="help" content="https://dom.spec.whatwg.org/#element">
<meta name="help" content="https://w3c.github.io/DOM-Parsing/">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../resources/custom-elements-helpers.js"></script>
<script src="./resources/reactions.js"></script>
</head>
<body>
<div id="log"></div>
<div id="container"></div>
<script>
// tentative -> AriaMixin-string-attributes.tentative.html
// testReflectAttribute('role', 'role', 'foo', 'bar', 'role on Element');
testReflectAttribute('ariaAtomic', 'aria-atomic', 'foo', 'bar', 'ariaAtomic on Element');
testReflectAttribute('ariaAutoComplete', 'aria-autocomplete', 'foo', 'bar', 'ariaAutoComplete on Element');
testReflectAttribute('ariaBrailleLabel', 'aria-braillelabel', 'foo', 'bar', 'ariaBrailleLabel on Element');
testReflectAttribute('ariaBrailleRoleDescription', 'aria-brailleroledescription', 'foo', 'bar', 'ariaBrailleRoleDescription on Element');
testReflectAttribute('ariaBusy', 'aria-busy', 'foo', 'bar', 'ariaBusy on Element');
testReflectAttribute('ariaChecked', 'aria-checked', 'foo', 'bar', 'ariaChecked on Element');
testReflectAttribute('ariaColCount', 'aria-colcount', 'foo', 'bar', 'ariaColCount on Element');
testReflectAttribute('ariaColIndex', 'aria-colindex', 'foo', 'bar', 'ariaColIndex on Element');
// tentative -> AriaMixin-string-attributes.tentative.html
// testReflectAttribute('ariaColIndexText', 'aria-colindextext', 'foo', 'bar', 'ariaColIndexText on Element');
testReflectAttribute('ariaColSpan', 'aria-colspan', 'foo', 'bar', 'ariaColSpan on Element');
testReflectAttribute('ariaCurrent', 'aria-current', 'foo', 'bar', 'ariaCurrent on Element');
// tentative -> AriaMixin-string-attributes.tentative.html
// testReflectAttribute('ariaDescription', 'aria-description', 'foo', 'bar', 'ariaDescription on Element');
testReflectAttribute('ariaDisabled', 'aria-disabled', 'foo', 'bar', 'ariaDisabled on Element');
testReflectAttribute('ariaExpanded', 'aria-expanded', 'foo', 'bar', 'ariaExpanded on Element');
testReflectAttribute('ariaHasPopup', 'aria-haspopup', 'foo', 'bar', 'ariaHasPopup on Element');
testReflectAttribute('ariaHidden', 'aria-hidden', 'foo', 'bar', 'ariaHidden on Element');
testReflectAttribute('ariaInvalid', 'aria-invalid', 'foo', 'bar', 'ariaInvalid on Element');
testReflectAttribute('ariaKeyShortcuts', 'aria-keyshortcuts', 'foo', 'bar', 'ariaKeyShortcuts on Element');
testReflectAttribute('ariaLabel', 'aria-label', 'foo', 'bar', 'ariaLabel on Element');
testReflectAttribute('ariaLevel', 'aria-level', 'foo', 'bar', 'ariaLevel on Element');
testReflectAttribute('ariaLive', 'aria-live', 'foo', 'bar', 'ariaLive on Element');
testReflectAttribute('ariaModal', 'aria-modal', 'foo', 'bar', 'ariaModal on Element');
testReflectAttribute('ariaMultiLine', 'aria-multiline', 'foo', 'bar', 'ariaMultiLine on Element');
testReflectAttribute('ariaMultiSelectable', 'aria-multiselectable', 'foo', 'bar', 'ariaMultiSelectable on Element');
testReflectAttribute('ariaOrientation', 'aria-orientation', 'foo', 'bar', 'ariaOrientation on Element');
testReflectAttribute('ariaPlaceholder', 'aria-placeholder', 'foo', 'bar', 'ariaPlaceholder on Element');
testReflectAttribute('ariaPosInSet', 'aria-posinset', 'foo', 'bar', 'ariaPosInSet on Element');
testReflectAttribute('ariaPressed', 'aria-pressed', 'foo', 'bar', 'ariaPressed on Element');
testReflectAttribute('ariaReadOnly', 'aria-readonly', 'foo', 'bar', 'ariaReadOnly on Element');
testReflectAttribute('ariaRelevant', 'aria-relevant', 'foo', 'bar', 'ariaRelevant on Element');
testReflectAttribute('ariaRequired', 'aria-required', 'foo', 'bar', 'ariaRequired on Element');
testReflectAttribute('ariaRoleDescription', 'aria-roledescription', 'foo', 'bar', 'ariaRoleDescription on Element');
testReflectAttribute('ariaRowCount', 'aria-rowcount', 'foo', 'bar', 'ariaRowCount on Element');
testReflectAttribute('ariaRowIndex', 'aria-rowindex', 'foo', 'bar', 'ariaRowIndex on Element');
// tentative -> AriaMixin-string-attributes.tentative.html
// testReflectAttribute('ariaRowIndexText', 'aria-rowindextext', 'foo', 'bar', 'ariaRowIndexText on Element');
testReflectAttribute('ariaRowSpan', 'aria-rowspan', 'foo', 'bar', 'ariaRowSpan on Element');
testReflectAttribute('ariaSelected', 'aria-selected', 'foo', 'bar', 'ariaSelected on Element');
testReflectAttribute('ariaSetSize', 'aria-setsize', 'foo', 'bar', 'ariaSetSize on Element');
testReflectAttribute('ariaSort', 'aria-sort', 'foo', 'bar', 'ariaSort on Element');
testReflectAttribute('ariaValueMax', 'aria-valuemax', 'foo', 'bar', 'ariaValueMax on Element');
testReflectAttribute('ariaValueMin', 'aria-valuemin', 'foo', 'bar', 'ariaValueMin on Element');
testReflectAttribute('ariaValueNow', 'aria-valuenow', 'foo', 'bar', 'ariaValueNow on Element');
testReflectAttribute('ariaValueText', 'aria-valuetext', 'foo', 'bar', 'ariaValueText on Element');
</script>
</body>
</html>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<title>Custom Elements: CEReactions on Element interface</title>
<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
<meta name="assert" content="String attributes of AriaAttributes interface must have CEReactions">
<meta name="help" content="https://dom.spec.whatwg.org/#element">
<meta name="help" content="https://w3c.github.io/DOM-Parsing/">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../resources/custom-elements-helpers.js"></script>
<script src="./resources/reactions.js"></script>
</head>
<body>
<div id="log"></div>
<div id="container"></div>
// tentative properties that were added mid-year... merge back in after Interop 2024 completes
<script>
testReflectAttribute('role', 'role', 'foo', 'bar', 'role on Element');
testReflectAttribute('ariaColIndexText', 'aria-colindextext', 'foo', 'bar', 'ariaColIndexText on Element');
testReflectAttribute('ariaDescription', 'aria-description', 'foo', 'bar', 'ariaDescription on Element');
testReflectAttribute('ariaRowIndexText', 'aria-rowindextext', 'foo', 'bar', 'ariaRowIndexText on Element');
</script>
</body>
</html>

View file

@ -0,0 +1,458 @@
let testNumber = 1;
function testNodeConnector(testFunction, name) {
let container = document.createElement('div');
container.appendChild(document.createElement('div'));
document.body.appendChild(container);
test(function () {
var element = define_new_custom_element();
var instance = document.createElement(element.name);
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(container, instance);
assert_array_equals(element.takeLog().types(), ['connected']);
}, name + ' must enqueue a connected reaction');
test(function () {
var element = define_new_custom_element();
var instance = document.createElement(element.name);
assert_array_equals(element.takeLog().types(), ['constructed']);
var newDoc = document.implementation.createHTMLDocument();
testFunction(container, instance);
assert_array_equals(element.takeLog().types(), ['connected']);
testFunction(newDoc.documentElement, instance);
assert_array_equals(element.takeLog().types(), ['disconnected', 'adopted', 'connected']);
}, name + ' must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document');
container.parentNode.removeChild(container);
}
function testNodeDisconnector(testFunction, name) {
let container = document.createElement('div');
container.appendChild(document.createElement('div'));
document.body.appendChild(container);
test(function () {
var element = define_new_custom_element();
var instance = document.createElement(element.name);
assert_array_equals(element.takeLog().types(), ['constructed']);
container.appendChild(instance);
assert_array_equals(element.takeLog().types(), ['connected']);
testFunction(instance, window);
assert_array_equals(element.takeLog().types(), ['disconnected']);
}, name + ' must enqueue a disconnected reaction');
container.parentNode.removeChild(container);
}
function testInsertingMarkup(testFunction, name) {
let container = document.createElement('div');
container.appendChild(document.createElement('div'));
document.body.appendChild(container);
test(function () {
var element = define_new_custom_element();
testFunction(container, `<${element.name}></${element.name}>`);
assert_array_equals(element.takeLog().types(), ['constructed', 'connected']);
}, name + ' must enqueue a connected reaction for a newly constructed custom element');
test(function () {
var element = define_new_custom_element(['title']);
testFunction(container, `<${element.name} id="hello" title="hi"></${element.name}>`);
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['constructed', 'attributeChanged', 'connected']);
assert_attribute_log_entry(logEntries[1], {name: 'title', oldValue: null, newValue: 'hi', namespace: null});
}, name + ' must enqueue a attributeChanged reaction for a newly constructed custom element');
container.parentNode.removeChild(container);
}
function testParsingMarkup(testFunction, name) {
test(function () {
var element = define_new_custom_element(['id']);
assert_array_equals(element.takeLog().types(), []);
var instance = testFunction(document, `<${element.name} id="hello" class="foo"></${element.name}>`);
assert_equals(Object.getPrototypeOf(instance.querySelector(element.name)), element.class.prototype);
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['constructed', 'attributeChanged']);
assert_attribute_log_entry(logEntries[1], {name: 'id', oldValue: null, newValue: 'hello', namespace: null});
}, name + ' must construct a custom element');
}
function testCloner(testFunction, name) {
let container = document.createElement('div');
container.appendChild(document.createElement('div'));
document.body.appendChild(container);
test(function () {
var element = define_new_custom_element(['id']);
var instance = document.createElement(element.name);
container.appendChild(instance);
instance.setAttribute('id', 'foo');
assert_array_equals(element.takeLog().types(), ['constructed', 'connected', 'attributeChanged']);
var newInstance = testFunction(instance);
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['constructed', 'attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: 'id', oldValue: null, newValue: 'foo', namespace: null});
}, name + ' must enqueue an attributeChanged reaction when cloning an element with an observed attribute');
test(function () {
var element = define_new_custom_element(['id']);
var instance = document.createElement(element.name);
container.appendChild(instance);
instance.setAttribute('lang', 'en');
assert_array_equals(element.takeLog().types(), ['constructed', 'connected']);
var newInstance = testFunction(instance);
assert_array_equals(element.takeLog().types(), ['constructed']);
}, name + ' must not enqueue an attributeChanged reaction when cloning an element with an unobserved attribute');
test(function () {
var element = define_new_custom_element(['title', 'class']);
var instance = document.createElement(element.name);
container.appendChild(instance);
instance.setAttribute('lang', 'en');
instance.className = 'foo';
instance.setAttribute('title', 'hello world');
assert_array_equals(element.takeLog().types(), ['constructed', 'connected', 'attributeChanged', 'attributeChanged']);
var newInstance = testFunction(instance);
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['constructed', 'attributeChanged', 'attributeChanged']);
assert_attribute_log_entry(logEntries[1], {name: 'class', oldValue: null, newValue: 'foo', namespace: null});
assert_attribute_log_entry(logEntries[2], {name: 'title', oldValue: null, newValue: 'hello world', namespace: null});
}, name + ' must enqueue an attributeChanged reaction when cloning an element only for observed attributes');
}
function testReflectAttributeWithContentValues(jsAttributeName, contentAttributeName, validValue1, contentValue1, validValue2, contentValue2, name, elementName, interfaceName, optionalSupportPredicate) {
test(function () {
if (optionalSupportPredicate) {
assert_implements_optional(optionalSupportPredicate());
}
if (elementName === undefined) {
var element = define_new_custom_element([contentAttributeName]);
var instance = document.createElement(element.name);
} else {
var element = define_build_in_custom_element([contentAttributeName], interfaceName, elementName);
var instance = document.createElement(elementName, { is: element.name });
}
assert_array_equals(element.takeLog().types(), ['constructed']);
instance[jsAttributeName] = validValue1;
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: contentAttributeName, oldValue: null, newValue: contentValue1, namespace: null});
}, name + ' must enqueue an attributeChanged reaction when adding ' + contentAttributeName + ' content attribute');
test(function () {
if (optionalSupportPredicate) {
assert_implements_optional(optionalSupportPredicate());
}
if (elementName === undefined) {
var element = define_new_custom_element([contentAttributeName]);
var instance = document.createElement(element.name);
} else {
var element = define_build_in_custom_element([contentAttributeName], interfaceName, elementName);
var instance = document.createElement(elementName, { is: element.name });
}
instance[jsAttributeName] = validValue1;
assert_array_equals(element.takeLog().types(), ['constructed', 'attributeChanged']);
instance[jsAttributeName] = validValue2;
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: contentAttributeName, oldValue: contentValue1, newValue: contentValue2, namespace: null});
}, name + ' must enqueue an attributeChanged reaction when replacing an existing attribute');
}
function testReflectAttribute(jsAttributeName, contentAttributeName, validValue1, validValue2, name, elementName, interfaceName, optionalSupportPredicate) {
testReflectAttributeWithContentValues(jsAttributeName, contentAttributeName, validValue1, validValue1, validValue2, validValue2, name, elementName, interfaceName, optionalSupportPredicate);
}
function testReflectBooleanAttribute(jsAttributeName, contentAttributeName, name, elementName, interfaceName) {
testReflectAttributeWithContentValues(jsAttributeName, contentAttributeName, true, '', false, null, name, elementName, interfaceName);
}
function testReflectAttributeWithContentValuesAndDependentAttributes(jsAttributeName, contentAttributeName, validValue1, contentValue1, validValue2, contentValue2, name, elementName, getParentElement, setAttributes, interfaceName) {
let parentElement = getParentElement();
test(() => {
let element = define_build_in_custom_element([contentAttributeName], interfaceName, elementName);
let instance = document.createElement(elementName, { is: element.name });
assert_array_equals(element.takeLog().types(), ['constructed']);
parentElement.appendChild(instance);
assert_array_equals(element.takeLog().types(), ['connected']);
setAttributes(instance);
instance[jsAttributeName] = validValue1;
let logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), { name: contentAttributeName, oldValue: null, newValue: contentValue1, namespace: null });
}, name + ' must enqueue an attributeChanged reaction when adding a new attribute');
test(() => {
let element = define_build_in_custom_element([contentAttributeName], interfaceName, elementName);
let instance = document.createElement(elementName, { is: element.name });
parentElement.appendChild(instance);
setAttributes(instance);
instance[jsAttributeName] = validValue1;
assert_array_equals(element.takeLog().types(), ['constructed', 'connected', 'attributeChanged']);
instance[jsAttributeName] = validValue2;
let logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), { name: contentAttributeName, oldValue: contentValue1, newValue: contentValue2, namespace: null });
}, name + ' must enqueue an attributeChanged reaction when replacing an existing attribute');
}
function testReflectAttributeWithDependentAttributes(jsAttributeName, contentAttributeName, validValue1, validValue2, name, elementName, getParentElement, setAttributes, interfaceName) {
testReflectAttributeWithContentValuesAndDependentAttributes(jsAttributeName, contentAttributeName, validValue1, validValue1, validValue2, validValue2, name, elementName, getParentElement, setAttributes, interfaceName);
}
function testReflectBooleanAttributeWithDependentAttributes(jsAttributeName, contentAttributeName, name, elementName, getParentElement, setAttributes, interfaceName) {
testReflectAttributeWithContentValuesAndDependentAttributes(jsAttributeName, contentAttributeName, true, '', false, null, name, elementName, getParentElement, setAttributes, interfaceName);
}
function testReflectAttributeWithContentValuesAndParentNode(jsAttributeName, contentAttributeName, validValue1, contentValue1, validValue2, contentValue2, name, elementName, getParentElement, interfaceName) {
let parentElement = getParentElement();
test(() => {
let element = define_build_in_custom_element([contentAttributeName], interfaceName, elementName);
let instance = document.createElement(elementName, { is: element.name });
assert_array_equals(element.takeLog().types(), ['constructed']);
parentElement.appendChild(instance);
assert_array_equals(element.takeLog().types(), ['connected']);
instance[jsAttributeName] = validValue1;
let logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), { name: contentAttributeName, oldValue: null, newValue: contentValue1, namespace: null });
}, name + ' must enqueue an attributeChanged reaction when adding a new attribute');
test(() => {
let element = define_build_in_custom_element([contentAttributeName], interfaceName, elementName);
let instance = document.createElement(elementName, { is: element.name });
parentElement.appendChild(instance);
assert_array_equals(element.takeLog().types(), ['constructed', 'connected']);
instance[jsAttributeName] = validValue1;
assert_array_equals(element.takeLog().types(), ['attributeChanged']);
instance[jsAttributeName] = validValue2;
let logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), { name: contentAttributeName, oldValue: contentValue1, newValue: contentValue2, namespace: null });
}, name + ' must enqueue an attributeChanged reaction when replacing an existing attribute');
}
function testReflectAttributeWithParentNode(jsAttributeName, contentAttributeName, validValue1, validValue2, name, elementName, getParentElement, interfaceName) {
testReflectAttributeWithContentValuesAndParentNode(jsAttributeName, contentAttributeName, validValue1, validValue1, validValue2, validValue2, name, elementName, getParentElement, interfaceName);
}
function testReflectBooleanAttributeWithParentNode(jsAttributeName, contentAttributeName, name, elementName, getParentElement, interfaceName) {
testReflectAttributeWithContentValuesAndParentNode(jsAttributeName, contentAttributeName, true, '', false, null, name, elementName, getParentElement, interfaceName);
}
function testAttributeAdder(testFunction, name) {
test(function () {
var element = define_new_custom_element(['id']);
var instance = document.createElement(element.name);
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, 'id', 'foo');
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: 'id', oldValue: null, newValue: 'foo', namespace: null});
}, name + ' must enqueue an attributeChanged reaction when adding an attribute');
test(function () {
var element = define_new_custom_element(['class']);
var instance = document.createElement(element.name);
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, 'data-lang', 'en');
assert_array_equals(element.takeLog().types(), []);
}, name + ' must not enqueue an attributeChanged reaction when adding an unobserved attribute');
test(function () {
var element = define_new_custom_element(['title']);
var instance = document.createElement(element.name);
instance.setAttribute('title', 'hello');
assert_array_equals(element.takeLog().types(), ['constructed', 'attributeChanged']);
testFunction(instance, 'title', 'world');
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: 'title', oldValue: 'hello', newValue: 'world', namespace: null});
}, name + ' must enqueue an attributeChanged reaction when replacing an existing attribute');
test(function () {
var element = define_new_custom_element([]);
var instance = document.createElement(element.name);
instance.setAttribute('data-lang', 'zh');
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, 'data-lang', 'en');
assert_array_equals(element.takeLog().types(), []);
}, name + ' must enqueue an attributeChanged reaction when replacing an existing unobserved attribute');
}
function testAttributeMutator(testFunction, name) {
test(function () {
var element = define_new_custom_element(['title']);
var instance = document.createElement(element.name);
instance.setAttribute('title', 'hello');
assert_array_equals(element.takeLog().types(), ['constructed', 'attributeChanged']);
testFunction(instance, 'title', 'world');
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: 'title', oldValue: 'hello', newValue: 'world', namespace: null});
}, name + ' must enqueue an attributeChanged reaction when replacing an existing attribute');
test(function () {
var element = define_new_custom_element(['class']);
var instance = document.createElement(element.name);
instance.setAttribute('data-lang', 'zh');
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, 'data-lang', 'en');
assert_array_equals(element.takeLog().types(), []);
}, name + ' must not enqueue an attributeChanged reaction when replacing an existing unobserved attribute');
}
function testAttributeRemover(testFunction, name, options) {
if (options && !options.onlyExistingAttribute) {
test(function () {
var element = define_new_custom_element(['title']);
var instance = document.createElement(element.name);
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, 'title');
assert_array_equals(element.takeLog().types(), []);
}, name + ' must not enqueue an attributeChanged reaction when removing an attribute that does not exist');
}
test(function () {
var element = define_new_custom_element([]);
var instance = document.createElement(element.name);
instance.setAttribute('data-lang', 'hello');
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, 'data-lang');
assert_array_equals(element.takeLog().types(), []);
}, name + ' must not enqueue an attributeChanged reaction when removing an unobserved attribute');
test(function () {
var element = define_new_custom_element(['title']);
var instance = document.createElement(element.name);
instance.setAttribute('title', 'hello');
assert_array_equals(element.takeLog().types(), ['constructed', 'attributeChanged']);
testFunction(instance, 'title');
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: 'title', oldValue: 'hello', newValue: null, namespace: null});
}, name + ' must enqueue an attributeChanged reaction when removing an existing attribute');
test(function () {
var element = define_new_custom_element([]);
var instance = document.createElement(element.name);
instance.setAttribute('data-lang', 'ja');
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, 'data-lang');
assert_array_equals(element.takeLog().types(), []);
}, name + ' must not enqueue an attributeChanged reaction when removing an existing unobserved attribute');
}
function test_mutating_style_property_value(testFunction, name, options) {
const propertyName = (options || {}).propertyName || 'color';
const idlName = (options || {}).idlName || 'color';
const value1 = (options || {}).value1 || 'blue';
const rule1 = `${propertyName}: ${value1};`;
const value2 = (options || {}).value2 || 'red';
const rule2 = `${propertyName}: ${value2};`;
test(function () {
var element = define_new_custom_element(['style']);
var instance = document.createElement(element.name);
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, propertyName, idlName, value1);
assert_equals(instance.getAttribute('style'), rule1);
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: 'style', oldValue: null, newValue: rule1, namespace: null});
}, name + ' must enqueue an attributeChanged reaction when it adds the observed style attribute');
test(function () {
var element = define_new_custom_element(['title']);
var instance = document.createElement(element.name);
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, propertyName, idlName, value1);
assert_equals(instance.getAttribute('style'), rule1);
assert_array_equals(element.takeLog().types(), []);
}, name + ' must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed');
test(function () {
var element = define_new_custom_element(['style']);
var instance = document.createElement(element.name);
testFunction(instance, propertyName, idlName, value1);
assert_array_equals(element.takeLog().types(), ['constructed', 'attributeChanged']);
testFunction(instance, propertyName, idlName, value2);
assert_equals(instance.getAttribute('style'), rule2);
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: 'style', oldValue: rule1, newValue: rule2, namespace: null});
}, name + ' must enqueue an attributeChanged reaction when it mutates the observed style attribute');
test(function () {
var element = define_new_custom_element([]);
var instance = document.createElement(element.name);
testFunction(instance, propertyName, idlName, value1);
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, propertyName, idlName, value2);
assert_equals(instance.getAttribute('style'), rule2);
assert_array_equals(element.takeLog().types(), []);
}, name + ' must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed');
}
function test_removing_style_property_value(testFunction, name) {
test(function () {
var element = define_new_custom_element(['style']);
var instance = document.createElement(element.name);
instance.setAttribute('style', 'color: red; display: none;');
assert_array_equals(element.takeLog().types(), ['constructed', 'attributeChanged']);
testFunction(instance, 'color', 'color');
assert_equals(instance.getAttribute('style'), 'display: none;'); // Don't make this empty since browser behaviors are inconsistent now.
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: 'style', oldValue: 'color: red; display: none;', newValue: 'display: none;', namespace: null});
}, name + ' must enqueue an attributeChanged reaction when it removes a property from the observed style attribute');
test(function () {
var element = define_new_custom_element(['class']);
var instance = document.createElement(element.name);
instance.setAttribute('style', 'color: red; display: none;');
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, 'color', 'color');
assert_equals(instance.getAttribute('style'), 'display: none;'); // Don't make this empty since browser behaviors are inconsistent now.
assert_array_equals(element.takeLog().types(), []);
}, name + ' must not enqueue an attributeChanged reaction when it removes a property from the style attribute but the style attribute is not observed');
}
function test_mutating_style_property_priority(testFunction, name) {
test(function () {
var element = define_new_custom_element(['style']);
var instance = document.createElement(element.name);
instance.setAttribute('style', 'color: red');
assert_array_equals(element.takeLog().types(), ['constructed', 'attributeChanged']);
testFunction(instance, 'color', 'color', true);
assert_equals(instance.getAttribute('style'), 'color: red !important;');
var logEntries = element.takeLog();
assert_array_equals(logEntries.types(), ['attributeChanged']);
assert_attribute_log_entry(logEntries.last(), {name: 'style', oldValue: 'color: red', newValue: 'color: red !important;', namespace: null});
}, name + ' must enqueue an attributeChanged reaction when it makes a property important and the style attribute is observed');
test(function () {
var element = define_new_custom_element(['id']);
var instance = document.createElement(element.name);
instance.setAttribute('style', 'color: red');
assert_array_equals(element.takeLog().types(), ['constructed']);
testFunction(instance, 'color', 'color', true);
assert_equals(instance.getAttribute('style'), 'color: red !important;');
assert_array_equals(element.takeLog().types(), []);
}, name + ' must enqueue an attributeChanged reaction when it makes a property important but the style attribute is not observed');
}