summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/popovers/popover-focus-2.tentative.html
blob: 569b633886cf6a77546a5bd6680b339ff05db1c3 (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
<!DOCTYPE html>
<meta charset="utf-8" />
<title>Popover focus behaviors</title>
<link rel="author" href="mailto:masonf@chromium.org">
<link rel=help href="https://open-ui.org/components/popover.research.explainer">
<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="resources/popover-utils.js"></script>

<div id=fixup>
  <button id=button1>Button1</button>
  <div popover id=popover1 style="top:100px">
    <button id=inside_popover1>Inside1</button>
    <button id=invoker2 popovertoggletarget=popover2>Nested Invoker 2</button>
    <button id=inside_popover2>Inside2</button>
  </div>
  <button id=button2>Button2</button>
  <button popovertoggletarget=popover1 id=invoker1>Invoker1</button>
  <button id=button3>Button3</button>
  <div popover id=popover2 style="top:200px">
    <button id=inside_popover3>Inside3</button>
    <button id=invoker3 popovertoggletarget=popover3>Nested Invoker 3</button>
  </div>
  <div popover id=popover3 style="top:300px">
    Non-focusable popover
  </div>
  <button id=button4>Button4</button>
</div>
<style>
  #fixup [popover] {
    bottom:auto;
  }
</style>
<script>
async function verifyFocusOrder(order) {
  order[0].focus();
  for(let i=0;i<order.length;++i) {
    const control = order[i];
    assert_equals(document.activeElement,control,`Step ${i+1}`);
    await sendTab();
  }
  // Shift-tab not supported, crbug.com/893480.
  // for(let i=order.length-1;i>=0;--i) {
  //   const control = order[i];
  //   await sendShiftTab();
  //   assert_equals(document.activeElement,control,`Step ${i+1} (backwards)`);
  // }
}
promise_test(async t => {
  button1.focus();
  assert_equals(document.activeElement,button1);
  await sendTab();
  assert_equals(document.activeElement,button2,'Hidden popover should be skipped');
  // Shift-tab not supported, crbug.com/893480.
  // await sendShiftTab();
  // assert_equals(document.activeElement,button1,'Hidden popover should be skipped backwards');
  //await sendTab();
  await sendTab();
  assert_equals(document.activeElement,invoker1);
  await sendEnter(); // Activate the invoker
  assert_true(popover1.matches(':open'), 'popover1 should be invoked by invoker1');
  assert_equals(document.activeElement,invoker1,'Focus should not move when popover is shown');
  await sendTab();
  assert_equals(document.activeElement,inside_popover1,'Focus should move from invoker into the open popover');
  await sendTab();
  assert_equals(document.activeElement,invoker2,'Focus should move within popover');
  await verifyFocusOrder([button1, button2, invoker1, inside_popover1, invoker2, inside_popover2, button3, button4]);
  invoker2.focus();
  await sendEnter(); // Activate the nested invoker
  assert_true(popover2.matches(':open'), 'popover2 should be invoked by nested invoker');
  assert_equals(document.activeElement,invoker2,'Focus should stay on the invoker');
  await sendTab();
  assert_equals(document.activeElement,inside_popover3,'Focus should move into nested popover');
  await sendTab();
  assert_equals(document.activeElement,invoker3);
  await sendEnter(); // Activate the (empty) nested invoker
  assert_true(popover3.matches(':open'), 'popover3 should be invoked by nested invoker');
  assert_equals(document.activeElement,invoker3,'Focus should stay on the invoker');
  await sendTab();
  assert_equals(document.activeElement,inside_popover2,'Focus should skip popover without focusable content, going back to higher scope');
  await sendTab();
  assert_equals(document.activeElement,button3,'Focus should exit popovers');
  await sendTab();
  assert_equals(document.activeElement,button4,'Focus should skip popovers');
  button1.focus();
  await verifyFocusOrder([button1, button2, invoker1, inside_popover1, invoker2, inside_popover3, invoker3, inside_popover2, button3, button4]);
}, "Popover focus navigation");
</script>

<button id=circular0 popovertoggletarget=popover4>Invoker</button>
<div id=popover4 popover>
  <button id=circular1 autofocus popoverhidetarget=popover4></button>
  <button id=circular2 popovershowtarget=popover4></button>
  <button id=circular3 popovertoggletarget=popover4></button>
</div>
<button id=circular4>after</button>
<script>
promise_test(async t => {
  circular0.focus();
  await sendEnter(); // Activate the invoker
  await verifyFocusOrder([circular0, circular1, circular2, circular3, circular4]);
  popover4.hidePopover();
}, "Circular reference tab navigation");
</script>

<div id=deleted>
  <button popovershowtarget=deleted1>Show popover</button>
  <div popover id=deleted1>
    <button popoverhidetarget=deleted1 autofocus>Hide popover</button>
  </div>
</div>
<script>
promise_test(async t => {
  const invoker = document.querySelector('#deleted>button');
  const popover = document.querySelector('#deleted>[popover]');
  const hideButton = popover.querySelector('[popoverhidetarget]');
  invoker.focus(); // Make sure button is focused.
  assert_equals(document.activeElement,invoker);
  await sendEnter(); // Activate the invoker
  assert_true(popover.matches(':open'), 'popover should be invoked by invoker');
  assert_equals(document.activeElement,hideButton,'Hide button should be focused due to autofocus attribute');
  await sendEnter(); // Activate the hide invoker
  assert_false(popover.matches(':open'), 'popover should be hidden by invoker');
  assert_equals(document.activeElement,invoker,'Focus should be returned to the invoker');
}, "Popover focus returns when popover is hidden by invoker");
</script>