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

// Tests for input history related to autofill.

"use strict";

let addToInputHistorySpy;

add_setup(async function () {
  await SpecialPowers.pushPrefEnv({
    set: [["browser.urlbar.autoFill.adaptiveHistory.enabled", true]],
  });

  await PlacesUtils.bookmarks.eraseEverything();
  await PlacesUtils.history.clear();

  let sandbox = sinon.createSandbox();
  addToInputHistorySpy = sandbox.spy(UrlbarUtils, "addToInputHistory");

  registerCleanupFunction(async () => {
    sandbox.restore();
  });
});

// Input history use count should be bumped when an adaptive history autofill
// result is triggered and picked.
add_task(async function bumped() {
  let input = "exam";
  let tests = [
    // Basic test where the search string = the adaptive history input.
    {
      url: "http://example.com/test",
      searchString: "exam",
    },
    // The history with input "exam" should be bumped, not "example", even
    // though the search string is "example".
    {
      url: "http://example.com/test",
      searchString: "example",
    },
    // The history with URL "http://www.example.com/test" should be bumped, not
    // "http://example.com/test", even though the search string starts with
    // "example".
    {
      url: "http://www.example.com/test",
      searchString: "exam",
    },
  ];

  for (let { url, searchString } of tests) {
    info("Running subtest: " + JSON.stringify({ url, searchString }));

    await PlacesTestUtils.addVisits(url);
    await UrlbarUtils.addToInputHistory(url, input);
    addToInputHistorySpy.resetHistory();

    let initialUseCount = await getUseCount({ url, input });
    info("Got initial use count: " + initialUseCount);

    await triggerAutofillAndPickResult(searchString, "example.com/test");

    let calls = addToInputHistorySpy.getCalls();
    Assert.equal(
      calls.length,
      1,
      "UrlbarUtils.addToInputHistory() called once"
    );
    Assert.deepEqual(
      calls[0].args,
      [url, input],
      "UrlbarUtils.addToInputHistory() called with expected args"
    );

    Assert.greater(
      await getUseCount({ url, input }),
      initialUseCount,
      "New use count > initial use count"
    );

    if (searchString != input) {
      Assert.strictEqual(
        await getUseCount({ input: searchString }),
        undefined,
        "Search string not present in input history: " + searchString
      );
    }

    await PlacesUtils.history.clear();
    await PlacesTestUtils.clearInputHistory();
    addToInputHistorySpy.resetHistory();
  }
});

// Input history use count should not be bumped when an origin autofill result
// is triggered and picked.
add_task(async function notBumped_origin() {
  // Add enough visits to trigger origin autofill.
  let url = "http://example.com/test";
  for (let i = 0; i < 5; i++) {
    await PlacesTestUtils.addVisits(url);
  }

  await triggerAutofillAndPickResult("exam", "example.com/");

  let calls = addToInputHistorySpy.getCalls();
  Assert.equal(calls.length, 0, "UrlbarUtils.addToInputHistory() not called");

  Assert.strictEqual(
    await getUseCount({ url }),
    undefined,
    "URL not present in input history: " + url
  );

  await PlacesUtils.history.clear();
});

// Input history use count should not be bumped when a URL autofill result is
// triggered and picked.
add_task(async function notBumped_url() {
  let url = "http://example.com/test";
  await PlacesTestUtils.addVisits(url);

  await triggerAutofillAndPickResult("example.com/t", "example.com/test");

  let calls = addToInputHistorySpy.getCalls();
  Assert.equal(calls.length, 0, "UrlbarUtils.addToInputHistory() not called");

  Assert.strictEqual(
    await getUseCount({ url }),
    undefined,
    "URL not present in input history: " + url
  );

  await PlacesUtils.history.clear();
});

/**
 * Performs a search and picks the first result.
 *
 * @param {string} searchString
 *   The search string. Assumed to trigger an autofill result.
 * @param {string} autofilledValue
 *   The input's expected value after autofill occurs.
 */
async function triggerAutofillAndPickResult(searchString, autofilledValue) {
  await BrowserTestUtils.withNewTab("about:blank", async () => {
    await UrlbarTestUtils.promiseAutocompleteResultPopup({
      window,
      value: searchString,
      fireInputEvent: true,
    });
    let details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
    Assert.ok(details.autofill, "Result is autofill");
    Assert.equal(gURLBar.value, autofilledValue, "gURLBar.value");
    Assert.equal(gURLBar.selectionStart, searchString.length, "selectionStart");
    Assert.equal(gURLBar.selectionEnd, autofilledValue.length, "selectionEnd");

    let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
    EventUtils.synthesizeKey("KEY_Enter");
    await loadPromise;
  });
}

/**
 * Gets the use count of an input history record.
 *
 * @param {object} options
 *   Options object.
 * @param {string} [options.url]
 *   The URL of the `moz_places` row corresponding to the record.
 * @param {string} [options.input]
 *   The `input` value in the record.
 * @returns {number}
 *   The use count. If no record exists with the URL and/or input, undefined is
 *   returned.
 */
async function getUseCount({ url = undefined, input = undefined }) {
  return PlacesUtils.withConnectionWrapper("test::getUseCount", async db => {
    let rows;
    if (input && url) {
      rows = await db.executeCached(
        `SELECT i.use_count
           FROM moz_inputhistory i
           JOIN moz_places h ON h.id = i.place_id
           WHERE h.url = :url AND i.input = :input`,
        { url, input }
      );
    } else if (url) {
      rows = await db.executeCached(
        `SELECT i.use_count
           FROM moz_inputhistory i
           JOIN moz_places h ON h.id = i.place_id
           WHERE h.url = :url`,
        { url }
      );
    } else if (input) {
      rows = await db.executeCached(
        `SELECT use_count
           FROM moz_inputhistory i
           WHERE input = :input`,
        { input }
      );
    }
    return rows[0]?.getResultByIndex(0);
  });
}