summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/tests/browser/browser_ime_composition.js
blob: 13a0cf0584692c85b73bfd81da23a8b42ceafb49 (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
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

// Tests ime composition handling.

function composeAndCheckPanel(string, isPopupOpen) {
  EventUtils.synthesizeCompositionChange({
    composition: {
      string,
      clauses: [
        {
          length: string.length,
          attr: Ci.nsITextInputProcessor.ATTR_RAW_CLAUSE,
        },
      ],
    },
    caret: { start: string.length, length: 0 },
    key: { key: string ? string[string.length - 1] : "KEY_Backspace" },
  });
  Assert.equal(
    UrlbarTestUtils.isPopupOpen(window),
    isPopupOpen,
    "Check panel open state"
  );
}

add_task(async function () {
  await SpecialPowers.pushPrefEnv({
    set: [
      ["browser.urlbar.tabToSearch.onboard.interactionsLeft", 0],
      ["browser.urlbar.suggest.quickactions", false],
    ],
  });

  await PlacesUtils.history.clear();
  // Add at least one typed entry for the empty results set. Also clear history
  // so that this can be over the autofill threshold.
  await PlacesTestUtils.addVisits({
    uri: "http://mozilla.org/",
    transition: PlacesUtils.history.TRANSITIONS.TYPED,
  });
  // Add a bookmark to ensure we autofill the engine domain for tab-to-search.
  let bm = await PlacesUtils.bookmarks.insert({
    url: "http://example.com/",
    parentGuid: PlacesUtils.bookmarks.menuGuid,
  });

  await SearchTestUtils.installSearchExtension(
    {
      name: "Test",
      keyword: "@test",
    },
    { setAsDefault: true }
  );

  registerCleanupFunction(async () => {
    await PlacesUtils.bookmarks.remove(bm);
    await PlacesUtils.history.clear();
  });

  // Test both pref values.
  for (let val of [true, false]) {
    await SpecialPowers.pushPrefEnv({
      set: [["browser.urlbar.keepPanelOpenDuringImeComposition", val]],
    });
    await test_composition(val);
    await test_composition_searchMode_preview(val);
    await test_composition_tabToSearch(val);
    await test_composition_autofill(val);
  }
  await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur());
});

async function test_composition(keepPanelOpenDuringImeComposition) {
  gURLBar.focus();
  await UrlbarTestUtils.promisePopupClose(window);

  info("Check the panel state during composition");
  composeAndCheckPanel("I", false);
  Assert.equal(gURLBar.value, "I", "Check urlbar value");
  composeAndCheckPanel("In", false);
  Assert.equal(gURLBar.value, "In", "Check urlbar value");

  info("Committing composition should open the panel.");
  await UrlbarTestUtils.promisePopupOpen(window, () => {
    EventUtils.synthesizeComposition({
      type: "compositioncommitasis",
      key: { key: "KEY_Enter" },
    });
  });
  Assert.equal(gURLBar.value, "In", "Check urlbar value");

  info("Check the panel state starting from an open panel.");
  Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
  composeAndCheckPanel("t", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "Int", "Check urlbar value");
  composeAndCheckPanel("te", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "Inte", "Check urlbar value");

  // Committing composition should open the popup.
  await UrlbarTestUtils.promisePopupOpen(window, () => {
    EventUtils.synthesizeComposition({
      type: "compositioncommitasis",
      key: { key: "KEY_Enter" },
    });
  });
  Assert.equal(gURLBar.value, "Inte", "Check urlbar value");

  info("If composition is cancelled, the value shouldn't be changed.");
  Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
  composeAndCheckPanel("r", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "Inter", "Check urlbar value");
  composeAndCheckPanel("", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "Inte", "Check urlbar value");
  // Canceled compositionend should reopen the popup.
  await UrlbarTestUtils.promisePopupOpen(window, () => {
    EventUtils.synthesizeComposition({
      type: "compositioncommit",
      data: "",
      key: { key: "KEY_Escape" },
    });
  });
  Assert.equal(gURLBar.value, "Inte", "Check urlbar value");

  info(
    "If composition replaces some characters and canceled, the search string should be the latest value."
  );
  Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
  EventUtils.synthesizeKey("VK_LEFT", { shiftKey: true });
  EventUtils.synthesizeKey("VK_LEFT", { shiftKey: true });
  composeAndCheckPanel("t", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "Int", "Check urlbar value");
  composeAndCheckPanel("te", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "Inte", "Check urlbar value");
  composeAndCheckPanel("", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "In", "Check urlbar value");

  // Canceled compositionend should search the result with the latest value.
  await UrlbarTestUtils.promisePopupOpen(window, () => {
    EventUtils.synthesizeComposition({
      type: "compositioncommitasis",
      key: { key: "KEY_Escape" },
    });
  });
  Assert.equal(gURLBar.value, "In", "Check urlbar value");

  Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
  info(
    "Removing all characters should leave the popup open, Esc should then close it."
  );
  EventUtils.synthesizeKey("KEY_Backspace", {});
  EventUtils.synthesizeKey("KEY_Backspace", {});
  Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
  await UrlbarTestUtils.promisePopupClose(window, () => {
    EventUtils.synthesizeKey("KEY_Escape", {});
  });
  Assert.equal(gURLBar.value, "", "Check urlbar value");

  info("Composition which is canceled shouldn't cause opening the popup.");
  Assert.ok(!UrlbarTestUtils.isPopupOpen(window), "Popup should be closed");
  composeAndCheckPanel("I", false);
  Assert.equal(gURLBar.value, "I", "Check urlbar value");
  composeAndCheckPanel("In", false);
  Assert.equal(gURLBar.value, "In", "Check urlbar value");
  composeAndCheckPanel("", false);
  Assert.equal(gURLBar.value, "", "Check urlbar value");

  info("Canceled compositionend shouldn't open the popup if it was closed.");
  await UrlbarTestUtils.promisePopupClose(window);
  EventUtils.synthesizeComposition({
    type: "compositioncommitasis",
    key: { key: "KEY_Escape" },
  });
  Assert.ok(!UrlbarTestUtils.isPopupOpen(window), "Popup should be closed");
  Assert.equal(gURLBar.value, "", "Check urlbar value");

  info("Down key should open the popup even if the editor is empty.");
  await UrlbarTestUtils.promisePopupOpen(window, () => {
    EventUtils.synthesizeKey("KEY_ArrowDown", {});
  });
  Assert.equal(gURLBar.value, "", "Check urlbar value");

  info(
    "If popup is open at starting composition, the popup should be reopened after composition anyway."
  );
  Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
  composeAndCheckPanel("I", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "I", "Check urlbar value");
  composeAndCheckPanel("In", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "In", "Check urlbar value");
  composeAndCheckPanel("", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "", "Check urlbar value");
  // A canceled compositionend should open the popup if it was open.
  await UrlbarTestUtils.promisePopupOpen(window, () => {
    EventUtils.synthesizeComposition({
      type: "compositioncommitasis",
      key: { key: "KEY_Escape" },
    });
  });
  Assert.equal(gURLBar.value, "", "Check urlbar value");

  info("Type normally, and hit escape, the popup should be closed.");
  Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
  EventUtils.synthesizeKey("I", {});
  EventUtils.synthesizeKey("n", {});
  await UrlbarTestUtils.promisePopupClose(window, () => {
    EventUtils.synthesizeKey("KEY_Escape", {});
  });
  Assert.equal(gURLBar.value, "In", "Check urlbar value");
  // Clear typed chars.
  EventUtils.synthesizeKey("KEY_Backspace", {});
  EventUtils.synthesizeKey("KEY_Backspace", {});
  Assert.equal(gURLBar.value, "", "Check urlbar value");
  await UrlbarTestUtils.promisePopupClose(window, () => {
    EventUtils.synthesizeKey("KEY_Escape", {});
  });

  info("With autofill, compositionstart shouldn't open the popup");
  Assert.ok(!UrlbarTestUtils.isPopupOpen(window), "Popup should be closed");
  composeAndCheckPanel("M", false);
  Assert.equal(gURLBar.value, "M", "Check urlbar value");
  composeAndCheckPanel("Mo", false);
  Assert.equal(gURLBar.value, "Mo", "Check urlbar value");
  // Committing composition should open the popup.
  await UrlbarTestUtils.promisePopupOpen(window, () => {
    EventUtils.synthesizeComposition({
      type: "compositioncommitasis",
      key: { key: "KEY_Enter" },
    });
  });
  Assert.equal(gURLBar.value, "Mozilla.org/", "Check urlbar value");
}

async function test_composition_searchMode_preview(
  keepPanelOpenDuringImeComposition
) {
  info("Check Search Mode preview is retained by composition");

  await UrlbarTestUtils.promiseAutocompleteResultPopup({
    window,
    value: "@",
  });

  while (gURLBar.searchMode?.engineName != "Test") {
    EventUtils.synthesizeKey("KEY_ArrowDown", {}, window);
  }
  let expectedSearchMode = {
    engineName: "Test",
    isPreview: true,
    entry: "keywordoffer",
  };
  await UrlbarTestUtils.assertSearchMode(window, expectedSearchMode);
  composeAndCheckPanel("I", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "I", "Check urlbar value");
  if (keepPanelOpenDuringImeComposition) {
    await UrlbarTestUtils.promiseSearchComplete(window);
  }
  // Test that we are in confirmed search mode.
  await UrlbarTestUtils.assertSearchMode(window, {
    engineName: "Test",
    entry: "keywordoffer",
  });
  await UrlbarTestUtils.exitSearchMode(window);
}

async function test_composition_tabToSearch(keepPanelOpenDuringImeComposition) {
  info("Check Tab-to-Search is retained by composition");

  await UrlbarTestUtils.promiseAutocompleteResultPopup({
    window,
    value: "exa",
    fireInputEvent: true,
  });

  while (gURLBar.searchMode?.engineName != "Test") {
    EventUtils.synthesizeKey("KEY_Tab", {}, window);
  }
  let expectedSearchMode = {
    engineName: "Test",
    isPreview: true,
    entry: "tabtosearch",
  };
  await UrlbarTestUtils.assertSearchMode(window, expectedSearchMode);
  composeAndCheckPanel("I", keepPanelOpenDuringImeComposition);
  Assert.equal(gURLBar.value, "I", "Check urlbar value");
  if (keepPanelOpenDuringImeComposition) {
    await UrlbarTestUtils.promiseSearchComplete(window);
  }
  // Test that we are in confirmed search mode.
  await UrlbarTestUtils.assertSearchMode(window, {
    engineName: "Test",
    entry: "tabtosearch",
  });
  await UrlbarTestUtils.exitSearchMode(window);
}

async function test_composition_autofill(keepPanelOpenDuringImeComposition) {
  info("Check whether autofills or not");
  await UrlbarTestUtils.promisePopupClose(window);

  info("Check the urlbar value during composition");
  composeAndCheckPanel("m", false);

  if (keepPanelOpenDuringImeComposition) {
    info("Wait for search suggestions");
    await UrlbarTestUtils.promiseSearchComplete(window);
  }

  Assert.equal(
    gURLBar.value,
    "m",
    "The urlbar value is not autofilled while turning IME on"
  );

  info("Check the urlbar value after committing composition");
  await UrlbarTestUtils.promisePopupOpen(window, () => {
    EventUtils.synthesizeComposition({
      type: "compositioncommitasis",
      key: { key: "KEY_Enter" },
    });
  });
  await UrlbarTestUtils.promiseSearchComplete(window);
  Assert.equal(gURLBar.value, "mozilla.org/", "The urlbar value is autofilled");

  // Clean-up.
  gURLBar.value = "";
}