summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/tests/browser/browser_searchMode_alias_replacement.js
blob: 9f4558e6c9fedc0a13a24c0fe2a8c5e5169ff1c5 (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
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

/**
 * Tests that user-defined aliases are replaced by the search mode indicator.
 */

const ALIAS = "testalias";
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";

// We make sure that aliases and search terms are correctly recognized when they
// are separated by each of these different types of spaces and combinations of
// spaces.  U+3000 is the ideographic space in CJK and is commonly used by CJK
// speakers.
const TEST_SPACES = [" ", "\u3000", " \u3000", "\u3000 "];

let defaultEngine, aliasEngine;

add_setup(async function () {
  defaultEngine = await SearchTestUtils.promiseNewSearchEngine({
    url: getRootDirectory(gTestPath) + TEST_ENGINE_BASENAME,
    setAsDefault: true,
  });
  defaultEngine.alias = "@default";
  await SearchTestUtils.installSearchExtension({
    keyword: ALIAS,
  });
  aliasEngine = Services.search.getEngineByName("Example");
});

// An incomplete alias should not be replaced.
add_task(async function incompleteAlias() {
  // Check that a non-fully typed alias is not replaced.
  await UrlbarTestUtils.promiseAutocompleteResultPopup({
    window,
    value: ALIAS.slice(0, -1),
  });
  await UrlbarTestUtils.assertSearchMode(window, null);

  // Type a space just to make sure it's not replaced.
  let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
  EventUtils.synthesizeKey(" ");
  await searchPromise;

  await UrlbarTestUtils.assertSearchMode(window, null);
  Assert.equal(
    gURLBar.value,
    ALIAS.slice(0, -1) + " ",
    "The typed value should be unchanged except for the space."
  );
  await UrlbarTestUtils.promisePopupClose(window, () =>
    EventUtils.synthesizeKey("KEY_Escape")
  );
});

// A complete alias without a trailing space should not be replaced.
add_task(async function noTrailingSpace() {
  let value = ALIAS;
  await UrlbarTestUtils.promiseAutocompleteResultPopup({
    window,
    value,
  });
  await UrlbarTestUtils.assertSearchMode(window, null);
  await UrlbarTestUtils.promisePopupClose(window, () =>
    EventUtils.synthesizeKey("KEY_Escape")
  );
});

// A complete typed alias without a trailing space should not be replaced.
add_task(async function noTrailingSpace_typed() {
  // Start by searching for the alias minus its last char.
  await UrlbarTestUtils.promiseAutocompleteResultPopup({
    window,
    value: ALIAS.slice(0, -1),
  });
  await UrlbarTestUtils.assertSearchMode(window, null);

  // Now type the last char.
  let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
  EventUtils.synthesizeKey(ALIAS.slice(-1));
  await searchPromise;

  await UrlbarTestUtils.assertSearchMode(window, null);
  Assert.equal(
    gURLBar.value,
    ALIAS,
    "The typed value should be the full alias."
  );

  await UrlbarTestUtils.promisePopupClose(window, () =>
    EventUtils.synthesizeKey("KEY_Escape")
  );
});

// A complete alias with a trailing space should be replaced.
add_task(async function trailingSpace() {
  for (let spaces of TEST_SPACES) {
    info("Testing: " + JSON.stringify({ spaces: codePoints(spaces) }));
    await UrlbarTestUtils.promiseAutocompleteResultPopup({
      window,
      value: ALIAS + spaces,
    });
    await UrlbarTestUtils.assertSearchMode(window, {
      engineName: aliasEngine.name,
      entry: "typed",
    });
    Assert.ok(!gURLBar.value, "The urlbar value should be cleared.");
    await UrlbarTestUtils.exitSearchMode(window);
    await UrlbarTestUtils.promisePopupClose(window);
  }
});

// A complete alias should be replaced after typing a space.
add_task(async function trailingSpace_typed() {
  for (let spaces of TEST_SPACES) {
    if (spaces.length != 1) {
      continue;
    }
    info("Testing: " + JSON.stringify({ spaces: codePoints(spaces) }));

    await UrlbarTestUtils.promiseAutocompleteResultPopup({
      window,
      value: ALIAS,
    });
    await UrlbarTestUtils.assertSearchMode(window, null);

    // We need to wait for two searches: The first enters search mode, the second
    // does the search in search mode.
    let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
    EventUtils.synthesizeKey(spaces);
    await searchPromise;

    await UrlbarTestUtils.assertSearchMode(window, {
      engineName: aliasEngine.name,
      entry: "typed",
    });
    Assert.ok(!gURLBar.value, "The urlbar value should be cleared.");
    await UrlbarTestUtils.exitSearchMode(window);
    await UrlbarTestUtils.promisePopupClose(window);
  }
});

// A complete alias with a trailing space should be replaced, and the query
// after the trailing space should be the new value of the input.
add_task(async function trailingSpace_query() {
  for (let spaces of TEST_SPACES) {
    info("Testing: " + JSON.stringify({ spaces: codePoints(spaces) }));

    await UrlbarTestUtils.promiseAutocompleteResultPopup({
      window,
      value: ALIAS + spaces + "query",
    });

    await UrlbarTestUtils.assertSearchMode(window, {
      engineName: aliasEngine.name,
      entry: "typed",
    });
    Assert.equal(
      gURLBar.value,
      "query",
      "The urlbar value should be the query."
    );
    await UrlbarTestUtils.exitSearchMode(window);
    await UrlbarTestUtils.promisePopupClose(window);
  }
});

add_task(async function () {
  info("Test search mode when typing an alias after selecting one-off button");

  info("Open the result popup");
  await UrlbarTestUtils.promiseAutocompleteResultPopup({
    window,
    value: "",
  });

  info("Select one of one-off button");
  const oneOffs = UrlbarTestUtils.getOneOffSearchButtons(window);
  await TestUtils.waitForCondition(
    () => !oneOffs._rebuilding,
    "Waiting for one-offs to finish rebuilding"
  );
  EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true });
  ok(oneOffs.selectedButton, "There is a selected one-off button");
  const selectedEngine = oneOffs.selectedButton.engine;
  await UrlbarTestUtils.assertSearchMode(window, {
    engineName: selectedEngine.name,
    source: UrlbarUtils.RESULT_SOURCE.SEARCH,
    entry: "oneoff",
    isPreview: true,
  });

  info("Type a search engine alias and query");
  const inputString = "@default query";
  inputString.split("").forEach(c => EventUtils.synthesizeKey(c));
  await UrlbarTestUtils.promiseSearchComplete(window);
  Assert.equal(
    gURLBar.value,
    inputString,
    "Alias and query is inputed correctly to the urlbar"
  );
  await UrlbarTestUtils.assertSearchMode(window, {
    engineName: selectedEngine.name,
    source: UrlbarUtils.RESULT_SOURCE.SEARCH,
    entry: "oneoff",
  });

  // When starting typing, as the search mode is confirmed, the one-off
  // selection is removed.
  ok(!oneOffs.selectedButton, "There is no any selected one-off button");

  // Clean up
  gURLBar.value = "";
  await UrlbarTestUtils.exitSearchMode(window);
  await UrlbarTestUtils.promisePopupClose(window);
});

add_task(async function () {
  info(
    "Test search mode after removing current search mode when multiple aliases are written"
  );

  info("Open the result popup with multiple aliases");
  await UrlbarTestUtils.promiseAutocompleteResultPopup({
    window,
    value: "@default testalias @default",
  });

  await UrlbarTestUtils.assertSearchMode(window, {
    engineName: defaultEngine.name,
    entry: "typed",
  });
  Assert.equal(
    gURLBar.value,
    "testalias @default",
    "The value on the urlbar is correct"
  );

  info("Exit search mode by clicking");
  const indicator = gURLBar.querySelector("#urlbar-search-mode-indicator");
  EventUtils.synthesizeMouseAtCenter(indicator, { type: "mouseover" }, window);
  const closeButton = gURLBar.querySelector(
    "#urlbar-search-mode-indicator-close"
  );
  const searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
  EventUtils.synthesizeMouseAtCenter(closeButton, {}, window);
  await searchPromise;

  await UrlbarTestUtils.assertSearchMode(window, {
    engineName: aliasEngine.name,
    entry: "typed",
  });
  Assert.equal(gURLBar.value, "@default", "The value on the urlbar is correct");

  // Clean up
  gURLBar.value = "";
  await UrlbarTestUtils.exitSearchMode(window);
  await UrlbarTestUtils.promisePopupClose(window);
});

/**
 * Returns an array of code points in the given string.  Each code point is
 * returned as a hexidecimal string.
 *
 * @param {string} str
 *   The code points of this string will be returned.
 * @returns {Array}
 *   Array of code points in the string, where each is a hexidecimal string.
 */
function codePoints(str) {
  return str.split("").map(s => s.charCodeAt(0).toString(16));
}