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
6 #include <string>
7
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/values.h"
14 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
15 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
16 #include "chrome/browser/extensions/extension_function_test_utils.h"
17 #include "chrome/browser/extensions/extension_tab_util.h"
18 #include "chrome/browser/prefs/incognito_mode_prefs.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_commands.h"
22 #include "chrome/browser/ui/browser_window.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/test/base/in_process_browser_test.h"
25 #include "chrome/test/base/ui_test_utils.h"
26 #include "content/public/common/page_zoom.h"
27 #include "content/public/common/url_constants.h"
28 #include "extensions/common/manifest_constants.h"
29 #include "extensions/common/test_util.h"
30 #include "net/test/spawned_test_server/spawned_test_server.h"
31 #include "ui/gfx/rect.h"
32
33 namespace extensions {
34
35 namespace keys = tabs_constants;
36 namespace utils = extension_function_test_utils;
37
38 namespace {
39
40 class ExtensionTabsTest : public InProcessBrowserTest {
41 };
42
43 }
44
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,GetWindow)45 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) {
46 int window_id = ExtensionTabUtil::GetWindowId(browser());
47
48 // Invalid window ID error.
49 scoped_refptr<WindowsGetFunction> function = new WindowsGetFunction();
50 scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
51 function->set_extension(extension.get());
52 EXPECT_TRUE(MatchPattern(
53 utils::RunFunctionAndReturnError(
54 function.get(),
55 base::StringPrintf("[%u]", window_id + 1),
56 browser()),
57 keys::kWindowNotFoundError));
58
59 // Basic window details.
60 gfx::Rect bounds;
61 if (browser()->window()->IsMinimized())
62 bounds = browser()->window()->GetRestoredBounds();
63 else
64 bounds = browser()->window()->GetBounds();
65
66 function = new WindowsGetFunction();
67 function->set_extension(extension.get());
68 scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
69 utils::RunFunctionAndReturnSingleResult(
70 function.get(),
71 base::StringPrintf("[%u]", window_id),
72 browser())));
73 EXPECT_EQ(window_id, utils::GetInteger(result.get(), "id"));
74 EXPECT_FALSE(utils::GetBoolean(result.get(), "incognito"));
75 EXPECT_EQ("normal", utils::GetString(result.get(), "type"));
76 EXPECT_EQ(bounds.x(), utils::GetInteger(result.get(), "left"));
77 EXPECT_EQ(bounds.y(), utils::GetInteger(result.get(), "top"));
78 EXPECT_EQ(bounds.width(), utils::GetInteger(result.get(), "width"));
79 EXPECT_EQ(bounds.height(), utils::GetInteger(result.get(), "height"));
80
81 // With "populate" enabled.
82 function = new WindowsGetFunction();
83 function->set_extension(extension.get());
84 result.reset(utils::ToDictionary(
85 utils::RunFunctionAndReturnSingleResult(
86 function.get(),
87 base::StringPrintf("[%u, {\"populate\": true}]", window_id),
88 browser())));
89
90 EXPECT_EQ(window_id, utils::GetInteger(result.get(), "id"));
91 // "populate" was enabled so tabs should be populated.
92 base::ListValue* tabs = NULL;
93 EXPECT_TRUE(result.get()->GetList(keys::kTabsKey, &tabs));
94
95 // TODO(aa): Can't assume window is focused. On mac, calling Activate() from a
96 // browser test doesn't seem to do anything, so can't test the opposite
97 // either.
98 EXPECT_EQ(browser()->window()->IsActive(),
99 utils::GetBoolean(result.get(), "focused"));
100
101 // TODO(aa): Minimized and maximized dimensions. Is there a way to set
102 // minimize/maximize programmatically?
103
104 // Popup.
105 Browser* popup_browser = new Browser(
106 Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(),
107 browser()->host_desktop_type()));
108 function = new WindowsGetFunction();
109 function->set_extension(extension.get());
110 result.reset(utils::ToDictionary(
111 utils::RunFunctionAndReturnSingleResult(
112 function.get(),
113 base::StringPrintf(
114 "[%u]", ExtensionTabUtil::GetWindowId(popup_browser)),
115 browser())));
116 EXPECT_EQ("popup", utils::GetString(result.get(), "type"));
117
118 // Incognito.
119 Browser* incognito_browser = CreateIncognitoBrowser();
120 int incognito_window_id = ExtensionTabUtil::GetWindowId(incognito_browser);
121
122 // Without "include_incognito".
123 function = new WindowsGetFunction();
124 function->set_extension(extension.get());
125 EXPECT_TRUE(MatchPattern(
126 utils::RunFunctionAndReturnError(
127 function.get(),
128 base::StringPrintf("[%u]", incognito_window_id),
129 browser()),
130 keys::kWindowNotFoundError));
131
132 // With "include_incognito".
133 function = new WindowsGetFunction();
134 function->set_extension(extension.get());
135 result.reset(utils::ToDictionary(
136 utils::RunFunctionAndReturnSingleResult(
137 function.get(),
138 base::StringPrintf("[%u]", incognito_window_id),
139 browser(),
140 utils::INCLUDE_INCOGNITO)));
141 EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito"));
142 }
143
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,GetCurrentWindow)144 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetCurrentWindow) {
145 int window_id = ExtensionTabUtil::GetWindowId(browser());
146 Browser* new_browser = CreateBrowser(browser()->profile());
147 int new_id = ExtensionTabUtil::GetWindowId(new_browser);
148
149 // Get the current window using new_browser.
150 scoped_refptr<WindowsGetCurrentFunction> function =
151 new WindowsGetCurrentFunction();
152 scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
153 function->set_extension(extension.get());
154 scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
155 utils::RunFunctionAndReturnSingleResult(function.get(),
156 "[]",
157 new_browser)));
158
159 // The id should match the window id of the browser instance that was passed
160 // to RunFunctionAndReturnSingleResult.
161 EXPECT_EQ(new_id, utils::GetInteger(result.get(), "id"));
162 base::ListValue* tabs = NULL;
163 EXPECT_FALSE(result.get()->GetList(keys::kTabsKey, &tabs));
164
165 // Get the current window using the old window and make the tabs populated.
166 function = new WindowsGetCurrentFunction();
167 function->set_extension(extension.get());
168 result.reset(utils::ToDictionary(
169 utils::RunFunctionAndReturnSingleResult(function.get(),
170 "[{\"populate\": true}]",
171 browser())));
172
173 // The id should match the window id of the browser instance that was passed
174 // to RunFunctionAndReturnSingleResult.
175 EXPECT_EQ(window_id, utils::GetInteger(result.get(), "id"));
176 // "populate" was enabled so tabs should be populated.
177 EXPECT_TRUE(result.get()->GetList(keys::kTabsKey, &tabs));
178 }
179
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,GetAllWindows)180 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetAllWindows) {
181 const size_t NUM_WINDOWS = 5;
182 std::set<int> window_ids;
183 std::set<int> result_ids;
184 window_ids.insert(ExtensionTabUtil::GetWindowId(browser()));
185
186 for (size_t i = 0; i < NUM_WINDOWS - 1; ++i) {
187 Browser* new_browser = CreateBrowser(browser()->profile());
188 window_ids.insert(ExtensionTabUtil::GetWindowId(new_browser));
189 }
190
191 scoped_refptr<WindowsGetAllFunction> function = new WindowsGetAllFunction();
192 scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
193 function->set_extension(extension.get());
194 scoped_ptr<base::ListValue> result(utils::ToList(
195 utils::RunFunctionAndReturnSingleResult(function.get(),
196 "[]",
197 browser())));
198
199 base::ListValue* windows = result.get();
200 EXPECT_EQ(NUM_WINDOWS, windows->GetSize());
201 for (size_t i = 0; i < NUM_WINDOWS; ++i) {
202 base::DictionaryValue* result_window = NULL;
203 EXPECT_TRUE(windows->GetDictionary(i, &result_window));
204 result_ids.insert(utils::GetInteger(result_window, "id"));
205
206 // "populate" was not passed in so tabs are not populated.
207 base::ListValue* tabs = NULL;
208 EXPECT_FALSE(result_window->GetList(keys::kTabsKey, &tabs));
209 }
210 // The returned ids should contain all the current browser instance ids.
211 EXPECT_EQ(window_ids, result_ids);
212
213 result_ids.clear();
214 function = new WindowsGetAllFunction();
215 function->set_extension(extension.get());
216 result.reset(utils::ToList(
217 utils::RunFunctionAndReturnSingleResult(function.get(),
218 "[{\"populate\": true}]",
219 browser())));
220
221 windows = result.get();
222 EXPECT_EQ(NUM_WINDOWS, windows->GetSize());
223 for (size_t i = 0; i < windows->GetSize(); ++i) {
224 base::DictionaryValue* result_window = NULL;
225 EXPECT_TRUE(windows->GetDictionary(i, &result_window));
226 result_ids.insert(utils::GetInteger(result_window, "id"));
227
228 // "populate" was enabled so tabs should be populated.
229 base::ListValue* tabs = NULL;
230 EXPECT_TRUE(result_window->GetList(keys::kTabsKey, &tabs));
231 }
232 // The returned ids should contain all the current browser instance ids.
233 EXPECT_EQ(window_ids, result_ids);
234 }
235
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,UpdateNoPermissions)236 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, UpdateNoPermissions) {
237 // The test empty extension has no permissions, therefore it should not get
238 // tab data in the function result.
239 scoped_refptr<TabsUpdateFunction> update_tab_function(
240 new TabsUpdateFunction());
241 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
242 update_tab_function->set_extension(empty_extension.get());
243 // Without a callback the function will not generate a result.
244 update_tab_function->set_has_callback(true);
245
246 scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
247 utils::RunFunctionAndReturnSingleResult(
248 update_tab_function.get(),
249 "[null, {\"url\": \"about:blank\", \"pinned\": true}]",
250 browser())));
251 // The url is stripped since the extension does not have tab permissions.
252 EXPECT_FALSE(result->HasKey("url"));
253 EXPECT_TRUE(utils::GetBoolean(result.get(), "pinned"));
254 }
255
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,DefaultToIncognitoWhenItIsForced)256 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,
257 DefaultToIncognitoWhenItIsForced) {
258 static const char kArgsWithoutExplicitIncognitoParam[] =
259 "[{\"url\": \"about:blank\"}]";
260 // Force Incognito mode.
261 IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
262 IncognitoModePrefs::FORCED);
263 // Run without an explicit "incognito" param.
264 scoped_refptr<WindowsCreateFunction> function(new WindowsCreateFunction());
265 scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
266 function->set_extension(extension.get());
267 scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
268 utils::RunFunctionAndReturnSingleResult(
269 function.get(),
270 kArgsWithoutExplicitIncognitoParam,
271 browser(),
272 utils::INCLUDE_INCOGNITO)));
273
274 // Make sure it is a new(different) window.
275 EXPECT_NE(ExtensionTabUtil::GetWindowId(browser()),
276 utils::GetInteger(result.get(), "id"));
277 // ... and it is incognito.
278 EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito"));
279
280 // Now try creating a window from incognito window.
281 Browser* incognito_browser = CreateIncognitoBrowser();
282 // Run without an explicit "incognito" param.
283 function = new WindowsCreateFunction();
284 function->set_extension(extension.get());
285 result.reset(utils::ToDictionary(
286 utils::RunFunctionAndReturnSingleResult(
287 function.get(),
288 kArgsWithoutExplicitIncognitoParam,
289 incognito_browser,
290 utils::INCLUDE_INCOGNITO)));
291 // Make sure it is a new(different) window.
292 EXPECT_NE(ExtensionTabUtil::GetWindowId(incognito_browser),
293 utils::GetInteger(result.get(), "id"));
294 // ... and it is incognito.
295 EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito"));
296 }
297
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,DefaultToIncognitoWhenItIsForcedAndNoArgs)298 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,
299 DefaultToIncognitoWhenItIsForcedAndNoArgs) {
300 static const char kEmptyArgs[] = "[]";
301 // Force Incognito mode.
302 IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
303 IncognitoModePrefs::FORCED);
304 // Run without an explicit "incognito" param.
305 scoped_refptr<WindowsCreateFunction> function = new WindowsCreateFunction();
306 scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
307 function->set_extension(extension.get());
308 scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
309 utils::RunFunctionAndReturnSingleResult(function.get(),
310 kEmptyArgs,
311 browser(),
312 utils::INCLUDE_INCOGNITO)));
313
314 // Make sure it is a new(different) window.
315 EXPECT_NE(ExtensionTabUtil::GetWindowId(browser()),
316 utils::GetInteger(result.get(), "id"));
317 // ... and it is incognito.
318 EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito"));
319
320 // Now try creating a window from incognito window.
321 Browser* incognito_browser = CreateIncognitoBrowser();
322 // Run without an explicit "incognito" param.
323 function = new WindowsCreateFunction();
324 function->set_extension(extension.get());
325 result.reset(utils::ToDictionary(
326 utils::RunFunctionAndReturnSingleResult(function.get(),
327 kEmptyArgs,
328 incognito_browser,
329 utils::INCLUDE_INCOGNITO)));
330 // Make sure it is a new(different) window.
331 EXPECT_NE(ExtensionTabUtil::GetWindowId(incognito_browser),
332 utils::GetInteger(result.get(), "id"));
333 // ... and it is incognito.
334 EXPECT_TRUE(utils::GetBoolean(result.get(), "incognito"));
335 }
336
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,DontCreateNormalWindowWhenIncognitoForced)337 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,
338 DontCreateNormalWindowWhenIncognitoForced) {
339 static const char kArgsWithExplicitIncognitoParam[] =
340 "[{\"url\": \"about:blank\", \"incognito\": false }]";
341 // Force Incognito mode.
342 IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
343 IncognitoModePrefs::FORCED);
344
345 // Run with an explicit "incognito" param.
346 scoped_refptr<WindowsCreateFunction> function = new WindowsCreateFunction();
347 scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
348 function->set_extension(extension.get());
349 EXPECT_TRUE(MatchPattern(
350 utils::RunFunctionAndReturnError(function.get(),
351 kArgsWithExplicitIncognitoParam,
352 browser()),
353 keys::kIncognitoModeIsForced));
354
355 // Now try opening a normal window from incognito window.
356 Browser* incognito_browser = CreateIncognitoBrowser();
357 // Run with an explicit "incognito" param.
358 function = new WindowsCreateFunction();
359 function->set_extension(extension.get());
360 EXPECT_TRUE(MatchPattern(
361 utils::RunFunctionAndReturnError(function.get(),
362 kArgsWithExplicitIncognitoParam,
363 incognito_browser),
364 keys::kIncognitoModeIsForced));
365 }
366
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,DontCreateIncognitoWindowWhenIncognitoDisabled)367 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,
368 DontCreateIncognitoWindowWhenIncognitoDisabled) {
369 static const char kArgs[] =
370 "[{\"url\": \"about:blank\", \"incognito\": true }]";
371
372 Browser* incognito_browser = CreateIncognitoBrowser();
373 // Disable Incognito mode.
374 IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
375 IncognitoModePrefs::DISABLED);
376 // Run in normal window.
377 scoped_refptr<WindowsCreateFunction> function = new WindowsCreateFunction();
378 scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
379 function->set_extension(extension.get());
380 EXPECT_TRUE(MatchPattern(
381 utils::RunFunctionAndReturnError(function.get(),
382 kArgs,
383 browser()),
384 keys::kIncognitoModeIsDisabled));
385
386 // Run in incognito window.
387 function = new WindowsCreateFunction();
388 function->set_extension(extension.get());
389 EXPECT_TRUE(MatchPattern(
390 utils::RunFunctionAndReturnError(function.get(),
391 kArgs,
392 incognito_browser),
393 keys::kIncognitoModeIsDisabled));
394 }
395
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,QueryCurrentWindowTabs)396 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, QueryCurrentWindowTabs) {
397 const size_t kExtraWindows = 3;
398 for (size_t i = 0; i < kExtraWindows; ++i)
399 CreateBrowser(browser()->profile());
400
401 GURL url(url::kAboutBlankURL);
402 AddTabAtIndexToBrowser(browser(), 0, url, ui::PAGE_TRANSITION_LINK);
403 int window_id = ExtensionTabUtil::GetWindowId(browser());
404
405 // Get tabs in the 'current' window called from non-focused browser.
406 scoped_refptr<TabsQueryFunction> function = new TabsQueryFunction();
407 function->set_extension(test_util::CreateEmptyExtension().get());
408 scoped_ptr<base::ListValue> result(utils::ToList(
409 utils::RunFunctionAndReturnSingleResult(function.get(),
410 "[{\"currentWindow\":true}]",
411 browser())));
412
413 base::ListValue* result_tabs = result.get();
414 // We should have one initial tab and one added tab.
415 EXPECT_EQ(2u, result_tabs->GetSize());
416 for (size_t i = 0; i < result_tabs->GetSize(); ++i) {
417 base::DictionaryValue* result_tab = NULL;
418 EXPECT_TRUE(result_tabs->GetDictionary(i, &result_tab));
419 EXPECT_EQ(window_id, utils::GetInteger(result_tab, keys::kWindowIdKey));
420 }
421
422 // Get tabs NOT in the 'current' window called from non-focused browser.
423 function = new TabsQueryFunction();
424 function->set_extension(test_util::CreateEmptyExtension().get());
425 result.reset(utils::ToList(
426 utils::RunFunctionAndReturnSingleResult(function.get(),
427 "[{\"currentWindow\":false}]",
428 browser())));
429
430 result_tabs = result.get();
431 // We should have one tab for each extra window.
432 EXPECT_EQ(kExtraWindows, result_tabs->GetSize());
433 for (size_t i = 0; i < kExtraWindows; ++i) {
434 base::DictionaryValue* result_tab = NULL;
435 EXPECT_TRUE(result_tabs->GetDictionary(i, &result_tab));
436 EXPECT_NE(window_id, utils::GetInteger(result_tab, keys::kWindowIdKey));
437 }
438 }
439
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,DontCreateTabInClosingPopupWindow)440 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DontCreateTabInClosingPopupWindow) {
441 // Test creates new popup window, closes it right away and then tries to open
442 // a new tab in it. Tab should not be opened in the popup window, but in a
443 // tabbed browser window.
444 Browser* popup_browser = new Browser(
445 Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(),
446 browser()->host_desktop_type()));
447 int window_id = ExtensionTabUtil::GetWindowId(popup_browser);
448 chrome::CloseWindow(popup_browser);
449
450 scoped_refptr<TabsCreateFunction> create_tab_function(
451 new TabsCreateFunction());
452 create_tab_function->set_extension(test_util::CreateEmptyExtension().get());
453 // Without a callback the function will not generate a result.
454 create_tab_function->set_has_callback(true);
455
456 static const char kNewBlankTabArgs[] =
457 "[{\"url\": \"about:blank\", \"windowId\": %u}]";
458
459 scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
460 utils::RunFunctionAndReturnSingleResult(
461 create_tab_function.get(),
462 base::StringPrintf(kNewBlankTabArgs, window_id),
463 browser())));
464
465 EXPECT_NE(window_id, utils::GetInteger(result.get(), "windowId"));
466 }
467
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,InvalidUpdateWindowState)468 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, InvalidUpdateWindowState) {
469 int window_id = ExtensionTabUtil::GetWindowId(browser());
470
471 static const char kArgsMinimizedWithFocus[] =
472 "[%u, {\"state\": \"minimized\", \"focused\": true}]";
473 scoped_refptr<WindowsUpdateFunction> function = new WindowsUpdateFunction();
474 scoped_refptr<Extension> extension(test_util::CreateEmptyExtension());
475 function->set_extension(extension.get());
476 EXPECT_TRUE(MatchPattern(
477 utils::RunFunctionAndReturnError(
478 function.get(),
479 base::StringPrintf(kArgsMinimizedWithFocus, window_id),
480 browser()),
481 keys::kInvalidWindowStateError));
482
483 static const char kArgsMaximizedWithoutFocus[] =
484 "[%u, {\"state\": \"maximized\", \"focused\": false}]";
485 function = new WindowsUpdateFunction();
486 function->set_extension(extension.get());
487 EXPECT_TRUE(MatchPattern(
488 utils::RunFunctionAndReturnError(
489 function.get(),
490 base::StringPrintf(kArgsMaximizedWithoutFocus, window_id),
491 browser()),
492 keys::kInvalidWindowStateError));
493
494 static const char kArgsMinimizedWithBounds[] =
495 "[%u, {\"state\": \"minimized\", \"width\": 500}]";
496 function = new WindowsUpdateFunction();
497 function->set_extension(extension.get());
498 EXPECT_TRUE(MatchPattern(
499 utils::RunFunctionAndReturnError(
500 function.get(),
501 base::StringPrintf(kArgsMinimizedWithBounds, window_id),
502 browser()),
503 keys::kInvalidWindowStateError));
504
505 static const char kArgsMaximizedWithBounds[] =
506 "[%u, {\"state\": \"maximized\", \"width\": 500}]";
507 function = new WindowsUpdateFunction();
508 function->set_extension(extension.get());
509 EXPECT_TRUE(MatchPattern(
510 utils::RunFunctionAndReturnError(
511 function.get(),
512 base::StringPrintf(kArgsMaximizedWithBounds, window_id),
513 browser()),
514 keys::kInvalidWindowStateError));
515 }
516
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,DuplicateTab)517 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DuplicateTab) {
518 content::OpenURLParams params(GURL(url::kAboutBlankURL),
519 content::Referrer(),
520 NEW_FOREGROUND_TAB,
521 ui::PAGE_TRANSITION_LINK,
522 false);
523 content::WebContents* web_contents = browser()->OpenURL(params);
524 int tab_id = ExtensionTabUtil::GetTabId(web_contents);
525 int window_id = ExtensionTabUtil::GetWindowIdOfTab(web_contents);
526 int tab_index = -1;
527 TabStripModel* tab_strip;
528 ExtensionTabUtil::GetTabStripModel(web_contents, &tab_strip, &tab_index);
529
530 scoped_refptr<TabsDuplicateFunction> duplicate_tab_function(
531 new TabsDuplicateFunction());
532 scoped_ptr<base::DictionaryValue> test_extension_value(
533 utils::ParseDictionary(
534 "{\"name\": \"Test\", \"version\": \"1.0\", \"permissions\": [\"tabs\"]}"
535 ));
536 scoped_refptr<Extension> empty_tab_extension(
537 utils::CreateExtension(test_extension_value.get()));
538 duplicate_tab_function->set_extension(empty_tab_extension.get());
539 duplicate_tab_function->set_has_callback(true);
540
541 scoped_ptr<base::DictionaryValue> duplicate_result(utils::ToDictionary(
542 utils::RunFunctionAndReturnSingleResult(
543 duplicate_tab_function.get(), base::StringPrintf("[%u]", tab_id),
544 browser())));
545
546 int duplicate_tab_id = utils::GetInteger(duplicate_result.get(), "id");
547 int duplicate_tab_window_id = utils::GetInteger(duplicate_result.get(),
548 "windowId");
549 int duplicate_tab_index = utils::GetInteger(duplicate_result.get(), "index");
550 EXPECT_EQ(base::Value::TYPE_DICTIONARY, duplicate_result->GetType());
551 // Duplicate tab id should be different from the original tab id.
552 EXPECT_NE(tab_id, duplicate_tab_id);
553 EXPECT_EQ(window_id, duplicate_tab_window_id);
554 EXPECT_EQ(tab_index + 1, duplicate_tab_index);
555 // The test empty tab extension has tabs permissions, therefore
556 // |duplicate_result| should contain url, title, and faviconUrl
557 // in the function result.
558 EXPECT_TRUE(utils::HasPrivacySensitiveFields(duplicate_result.get()));
559 }
560
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest,DuplicateTabNoPermission)561 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DuplicateTabNoPermission) {
562 content::OpenURLParams params(GURL(url::kAboutBlankURL),
563 content::Referrer(),
564 NEW_FOREGROUND_TAB,
565 ui::PAGE_TRANSITION_LINK,
566 false);
567 content::WebContents* web_contents = browser()->OpenURL(params);
568 int tab_id = ExtensionTabUtil::GetTabId(web_contents);
569 int window_id = ExtensionTabUtil::GetWindowIdOfTab(web_contents);
570 int tab_index = -1;
571 TabStripModel* tab_strip;
572 ExtensionTabUtil::GetTabStripModel(web_contents, &tab_strip, &tab_index);
573
574 scoped_refptr<TabsDuplicateFunction> duplicate_tab_function(
575 new TabsDuplicateFunction());
576 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
577 duplicate_tab_function->set_extension(empty_extension.get());
578 duplicate_tab_function->set_has_callback(true);
579
580 scoped_ptr<base::DictionaryValue> duplicate_result(utils::ToDictionary(
581 utils::RunFunctionAndReturnSingleResult(
582 duplicate_tab_function.get(), base::StringPrintf("[%u]", tab_id),
583 browser())));
584
585 int duplicate_tab_id = utils::GetInteger(duplicate_result.get(), "id");
586 int duplicate_tab_window_id = utils::GetInteger(duplicate_result.get(),
587 "windowId");
588 int duplicate_tab_index = utils::GetInteger(duplicate_result.get(), "index");
589 EXPECT_EQ(base::Value::TYPE_DICTIONARY, duplicate_result->GetType());
590 // Duplicate tab id should be different from the original tab id.
591 EXPECT_NE(tab_id, duplicate_tab_id);
592 EXPECT_EQ(window_id, duplicate_tab_window_id);
593 EXPECT_EQ(tab_index + 1, duplicate_tab_index);
594 // The test empty extension has no permissions, therefore |duplicate_result|
595 // should not contain url, title, and faviconUrl in the function result.
596 EXPECT_FALSE(utils::HasPrivacySensitiveFields(duplicate_result.get()));
597 }
598
599 // Tester class for the tabs.zoom* api functions.
600 class ExtensionTabsZoomTest : public ExtensionTabsTest {
601 public:
602 virtual void SetUpOnMainThread() OVERRIDE;
603
604 // Runs chrome.tabs.setZoom().
605 bool RunSetZoom(int tab_id, double zoom_factor);
606
607 // Runs chrome.tabs.getZoom().
608 testing::AssertionResult RunGetZoom(int tab_id, double* zoom_factor);
609
610 // Runs chrome.tabs.setZoomSettings().
611 bool RunSetZoomSettings(int tab_id, const char* mode, const char* scope);
612
613 // Runs chrome.tabs.getZoomSettings().
614 testing::AssertionResult RunGetZoomSettings(int tab_id,
615 std::string* mode,
616 std::string* scope);
617
618 // Runs chrome.tabs.setZoom(), expecting an error.
619 std::string RunSetZoomExpectError(int tab_id,
620 double zoom_factor);
621
622 // Runs chrome.tabs.setZoomSettings(), expecting an error.
623 std::string RunSetZoomSettingsExpectError(int tab_id,
624 const char* mode,
625 const char* scope);
626
627 content::WebContents* OpenUrlAndWaitForLoad(const GURL& url);
628
629 private:
630 scoped_refptr<Extension> extension_;
631 };
632
SetUpOnMainThread()633 void ExtensionTabsZoomTest::SetUpOnMainThread() {
634 ExtensionTabsTest::SetUpOnMainThread();
635 extension_ = test_util::CreateEmptyExtension();
636 }
637
RunSetZoom(int tab_id,double zoom_factor)638 bool ExtensionTabsZoomTest::RunSetZoom(int tab_id, double zoom_factor) {
639 scoped_refptr<TabsSetZoomFunction> set_zoom_function(
640 new TabsSetZoomFunction());
641 set_zoom_function->set_extension(extension_.get());
642 set_zoom_function->set_has_callback(true);
643
644 return utils::RunFunction(
645 set_zoom_function.get(),
646 base::StringPrintf("[%u, %lf]", tab_id, zoom_factor),
647 browser(),
648 extension_function_test_utils::NONE);
649 }
650
RunGetZoom(int tab_id,double * zoom_factor)651 testing::AssertionResult ExtensionTabsZoomTest::RunGetZoom(
652 int tab_id,
653 double* zoom_factor) {
654 scoped_refptr<TabsGetZoomFunction> get_zoom_function(
655 new TabsGetZoomFunction());
656 get_zoom_function->set_extension(extension_.get());
657 get_zoom_function->set_has_callback(true);
658
659 scoped_ptr<base::Value> get_zoom_result(
660 utils::RunFunctionAndReturnSingleResult(
661 get_zoom_function.get(),
662 base::StringPrintf("[%u]", tab_id),
663 browser()));
664
665 if (!get_zoom_result)
666 return testing::AssertionFailure() << "no result";
667 if (!get_zoom_result->GetAsDouble(zoom_factor))
668 return testing::AssertionFailure() << "result was not a double";
669
670 return testing::AssertionSuccess();
671 }
672
RunSetZoomSettings(int tab_id,const char * mode,const char * scope)673 bool ExtensionTabsZoomTest::RunSetZoomSettings(int tab_id,
674 const char* mode,
675 const char* scope) {
676 scoped_refptr<TabsSetZoomSettingsFunction> set_zoom_settings_function(
677 new TabsSetZoomSettingsFunction());
678 set_zoom_settings_function->set_extension(extension_.get());
679
680 std::string args;
681 if (scope) {
682 args = base::StringPrintf("[%u, {\"mode\": \"%s\", \"scope\": \"%s\"}]",
683 tab_id, mode, scope);
684 } else {
685 args = base::StringPrintf("[%u, {\"mode\": \"%s\"}]", tab_id, mode);
686 }
687
688 return utils::RunFunction(set_zoom_settings_function.get(),
689 args,
690 browser(),
691 extension_function_test_utils::NONE);
692 }
693
RunGetZoomSettings(int tab_id,std::string * mode,std::string * scope)694 testing::AssertionResult ExtensionTabsZoomTest::RunGetZoomSettings(
695 int tab_id,
696 std::string* mode,
697 std::string* scope) {
698 DCHECK(mode);
699 DCHECK(scope);
700 scoped_refptr<TabsGetZoomSettingsFunction> get_zoom_settings_function(
701 new TabsGetZoomSettingsFunction());
702 get_zoom_settings_function->set_extension(extension_.get());
703 get_zoom_settings_function->set_has_callback(true);
704
705 scoped_ptr<base::DictionaryValue> get_zoom_settings_result(
706 utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
707 get_zoom_settings_function.get(),
708 base::StringPrintf("[%u]", tab_id),
709 browser())));
710
711 if (!get_zoom_settings_result)
712 return testing::AssertionFailure() << "no result";
713
714 *mode = utils::GetString(get_zoom_settings_result.get(), "mode");
715 *scope = utils::GetString(get_zoom_settings_result.get(), "scope");
716
717 return testing::AssertionSuccess();
718 }
719
RunSetZoomExpectError(int tab_id,double zoom_factor)720 std::string ExtensionTabsZoomTest::RunSetZoomExpectError(int tab_id,
721 double zoom_factor) {
722 scoped_refptr<TabsSetZoomFunction> set_zoom_function(
723 new TabsSetZoomFunction());
724 set_zoom_function->set_extension(extension_.get());
725 set_zoom_function->set_has_callback(true);
726
727 return utils::RunFunctionAndReturnError(
728 set_zoom_function.get(),
729 base::StringPrintf("[%u, %lf]", tab_id, zoom_factor),
730 browser());
731 }
732
RunSetZoomSettingsExpectError(int tab_id,const char * mode,const char * scope)733 std::string ExtensionTabsZoomTest::RunSetZoomSettingsExpectError(
734 int tab_id,
735 const char* mode,
736 const char* scope) {
737 scoped_refptr<TabsSetZoomSettingsFunction> set_zoom_settings_function(
738 new TabsSetZoomSettingsFunction());
739 set_zoom_settings_function->set_extension(extension_.get());
740
741 return utils::RunFunctionAndReturnError(set_zoom_settings_function.get(),
742 base::StringPrintf(
743 "[%u, {\"mode\": \"%s\", "
744 "\"scope\": \"%s\"}]",
745 tab_id,
746 mode,
747 scope),
748 browser());
749 }
750
OpenUrlAndWaitForLoad(const GURL & url)751 content::WebContents* ExtensionTabsZoomTest::OpenUrlAndWaitForLoad(
752 const GURL& url) {
753 ui_test_utils::NavigateToURLWithDisposition(
754 browser(),
755 url,
756 NEW_FOREGROUND_TAB,
757 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
758 return browser()->tab_strip_model()->GetActiveWebContents();
759 }
760
761 namespace {
762
GetZoomLevel(const content::WebContents * web_contents)763 double GetZoomLevel(const content::WebContents* web_contents) {
764 return ZoomController::FromWebContents(web_contents)->GetZoomLevel();
765 }
766
GetOpenParams(const char * url)767 content::OpenURLParams GetOpenParams(const char* url) {
768 return content::OpenURLParams(GURL(url),
769 content::Referrer(),
770 NEW_FOREGROUND_TAB,
771 ui::PAGE_TRANSITION_LINK,
772 false);
773 }
774
775 } // namespace
776
IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest,SetAndGetZoom)777 IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, SetAndGetZoom) {
778 content::OpenURLParams params(GetOpenParams(url::kAboutBlankURL));
779 content::WebContents* web_contents = OpenUrlAndWaitForLoad(params.url);
780 int tab_id = ExtensionTabUtil::GetTabId(web_contents);
781
782 // Test default values before we set anything.
783 double zoom_factor = -1;
784 EXPECT_TRUE(RunGetZoom(tab_id, &zoom_factor));
785 EXPECT_EQ(1.0, zoom_factor);
786
787 // Test chrome.tabs.setZoom().
788 const double kZoomLevel = 0.8;
789 EXPECT_TRUE(RunSetZoom(tab_id, kZoomLevel));
790 EXPECT_EQ(kZoomLevel,
791 content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents)));
792
793 // Test chrome.tabs.getZoom().
794 zoom_factor = -1;
795 EXPECT_TRUE(RunGetZoom(tab_id, &zoom_factor));
796 EXPECT_EQ(kZoomLevel, zoom_factor);
797 }
798
IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest,ZoomSettings)799 IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, ZoomSettings) {
800 // In this test we need two URLs that (1) represent real pages (i.e. they
801 // load without causing an error page load), (2) have different domains, and
802 // (3) are zoomable by the extension API (this last condition rules out
803 // chrome:// urls). We achieve this by noting that about:blank meets these
804 // requirements, allowing us to spin up a spawned http server on localhost to
805 // get the other domain.
806 net::SpawnedTestServer http_server(
807 net::SpawnedTestServer::TYPE_HTTP,
808 net::SpawnedTestServer::kLocalhost,
809 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
810 ASSERT_TRUE(http_server.Start());
811
812 GURL url_A = http_server.GetURL("files/simple.html");
813 GURL url_B("about:blank");
814
815 // Tabs A1 and A2 are navigated to the same origin, while B is navigated
816 // to a different one.
817 content::WebContents* web_contents_A1 = OpenUrlAndWaitForLoad(url_A);
818 content::WebContents* web_contents_A2 = OpenUrlAndWaitForLoad(url_A);
819 content::WebContents* web_contents_B = OpenUrlAndWaitForLoad(url_B);
820
821 int tab_id_A1 = ExtensionTabUtil::GetTabId(web_contents_A1);
822 int tab_id_A2 = ExtensionTabUtil::GetTabId(web_contents_A2);
823 int tab_id_B = ExtensionTabUtil::GetTabId(web_contents_B);
824
825 ASSERT_FLOAT_EQ(
826 1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1)));
827 ASSERT_FLOAT_EQ(
828 1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2)));
829 ASSERT_FLOAT_EQ(
830 1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_B)));
831
832 // Test per-origin automatic zoom settings.
833 EXPECT_TRUE(RunSetZoom(tab_id_B, 1.f));
834 EXPECT_TRUE(RunSetZoom(tab_id_A2, 1.1f));
835 EXPECT_FLOAT_EQ(
836 1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1)));
837 EXPECT_FLOAT_EQ(
838 1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2)));
839 EXPECT_FLOAT_EQ(1.f,
840 content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_B)));
841
842 // Test per-tab automatic zoom settings.
843 EXPECT_TRUE(RunSetZoomSettings(tab_id_A1, "automatic", "per-tab"));
844 EXPECT_TRUE(RunSetZoom(tab_id_A1, 1.2f));
845 EXPECT_FLOAT_EQ(
846 1.2f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1)));
847 EXPECT_FLOAT_EQ(
848 1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2)));
849
850 // Test 'manual' mode.
851 EXPECT_TRUE(RunSetZoomSettings(tab_id_A1, "manual", NULL));
852 EXPECT_TRUE(RunSetZoom(tab_id_A1, 1.3f));
853 EXPECT_FLOAT_EQ(
854 1.3f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1)));
855 EXPECT_FLOAT_EQ(
856 1.1f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2)));
857
858 // Test 'disabled' mode, which will reset A1's zoom to 1.f.
859 EXPECT_TRUE(RunSetZoomSettings(tab_id_A1, "disabled", NULL));
860 std::string error = RunSetZoomExpectError(tab_id_A1, 1.4f);
861 EXPECT_TRUE(MatchPattern(error, keys::kCannotZoomDisabledTabError));
862 EXPECT_FLOAT_EQ(
863 1.f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A1)));
864 // We should still be able to zoom A2 though.
865 EXPECT_TRUE(RunSetZoom(tab_id_A2, 1.4f));
866 EXPECT_FLOAT_EQ(
867 1.4f, content::ZoomLevelToZoomFactor(GetZoomLevel(web_contents_A2)));
868 }
869
IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest,GetZoomSettings)870 IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, GetZoomSettings) {
871 content::OpenURLParams params(GetOpenParams(url::kAboutBlankURL));
872 content::WebContents* web_contents = OpenUrlAndWaitForLoad(params.url);
873 int tab_id = ExtensionTabUtil::GetTabId(web_contents);
874
875 std::string mode;
876 std::string scope;
877
878 EXPECT_TRUE(RunGetZoomSettings(tab_id, &mode, &scope));
879 EXPECT_EQ("automatic", mode);
880 EXPECT_EQ("per-origin", scope);
881
882 EXPECT_TRUE(RunSetZoomSettings(tab_id, "automatic", "per-tab"));
883 EXPECT_TRUE(RunGetZoomSettings(tab_id, &mode, &scope));
884
885 EXPECT_EQ("automatic", mode);
886 EXPECT_EQ("per-tab", scope);
887
888 std::string error =
889 RunSetZoomSettingsExpectError(tab_id, "manual", "per-origin");
890 EXPECT_TRUE(MatchPattern(error,
891 keys::kPerOriginOnlyInAutomaticError));
892 error =
893 RunSetZoomSettingsExpectError(tab_id, "disabled", "per-origin");
894 EXPECT_TRUE(MatchPattern(error,
895 keys::kPerOriginOnlyInAutomaticError));
896 }
897
IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest,CannotZoomInvalidTab)898 IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, CannotZoomInvalidTab) {
899 content::OpenURLParams params(GetOpenParams(url::kAboutBlankURL));
900 content::WebContents* web_contents = OpenUrlAndWaitForLoad(params.url);
901 int tab_id = ExtensionTabUtil::GetTabId(web_contents);
902
903 int bogus_id = tab_id + 100;
904 std::string error = RunSetZoomExpectError(bogus_id, 3.14159);
905 EXPECT_TRUE(MatchPattern(error, keys::kTabNotFoundError));
906
907 error = RunSetZoomSettingsExpectError(bogus_id, "manual", "per-tab");
908 EXPECT_TRUE(MatchPattern(error, keys::kTabNotFoundError));
909
910 const char kNewTestTabArgs[] = "chrome://version";
911 params = GetOpenParams(kNewTestTabArgs);
912 web_contents = browser()->OpenURL(params);
913 tab_id = ExtensionTabUtil::GetTabId(web_contents);
914
915 // Test chrome.tabs.setZoom().
916 error = RunSetZoomExpectError(tab_id, 3.14159);
917 EXPECT_TRUE(MatchPattern(error, manifest_errors::kCannotAccessChromeUrl));
918
919 // chrome.tabs.setZoomSettings().
920 error = RunSetZoomSettingsExpectError(tab_id, "manual", "per-tab");
921 EXPECT_TRUE(MatchPattern(error, manifest_errors::kCannotAccessChromeUrl));
922 }
923
924 } // namespace extensions
925