OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/format_macros.h" | |
6 #include "base/string_util.h" | |
7 #include "base/stringprintf.h" | |
8 #include "base/utf_string_conversions.h" | |
9 #include "chrome/browser/autocomplete/autocomplete.h" | |
10 #include "chrome/browser/autocomplete/autocomplete_edit.h" | |
11 #include "chrome/browser/autocomplete/autocomplete_match.h" | |
12 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" | |
13 #include "chrome/browser/extensions/extension_apitest.h" | |
14 #include "chrome/browser/profiles/profile.h" | |
15 #include "chrome/browser/search_engines/template_url.h" | |
16 #include "chrome/browser/search_engines/template_url_service.h" | |
17 #include "chrome/browser/search_engines/template_url_service_factory.h" | |
18 #include "chrome/browser/ui/browser.h" | |
19 #include "chrome/browser/ui/browser_window.h" | |
20 #include "chrome/browser/ui/omnibox/location_bar.h" | |
21 #include "chrome/browser/ui/omnibox/omnibox_view.h" | |
22 #include "chrome/common/chrome_notification_types.h" | |
23 #include "chrome/common/url_constants.h" | |
24 #include "chrome/test/base/ui_test_utils.h" | |
25 #include "content/public/browser/notification_types.h" | |
26 #include "content/public/browser/notification_service.h" | |
27 | |
28 #if defined(TOOLKIT_GTK) | |
29 #include "chrome/browser/ui/gtk/browser_window_gtk.h" | |
30 #endif | |
31 | |
32 namespace { | |
33 | |
34 string16 AutocompleteResultAsString(const AutocompleteResult& result) { | |
35 std::string output(base::StringPrintf("{%" PRIuS "} ", result.size())); | |
36 for (size_t i = 0; i < result.size(); ++i) { | |
37 AutocompleteMatch match = result.match_at(i); | |
38 std::string provider_name = match.provider->name(); | |
39 output.append(base::StringPrintf("[\"%s\" by \"%s\"] ", | |
40 UTF16ToUTF8(match.contents).c_str(), | |
41 provider_name.c_str())); | |
42 } | |
43 return UTF8ToUTF16(output); | |
44 } | |
45 | |
46 } // namespace | |
47 | |
48 class OmniboxApiTest : public ExtensionApiTest { | |
49 protected: | |
50 LocationBar* GetLocationBar(Browser* browser) const { | |
51 return browser->window()->GetLocationBar(); | |
52 } | |
53 | |
54 AutocompleteController* GetAutocompleteController(Browser* browser) const { | |
55 return GetLocationBar(browser)->location_entry()->model()->popup_model()-> | |
56 autocomplete_controller(); | |
57 } | |
58 | |
59 void WaitForTemplateURLServiceToLoad() { | |
60 ui_test_utils::WindowedNotificationObserver loaded_observer( | |
61 chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED, | |
62 content::NotificationService::AllSources()); | |
63 TemplateURLService* model = | |
64 TemplateURLServiceFactory::GetForProfile(browser()->profile()); | |
65 model->Load(); | |
66 if (!model->loaded()) | |
67 loaded_observer.Wait(); | |
68 } | |
69 | |
70 // TODO(phajdan.jr): Get rid of this wait-in-a-loop pattern. | |
71 void WaitForAutocompleteDone(AutocompleteController* controller) { | |
72 while (!controller->done()) { | |
73 ui_test_utils::WindowedNotificationObserver ready_observer( | |
74 chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY, | |
75 content::Source<AutocompleteController>(controller)); | |
76 ready_observer.Wait(); | |
77 } | |
78 } | |
79 }; | |
80 | |
81 IN_PROC_BROWSER_TEST_F(OmniboxApiTest, FLAKY_Basic) { | |
82 ASSERT_TRUE(RunExtensionTest("omnibox")) << message_; | |
83 | |
84 // The results depend on the TemplateURLService being loaded. Make sure it is | |
85 // loaded so that the autocomplete results are consistent. | |
86 WaitForTemplateURLServiceToLoad(); | |
87 | |
88 LocationBar* location_bar = GetLocationBar(browser()); | |
89 AutocompleteController* autocomplete_controller = | |
90 GetAutocompleteController(browser()); | |
91 | |
92 // Test that our extension's keyword is suggested to us when we partially type | |
93 // it. | |
94 { | |
95 autocomplete_controller->Start( | |
96 ASCIIToUTF16("keywor"), string16(), true, false, true, | |
97 AutocompleteInput::ALL_MATCHES); | |
98 WaitForAutocompleteDone(autocomplete_controller); | |
99 EXPECT_TRUE(autocomplete_controller->done()); | |
100 | |
101 // Now, peek into the controller to see if it has the results we expect. | |
102 // First result should be to search for what was typed, second should be to | |
103 // enter "extension keyword" mode. | |
104 const AutocompleteResult& result = autocomplete_controller->result(); | |
105 ASSERT_EQ(2U, result.size()) << AutocompleteResultAsString(result); | |
106 AutocompleteMatch match = result.match_at(0); | |
107 EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type); | |
108 EXPECT_FALSE(match.deletable); | |
109 | |
110 match = result.match_at(1); | |
111 ASSERT_TRUE(match.template_url); | |
112 EXPECT_TRUE(match.template_url->IsExtensionKeyword()); | |
113 EXPECT_EQ(ASCIIToUTF16("keyword"), match.template_url->keyword()); | |
114 } | |
115 | |
116 // Test that our extension can send suggestions back to us. | |
117 { | |
118 autocomplete_controller->Start( | |
119 ASCIIToUTF16("keyword suggestio"), string16(), true, false, true, | |
120 AutocompleteInput::ALL_MATCHES); | |
121 WaitForAutocompleteDone(autocomplete_controller); | |
122 EXPECT_TRUE(autocomplete_controller->done()); | |
123 | |
124 // Now, peek into the controller to see if it has the results we expect. | |
125 // First result should be to invoke the keyword with what we typed, 2-4 | |
126 // should be to invoke with suggestions from the extension, and the last | |
127 // should be to search for what we typed. | |
128 const AutocompleteResult& result = autocomplete_controller->result(); | |
129 ASSERT_EQ(5U, result.size()) << AutocompleteResultAsString(result); | |
130 | |
131 ASSERT_TRUE(result.match_at(0).template_url); | |
132 EXPECT_EQ(ASCIIToUTF16("keyword suggestio"), | |
133 result.match_at(0).fill_into_edit); | |
134 EXPECT_EQ(ASCIIToUTF16("keyword suggestion1"), | |
135 result.match_at(1).fill_into_edit); | |
136 EXPECT_EQ(ASCIIToUTF16("keyword suggestion2"), | |
137 result.match_at(2).fill_into_edit); | |
138 EXPECT_EQ(ASCIIToUTF16("keyword suggestion3"), | |
139 result.match_at(3).fill_into_edit); | |
140 | |
141 string16 description = | |
142 ASCIIToUTF16("Description with style: <match>, [dim], (url till end)"); | |
143 EXPECT_EQ(description, result.match_at(1).contents); | |
144 ASSERT_EQ(6u, result.match_at(1).contents_class.size()); | |
145 | |
146 EXPECT_EQ(0u, | |
147 result.match_at(1).contents_class[0].offset); | |
148 EXPECT_EQ(ACMatchClassification::NONE, | |
149 result.match_at(1).contents_class[0].style); | |
150 | |
151 EXPECT_EQ(description.find('<'), | |
152 result.match_at(1).contents_class[1].offset); | |
153 EXPECT_EQ(ACMatchClassification::MATCH, | |
154 result.match_at(1).contents_class[1].style); | |
155 | |
156 EXPECT_EQ(description.find('>') + 1u, | |
157 result.match_at(1).contents_class[2].offset); | |
158 EXPECT_EQ(ACMatchClassification::NONE, | |
159 result.match_at(1).contents_class[2].style); | |
160 | |
161 EXPECT_EQ(description.find('['), | |
162 result.match_at(1).contents_class[3].offset); | |
163 EXPECT_EQ(ACMatchClassification::DIM, | |
164 result.match_at(1).contents_class[3].style); | |
165 | |
166 EXPECT_EQ(description.find(']') + 1u, | |
167 result.match_at(1).contents_class[4].offset); | |
168 EXPECT_EQ(ACMatchClassification::NONE, | |
169 result.match_at(1).contents_class[4].style); | |
170 | |
171 EXPECT_EQ(description.find('('), | |
172 result.match_at(1).contents_class[5].offset); | |
173 EXPECT_EQ(ACMatchClassification::URL, | |
174 result.match_at(1).contents_class[5].style); | |
175 | |
176 AutocompleteMatch match = result.match_at(4); | |
177 EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type); | |
178 EXPECT_FALSE(match.deletable); | |
179 } | |
180 | |
181 { | |
182 ResultCatcher catcher; | |
183 location_bar->location_entry()->OnBeforePossibleChange(); | |
184 location_bar->location_entry()->SetUserText( | |
185 ASCIIToUTF16("keyword command")); | |
186 location_bar->location_entry()->OnAfterPossibleChange(); | |
187 location_bar->AcceptInput(); | |
188 // This checks that the keyword provider (via javascript) | |
189 // gets told to navigate to the string "command". | |
190 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); | |
191 } | |
192 } | |
193 | |
194 // Tests that the autocomplete popup doesn't reopen after accepting input for | |
195 // a given query. | |
196 // http://crbug.com/88552 | |
197 IN_PROC_BROWSER_TEST_F(OmniboxApiTest, FLAKY_PopupStaysClosed) { | |
198 ASSERT_TRUE(RunExtensionTest("omnibox")) << message_; | |
199 | |
200 // The results depend on the TemplateURLService being loaded. Make sure it is | |
201 // loaded so that the autocomplete results are consistent. | |
202 WaitForTemplateURLServiceToLoad(); | |
203 | |
204 LocationBar* location_bar = GetLocationBar(browser()); | |
205 AutocompleteController* autocomplete_controller = | |
206 GetAutocompleteController(browser()); | |
207 AutocompletePopupModel* popup_model = | |
208 GetLocationBar(browser())->location_entry()->model()->popup_model(); | |
209 | |
210 // Input a keyword query and wait for suggestions from the extension. | |
211 location_bar->location_entry()->OnBeforePossibleChange(); | |
212 location_bar->location_entry()->SetUserText(ASCIIToUTF16("keyword comman")); | |
213 location_bar->location_entry()->OnAfterPossibleChange(); | |
214 WaitForAutocompleteDone(autocomplete_controller); | |
215 EXPECT_TRUE(autocomplete_controller->done()); | |
216 EXPECT_TRUE(popup_model->IsOpen()); | |
217 | |
218 // Quickly type another query and accept it before getting suggestions back | |
219 // for the query. The popup will close after accepting input - ensure that it | |
220 // does not reopen when the extension returns its suggestions. | |
221 ResultCatcher catcher; | |
222 | |
223 // TODO: Rather than send this second request by talking to the controller | |
224 // directly, figure out how to send it via the proper calls to | |
225 // location_bar or location_bar->(). | |
226 autocomplete_controller->Start( | |
227 ASCIIToUTF16("keyword command"), string16(), true, false, true, | |
228 AutocompleteInput::ALL_MATCHES); | |
229 location_bar->AcceptInput(); | |
230 WaitForAutocompleteDone(autocomplete_controller); | |
231 EXPECT_TRUE(autocomplete_controller->done()); | |
232 // This checks that the keyword provider (via javascript) | |
233 // gets told to navigate to the string "command". | |
234 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); | |
235 EXPECT_FALSE(popup_model->IsOpen()); | |
236 } | |
237 | |
238 // Tests that we get suggestions from and send input to the incognito context | |
239 // of an incognito split mode extension. | |
240 // http://crbug.com/100927 | |
241 // Test is flaky: http://crbug.com/101219 | |
242 IN_PROC_BROWSER_TEST_F(OmniboxApiTest, DISABLED_IncognitoSplitMode) { | |
243 ResultCatcher catcher_incognito; | |
244 catcher_incognito.RestrictToProfile( | |
245 browser()->profile()->GetOffTheRecordProfile()); | |
246 | |
247 ASSERT_TRUE(RunExtensionTestIncognito("omnibox")) << message_; | |
248 | |
249 // Open an incognito window and wait for the incognito extension process to | |
250 // respond. | |
251 Browser* incognito_browser = CreateIncognitoBrowser(); | |
252 ASSERT_TRUE(catcher_incognito.GetNextResult()) << catcher_incognito.message(); | |
253 | |
254 // The results depend on the TemplateURLService being loaded. Make sure it is | |
255 // loaded so that the autocomplete results are consistent. | |
256 WaitForTemplateURLServiceToLoad(); | |
257 | |
258 LocationBar* location_bar = GetLocationBar(incognito_browser); | |
259 AutocompleteController* autocomplete_controller = | |
260 GetAutocompleteController(incognito_browser); | |
261 | |
262 // Test that we get the incognito-specific suggestions. | |
263 { | |
264 autocomplete_controller->Start( | |
265 ASCIIToUTF16("keyword suggestio"), string16(), true, false, true, | |
266 AutocompleteInput::ALL_MATCHES); | |
267 WaitForAutocompleteDone(autocomplete_controller); | |
268 EXPECT_TRUE(autocomplete_controller->done()); | |
269 | |
270 // First result should be to invoke the keyword with what we typed, 2-4 | |
271 // should be to invoke with suggestions from the extension, and the last | |
272 // should be to search for what we typed. | |
273 const AutocompleteResult& result = autocomplete_controller->result(); | |
274 ASSERT_EQ(5U, result.size()) << AutocompleteResultAsString(result); | |
275 ASSERT_TRUE(result.match_at(0).template_url); | |
276 EXPECT_EQ(ASCIIToUTF16("keyword suggestion3 incognito"), | |
277 result.match_at(3).fill_into_edit); | |
278 } | |
279 | |
280 // Test that our input is sent to the incognito context. The test will do a | |
281 // text comparison and succeed only if "command incognito" is sent to the | |
282 // incognito context. | |
283 { | |
284 ResultCatcher catcher; | |
285 autocomplete_controller->Start( | |
286 ASCIIToUTF16("keyword command incognito"), string16(), | |
287 true, false, true, AutocompleteInput::ALL_MATCHES); | |
288 location_bar->AcceptInput(); | |
289 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); | |
290 } | |
291 } | |
OLD | NEW |