diff --git a/shadow-dom/focus-navigation/delegatesFocus-highlight-sibling.html b/shadow-dom/focus-navigation/delegatesFocus-highlight-sibling.html
new file mode 100644
index 000000000000000..dde18128ad8247f
--- /dev/null
+++ b/shadow-dom/focus-navigation/delegatesFocus-highlight-sibling.html
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slot-fallback-default-tabindex.html b/shadow-dom/focus-navigation/focus-navigation-slot-fallback-default-tabindex.html
new file mode 100644
index 000000000000000..e8e0293e77bd28a
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slot-fallback-default-tabindex.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
Tests for moving focus by pressing tab key across shadow boundaries.
+To manually test, press tab key six times then shift+tab seven times.
+It should traverse focusable elements in the increasing numerical order and then in the reverse order.
+
+
+
2. Assigned to slot5 whose tabindex is 2.
+
+
+ x. The default tabindex for a slot node is set to 0.
+ 5. The parent slot node's tabindex is 0. Second.
+ 4. The parent slot node's tabindex is 0. First.
+
+
+
+ x. The tabindex is 3. The slot node should be ignored.
+ 3. The parent slot node's tabindex is 3. The slot node's tabindex matters. This element's tabindex comes after.
+
+
+
+ x. The tabindex is 0. The slot node should be ignored. If there is another slot node in same tabindex, the younger child comes first.
+ 6. The parent slot node's tabindex is 0. First.
+ 7. The parent slot node's tabindex is 0. Second.
+
+
+
+ x. The tabindex is 1. The slot node should be ignored.
+ 1. The slot node tabindex is 1.
+
+
+
+ x. The tabindex is 2. The slot node should be ignored. The host child is assigned to this slot node.
+ -. The host child is assigned to the parent slot node. This text shouldn't apeare.
+
+
+
+ x. The tabindex is 5. The slot node should be ignored.
+ x. tabindex is -1. Should be skipped.
+
+
+
+ x. tabindex is -1. Should be skipped.
+ x. The parent slot node is skipped.
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slot-fallback.html b/shadow-dom/focus-navigation/focus-navigation-slot-fallback.html
new file mode 100644
index 000000000000000..8b29558b5047571
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slot-fallback.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+ document tree: [i0 -> [x-foo]]
+ x-foo's shadow tree: [j1 -> j2 -> [s1]]
+ slot #s1: [k1 -> [x-bar] -> k0 -> [s2] -> [s3]]
+ x-bar's shadow tree: [m1 -> m2]
+ slot #s2: [i1 -> i2]
+ slot #s3: [l1]
+ v1 ideal nav forward: [i0 -> j1 -> j2 -> k1 -> x-bar -> m1 -> m2 -> k0 -> i1 -> i2 -> l1]
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slot-nested-2levels.html b/shadow-dom/focus-navigation/focus-navigation-slot-nested-2levels.html
new file mode 100644
index 000000000000000..59f0e4f0cb7e026
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slot-nested-2levels.html
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slot-nested-delegatesFocus.html b/shadow-dom/focus-navigation/focus-navigation-slot-nested-delegatesFocus.html
new file mode 100644
index 000000000000000..94d8ce8e1f04b96
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slot-nested-delegatesFocus.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slot-nested-fallback.html b/shadow-dom/focus-navigation/focus-navigation-slot-nested-fallback.html
new file mode 100644
index 000000000000000..93a6240fe3e8f14
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slot-nested-fallback.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+Tests for moving focus by pressing tab key across shadow boundaries.
+To manually test, press tab key six times then shift+tab six times.
+It should traverse focusable elements in the increasing numerical order and then in the reverse order.
+
+
+ Slot shouldn't be focused.
+ Slot shouldn't be focused.
+ This text shouldn't appear.
+
+ Slot shouldn't be focused.
+ 2. No host child is assigned to slot3.
+
+
+
+ 3. Inner Shadow Host.
+
+ Slot shouldn't be focused.
+ Slot shouldn't be focused.
+ This text shouldn't appear.
+
+
+
+
4. Assigned to slot4.
+
+ This text shouldn't appear. slot5 is in the fallback content of slot4 which has assigned nodes.
+
+
+ 5. Inner Shadow Host.
+
+ Slot shouldn't be focused.
+ This text shouldn't appear.
+
+
+
Slot shouldn't be focused. Assigned to slot6.
+ This text shouldn't appear.
+
+
+
+
1. Assigned to slot2.
+
6. Assigned to slot7 which is assigned to slot6.
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slot-nested.html b/shadow-dom/focus-navigation/focus-navigation-slot-nested.html
new file mode 100644
index 000000000000000..7bfe5dc78440409
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slot-nested.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slot-shadow-in-fallback.html b/shadow-dom/focus-navigation/focus-navigation-slot-shadow-in-fallback.html
new file mode 100644
index 000000000000000..7192a42584b1f77
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slot-shadow-in-fallback.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slot-shadow-in-slot.html b/shadow-dom/focus-navigation/focus-navigation-slot-shadow-in-slot.html
new file mode 100644
index 000000000000000..4f320574ed58fad
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slot-shadow-in-slot.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slot-with-tabindex.html b/shadow-dom/focus-navigation/focus-navigation-slot-with-tabindex.html
new file mode 100644
index 000000000000000..880fb83130bbf23
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slot-with-tabindex.html
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+ document tree: [i0 -> [x-foo]]
+ x-foo's shadow tree: [j1 -> [s1] -> [s2] -> j2 ->[x-bar]]
+ x-bar's shadow tree: [[s3] -> k1]
+ slot #s1: [i1 -> i2]
+ slot #s2: [i3]
+ slot #s3: [l1 -> l2]
+ v1 ideal nav forward: [i0 -> j1 -> i1 -> i2 -> i3 -> j2 -> x-bar -> l1 -> l2 -> k1]
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slots-in-slot.html b/shadow-dom/focus-navigation/focus-navigation-slots-in-slot.html
new file mode 100644
index 000000000000000..025a4e0f52f7a78
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slots-in-slot.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+Tests for moving focus by pressing tab key across nodes in slot scope.
+
+outside
+
+
+
+
+
+ single nested slot
+ single nested slot
+
+
+ single nested slot
+
+
+
+ double nested slot
+ double nested slot
+
+
+
+ single nested slot
+
+ double nested slot
+
+ Triple nested slot
+ Triple nested slot
+
+ double nested slot
+
+ single nested slot
+
+
+outside
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-slots.html b/shadow-dom/focus-navigation/focus-navigation-slots.html
new file mode 100644
index 000000000000000..f2de50f6eba190a
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-slots.html
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+ document tree: [i0 -> [x-foo]]
+ x-foo's shadow tree: [j1 -> [s1] -> [s2] -> j2 ->[x-bar]]
+ x-bar's shadow tree: [k1 -> [s3]]
+ slot #s1: [i1 -> i2]
+ slot #s2: [i3]
+ slot #s3: [[s4]]
+ slot #s4: [i4 -> i5]
+ v1 ideal nav forward: [i0 -> j1 -> i1 -> i2 -> i3 -> j2 -> x-bar -> k1 -> i4 -> i5]
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation-with-delegatesFocus.html b/shadow-dom/focus-navigation/focus-navigation-with-delegatesFocus.html
new file mode 100644
index 000000000000000..e09726152678e20
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation-with-delegatesFocus.html
@@ -0,0 +1,358 @@
+
+
+
+
+
+
+
+
+
+This tests TAB focus navigation with delegatesFocus flag on shadow hosts
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-navigation.html b/shadow-dom/focus-navigation/focus-navigation.html
new file mode 100644
index 000000000000000..fabcf881708d337
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-navigation.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+ document tree: [i0 -> [x-foo]]
+ x-foo's shadow tree: [j5 -> [x-bar] -> j6]
+ x-bar's shadow tree: [k1 -> k0 -> [s2]]
+ slot #s2: [j1 -> j2 -> j3 -> j4 -> [s1] -> j0]
+ slot #s1: [i1 -> i2]
+ v1 ideal nav forward: [i0 -> j5 -> xbar -> k1 -> k0 -> j1 -> j2 -> j3 -> j4 -> i1 -> i2 -> j0 -> j6]
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-nested-slots.html b/shadow-dom/focus-navigation/focus-nested-slots.html
new file mode 100644
index 000000000000000..747a8a1262fad5a
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-nested-slots.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+one
+
+
+
+
+
+ two
+ three
+ four
+
+
+five
+
+
diff --git a/shadow-dom/focus-navigation/focus-reverse-unassignable-slot.html b/shadow-dom/focus-navigation/focus-reverse-unassignable-slot.html
new file mode 100644
index 000000000000000..cacf94f4121167e
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-reverse-unassignable-slot.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-reverse-unassigned-slot.html b/shadow-dom/focus-navigation/focus-reverse-unassigned-slot.html
new file mode 100644
index 000000000000000..e19ea44288bc274
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-reverse-unassigned-slot.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-slide-on-shadow-host.html b/shadow-dom/focus-navigation/focus-slide-on-shadow-host.html
new file mode 100644
index 000000000000000..433ac1ae4c54635
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-slide-on-shadow-host.html
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-unassignable-slot.html b/shadow-dom/focus-navigation/focus-unassignable-slot.html
new file mode 100644
index 000000000000000..135569d94ccbe66
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-unassignable-slot.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/focus-with-negative-index.html b/shadow-dom/focus-navigation/focus-with-negative-index.html
new file mode 100644
index 000000000000000..95dc98fc02dc61f
--- /dev/null
+++ b/shadow-dom/focus-navigation/focus-with-negative-index.html
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+ document tree: [i0 -> [x-foo]]
+ x-foo's shadow tree: [j5 -> [x-bar] -> j6]
+ x-bar's shadow tree: [k1 -> k0 -> [s2]]
+ slot #s2: [j1 -> j2 -> j3 -> j4 -> [s1] -> j0]
+ slot #s1: [i1 -> i2]
+ v1 ideal nav forward: [i0 -> j5 -> xbar -> k1 -> k0 -> j6]
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus-navigation/resources/focus-utils.js b/shadow-dom/focus-navigation/resources/focus-utils.js
new file mode 100644
index 000000000000000..75e20ee12ebb8cb
--- /dev/null
+++ b/shadow-dom/focus-navigation/resources/focus-utils.js
@@ -0,0 +1,146 @@
+'use strict';
+
+async function navigateFocusForward() {
+ return new test_driver.Actions()
+ .keyDown('\uE004')
+ .keyUp('\uE004')
+ .send();
+}
+
+async function navigateFocusBackward() {
+ return new test_driver.Actions()
+ .keyDown('\uE050')
+ .keyDown('\uE004')
+ .keyUp('\uE004')
+ .keyUp('\uE050')
+ .send();
+}
+
+// If shadow root is open, can find element using element path
+// If shadow root is open, can find the shadowRoot from the element
+
+function innermostActiveElement(element) {
+ element = element || document.activeElement;
+ if (isIFrameElement(element)) {
+ if (element.contentDocument.activeElement)
+ return innermostActiveElement(element.contentDocument.activeElement);
+ return element;
+ }
+ if (isShadowHost(element)) {
+ let shadowRoot = element.shadowRoot;
+ if (shadowRoot) {
+ if (shadowRoot.activeElement)
+ return innermostActiveElement(shadowRoot.activeElement);
+ }
+ }
+ return element;
+}
+
+async function shouldNavigateFocus(fromElement, direction) {
+ if (!fromElement)
+ return false;
+
+ fromElement.focus();
+ if (fromElement !== innermostActiveElement())
+ return false;
+
+ if (direction == 'forward')
+ await navigateFocusForward();
+ else
+ await navigateFocusBackward();
+
+ return true;
+}
+
+async function assert_focus_navigation_element(fromPath, toPath, direction) {
+ const fromElement = getNodeInComposedTree(fromPath);
+ const result = await shouldNavigateFocus(fromElement, direction);
+ assert_true(result, 'Failed to focus ' + fromPath);
+
+ const message =
+ `Focus should move ${direction} from ${fromPath} to ${toPath}`;
+ const toElement = getNodeInComposedTree(toPath);
+ assert_equals(innermostActiveElement(), toElement, message);
+}
+
+async function assert_focus_navigation_elements(elements, direction) {
+ assert_true(
+ elements.length >= 2,
+ 'length of elements should be greater than or equal to 2.');
+ for (var i = 0; i + 1 < elements.length; ++i)
+ await assert_focus_navigation_element(elements[i], elements[i + 1], direction);
+
+}
+
+async function assert_focus_navigation_forward(elements) {
+ return assert_focus_navigation_elements(elements, 'forward');
+}
+
+async function assert_focus_navigation_backward(elements) {
+ return assert_focus_navigation_elements(elements, 'backward');
+}
+
+
+// If shadow root is closed, need to pass shadowRoot and element to find
+// innermost active element
+
+function isShadowHostOfRoot(shadowRoot, node) {
+ return shadowRoot && shadowRoot.host.isEqualNode(node);
+}
+
+function innermostActiveElementWithShadowRoot(shadowRoot, element) {
+ element = element || document.activeElement;
+ if (isIFrameElement(element)) {
+ if (element.contentDocument.activeElement)
+ return innermostActiveElementWithShadowRoot(shadowRoot, element.contentDocument.activeElement);
+ return element;
+ }
+ if (isShadowHostOfRoot(shadowRoot, element)) {
+ if (shadowRoot.activeElement)
+ return innermostActiveElementWithShadowRoot(shadowRoot, shadowRoot.activeElement);
+ }
+ return element;
+}
+
+async function shouldNavigateFocusWithShadowRoot(from, direction) {
+ const [fromElement, shadowRoot] = from;
+ if (!fromElement)
+ return false;
+
+ fromElement.focus();
+ if (fromElement !== innermostActiveElementWithShadowRoot(shadowRoot))
+ return false;
+
+ if (direction == 'forward')
+ await navigateFocusForward();
+ else
+ await navigateFocusBackward();
+
+ return true;
+}
+
+async function assert_focus_navigation_element_with_shadow_root(from, to, direction) {
+ const result = await shouldNavigateFocusWithShadowRoot(from, direction);
+ const [fromElement] = from;
+ const [toElement, toShadowRoot] = to;
+ assert_true(result, 'Failed to focus ' + fromElement.id);
+ const message =
+ `Focus should move ${direction} from ${fromElement.id} to ${toElement.id}`;
+ assert_equals(innermostActiveElementWithShadowRoot(toShadowRoot), toElement, message);
+}
+
+async function assert_focus_navigation_elements_with_shadow_root(elements, direction) {
+ assert_true(
+ elements.length >= 2,
+ 'length of elements should be greater than or equal to 2.');
+ for (var i = 0; i + 1 < elements.length; ++i)
+ await assert_focus_navigation_element_with_shadow_root(elements[i], elements[i + 1], direction);
+}
+
+async function assert_focus_navigation_forward_with_shadow_root(elements) {
+ return assert_focus_navigation_elements_with_shadow_root(elements, 'forward');
+}
+
+async function assert_focus_navigation_backward_with_shadow_root(elements) {
+ return assert_focus_navigation_elements_with_shadow_root(elements, 'backward');
+}
\ No newline at end of file
diff --git a/shadow-dom/focus-navigation/resources/shadow-dom.js b/shadow-dom/focus-navigation/resources/shadow-dom.js
new file mode 100644
index 000000000000000..506d715cc3d49a9
--- /dev/null
+++ b/shadow-dom/focus-navigation/resources/shadow-dom.js
@@ -0,0 +1,178 @@
+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 convertTemplatesToShadowRootsWithin(node) {
+ var nodes = node.querySelectorAll('template');
+ for (var i = 0; i < nodes.length; ++i) {
+ var template = nodes[i];
+ var mode = template.getAttribute('data-mode');
+ var delegatesFocus = template.hasAttribute('data-delegatesFocus');
+ var parent = template.parentNode;
+ parent.removeChild(template);
+ var shadowRoot;
+ if (!mode || mode == 'v0') {
+ shadowRoot = parent.attachShadow({ mode: 'open' });
+ } else {
+ shadowRoot =
+ parent.attachShadow({ 'mode': mode, 'delegatesFocus': delegatesFocus });
+ }
+ var expose = template.getAttribute('data-expose-as');
+ if (expose)
+ window[expose] = shadowRoot;
+ if (template.id)
+ shadowRoot.id = template.id;
+ var fragments = document.importNode(template.content, true);
+ shadowRoot.appendChild(fragments);
+
+ convertTemplatesToShadowRootsWithin(shadowRoot);
+ }
+}
+
+function convertDeclarativeTemplatesToShadowRootsWithin(root) {
+ root.querySelectorAll("template[shadowroot]").forEach(template => {
+ const mode = template.getAttribute("shadowroot");
+ const shadowRoot = template.parentNode.attachShadow({ mode });
+ shadowRoot.appendChild(template.content);
+ template.remove();
+ attachShadowRoots(shadowRoot);
+ });
+}
+
+function isShadowHost(node) {
+ return node && node.nodeType == Node.ELEMENT_NODE && node.shadowRoot;
+}
+
+function isIFrameElement(element) {
+ return element && element.nodeName == 'IFRAME';
+}
+
+// Returns node from shadow/iframe tree "path".
+function getNodeInComposedTree(path) {
+ var ids = path.split('/');
+ var node = document.getElementById(ids[0]);
+ for (var i = 1; node != null && i < ids.length; ++i) {
+ if (isIFrameElement(node))
+ node = node.contentDocument.getElementById(ids[i]);
+ else if (isShadowHost(node))
+ node = node.shadowRoot.getElementById(ids[i]);
+ else
+ return null;
+ }
+ return node;
+}
+
+function createTestTree(node) {
+ let ids = {};
+
+ function attachShadowFromTemplate(template) {
+ let parent = template.parentNode;
+ parent.removeChild(template);
+ let shadowRoot;
+ if (template.getAttribute('data-mode') === 'v0') {
+ // For legacy Shadow DOM
+ shadowRoot = parent.attachShadow({ mode: 'open' });
+ } else 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;
+}
+
+function dispatchEventWithLog(nodes, target, event) {
+ 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(event.type, (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);
+ })
+ ]);
+ });
+ }
+ }
+ target.dispatchEvent(event);
+ 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][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');
+ }
+}
+
+function assert_background_color(path, color) {
+ assert_equals(
+ window.getComputedStyle(getNodeInComposedTree(path)).backgroundColor,
+ color, 'backgroundColor for ' + path + ' should be ' + color);
+}
diff --git a/shadow-dom/focus/focus-method-with-delegatesFocus.html b/shadow-dom/focus/focus-method-with-delegatesFocus.html
new file mode 100644
index 000000000000000..8caea8ccda47591
--- /dev/null
+++ b/shadow-dom/focus/focus-method-with-delegatesFocus.html
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shadow-dom/focus/focus-shadowhost-display-none.html b/shadow-dom/focus/focus-shadowhost-display-none.html
new file mode 100644
index 000000000000000..40f1b01f6644bb3
--- /dev/null
+++ b/shadow-dom/focus/focus-shadowhost-display-none.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+