Tests/LibWeb: Import a bunch of slots WPT tests

This commit is contained in:
Shannon Booth 2025-05-10 10:31:08 +12:00 committed by Shannon Booth
commit 98c45f3f03
Notes: github-actions[bot] 2025-05-19 11:27:28 +00:00
9 changed files with 1076 additions and 0 deletions

View file

@ -0,0 +1,7 @@
Harness status: OK
Found 2 tests
2 Fail
Fail Children of a slot in a document tree should not be counted in flattened assigned nodes.
Fail Slot fallback content in shadow tree should be counted in flattened assigned nodes.

View file

@ -0,0 +1,18 @@
Harness status: OK
Found 13 tests
13 Fail
Fail Slots fallback: Basic.
Fail Slots fallback: Basic, elements only.
Fail Slots fallback: Slots in Slots.
Fail Slots fallback: Slots in Slots, elements only.
Fail Slots fallback: Fallback contents should not be used if a node is assigned.
Fail Slots fallback: Slots in Slots: Assigned nodes should be used as fallback contents of another slot
Fail Slots fallback: Complex case.
Fail Slots fallback: Complex case, elements only.
Fail Slots fallback: Mutation. Append fallback contents.
Fail Slots fallback: Mutation. Remove fallback contents.
Fail Slots fallback: Mutation. Assign a node to a slot so that fallback contens are no longer used.
Fail Slots fallback: Mutation. Remove an assigned node from a slot so that fallback contens will be used.
Fail Slots fallback: Mutation. Remove a slot which is a fallback content of another slot.

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Fail
Fail Light DOM slot element should be in flattened assignedNodes

View file

@ -0,0 +1,32 @@
Harness status: OK
Found 26 tests
12 Pass
14 Fail
Pass Slots: Basic.
Pass Slots: Basic, elements only.
Pass Slots: Slots in closed.
Pass Slots: Slots in closed, elements only.
Pass Slots: Slots not in a shadow tree.
Pass Slots: Slots not in a shadow tree, elements only.
Pass Slots: Distributed nodes for Slots not in a shadow tree.
Pass Slots: Name matching
Pass Slots: No direct host child.
Pass Slots: Default Slot.
Pass Slots: Slot in Slot does not matter in assignment.
Fail Slots: Slot is assigned to another slot
Fail Slots: Open > Closed.
Fail Slots: Closed > Closed.
Fail Slots: Closed > Open.
Fail Slots: Complex case: Basi line.
Fail Slots: Mutation: appendChild.
Fail Slots: Mutation: Change slot= attribute 1.
Fail Slots: Mutation: Change slot= attribute 2.
Fail Slots: Mutation: Change slot= attribute 3.
Fail Slots: Mutation: Remove a child.
Pass Slots: Mutation: Add a slot: after.
Fail Slots: Mutation: Add a slot: before.
Fail Slots: Mutation: Remove a slot.
Fail Slots: Mutation: Change slot name= attribute.
Fail Slots: Mutation: Change slot slot= attribute.

View file

@ -0,0 +1,163 @@
function removeWhiteSpaceOnlyTextNodes(node)
{
for (var i = 0; i < node.childNodes.length; i++) {
var child = node.childNodes[i];
if (child.nodeType === Node.TEXT_NODE && child.nodeValue.trim().length == 0) {
node.removeChild(child);
i--;
} else if (child.nodeType === Node.ELEMENT_NODE || child.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
removeWhiteSpaceOnlyTextNodes(child);
}
}
if (node.shadowRoot) {
removeWhiteSpaceOnlyTextNodes(node.shadowRoot);
}
}
function createTestTree(node) {
let ids = {};
function attachShadowFromTemplate(template) {
let parent = template.parentNode;
parent.removeChild(template);
let shadowRoot;
if (template.getAttribute('data-slot-assignment') === 'manual') {
shadowRoot =
parent.attachShadow({mode: template.getAttribute('data-mode'),
slotAssignment: 'manual'});
} else {
shadowRoot = parent.attachShadow(
{mode: template.getAttribute('data-mode')});
}
let id = template.id;
if (id) {
shadowRoot.id = id;
ids[id] = shadowRoot;
}
shadowRoot.appendChild(document.importNode(template.content, true));
return shadowRoot;
}
function walk(root) {
if (root.id) {
ids[root.id] = root;
}
for (let e of Array.from(root.querySelectorAll('[id]'))) {
ids[e.id] = e;
}
for (let e of Array.from(root.querySelectorAll('template'))) {
walk(attachShadowFromTemplate(e));
}
}
walk(node.cloneNode(true));
return ids;
}
// TODO: Refactor this so that only interested results are recorded.
// Callers of this function would not be interested in every results.
function dispatchEventWithLog(nodes, target, event, options) {
function labelFor(e) {
return e.id || e.tagName;
}
let log = [];
let attachedNodes = [];
for (let label in nodes) {
let startingNode = nodes[label];
for (let node = startingNode; node; node = node.parentNode) {
if (attachedNodes.indexOf(node) >= 0)
continue;
let id = node.id;
if (!id)
continue;
attachedNodes.push(node);
if (options && options.capture) {
// Record [currentTarget, target, relatedTarget, composedPath(), 'capture' | 'non-capture']
// TODO: Support registering listeners in different orders.
// e.g. Register a non-capture listener at first, then register a capture listener.
node.addEventListener(event.type, (e) => {
log.push([id,
labelFor(e.target),
e.relatedTarget ? labelFor(e.relatedTarget) : null,
e.composedPath().map((n) => {
return labelFor(n);
}),
'capture']);
}, true);
node.addEventListener(event.type, (e) => {
log.push([id,
labelFor(e.target),
e.relatedTarget ? labelFor(e.relatedTarget) : null,
e.composedPath().map((n) => {
return labelFor(n);
}),
'non-capture']);
});
} else {
// Record [currentTarget, target, relatedTarget, composedPath()]
node.addEventListener(event.type, (e) => {
log.push([id,
labelFor(e.target),
e.relatedTarget ? labelFor(e.relatedTarget) : null,
e.composedPath().map((n) => {
return labelFor(n);
})]
);
});
}
}
}
target.dispatchEvent(event);
return log;
}
// TODO(hayato): Merge this into dispatchEventWithLog
function dispatchUAEventWithLog(nodes, target, eventType, callback) {
function labelFor(e) {
return e.id || e.tagName;
}
let log = [];
let attachedNodes = [];
for (let label in nodes) {
let startingNode = nodes[label];
for (let node = startingNode; node; node = node.parentNode) {
if (attachedNodes.indexOf(node) >= 0)
continue;
let id = node.id;
if (!id)
continue;
attachedNodes.push(node);
node.addEventListener(eventType, (e) => {
// Record [currentTarget, target, relatedTarget, composedPath()]
log.push([id,
labelFor(e.target),
e.relatedTarget ? labelFor(e.relatedTarget) : null,
e.composedPath().map((n) => {
return labelFor(n);
})]);
});
}
}
callback(target);
return log;
}
// This function assumes that testharness.js is available.
function assert_event_path_equals(actual, expected) {
assert_equals(actual.length, expected.length);
for (let i = 0; i < actual.length; ++i) {
assert_equals(actual[i].length, expected[i].length);
assert_equals(actual[i][0], expected[i][0], 'currentTarget at ' + i + ' should be same');
assert_equals(actual[i][1], expected[i][1], 'target at ' + i + ' should be same');
assert_equals(actual[i][2], expected[i][2], 'relatedTarget at ' + i + ' should be same');
assert_array_equals(actual[i][3], expected[i][3], 'composedPath at ' + i + ' should be same');
if (actual[i][4]) {
assert_equals(actual[i][4], expected[i][4], 'listener type should be same at ' + i);
}
}
}

View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<title>Shadow DOM: Slots and fallback contents in Document tree</title>
<meta name="author" title="Takayoshi Kochi" href="mailto:kochi@google.com">
<script src='../resources/testharness.js'></script>
<script src='../resources/testharnessreport.js'></script>
<script src="resources/shadow-dom.js"></script>
<div id="test1">
<div id="host">
<template data-mode="open">
<slot id="innerSlot"></slot>
</template>
<slot id="slot"><div id="fallback">This is fallback content</div></slot>
</div>
</div>
<script>
'use strict';
let n1 = createTestTree(test1);
removeWhiteSpaceOnlyTextNodes(n1.test1);
test(() => {
assert_array_equals(n1.innerSlot.assignedNodes(), [n1.slot]);
assert_array_equals(n1.innerSlot.assignedNodes({ flatten: true }), [n1.slot]);
}, 'Children of a slot in a document tree should not be counted in flattened ' +
'assigned nodes.');
</script>
<div id="test2">
<div id="host">
<template data-mode="open">
<div id="innerHost">
<template data-mode="open">
<slot id="innerSlot"></slot>
</template>
<slot id="slot"><div id="fallback">This is fallback content</div></slot>
</div>
</template>
</div>
</div>
<script>
'use strict';
let n2 = createTestTree(test2);
removeWhiteSpaceOnlyTextNodes(n2.test2);
test(() => {
assert_array_equals(n2.innerSlot.assignedNodes(), [n2.slot]);
assert_array_equals(n2.innerSlot.assignedNodes({ flatten: true }),
[n2.fallback]);
}, 'Slot fallback content in shadow tree should be counted in flattened ' +
'assigned nodes.');
</script>

View file

@ -0,0 +1,253 @@
<!DOCTYPE html>
<title>Shadow DOM: Slots and fallback contents</title>
<meta name="author" title="Hayato Ito" href="mailto:hayato@google.com">
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="resources/shadow-dom.js"></script>
<div id="test1">
<div id="host">
<template data-mode="open">
<slot id="s1" name="slot1">
<div id="f1"></div>
</slot>
</template>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test1);
removeWhiteSpaceOnlyTextNodes(n.test1);
assert_equals(n.f1.assignedSlot, null);
assert_array_equals(n.s1.assignedNodes(), []);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]);
}, 'Slots fallback: Basic.');
test(() => {
let n = createTestTree(test1);
assert_array_equals(n.s1.assignedElements(), []);
assert_array_equals(n.s1.assignedElements({ flatten: true }), [n.f1]);
}, 'Slots fallback: Basic, elements only.');
</script>
<div id="test2">
<div id="host">
<template data-mode="open">
<slot id="s1" name="slot1">
<slot id="s2" name="slot2">
<div id="f1"></div>
</slot>
</slot>
</template>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test2);
removeWhiteSpaceOnlyTextNodes(n.test2);
assert_equals(n.f1.assignedSlot, null);
assert_array_equals(n.s1.assignedNodes(), []);
assert_array_equals(n.s2.assignedNodes(), []);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f1]);
}, 'Slots fallback: Slots in Slots.');
test(() => {
let n = createTestTree(test2);
assert_array_equals(n.s1.assignedElements(), []);
assert_array_equals(n.s2.assignedElements(), []);
assert_array_equals(n.s1.assignedElements({ flatten: true }), [n.f1]);
assert_array_equals(n.s2.assignedElements({ flatten: true }), [n.f1]);
}, 'Slots fallback: Slots in Slots, elements only.');
</script>
<div id="test3">
<div id="host">
<template data-mode="open">
<slot id="s1" name="slot1">
<slot id="s2" name="slot2">
<div id="f1"></div>
</slot>
</slot>
</template>
<div id="c1" slot="slot1"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test3);
removeWhiteSpaceOnlyTextNodes(n.test3);
assert_equals(n.c1.assignedSlot, n.s1);
assert_equals(n.f1.assignedSlot, null);
assert_array_equals(n.s1.assignedNodes(), [n.c1]);
assert_array_equals(n.s2.assignedNodes(), []);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f1]);
}, 'Slots fallback: Fallback contents should not be used if a node is assigned.');
</script>
<div id="test4">
<div id="host">
<template data-mode="open">
<slot id="s1" name="slot1">
<slot id="s2" name="slot2">
<div id="f1"></div>
</slot>
</slot>
</template>
<div id="c1" slot="slot2"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test4);
removeWhiteSpaceOnlyTextNodes(n.test4);
assert_equals(n.c1.assignedSlot, n.s2);
assert_equals(n.f1.assignedSlot, null);
assert_array_equals(n.s1.assignedNodes(), []);
assert_array_equals(n.s2.assignedNodes(), [n.c1]);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
}, 'Slots fallback: Slots in Slots: Assigned nodes should be used as fallback contents of another slot');
</script>
<div id="test5">
<div id="host1">
<template data-mode="open">
<div id="host2">
<template data-mode="open">
<slot id="s4" name="slot4">
<slot id="s3" name="slot3">
<div id="f3"></div>
</slot>
<div id="f4"></div>
</slot>
</template>
<slot id="s2" name="slot2" slot="slot3">
<slot id="s1" name="slot1">
<div id="f1"></div>
</slot>
<div id="f2"></div>
</slot>
</div>
</template>
<div id="c1" slot="slot1"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test5);
removeWhiteSpaceOnlyTextNodes(n.test5);
assert_array_equals(n.s1.assignedNodes(), [n.c1]);
assert_array_equals(n.s2.assignedNodes(), []);
assert_array_equals(n.s3.assignedNodes(), [n.s2]);
assert_array_equals(n.s4.assignedNodes(), []);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1, n.f2]);
assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c1, n.f2]);
assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.c1, n.f2, n.f4]);
}, 'Slots fallback: Complex case.');
test(() => {
let n = createTestTree(test5);
assert_array_equals(n.s1.assignedElements(), [n.c1]);
assert_array_equals(n.s2.assignedElements(), []);
assert_array_equals(n.s3.assignedElements(), [n.s2]);
assert_array_equals(n.s4.assignedElements(), []);
assert_array_equals(n.s1.assignedElements({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedElements({ flatten: true }), [n.c1, n.f2]);
assert_array_equals(n.s3.assignedElements({ flatten: true }), [n.c1, n.f2]);
assert_array_equals(n.s4.assignedElements({ flatten: true }), [n.c1, n.f2, n.f4]);
}, 'Slots fallback: Complex case, elements only.');
test(() => {
let n = createTestTree(test5);
removeWhiteSpaceOnlyTextNodes(n.test5);
let d1 = document.createElement('div');
n.s2.appendChild(d1);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1, n.f2, d1]);
assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c1, n.f2, d1]);
assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.c1, n.f2, d1, n.f4]);
}, 'Slots fallback: Mutation. Append fallback contents.');
test(() => {
let n = createTestTree(test5);
removeWhiteSpaceOnlyTextNodes(n.test5);
n.f2.remove();
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.c1, n.f4]);
}, 'Slots fallback: Mutation. Remove fallback contents.');
test(() => {
let n = createTestTree(test5);
removeWhiteSpaceOnlyTextNodes(n.test5);
let d2 = document.createElement('div');
d2.setAttribute('slot', 'slot2');
n.host1.appendChild(d2);
assert_array_equals(n.s2.assignedNodes(), [d2]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [d2]);
assert_array_equals(n.s3.assignedNodes({ flatten: true }), [d2]);
assert_array_equals(n.s4.assignedNodes({ flatten: true }), [d2, n.f4]);
}, 'Slots fallback: Mutation. Assign a node to a slot so that fallback contens are no longer used.');
test(() => {
let n = createTestTree(test5);
removeWhiteSpaceOnlyTextNodes(n.test5);
n.c1.remove();
assert_array_equals(n.s1.assignedNodes(), []);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f1, n.f2]);
assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.f1, n.f2]);
assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.f1, n.f2, n.f4]);
}, 'Slots fallback: Mutation. Remove an assigned node from a slot so that fallback contens will be used.');
test(() => {
let n = createTestTree(test5);
removeWhiteSpaceOnlyTextNodes(n.test5);
n.s1.remove();
assert_array_equals(n.s1.assignedNodes(), []);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [],
'fall back contents should be empty because s1 is not in a shadow tree.');
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f2]);
assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.f2]);
assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.f2, n.f4]);
}, 'Slots fallback: Mutation. Remove a slot which is a fallback content of another slot.');
</script>

View file

@ -0,0 +1,16 @@
<!doctype html>
<meta charset=utf-8>
<title></title>
<script src=../resources/testharness.js></script>
<script src=../resources/testharnessreport.js></script>
<div id="host1"><slot>foo</slot></div>
<script>
test(() => {
var host1 = document.getElementById("host1");
var sr = host1.attachShadow({mode: "open"});
sr.innerHTML = "<slot></slot>";
assert_array_equals(sr.firstChild.assignedNodes({ flatten: true }), [host1.firstChild]);
}, "Light DOM slot element should be in flattened assignedNodes");
</script>

View file

@ -0,0 +1,526 @@
<!DOCTYPE html>
<title>Shadow DOM: Slots and assignments</title>
<meta name="author" title="Hayato Ito" href="mailto:hayato@google.com">
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="resources/shadow-dom.js"></script>
<div id="test_basic">
<div id="host">
<template data-mode="open">
<slot id="s1" name="slot1"></slot>
</template>
<div id="c1" slot="slot1"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_basic);
removeWhiteSpaceOnlyTextNodes(n.test_basic);
assert_equals(n.c1.assignedSlot, n.s1);
assert_array_equals(n.s1.assignedNodes(), [n.c1]);
}, 'Slots: Basic.');
test(() => {
let n = createTestTree(test_basic);
assert_array_equals(n.s1.assignedElements(), [n.c1]);
}, 'Slots: Basic, elements only.');
</script>
<div id="test_basic_closed">
<div id="host">
<template data-mode="closed">
<slot id="s1" name="slot1"></slot>
</template>
<div id="c1" slot="slot1"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_basic_closed);
removeWhiteSpaceOnlyTextNodes(n.test_basic_closed);
assert_equals(n.c1.assignedSlot, null);
assert_array_equals(n.s1.assignedNodes(), [n.c1]);
}, 'Slots: Slots in closed.');
test(() => {
let n = createTestTree(test_basic_closed);
assert_array_equals(n.s1.assignedElements(), [n.c1]);
}, 'Slots: Slots in closed, elements only.');
</script>
<div id="test_slot_not_in_shadow">
<slot id="s1"></slot>
</div>
<script>
test(() => {
let n = createTestTree(test_slot_not_in_shadow);
removeWhiteSpaceOnlyTextNodes(n.test_slot_not_in_shadow);
assert_array_equals(n.s1.assignedNodes(), []);
}, 'Slots: Slots not in a shadow tree.');
test(() => {
let n = createTestTree(test_slot_not_in_shadow);
assert_array_equals(n.s1.assignedElements(), []);
}, 'Slots: Slots not in a shadow tree, elements only.');
</script>
<div id="test_slot_not_in_shadow_2">
<slot id="s1">
<div id="c1"></div>
</slot>
<slot id="s2">
<div id="c2"></div>
<slot id="s3">
<div id="c3_1"></div>
<div id="c3_2"></div>
</slot>
</slot>
</div>
<script>
test(() => {
let n = createTestTree(test_slot_not_in_shadow_2);
removeWhiteSpaceOnlyTextNodes(n.test_slot_not_in_shadow_2);
assert_equals(n.c1.assignedSlot, null);
assert_equals(n.c2.assignedSlot, null);
assert_equals(n.c3_1.assignedSlot, null);
assert_equals(n.c3_2.assignedSlot, null);
assert_array_equals(n.s1.assignedNodes(), []);
assert_array_equals(n.s2.assignedNodes(), []);
assert_array_equals(n.s3.assignedNodes(), []);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), []);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), []);
assert_array_equals(n.s3.assignedNodes({ flatten: true }), []);
}, 'Slots: Distributed nodes for Slots not in a shadow tree.');
</script>
<div id="test_slot_name_matching">
<div id="host">
<template data-mode="open">
<slot id="s1" name="slot1"></slot>
<slot id="s2" name="slot2"></slot>
<slot id="s3" name="xxx"></slot>
</template>
<div id="c1" slot="slot1"></div>
<div id="c2" slot="slot2"></div>
<div id="c3" slot="yyy"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_slot_name_matching);
removeWhiteSpaceOnlyTextNodes(n.test_slot_name_matching);
assert_equals(n.c1.assignedSlot, n.s1);
assert_equals(n.c2.assignedSlot, n.s2);
assert_equals(n.c3.assignedSlot, null);
}, 'Slots: Name matching');
</script>
<div id="test_no_direct_host_child">
<div id="host">
<template data-mode="open">
<slot id="s1" name="slot1"></slot>
<slot id="s2" name="slot1"></slot>
</template>
<div id="c1" slot="slot1"></div>
<div id="c2" slot="slot1"></div>
<div>
<div id="c3" slot="slot1"></div>
</div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_no_direct_host_child);
removeWhiteSpaceOnlyTextNodes(n.test_no_direct_host_child);
assert_equals(n.c1.assignedSlot, n.s1);
assert_equals(n.c2.assignedSlot, n.s1);
assert_equals(n.c3.assignedSlot, null);
assert_array_equals(n.s1.assignedNodes(), [n.c1, n.c2]);
}, 'Slots: No direct host child.');
</script>
<div id="test_default_slot">
<div id="host">
<template data-mode="open">
<slot id="s1" name="slot1"></slot>
<slot id="s2"></slot>
<slot id="s3"></slot>
</template>
<div id="c1"></div>
<div id="c2" slot=""></div>
<div id="c3" slot="foo"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_default_slot);
removeWhiteSpaceOnlyTextNodes(n.test_default_slot);
assert_equals(n.c1.assignedSlot, n.s2);
assert_equals(n.c2.assignedSlot, n.s2);
assert_equals(n.c3.assignedSlot, null);
}, 'Slots: Default Slot.');
</script>
<div id="test_slot_in_slot">
<div id="host">
<template data-mode="open">
<slot id="s1" name="slot1">
<slot id="s2" name="slot2"></slot>
</slot>
</template>
<div id="c1" slot="slot2"></div>
<div id="c2" slot="slot1"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_slot_in_slot);
removeWhiteSpaceOnlyTextNodes(n.test_slot_in_slot);
assert_equals(n.c1.assignedSlot, n.s2);
assert_equals(n.c2.assignedSlot, n.s1);
}, 'Slots: Slot in Slot does not matter in assignment.');
</script>
<div id="test_slot_is_assigned_to_slot">
<div id="host1">
<template data-mode="open">
<div id="host2">
<template data-mode="open">
<slot id="s2" name="slot2"></slot>
</template>
<slot id="s1" name="slot1" slot="slot2"></slot>
</div>
</template>
<div id="c1" slot="slot1"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_slot_is_assigned_to_slot);
removeWhiteSpaceOnlyTextNodes(n.test_slot_is_assigned_to_slot);
assert_equals(n.c1.assignedSlot, n.s1);
assert_equals(n.s1.assignedSlot, n.s2);
assert_array_equals(n.s1.assignedNodes(), [n.c1]);
assert_array_equals(n.s2.assignedNodes(), [n.s1]);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
}, 'Slots: Slot is assigned to another slot');
</script>
<div id="test_open_closed">
<div id="host1">
<template data-mode="open">
<div id="host2">
<template data-mode="closed">
<slot id="s2" name="slot2"></slot>
</template>
<slot id="s1" name="slot1" slot="slot2"></slot>
</div>
</template>
<div id="c1" slot="slot1"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_open_closed);
removeWhiteSpaceOnlyTextNodes(n.test_open_closed);
assert_equals(n.c1.assignedSlot, n.s1);
assert_equals(n.s1.assignedSlot, null,
'A slot in a closed shadow tree should not be accessed via assignedSlot');
assert_array_equals(n.s1.assignedNodes(), [n.c1]);
assert_array_equals(n.s2.assignedNodes(), [n.s1]);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
}, 'Slots: Open > Closed.');
</script>
<div id="test_closed_closed">
<div id="host1">
<template data-mode="closed">
<div id="host2">
<template data-mode="closed">
<slot id="s2" name="slot2"></slot>
</template>
<slot id="s1" name="slot1" slot="slot2"></slot>
</div>
</template>
<div id="c1" slot="slot1"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_closed_closed);
removeWhiteSpaceOnlyTextNodes(n.test_closed_closed);
assert_equals(n.c1.assignedSlot, null,
'A slot in a closed shadow tree should not be accessed via assignedSlot');
assert_equals(n.s1.assignedSlot, null,
'A slot in a closed shadow tree should not be accessed via assignedSlot');
assert_array_equals(n.s1.assignedNodes(), [n.c1]);
assert_array_equals(n.s2.assignedNodes(), [n.s1]);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
}, 'Slots: Closed > Closed.');
</script>
<div id="test_closed_open">
<div id="host1">
<template data-mode="closed">
<div id="host2">
<template data-mode="open">
<slot id="s2" name="slot2"></slot>
</template>
<slot id="s1" name="slot1" slot="slot2"></slot>
</div>
</template>
<div id="c1" slot="slot1"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_closed_open);
removeWhiteSpaceOnlyTextNodes(n.test_closed_open);
assert_equals(n.c1.assignedSlot, null,
'A slot in a closed shadow tree should not be accessed via assignedSlot');
assert_equals(n.s1.assignedSlot, n.s2);
assert_array_equals(n.s1.assignedNodes(), [n.c1]);
assert_array_equals(n.s2.assignedNodes(), [n.s1]);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
}, 'Slots: Closed > Open.');
</script>
<div id="test_complex">
<div id="host1">
<template data-mode="open">
<div id="host2">
<template data-mode="open">
<slot id="s5" name="slot5"></slot>
<slot id="s6" name="slot6"></slot>
<slot id="s7"></slot>
<slot id="s8" name="slot8"></slot>
</template>
<slot id="s1" name="slot1" slot="slot5"></slot>
<slot id="s2" name="slot2" slot="slot6"></slot>
<slot id="s3"></slot>
<slot id="s4" name="slot4" slot="slot-none"></slot>
<div id="c5" slot="slot5"></div>
<div id="c6" slot="slot6"></div>
<div id="c7"></div>
<div id="c8" slot="slot-none"></div>
</div>
</template>
<div id="c1" slot="slot1"></div>
<div id="c2" slot="slot2"></div>
<div id="c3"></div>
<div id="c4" slot="slot-none"></div>
</div>
</div>
<script>
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
assert_equals(n.c1.assignedSlot, n.s1);
assert_equals(n.c2.assignedSlot, n.s2);
assert_equals(n.c3.assignedSlot, n.s3);
assert_equals(n.c4.assignedSlot, null);
assert_equals(n.s1.assignedSlot, n.s5);
assert_equals(n.s2.assignedSlot, n.s6);
assert_equals(n.s3.assignedSlot, n.s7);
assert_equals(n.s4.assignedSlot, null);
assert_equals(n.c5.assignedSlot, n.s5);
assert_equals(n.c6.assignedSlot, n.s6);
assert_equals(n.c7.assignedSlot, n.s7);
assert_equals(n.c8.assignedSlot, null);
assert_array_equals(n.s1.assignedNodes(), [n.c1]);
assert_array_equals(n.s2.assignedNodes(), [n.c2]);
assert_array_equals(n.s3.assignedNodes(), [n.c3]);
assert_array_equals(n.s4.assignedNodes(), []);
assert_array_equals(n.s5.assignedNodes(), [n.s1, n.c5]);
assert_array_equals(n.s6.assignedNodes(), [n.s2, n.c6]);
assert_array_equals(n.s7.assignedNodes(), [n.s3, n.c7]);
assert_array_equals(n.s8.assignedNodes(), []);
assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c2]);
assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c3]);
assert_array_equals(n.s4.assignedNodes({ flatten: true }), []);
assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c1, n.c5]);
assert_array_equals(n.s6.assignedNodes({ flatten: true }), [n.c2, n.c6]);
assert_array_equals(n.s7.assignedNodes({ flatten: true }), [n.c3, n.c7]);
assert_array_equals(n.s8.assignedNodes({ flatten: true }), []);
}, 'Slots: Complex case: Basi line.');
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
let d1 = document.createElement('div');
d1.setAttribute('slot', 'slot1');
n.host1.appendChild(d1);
assert_array_equals(n.s1.assignedNodes(), [n.c1, d1]);
assert_equals(d1.assignedSlot, n.s1);
assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c1, d1, n.c5]);
}, 'Slots: Mutation: appendChild.');
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
n.c1.setAttribute('slot', 'slot-none');
assert_array_equals(n.s1.assignedNodes(), []);
assert_equals(n.c1.assignedSlot, null);
assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]);
}, 'Slots: Mutation: Change slot= attribute 1.');
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
n.c1.setAttribute('slot', 'slot2');
assert_array_equals(n.s1.assignedNodes(), []);
assert_array_equals(n.s2.assignedNodes(), [n.c1, n.c2]);
assert_equals(n.c1.assignedSlot, n.s2);
assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]);
assert_array_equals(n.s6.assignedNodes({ flatten: true }), [n.c1, n.c2, n.c6]);
}, 'Slots: Mutation: Change slot= attribute 2.');
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
n.c4.setAttribute('slot', 'slot1');
assert_array_equals(n.s1.assignedNodes(), [n.c1, n.c4]);
assert_equals(n.c4.assignedSlot, n.s1);
assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c1, n.c4, n.c5]);
}, 'Slots: Mutation: Change slot= attribute 3.');
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
n.c1.remove();
assert_array_equals(n.s1.assignedNodes(), []);
assert_equals(n.c1.assignedSlot, null);
assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]);
}, 'Slots: Mutation: Remove a child.');
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
let slot = document.createElement('slot');
slot.setAttribute('name', 'slot1');
n.host2.appendChild(slot);
assert_array_equals(slot.assignedNodes(), []);
}, 'Slots: Mutation: Add a slot: after.');
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
let slot = document.createElement('slot');
slot.setAttribute('name', 'slot1');
n.host2.insertBefore(slot, n.s1);
assert_array_equals(slot.assignedNodes(), [n.c1]);
assert_equals(n.c1.assignedSlot, slot);
assert_array_equals(n.s7.assignedNodes(), [slot, n.s3, n.c7]);
assert_array_equals(n.s7.assignedNodes({ flatten: true }), [n.c1, n.c3, n.c7]);
}, 'Slots: Mutation: Add a slot: before.');
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
n.s1.remove();
assert_array_equals(n.s1.assignedNodes(), []);
assert_equals(n.c1.assignedSlot, null);
assert_array_equals(n.s5.assignedNodes(), [n.c5]);
assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]);
}, 'Slots: Mutation: Remove a slot.');
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
n.s1.setAttribute('name', 'slot2');
assert_array_equals(n.s1.assignedNodes(), [n.c2]);
assert_equals(n.c1.assignedSlot, null);
assert_equals(n.c2.assignedSlot, n.s1);
assert_array_equals(n.s5.assignedNodes(), [n.s1, n.c5]);
assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c2, n.c5]);
}, 'Slots: Mutation: Change slot name= attribute.');
test(() => {
let n = createTestTree(test_complex);
removeWhiteSpaceOnlyTextNodes(n.test_complex);
n.s1.setAttribute('slot', 'slot6');
assert_array_equals(n.s1.assignedNodes(), [n.c1]);
assert_array_equals(n.s5.assignedNodes(), [n.c5]);
assert_array_equals(n.s6.assignedNodes(), [n.s1, n.s2, n.c6]);
assert_array_equals(n.s6.assignedNodes({ flatten: true }), [n.c1, n.c2, n.c6]);
}, 'Slots: Mutation: Change slot slot= attribute.');
</script>