1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
<!DOCTYPE html>
<title>Test Script-Based Focus for Fenced Frames</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/common/utils.js"></script>
<script src="resources/utils.js"></script>
<script src="/common/dispatcher/dispatcher.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<body>
<script>
async function AttemptButtonFocus(frame, expecting_focus) {
await frame.execute(async (expecting_focus) => {
const button = document.createElement("button");
document.body.append(button);
button.focus();
assert_equals(document.activeElement == button, expecting_focus,
"Button's focus should match expected focus");
}, [expecting_focus]);
}
async function ClickOn(element, actions) {
// Wait until the window size is initialized.
while (window.innerWidth == 0) {
await new Promise(resolve => requestAnimationFrame(resolve));
}
await actions.pointerMove(0, 0, {origin: element})
.pointerDown()
.pointerUp()
.send();
}
async function SetupTest(click=true) {
// Clean up any leftover frames from prior tests.
document.querySelectorAll("fencedframe").forEach(e => {
e.remove();
})
const actions = new test_driver.Actions();
const frame = attachFencedFrameContext();
const fencedframe_element = frame.element;
if (click)
await ClickOn(document.body, actions);
return [actions, frame, fencedframe_element];
}
promise_test(async () => {
const [actions, ff1, ff1_element] = await SetupTest(false);
await ClickOn(ff1_element, actions);
await AttemptButtonFocus(ff1, true);
const button = document.createElement("button");
document.body.append(button);
button.focus();
assert_true(document.activeElement == button,
"The button should have focus");
assert_false(navigator.userActivation.isActive,
"Window should not have user activation");
}, "An embedder can focus out of a fenced frame");
promise_test(async () => {
const [actions, frame, fencedframe_element] = await SetupTest();
await AttemptButtonFocus(frame, false);
await ClickOn(fencedframe_element, actions);
await AttemptButtonFocus(frame, true);
}, "Fenced frames can't pull script focus until getting user activation");
promise_test(async t => {
const [actions, frame, fencedframe_element] = await SetupTest();
await ClickOn(fencedframe_element, actions);
await ClickOn(document.body, actions);
await AttemptButtonFocus(frame, true);
// Give the browser time to receive the focus event before attempting
// another focus.
await t.step_timeout(async () => {await AttemptButtonFocus(frame, true);},
500);
}, "Focused fenced frames can move programmatic focus within frame");
promise_test(async () => {
const [actions, frame, fencedframe_element] = await SetupTest();
await ClickOn(fencedframe_element, actions);
await ClickOn(document.body, actions);
// This will pull focus across a frame boundary and consume user activation.
await AttemptButtonFocus(frame, true);
await ClickOn(document.body, actions);
await AttemptButtonFocus(frame, false);
}, "Script focus into a fenced frame consumes user activation");
promise_test(async () => {
const [actions, ff1, ff1_element] = await SetupTest();
const ff2 = attachFencedFrameContext();
const ff2_element = ff2.element;
await ClickOn(ff1_element, actions);
await AttemptButtonFocus(ff1, true);
await AttemptButtonFocus(ff2, false);
}, "Another fenced frame cannot pull focus out of a focused fenced frame");
promise_test(async () => {
const [actions, ff1, ff1_element] = await SetupTest();
await ClickOn(ff1_element, actions);
await AttemptButtonFocus(ff1, true);
await ff1.execute(async () => {
const ff2 = attachFencedFrameContext();
await ff2.execute(async () => {
const button = document.createElement("button");
document.body.append(button);
button.focus();
assert_false(document.activeElement == button,
"The button should not have focus");
assert_false(navigator.userActivation.isActive,
"The fenced frame should not have user activation");
});
});
}, "A fenced frame nested in another fenced frame cannot pull focus");
promise_test(async () => {
const [actions, ff1, ff1_element] = await SetupTest();
await ClickOn(document.body, actions);
const button = document.createElement("button");
document.body.append(button);
button.focus();
assert_equals(document.activeElement, button,
"The button in the main page should have focus.");
await ff1.execute(async () => {
assert_false(navigator.userActivation.isActive,
"The fenced frame should not have user activation.");
window.focus();
});
assert_equals(document.activeElement, button,
"The button in the main page should still have focus.");
}, "A fenced frame cannot pull window.focus() without user activation");
promise_test(async () => {
const [actions, ff1, ff1_element] = await SetupTest();
await ClickOn(ff1_element, actions);
await ClickOn(document.body, actions);
const button = document.createElement("button");
document.body.append(button);
button.focus();
assert_equals(document.activeElement, button,
"The button should have focus.");
await ff1.execute(async () => {
assert_true(navigator.userActivation.isActive,
"The fenced frame should have user activation.");
window.focus();
assert_false(navigator.userActivation.isActive,
"The fenced frame's user activation should be consumed by the focus");
});
assert_equals(document.activeElement, document.body,
"The main page's focus should be pulled away from the button.");
}, "A fenced frame can pull window.focus() after user activation");
promise_test(async () => {
var actions = new test_driver.Actions();
const frame = attachIFrameContext(
{origin: get_host_info().HTTPS_REMOTE_ORIGIN});
const iframe_element =
document.body.getElementsByTagName('iframe')[0];
await frame.execute(async () => {
const button = document.createElement("button");
document.body.append(button);
button.focus();
assert_equals(document.activeElement, button,
"The button in the iframe should have focus.");
}, [true]);
const button = document.createElement("button");
document.body.append(button);
button.focus();
assert_equals(document.activeElement, button,
"The button in the main page should have focus.");
}, "An cross-origin iframe can pull focus back and forth without activation");
</script>
</body>
|