summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/fenced-frame/script-focus.https.html
blob: 0bef98219bd192851b30a9f8dbd61fe17c724962 (plain)
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>