summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/browser/datetime/browser_datetime_blur.js
blob: 0671661e3142d608a793fde028148fb4926b5a4b (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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const PAGE_CONTENT = `data:text/html,
  <body onload='gBlurEvents = 0; gDateFocusEvents = 0; gTextFocusEvents = 0'>
    <input type='date' id='date' onfocus='gDateFocusEvents++' onblur='gBlurEvents++'>
    <input type='text' id='text' onfocus='gTextFocusEvents++'>
  </body>`;

function getBlurEvents() {
  return SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
    return content.wrappedJSObject.gBlurEvents;
  });
}

function getDateFocusEvents() {
  return SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
    return content.wrappedJSObject.gDateFocusEvents;
  });
}

function getTextFocusEvents() {
  return SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
    return content.wrappedJSObject.gTextFocusEvents;
  });
}

/**
 * Test that when a picker panel is opened by an input
 * the input is not blurred
 */
add_task(async function test_parent_blur() {
  info(
    "Test that when a picker panel is opened by an input the parent is not blurred"
  );

  // Set "prefers-reduced-motion" media to "reduce"
  // to avoid intermittent scroll failures (1803612, 1803687)
  await SpecialPowers.pushPrefEnv({
    set: [["ui.prefersReducedMotion", 1]],
  });
  Assert.ok(
    matchMedia("(prefers-reduced-motion: reduce)").matches,
    "The reduce motion mode is active"
  );

  await helper.openPicker(PAGE_CONTENT, false, "showPicker");

  Assert.equal(
    await getDateFocusEvents(),
    0,
    "Date input field is not calling a focus event when the '.showPicker()' method is called"
  );
  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    const input = content.document.querySelector("#date");

    Assert.ok(
      !input.matches(":focus"),
      `The keyboard focus is not placed on the date input after showPicker is called`
    );
  });

  let closedOnEsc = helper.promisePickerClosed();

  // Close a date picker
  EventUtils.synthesizeKey("KEY_Escape", {});

  await closedOnEsc;

  Assert.equal(
    helper.panel.state,
    "closed",
    "Panel should be closed on Escape"
  );
  Assert.equal(
    await getDateFocusEvents(),
    0,
    "Date input field is not focused when its picker is dismissed with Escape key"
  );
  Assert.equal(
    await getBlurEvents(),
    0,
    "Date input field is not blurred when the picker is closed with Escape key"
  );

  // Ensure focus is on the input field
  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    const input = content.document.querySelector("#date");

    input.focus();

    Assert.ok(
      input.matches(":focus"),
      `The keyboard focus is placed on the date input field`
    );
  });
  Assert.equal(
    await getDateFocusEvents(),
    1,
    "A focus event was fired on the Date input field"
  );

  let readyOnKey = helper.waitForPickerReady();

  // Open a date picker
  EventUtils.synthesizeKey(" ", {});

  await readyOnKey;

  Assert.equal(
    helper.panel.state,
    "open",
    "Date picker panel should be opened"
  );
  Assert.equal(
    helper.panel
      .querySelector("#dateTimePopupFrame")
      .contentDocument.activeElement.getAttribute("role"),
    "gridcell",
    "The picker is opened and a calendar day is focused"
  );

  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    const input = content.document.querySelector("#date");

    Assert.ok(
      input.matches(":focus"),
      `The keyboard focus is retained on the date input field`
    );
    Assert.equal(
      input,
      content.document.activeElement,
      "Input field does not loose focus when its picker is opened and focused"
    );
  });

  Assert.equal(
    await getBlurEvents(),
    0,
    "Date input field is not blurred when its picker is opened and focused"
  );
  Assert.equal(
    await getDateFocusEvents(),
    1,
    "No new focus events were fired on the Date input while its picker is opened"
  );

  info(
    `Test that the date input field is not blurred after interacting
    with a month-year panel`
  );

  // Move focus from the today's date to the month-year toggle button:
  EventUtils.synthesizeKey("KEY_Tab", { repeat: 3 });

  Assert.ok(
    helper.getElement(BTN_MONTH_YEAR).matches(":focus"),
    "The month-year toggle button is focused"
  );

  // Open the month-year selection panel:
  EventUtils.synthesizeKey(" ", {});

  Assert.equal(
    helper.getElement(BTN_MONTH_YEAR).getAttribute("aria-expanded"),
    "true",
    "Month-year button is expanded when the spinners are shown"
  );
  Assert.ok(
    BrowserTestUtils.is_visible(helper.getElement(MONTH_YEAR_VIEW)),
    "Month-year selection panel is visible"
  );

  // Move focus from the month-year toggle button to the year spinner:
  EventUtils.synthesizeKey("KEY_Tab", { repeat: 2 });

  // Change the year spinner value from February 2023 to March 2023:
  EventUtils.synthesizeKey("KEY_ArrowDown", {});

  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    const input = content.document.querySelector("#date");

    Assert.ok(
      input.matches(":focus"),
      `The keyboard focus is retained on the date input field`
    );
    Assert.equal(
      input,
      content.document.activeElement,
      "Input field does not loose focus when the month-year picker is opened and interacted with"
    );
  });

  Assert.equal(
    await getBlurEvents(),
    0,
    "Date input field is not blurred after interacting with a month-year panel"
  );

  info(`Test that when a picker panel is opened and then it is closed
  with a click on the other field, the focus is updated`);

  let closedOnClick = helper.promisePickerClosed();

  // Close a picker by clicking on another input
  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#text",
    {},
    gBrowser.selectedBrowser
  );

  await closedOnClick;

  Assert.equal(
    helper.panel.state,
    "closed",
    "Panel should be closed when another element is clicked"
  );

  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => {
    const inputText = content.document.querySelector("#text");
    const inputDate = content.document.querySelector("#date");

    Assert.ok(
      inputText.matches(":focus"),
      `The keyboard focus is moved to the text input field`
    );
    Assert.equal(
      inputText,
      content.document.activeElement,
      "Text input field gains a focus when clicked"
    );
    Assert.ok(
      !inputDate.matches(":focus"),
      `The keyboard focus is moved from the date input field`
    );
    Assert.notEqual(
      inputDate,
      content.document.activeElement,
      "Date input field is not focused anymore"
    );
  });

  Assert.equal(
    await getBlurEvents(),
    1,
    "Date input field is blurred when focus is moved to the text input field"
  );
  Assert.equal(
    await getTextFocusEvents(),
    1,
    "Text input field is focused when it is clicked"
  );
  Assert.equal(
    await getDateFocusEvents(),
    1,
    "No new focus events were fired on the Date input after its picker was closed"
  );

  await helper.tearDown();
  // Clear the prefers-reduced-motion pref from the test profile:
  await SpecialPowers.popPrefEnv();
});