Skip to content

Initial attempt at implementing referenceTarget. #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Reference Target tentative tests

Tests in this directory are for the proposed Reference Target feature for
shadow dom. This is not yet standardized and browsers should not be expected to
pass these tests.

See the explainer at
https://github.com/WICG/aom/blob/gh-pages/reference-target-explainer.md for
more information about the API.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Popover content

FAIL ShadowRoot ReferenceTarget works with anchor attribute. assert_equals: popover.offsetLeft expected 100 but got 682
FAIL ShadowRoot ReferenceTarget works with anchor attribute via options. assert_equals: popover.offsetLeft expected 100 but got 682
FAIL ShadowRoot ReferenceTarget works with .anchorElement property. assert_equals: popover.offsetLeft expected 100 but got 682

Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<!DOCTYPE HTML><!-- webkit-test-runner [ ShadowRootReferenceTargetEnabled=true ] -->
<html>

<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/wai-aria/scripts/aria-utils.js"></script>
<style>
body {
margin: 0;
}

[popover] {
position: absolute;
left: anchor(right);
top: anchor(top);
margin: 0;
}
</style>
</head>

<body>
<div>
<x-anchor id="x-anchor-1">
<template shadowrootmode="open" shadowrootreferencetarget="anchor">
<style>
div {
width: 100px;
height: 100px;
}

#anchor {
background-color: yellow;
}
</style>

<div></div>
<div id="anchor"></div>
</template>
</x-anchor>
<div id="popover-1" popover anchor="x-anchor-1">Popover content</div>
</div>

<div>
<x-anchor-2 id="x-anchor-2"></x-anchor-2>
<div id="popover-2" popover anchor="x-anchor-2">Popover content</div>
</div>
<script>
const customAnchor = document.querySelector('x-anchor-2');
customAnchor.attachShadow({ mode: 'open', referenceTarget: 'anchor' });
customAnchor.shadowRoot.innerHTML =`
<style>
div {
width: 100px;
height: 100px;
}

#anchor {
background-color: yellow;
}
</style>

<div></div>
<div id="anchor"></div>`;
</script>

<div>
<x-anchor id="x-anchor-3">
<template shadowrootmode="open" shadowrootreferencetarget="anchor">
<style>
div {
width: 100px;
height: 100px;
}

#anchor {
background-color: yellow;
}
</style>

<div></div>
<div id="anchor"></div>
</template>
</x-anchor>
<div id="popover-3" popover>Popover content</div>
</div>

<script>
function testPopoverAnchor(id, name) {
test(function () {
const popover = document.getElementById(id);
popover.showPopover();
assert_equals(popover.offsetLeft, 100, "popover.offsetLeft");
assert_equals(popover.offsetTop, 100, "popover.offsetTop");
// Clean up the test context for future tests.
popover.parentElement.remove();
}, name);
}
testPopoverAnchor('popover-1', "ShadowRoot ReferenceTarget works with anchor attribute.");
testPopoverAnchor('popover-2', "ShadowRoot ReferenceTarget works with anchor attribute via options.");
document.getElementById('popover-3').anchorElement = document.getElementById('x-anchor-3');
testPopoverAnchor('popover-3', "ShadowRoot ReferenceTarget works with .anchorElement property.");
</script>
</body>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Label 2

PASS Label 1
PASS Label 2
PASS Label 3

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!DOCTYPE HTML><!-- webkit-test-runner [ ShadowRootReferenceTargetEnabled=true ] -->
<html>

<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/wai-aria/scripts/aria-utils.js"></script>
</head>

<body>

<!-- 1. Declaratively defined custom label -->
<x-label1 id="x-label1">
<template shadowrootmode="closed" shadowrootreferencetarget="label1">
<span>FAIL IF INCLUDED</span>
<label id="label1">Label 1</label>
</template>
</x-label1>
<input class="ex" aria-labelledby="x-label1" data-expectedlabel="Label 1">

<!-- 2. Imperatively defined custom element -->
<script>
customElements.define(
"x-label2",
class XLabel2 extends HTMLElement {
constructor() {
super();

this.shadowRoot_ = this.attachShadow({ mode: "closed" });
this.shadowRoot_.innerHTML = `
<span>FAIL IF INCLUDED</span>
<label id="label2">
<slot></slot>
</label>
`;
this.shadowRoot_.referenceTarget = "label2";
}
}
);
</script>
<x-label2 id="x-label2">Label 2</x-label2>
<input class="ex" aria-labelledby="x-label2" data-expectedlabel="Label 2">

<!-- 3. Setting .ariaLabelledByElements to target a declaratively defined custom label -->
<x-label3 id="x-label3">
<template shadowrootmode="closed" shadowrootreferencetarget="label3">
<span>FAIL IF INCLUDED</span>
<label id="label3">Label 3</label>
</template>
</x-label3>
<input id="input3" class="ex" data-expectedlabel="Label 3">
<script>
document.getElementById("input3").ariaLabelledByElements = [ document.getElementById("x-label3") ];
</script>

<script>
AriaUtils.verifyLabelsBySelector('.ex');
</script>

</body>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@


FAIL Changing the ID of the referenced element updates the computed label assert_equals: expected "Outside the label Label 1 Label 2" but got ""
FAIL Removing the referenced element updates the computed label assert_equals: expected "Outside the label Label 2" but got ""
PASS New referenced element prepended to the shadow supercedes the existing label
PASS Changing the reference target ID updates the computed label

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<!DOCTYPE HTML><!-- webkit-test-runner [ ShadowRootReferenceTargetEnabled=true ] -->
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/wai-aria/scripts/aria-utils.js"></script>
</head>
<body>

<div id="test-container"></div>

<script>
async function setup_test() {
const test_container = document.querySelector("#test-container");
test_container.setHTMLUnsafe(`
<div id="host1">
<template shadowrootmode="open" shadowrootreferencetarget="label1">
<span>Outside the label</span>
<label id="label1">Label 1</label>
<label id="label2">Label 2</label>
</template>
</div>
<input id="input1" aria-labelledby="host1">`);
const input1 = test_container.querySelector("#input1");
assert_equals(await test_driver.get_computed_label(input1), "Label 1");
return test_container
}

promise_test(async t => {
const test_container = await setup_test();
const host1 = test_container.querySelector("#host1");
const label1 = host1.shadowRoot.querySelector("#label1");
label1.id = "changed";
assert_equals(await test_driver.get_computed_label(input1), "Outside the label Label 1 Label 2");
}, "Changing the ID of the referenced element updates the computed label");

promise_test(async t => {
const test_container = await setup_test();
const host1 = test_container.querySelector("#host1");
const label1 = host1.shadowRoot.querySelector("#label1");
label1.remove();
assert_equals(await test_driver.get_computed_label(input1), "Outside the label Label 2");
}, "Removing the referenced element updates the computed label");

promise_test(async t => {
const test_container = await setup_test();
const host1 = test_container.querySelector("#host1");
const new_label = document.createElement("label");
new_label.id = "label1";
new_label.textContent = "New label";
host1.shadowRoot.prepend(new_label);
assert_equals(await test_driver.get_computed_label(input1), "New label");
}, "New referenced element prepended to the shadow supercedes the existing label");

promise_test(async t => {
const test_container = await setup_test();
const host1 = test_container.querySelector("#host1");
host1.shadowRoot.referenceTarget = "label2";
assert_equals(await test_driver.get_computed_label(input1), "Label 2");
}, "Changing the reference target ID updates the computed label");
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Input 1
Input 1 via Options
Input 2 Input 2 via Options

PASS Label applies to descendant custom element that uses shadowrootreferencetarget (Input 1)
PASS Label applies to descendant custom element that uses shadowrootreferencetarget (Input 1 via Options)
PASS Label applies to multiple layers of descendant custom elements that use shadowrootreferencetarget (Input 2)
PASS Label applies to multiple layers of descendant custom elements that use shadowrootreferencetarget (Input 2 via Options)

Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!DOCTYPE HTML><!-- webkit-test-runner [ ShadowRootReferenceTargetEnabled=true ] -->
<html>

<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/wai-aria/scripts/aria-utils.js"></script>
</head>

<body>
<!-- 1. Label applies to descendant custom element that uses shadowrootreferencetarget -->

<label>
Input 1
<div>
<x-input1 id="x-input1">
<template shadowrootmode="open" shadowrootreferencetarget="input">
<input id="input">
</template>
</x-input1>
</div>
</label>

<label>
Input 1 via Options
<div>
<x-input1 id="x-input1-a"></x-input1>
</div>
</label>
<script>
const customInput1 = document.querySelector('#x-input1-a');
customInput1.attachShadow({ mode: 'open', referenceTarget: 'input' });
customInput1.shadowRoot.innerHTML = `<input id="input">`;
</script>

<script>
function testImplicitLabelAssociation(id, label) {
promise_test(async t => {
const x_input = document.getElementById(id);
const input = x_input.shadowRoot.getElementById('input');

// The label should apply to the input element and not the host.
assert_equals(await test_driver.get_computed_label(x_input), "");
assert_equals(await test_driver.get_computed_label(input), label);
}, "Label applies to descendant custom element that uses shadowrootreferencetarget (" + label + ")");
}
testImplicitLabelAssociation('x-input1', 'Input 1');
testImplicitLabelAssociation('x-input1-a', 'Input 1 via Options');
</script>

<!-- 2. Label applies to multiple layers of descendant custom elements that use shadowrootreferencetarget -->

<label>
Input 2
<x-outer2 id="x-outer2">
<template shadowrootmode="open" shadowrootreferencetarget="x-inner2">
<x-inner2 id="x-inner2">
<template shadowrootmode="open" shadowrootreferencetarget="input">
<input id="input">
</template>
</x-inner2>
</template>
</x-outer2>
</label>

<label>
Input 2 via Options
<x-outer2 id="x-outer2-a"></x-outer2>
</label>

<script>
const customOuter2 = document.querySelector('#x-outer2-a');
customOuter2.attachShadow({ mode: 'open', referenceTarget: 'x-inner2' });
customOuter2.shadowRoot.innerHTML = `<x-inner2 id="x-inner2"></x-inner2>`;
const customInner2 = customOuter2.shadowRoot.querySelector('x-inner2');
customInner2.attachShadow({ mode: 'open', referenceTarget: 'input' });
customInner2.shadowRoot.innerHTML = `<input id="input">`;
</script>

<script>
function testDeepImplicitLabelAssociation(id, label) {
promise_test(async t => {
const outer = document.getElementById(id);
const inner = outer.shadowRoot.getElementById('x-inner2');
const input = inner.shadowRoot.getElementById('input');

// The label should apply to the input element and not any of the hosts.
assert_equals(await test_driver.get_computed_label(outer), "");
assert_equals(await test_driver.get_computed_label(inner), "");
assert_equals(await test_driver.get_computed_label(input), label);
}, "Label applies to multiple layers of descendant custom elements that use shadowrootreferencetarget (" + label + ")");
}
testDeepImplicitLabelAssociation('x-outer2', 'Input 2');
testDeepImplicitLabelAssociation('x-outer2-a', 'Input 2 via Options');
</script>

</body>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Input 1 Input 2 A F Input 4

PASS Label for attribute targets a custom element using shadowrootreferencetarget
PASS Label for attribute targets a custom element using shadowrootreferencetarget inside multiple layers of shadow roots
PASS Multiple labels targeting a custom element using shadowrootreferencetarget inside multiple layers of shadow roots
PASS Setting .htmlFor property to target a custom element using shadowrootreferencetarget

Loading