|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 const Ci = Components.interfaces; |
|
6 const Cc = Components.classes; |
|
7 const Cr = Components.results; |
|
8 const Cu = Components.utils; |
|
9 |
|
10 Cu.import("resource://gre/modules/Services.jsm"); |
|
11 |
|
12 // Import common head. |
|
13 let (commonFile = do_get_file("../head_common.js", false)) { |
|
14 let uri = Services.io.newFileURI(commonFile); |
|
15 Services.scriptloader.loadSubScript(uri.spec, this); |
|
16 } |
|
17 |
|
18 // Put any other stuff relative to this test folder below. |
|
19 |
|
20 XPCOMUtils.defineLazyServiceGetter(this, "gHistory", |
|
21 "@mozilla.org/browser/history;1", |
|
22 "mozIAsyncHistory"); |
|
23 |
|
24 /** |
|
25 * @param aSearches |
|
26 * Array of AutoCompleteSearch names. |
|
27 */ |
|
28 function AutoCompleteInput(aSearches) { |
|
29 this.searches = aSearches; |
|
30 } |
|
31 AutoCompleteInput.prototype = { |
|
32 searches: null, |
|
33 minResultsForPopup: 0, |
|
34 timeout: 10, |
|
35 searchParam: "", |
|
36 textValue: "", |
|
37 disableAutoComplete: false, |
|
38 |
|
39 completeDefaultIndex: true, |
|
40 defaultIndex: 0, |
|
41 |
|
42 // Text selection range |
|
43 _selStart: 0, |
|
44 _selEnd: 0, |
|
45 get selectionStart() { |
|
46 return this._selStart; |
|
47 }, |
|
48 get selectionEnd() { |
|
49 return this._selEnd; |
|
50 }, |
|
51 selectTextRange: function(aStart, aEnd) { |
|
52 this._selStart = aStart; |
|
53 this._selEnd = aEnd; |
|
54 }, |
|
55 |
|
56 onTextEntered: function() false, |
|
57 onTextReverted: function() false, |
|
58 |
|
59 get searchCount() { |
|
60 return this.searches.length; |
|
61 }, |
|
62 getSearchAt: function(aIndex) { |
|
63 return this.searches[aIndex]; |
|
64 }, |
|
65 |
|
66 onSearchBegin: function () {}, |
|
67 onSearchComplete: function () {}, |
|
68 |
|
69 popupOpen: false, |
|
70 |
|
71 popup: { |
|
72 selectedIndex: -1, |
|
73 invalidate: function () {}, |
|
74 |
|
75 QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompletePopup]) |
|
76 }, |
|
77 |
|
78 QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteInput]) |
|
79 } |
|
80 |
|
81 /** |
|
82 * @param aSearchString |
|
83 * String to search. |
|
84 * @param aExpectedValue |
|
85 * Expected value returned by autoFill. |
|
86 * May be a string, or an object like |
|
87 * { |
|
88 * autoFilled: the value suggested by autofill, |
|
89 * completed: the value completed on user's confirmation |
|
90 * } |
|
91 * In the latter case this will also check that on user's confirmation |
|
92 * the result's casing is correctly applied. |
|
93 */ |
|
94 function ensure_results(aSearchString, aExpectedValue) { |
|
95 let autoFilledValue, completedValue; |
|
96 if (typeof(aExpectedValue) == "string") { |
|
97 autoFilledValue = aExpectedValue; |
|
98 } |
|
99 else { |
|
100 autoFilledValue = aExpectedValue.autoFilled; |
|
101 completedValue = aExpectedValue.completed; |
|
102 } |
|
103 |
|
104 // Make an AutoCompleteInput that uses our searches and confirms results. |
|
105 let input = new AutoCompleteInput(["urlinline"]); |
|
106 input.textValue = aSearchString; |
|
107 |
|
108 // Caret must be at the end for autoFill to happen. |
|
109 let strLen = aSearchString.length; |
|
110 input.selectTextRange(strLen, strLen); |
|
111 do_check_eq(input.selectionStart, strLen); |
|
112 do_check_eq(input.selectionEnd, strLen); |
|
113 |
|
114 let controller = Cc["@mozilla.org/autocomplete/controller;1"]. |
|
115 getService(Ci.nsIAutoCompleteController); |
|
116 controller.input = input; |
|
117 |
|
118 let numSearchesStarted = 0; |
|
119 input.onSearchBegin = function() { |
|
120 numSearchesStarted++; |
|
121 do_check_eq(numSearchesStarted, 1); |
|
122 }; |
|
123 |
|
124 input.onSearchComplete = function() { |
|
125 // We should be running only one query. |
|
126 do_check_eq(numSearchesStarted, 1); |
|
127 |
|
128 // Check the autoFilled result. |
|
129 do_check_eq(input.textValue, autoFilledValue); |
|
130 |
|
131 if (completedValue) { |
|
132 // Now force completion and check correct casing of the result. |
|
133 // This ensures the controller is able to do its magic case-preserving |
|
134 // stuff and correct replacement of the user's casing with result's one. |
|
135 controller.handleEnter(false); |
|
136 do_check_eq(input.textValue, completedValue); |
|
137 } |
|
138 |
|
139 waitForCleanup(run_next_test); |
|
140 }; |
|
141 |
|
142 do_log_info("Searching for: '" + aSearchString + "'"); |
|
143 controller.startSearch(aSearchString); |
|
144 } |
|
145 |
|
146 function run_test() { |
|
147 do_register_cleanup(function () { |
|
148 Services.prefs.clearUserPref("browser.urlbar.autocomplete.enabled"); |
|
149 Services.prefs.clearUserPref("browser.urlbar.autoFill"); |
|
150 Services.prefs.clearUserPref("browser.urlbar.autoFill.typed"); |
|
151 }); |
|
152 |
|
153 gAutoCompleteTests.forEach(function (testData) { |
|
154 let [description, searchString, expectedValue, setupFunc] = testData; |
|
155 add_test(function () { |
|
156 do_log_info(description); |
|
157 Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", true); |
|
158 Services.prefs.setBoolPref("browser.urlbar.autoFill", true); |
|
159 Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false); |
|
160 |
|
161 if (setupFunc) { |
|
162 setupFunc(); |
|
163 } |
|
164 |
|
165 // At this point frecency could still be updating due to latest pages |
|
166 // updates. |
|
167 // This is not a problem in real life, but autocomplete tests should |
|
168 // return reliable resultsets, thus we have to wait. |
|
169 promiseAsyncUpdates().then(function () ensure_results(searchString, |
|
170 expectedValue)); |
|
171 }) |
|
172 }, this); |
|
173 |
|
174 run_next_test(); |
|
175 } |
|
176 |
|
177 let gAutoCompleteTests = []; |
|
178 function add_autocomplete_test(aTestData) { |
|
179 gAutoCompleteTests.push(aTestData); |
|
180 } |
|
181 |
|
182 function waitForCleanup(aCallback) { |
|
183 remove_all_bookmarks(); |
|
184 promiseClearHistory().then(aCallback); |
|
185 } |
|
186 |
|
187 function addBookmark(aBookmarkObj) { |
|
188 do_check_true(!!aBookmarkObj.url); |
|
189 let parentId = aBookmarkObj.parentId ? aBookmarkObj.parentId |
|
190 : PlacesUtils.unfiledBookmarksFolderId; |
|
191 let itemId = PlacesUtils.bookmarks |
|
192 .insertBookmark(parentId, |
|
193 NetUtil.newURI(aBookmarkObj.url), |
|
194 PlacesUtils.bookmarks.DEFAULT_INDEX, |
|
195 "A bookmark"); |
|
196 if (aBookmarkObj.keyword) { |
|
197 PlacesUtils.bookmarks.setKeywordForBookmark(itemId, aBookmarkObj.keyword); |
|
198 } |
|
199 } |