1 // Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights 2 // reserved. Use of this source code is governed by a BSD-style license that 3 // can be found in the LICENSE file. 4 5 #include "tests/ceftests/extensions/extension_test_handler.h" 6 7 #include <sstream> 8 9 #include "include/cef_parser.h" 10 11 #include "tests/ceftests/test_util.h" 12 #include "tests/shared/browser/extension_util.h" 13 14 #define TABS_TEST_GROUP_ALL(name, test_class) \ 15 EXTENSION_TEST_GROUP_ALL(ChromeTabs##name, test_class) 16 #define TABS_TEST_GROUP_MINIMAL(name, test_class) \ 17 EXTENSION_TEST_GROUP_MINIMAL(ChromeTabs##name, test_class) 18 19 namespace { 20 21 const char kMainBrowserURL[] = "https://test-extensions.com/chrome-tabs"; 22 const char kExtensionPath[] = "tabs-extension"; 23 const char kSuccessMessage[] = "success"; 24 25 // Base class for testing chrome.tabs methods. 26 // See https://developer.chrome.com/extensions/tabs 27 class TabsTestHandler : public ExtensionTestHandler { 28 public: TabsTestHandler(RequestContextType request_context_type)29 explicit TabsTestHandler(RequestContextType request_context_type) 30 : ExtensionTestHandler(request_context_type), 31 create_main_browser_first_(false), 32 expect_get_active_browser_(true), 33 expect_success_in_main_browser_(true), 34 expected_api_call_count_(1), 35 got_get_active_browser_count_(0), 36 got_can_access_browser_count_(0) {} 37 38 // CefExtensionHandler methods: OnExtensionLoaded(CefRefPtr<CefExtension> extension)39 void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override { 40 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 41 EXPECT_FALSE(got_extension_loaded_); 42 got_extension_loaded_.yes(); 43 44 // Verify |extension| contents. 45 EXPECT_FALSE(extension->GetIdentifier().empty()); 46 EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(), 47 client::extension_util::GetInternalExtensionResourcePath( 48 extension->GetPath()) 49 .c_str()); 50 TestDictionaryEqual(CreateManifest(), extension->GetManifest()); 51 52 EXPECT_FALSE(extension_); 53 extension_ = extension; 54 55 if (create_main_browser_first_) 56 CreateBrowserForExtensionIfReady(); 57 else 58 CreateBrowserForExtension(); 59 } 60 OnExtensionUnloaded(CefRefPtr<CefExtension> extension)61 void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override { 62 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 63 EXPECT_TRUE(extension_); 64 EXPECT_TRUE(extension_->IsSame(extension)); 65 EXPECT_FALSE(got_extension_unloaded_); 66 got_extension_unloaded_.yes(); 67 extension_ = nullptr; 68 69 // Execute asynchronously so call stacks have a chance to unwind. 70 // Will close the browser windows. 71 CefPostTask(TID_UI, base::BindOnce(&TabsTestHandler::DestroyTest, this)); 72 } 73 GetActiveBrowser(CefRefPtr<CefExtension> extension,CefRefPtr<CefBrowser> browser,bool include_incognito)74 CefRefPtr<CefBrowser> GetActiveBrowser(CefRefPtr<CefExtension> extension, 75 CefRefPtr<CefBrowser> browser, 76 bool include_incognito) override { 77 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 78 EXPECT_TRUE(extension_); 79 EXPECT_TRUE(extension_->IsSame(extension)); 80 EXPECT_TRUE(main_browser_); 81 82 EXPECT_LE(got_get_active_browser_count_, expected_api_call_count_); 83 got_get_active_browser_count_++; 84 85 // Tabs APIs will operate on the main browser. 86 return main_browser_; 87 } 88 CanAccessBrowser(CefRefPtr<CefExtension> extension,CefRefPtr<CefBrowser> browser,bool include_incognito,CefRefPtr<CefBrowser> target_browser)89 bool CanAccessBrowser(CefRefPtr<CefExtension> extension, 90 CefRefPtr<CefBrowser> browser, 91 bool include_incognito, 92 CefRefPtr<CefBrowser> target_browser) override { 93 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 94 EXPECT_TRUE(extension_); 95 EXPECT_TRUE(extension_->IsSame(extension)); 96 EXPECT_TRUE(main_browser_); 97 EXPECT_TRUE(main_browser_->IsSame(target_browser)); 98 99 EXPECT_LE(got_can_access_browser_count_, expected_api_call_count_); 100 got_can_access_browser_count_++; 101 102 return true; 103 } 104 105 // CefLoadHandler methods: OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)106 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser, 107 bool isLoading, 108 bool canGoBack, 109 bool canGoForward) override { 110 if (isLoading) { 111 // Keep a reference to both browsers. 112 if (browser->GetHost()->GetExtension()) { 113 EXPECT_FALSE(extension_browser_); 114 extension_browser_ = browser; 115 } else { 116 EXPECT_FALSE(main_browser_); 117 main_browser_ = browser; 118 } 119 } else { 120 const std::string& url = browser->GetMainFrame()->GetURL(); 121 if (browser->GetHost()->GetExtension()) { 122 EXPECT_TRUE(browser->IsSame(extension_browser_)); 123 EXPECT_STREQ(extension_url_.c_str(), url.c_str()); 124 } else { 125 EXPECT_TRUE(browser->IsSame(main_browser_)); 126 EXPECT_STREQ(kMainBrowserURL, url.c_str()); 127 } 128 } 129 } 130 131 // CefResourceRequestHandler methods: GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)132 CefRefPtr<CefResourceHandler> GetResourceHandler( 133 CefRefPtr<CefBrowser> browser, 134 CefRefPtr<CefFrame> frame, 135 CefRefPtr<CefRequest> request) override { 136 const std::string& url = request->GetURL(); 137 if (url == kMainBrowserURL) { 138 EXPECT_TRUE(browser->IsSame(main_browser_)); 139 EXPECT_FALSE(got_main_url_request_); 140 got_main_url_request_.yes(); 141 } else if (url == extension_url_) { 142 EXPECT_TRUE(browser->IsSame(extension_browser_)); 143 EXPECT_FALSE(got_extension_url_request_); 144 got_extension_url_request_.yes(); 145 } 146 147 // Handle the resource request. 148 return RoutingTestHandler::GetResourceHandler(browser, frame, request); 149 } 150 151 protected: OnAddMainBrowserResources()152 void OnAddMainBrowserResources() override { 153 AddResource(kMainBrowserURL, GetMainBrowserHTML(), "text/html"); 154 } 155 OnCreateMainBrowser()156 void OnCreateMainBrowser() override { 157 CreateBrowser(kMainBrowserURL, request_context()); 158 } 159 OnLoadExtensions()160 void OnLoadExtensions() override { 161 LoadExtension(kExtensionPath, CreateManifest()); 162 } 163 OnMessage(CefRefPtr<CefBrowser> browser,const std::string & message)164 bool OnMessage(CefRefPtr<CefBrowser> browser, 165 const std::string& message) override { 166 if (message == "main_onload") { 167 // From body onLoad in the main browser. 168 EXPECT_TRUE(browser->IsSame(main_browser_)); 169 EXPECT_FALSE(got_main_body_onload_); 170 got_main_body_onload_.yes(); 171 if (create_main_browser_first_) 172 CreateBrowserForExtensionIfReady(); 173 TriggerTabsApiJSFunctionIfReady(); 174 return true; 175 } 176 if (message == "extension_onload") { 177 // From body onLoad in the extension browser. 178 EXPECT_TRUE(browser->IsSame(extension_browser_)); 179 EXPECT_FALSE(got_extension_body_onload_); 180 got_extension_body_onload_.yes(); 181 TriggerTabsApiJSFunctionIfReady(); 182 return true; 183 } 184 185 // The success message usually orginates from the logic in 186 // GetMainBrowserSuccessHEAD/BODY(). It may occasionally originate from the 187 // extension browser if we don't know how to detect success in the main 188 // browser. 189 if (expect_success_in_main_browser_) { 190 EXPECT_TRUE(browser->IsSame(main_browser_)); 191 } else { 192 EXPECT_TRUE(browser->IsSame(extension_browser_)); 193 } 194 EXPECT_FALSE(got_success_message_); 195 got_success_message_.yes(); 196 EXPECT_STREQ(kSuccessMessage, message.c_str()); 197 TriggerDestroyTest(); 198 return true; 199 } 200 OnDestroyTest()201 void OnDestroyTest() override { 202 main_browser_ = nullptr; 203 extension_browser_ = nullptr; 204 205 EXPECT_TRUE(got_extension_loaded_); 206 EXPECT_TRUE(got_main_url_request_); 207 EXPECT_TRUE(got_extension_url_request_); 208 EXPECT_TRUE(got_main_body_onload_); 209 EXPECT_TRUE(got_extension_body_onload_); 210 EXPECT_TRUE(got_trigger_api_function_); 211 EXPECT_TRUE(got_success_message_); 212 EXPECT_TRUE(got_extension_unloaded_); 213 214 if (expect_get_active_browser_) { 215 EXPECT_EQ(expected_api_call_count_, got_get_active_browser_count_); 216 EXPECT_EQ(0, got_can_access_browser_count_); 217 } else { 218 EXPECT_EQ(0, got_get_active_browser_count_); 219 EXPECT_EQ(expected_api_call_count_, got_can_access_browser_count_); 220 } 221 } 222 223 // Create a manifest that grants access to the tabs API. CreateManifest() const224 virtual CefRefPtr<CefDictionaryValue> CreateManifest() const { 225 ApiPermissionsList api_permissions; 226 api_permissions.push_back("tabs"); 227 return CreateDefaultManifest(api_permissions); 228 } 229 230 // Add resources in the extension browser. OnAddExtensionResources(const std::string & origin)231 virtual void OnAddExtensionResources(const std::string& origin) { 232 extension_url_ = origin + "extension.html"; 233 AddResource(extension_url_, GetExtensionHTML(), "text/html"); 234 } 235 236 // Returns the target tabId (null, or value >= 0). GetTargetTabId() const237 virtual std::string GetTargetTabId() const { return "null"; } 238 239 // Returns the logic in the main browser that triggers on success. It should 240 // execute GetMessageJS(kSuccessMessage). GetMainBrowserSuccessHEAD() const241 virtual std::string GetMainBrowserSuccessHEAD() const { 242 return std::string(); 243 } GetMainBrowserSuccessBODY() const244 virtual std::string GetMainBrowserSuccessBODY() const { 245 return std::string(); 246 } 247 248 // Returns the HTML that will be loaded in the main browser. GetMainBrowserHTML() const249 virtual std::string GetMainBrowserHTML() const { 250 return "<html><head>" + GetMainBrowserSuccessHEAD() + 251 "</head><body onLoad=" + GetMessageJS("main_onload") + ">Main" + 252 GetMainBrowserSuccessBODY() + "</body></html>"; 253 } 254 255 // Returns the chrome.tabs.* JS that is executed in the extension browser 256 // when the triggerTabsApi() JS function is called. 257 virtual std::string GetTabsApiJS() const = 0; 258 259 // Returns the JS that will be loaded in the extension browser. This 260 // implements the triggerTabsApi() JS function called from 261 // TriggerTabsApiJSFunction(). GetExtensionJS() const262 virtual std::string GetExtensionJS() const { 263 return "function triggerTabsApi() {" + GetTabsApiJS() + "}"; 264 } 265 266 // Returns the HTML that will be loaded in the extension browser. GetExtensionHTML() const267 virtual std::string GetExtensionHTML() const { 268 return "<html><head><script>" + GetExtensionJS() + 269 "</script></head><body onLoad=" + GetMessageJS("extension_onload") + 270 ">Extension</body></html>"; 271 } 272 TriggerDestroyTest()273 virtual void TriggerDestroyTest() { 274 // Execute asynchronously so call stacks have a chance to unwind. 275 CefPostTask(TID_UI, base::BindOnce(&TabsTestHandler::UnloadExtension, this, 276 extension_)); 277 } 278 extension() const279 CefRefPtr<CefExtension> extension() const { return extension_; } extension_url() const280 std::string extension_url() const { return extension_url_; } main_browser() const281 CefRefPtr<CefBrowser> main_browser() const { return main_browser_; } extension_browser() const282 CefRefPtr<CefBrowser> extension_browser() const { return extension_browser_; } 283 set_create_main_browser_first(bool val)284 void set_create_main_browser_first(bool val) { 285 create_main_browser_first_ = val; 286 } set_expect_get_active_browser(bool val)287 void set_expect_get_active_browser(bool val) { 288 expect_get_active_browser_ = val; 289 } set_expect_success_in_main_browser(bool val)290 void set_expect_success_in_main_browser(bool val) { 291 expect_success_in_main_browser_ = val; 292 } set_expected_api_call_count(int val)293 void set_expected_api_call_count(int val) { expected_api_call_count_ = val; } 294 got_success_message() const295 bool got_success_message() const { return got_success_message_; } set_got_success_message()296 void set_got_success_message() { got_success_message_.yes(); } 297 298 private: CreateBrowserForExtensionIfReady()299 void CreateBrowserForExtensionIfReady() { 300 DCHECK(create_main_browser_first_); 301 if (extension_ && main_browser_) 302 CreateBrowserForExtension(); 303 } 304 CreateBrowserForExtension()305 void CreateBrowserForExtension() { 306 const std::string& identifier = extension_->GetIdentifier(); 307 EXPECT_FALSE(identifier.empty()); 308 const std::string& origin = 309 client::extension_util::GetExtensionOrigin(identifier); 310 EXPECT_FALSE(origin.empty()); 311 312 // Add extension resources. 313 OnAddExtensionResources(origin); 314 315 // Create a browser to host the extension. 316 CreateBrowser(extension_url_, request_context()); 317 } 318 TriggerTabsApiJSFunctionIfReady()319 void TriggerTabsApiJSFunctionIfReady() { 320 if (got_main_body_onload_ && got_extension_body_onload_) 321 TriggerTabsApiJSFunction(); 322 } 323 TriggerTabsApiJSFunction()324 void TriggerTabsApiJSFunction() { 325 EXPECT_FALSE(got_trigger_api_function_); 326 got_trigger_api_function_.yes(); 327 328 extension_browser_->GetMainFrame()->ExecuteJavaScript("triggerTabsApi();", 329 extension_url_, 0); 330 } 331 332 // If true the main browser will be created before the extension browser. 333 // Otherwise the creation order is undefined. 334 bool create_main_browser_first_; 335 336 // If true we expect GetActiveBrowser() but not CanAccessBrowser() to be 337 // called. Else visa-versa. 338 bool expect_get_active_browser_; 339 340 // If true we expect the success message to be delivered in the main browser. 341 // Else expect it in the extension browser. 342 bool expect_success_in_main_browser_; 343 344 // Number of expected calls to GetActiveBrowser or CanAccessBrowser. This 345 // should match the number of calls to chrome.tabs.* API functions in the 346 // test. 347 int expected_api_call_count_; 348 349 CefRefPtr<CefExtension> extension_; 350 std::string extension_url_; 351 CefRefPtr<CefBrowser> main_browser_; 352 CefRefPtr<CefBrowser> extension_browser_; 353 354 TrackCallback got_extension_loaded_; 355 TrackCallback got_main_url_request_; 356 TrackCallback got_extension_url_request_; 357 TrackCallback got_main_body_onload_; 358 TrackCallback got_extension_body_onload_; 359 TrackCallback got_trigger_api_function_; 360 TrackCallback got_success_message_; 361 TrackCallback got_extension_unloaded_; 362 363 int got_get_active_browser_count_; 364 int got_can_access_browser_count_; 365 }; 366 367 // 368 // chrome.tabs.create tests. 369 // 370 371 const char kCreateBrowserURL[] = 372 "https://test-extensions.com/chrome-tabs-create"; 373 const char kTabCallbackMessage[] = "tab-callback"; 374 const int kCreateTabIndex = 2; 375 376 // Class for chrome.tabs.create tests. 377 class CreateTestHandler : public TabsTestHandler { 378 public: CreateTestHandler(RequestContextType request_context_type)379 explicit CreateTestHandler(RequestContextType request_context_type) 380 : TabsTestHandler(request_context_type) {} 381 OnBeforeBrowser(CefRefPtr<CefExtension> extension,CefRefPtr<CefBrowser> browser,CefRefPtr<CefBrowser> active_browser,int index,const CefString & url,bool foreground,CefWindowInfo & windowInfo,CefRefPtr<CefClient> & client,CefBrowserSettings & settings)382 bool OnBeforeBrowser(CefRefPtr<CefExtension> extension, 383 CefRefPtr<CefBrowser> browser, 384 CefRefPtr<CefBrowser> active_browser, 385 int index, 386 const CefString& url, 387 bool foreground, 388 CefWindowInfo& windowInfo, 389 CefRefPtr<CefClient>& client, 390 CefBrowserSettings& settings) override { 391 EXPECT_TRUE(extension->IsSame(this->extension())); 392 EXPECT_TRUE(browser->IsSame(extension_browser())); 393 EXPECT_TRUE(active_browser->IsSame(main_browser())); 394 EXPECT_EQ(kCreateTabIndex, index); 395 EXPECT_STREQ(kCreateBrowserURL, url.ToString().c_str()); 396 EXPECT_TRUE(foreground); 397 EXPECT_TRUE(client); 398 399 EXPECT_FALSE(got_on_before_browser_); 400 got_on_before_browser_.yes(); 401 402 return false; 403 } 404 OnAddMainBrowserResources()405 void OnAddMainBrowserResources() override { 406 AddResource(kCreateBrowserURL, GetCreatedBrowserHTML(), "text/html"); 407 408 TabsTestHandler::OnAddMainBrowserResources(); 409 } 410 OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)411 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser, 412 bool isLoading, 413 bool canGoBack, 414 bool canGoForward) override { 415 if (extension_browser() && main_browser()) { 416 if (isLoading) { 417 // Keep a reference to the newly created browser. 418 EXPECT_FALSE(created_browser_); 419 created_browser_ = browser; 420 return; 421 } else { 422 const std::string& url = browser->GetMainFrame()->GetURL(); 423 if (url == kCreateBrowserURL) { 424 EXPECT_TRUE(browser->IsSame(created_browser_)); 425 return; 426 } 427 } 428 } 429 430 TabsTestHandler::OnLoadingStateChange(browser, isLoading, canGoBack, 431 canGoForward); 432 } 433 GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)434 CefRefPtr<CefResourceHandler> GetResourceHandler( 435 CefRefPtr<CefBrowser> browser, 436 CefRefPtr<CefFrame> frame, 437 CefRefPtr<CefRequest> request) override { 438 const std::string& url = request->GetURL(); 439 if (url == kCreateBrowserURL) { 440 EXPECT_TRUE(browser->IsSame(created_browser_)); 441 EXPECT_FALSE(got_create_browser_url_request_); 442 got_create_browser_url_request_.yes(); 443 } 444 445 return TabsTestHandler::GetResourceHandler(browser, frame, request); 446 } 447 448 protected: GetTabsApiJS() const449 std::string GetTabsApiJS() const override { 450 std::stringstream ss; 451 ss << kCreateTabIndex; 452 453 return "chrome.tabs.create({url: \"" + std::string(kCreateBrowserURL) + 454 "\", index: " + ss.str() + 455 "}, function(tab) { window.testQuery({request:'" + 456 kTabCallbackMessage + ":' + JSON.stringify(tab)}); });"; 457 } 458 OnMessage(CefRefPtr<CefBrowser> browser,const std::string & message)459 bool OnMessage(CefRefPtr<CefBrowser> browser, 460 const std::string& message) override { 461 if (message.find(kTabCallbackMessage) != std::string::npos) { 462 EXPECT_TRUE(browser->IsSame(extension_browser())); 463 EXPECT_FALSE(got_tab_callback_message_); 464 got_tab_callback_message_.yes(); 465 466 // Verify the contents of the Tab object. 467 const std::string& json_str = 468 message.substr(strlen(kTabCallbackMessage) + 1); 469 CefRefPtr<CefValue> obj = CefParseJSON(json_str, JSON_PARSER_RFC); 470 EXPECT_TRUE(obj); 471 EXPECT_EQ(VTYPE_DICTIONARY, obj->GetType()); 472 CefRefPtr<CefDictionaryValue> dict = obj->GetDictionary(); 473 474 int index = dict->GetInt("index"); 475 EXPECT_EQ(kCreateTabIndex, index); 476 477 int id = dict->GetInt("id"); 478 int windowId = dict->GetInt("windowId"); 479 EXPECT_EQ(created_browser_->GetIdentifier(), id); 480 EXPECT_EQ(created_browser_->GetIdentifier(), windowId); 481 482 const std::string& url = dict->GetString("url"); 483 EXPECT_STREQ(kCreateBrowserURL, url.c_str()); 484 485 TriggerDestroyTestIfReady(); 486 return true; 487 } else if (message == kSuccessMessage) { 488 // Overriding default kSuccessMessage handling. 489 EXPECT_TRUE(browser->IsSame(created_browser_)); 490 EXPECT_FALSE(got_success_message()); 491 set_got_success_message(); 492 TriggerDestroyTestIfReady(); 493 return true; 494 } 495 496 return TabsTestHandler::OnMessage(browser, message); 497 } 498 OnDestroyTest()499 void OnDestroyTest() override { 500 created_browser_ = nullptr; 501 502 EXPECT_TRUE(got_on_before_browser_); 503 EXPECT_TRUE(got_create_browser_url_request_); 504 EXPECT_TRUE(got_tab_callback_message_); 505 506 TabsTestHandler::OnDestroyTest(); 507 } 508 509 private: GetCreatedBrowserHTML()510 std::string GetCreatedBrowserHTML() { 511 return "<html><body onLoad=" + GetMessageJS(kSuccessMessage) + 512 ">Created</body></html>"; 513 } 514 TriggerDestroyTestIfReady()515 void TriggerDestroyTestIfReady() { 516 if (got_tab_callback_message_ && got_success_message()) 517 TriggerDestroyTest(); 518 } 519 520 CefRefPtr<CefBrowser> created_browser_; 521 522 TrackCallback got_on_before_browser_; 523 TrackCallback got_create_browser_url_request_; 524 TrackCallback got_tab_callback_message_; 525 526 IMPLEMENT_REFCOUNTING(CreateTestHandler); 527 DISALLOW_COPY_AND_ASSIGN(CreateTestHandler); 528 }; 529 530 } // namespace 531 532 TABS_TEST_GROUP_ALL(Create, CreateTestHandler) 533 534 namespace { 535 536 // 537 // chrome.tabs.executeScript tests. 538 // 539 540 // Base class for chrome.tabs.executeScript tests. 541 class ExecuteScriptTestHandler : public TabsTestHandler { 542 public: ExecuteScriptTestHandler(RequestContextType request_context_type)543 explicit ExecuteScriptTestHandler(RequestContextType request_context_type) 544 : TabsTestHandler(request_context_type) {} 545 546 protected: GetMainBrowserSuccessHEAD() const547 std::string GetMainBrowserSuccessHEAD() const override { 548 return "<script>function onTrigger() {" + GetMessageJS(kSuccessMessage) + 549 "}</script>"; 550 } 551 552 // Returns the code that will be injected as a content script. GetContentScriptJS() const553 virtual std::string GetContentScriptJS() const { 554 // Execute the onTrigger() JS function. 555 return "var s = document.createElement('script');" 556 "s.textContent = 'onTrigger();';" 557 "document.head.appendChild(s);"; 558 } 559 GetTabsApiJS() const560 std::string GetTabsApiJS() const override { 561 return "chrome.tabs.executeScript(" + GetTargetTabId() + ", {code:\"" + 562 GetContentScriptJS() + "\"});"; 563 } 564 }; 565 566 // Test for chrome.tabs.executeScript with a null tabId value. 567 class ExecuteScriptNullTabTestHandler : public ExecuteScriptTestHandler { 568 public: ExecuteScriptNullTabTestHandler(RequestContextType request_context_type)569 explicit ExecuteScriptNullTabTestHandler( 570 RequestContextType request_context_type) 571 : ExecuteScriptTestHandler(request_context_type) {} 572 573 private: 574 IMPLEMENT_REFCOUNTING(ExecuteScriptNullTabTestHandler); 575 DISALLOW_COPY_AND_ASSIGN(ExecuteScriptNullTabTestHandler); 576 }; 577 578 } // namespace 579 580 TABS_TEST_GROUP_ALL(ExecuteScriptNullTab, ExecuteScriptNullTabTestHandler) 581 582 namespace { 583 584 // Test for chrome.tabs.executeScript with an explicit tabId value. 585 class ExecuteScriptExplicitTabTestHandler : public ExecuteScriptTestHandler { 586 public: ExecuteScriptExplicitTabTestHandler(RequestContextType request_context_type)587 explicit ExecuteScriptExplicitTabTestHandler( 588 RequestContextType request_context_type) 589 : ExecuteScriptTestHandler(request_context_type) { 590 // Create the main browser first so we can retrieve the id. 591 set_create_main_browser_first(true); 592 // When a tabId is specified we should get a call to CanAccessBrowser 593 // instead of GetActiveBrowser. 594 set_expect_get_active_browser(false); 595 } 596 597 protected: GetTargetTabId() const598 std::string GetTargetTabId() const override { 599 DCHECK(main_browser()); 600 std::stringstream ss; 601 ss << main_browser()->GetIdentifier(); 602 return ss.str(); 603 } 604 605 private: 606 IMPLEMENT_REFCOUNTING(ExecuteScriptExplicitTabTestHandler); 607 DISALLOW_COPY_AND_ASSIGN(ExecuteScriptExplicitTabTestHandler); 608 }; 609 610 } // namespace 611 612 TABS_TEST_GROUP_ALL(ExecuteScriptExplicitTab, 613 ExecuteScriptExplicitTabTestHandler) 614 615 namespace { 616 617 // Test for chrome.tabs.executeScript with a file argument loading a content 618 // script. 619 class ExecuteScriptFileTestHandler : public ExecuteScriptTestHandler { 620 public: ExecuteScriptFileTestHandler(RequestContextType request_context_type)621 explicit ExecuteScriptFileTestHandler(RequestContextType request_context_type) 622 : ExecuteScriptTestHandler(request_context_type) {} 623 624 // CefExtensionHandler methods: GetExtensionResource(CefRefPtr<CefExtension> extension,CefRefPtr<CefBrowser> browser,const CefString & file,CefRefPtr<CefGetExtensionResourceCallback> callback)625 bool GetExtensionResource( 626 CefRefPtr<CefExtension> extension, 627 CefRefPtr<CefBrowser> browser, 628 const CefString& file, 629 CefRefPtr<CefGetExtensionResourceCallback> callback) override { 630 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 631 EXPECT_TRUE(this->extension()); 632 EXPECT_TRUE(this->extension()->IsSame(extension)); 633 634 if (file == "script.js") { 635 EXPECT_FALSE(got_get_extension_resource_); 636 got_get_extension_resource_.yes(); 637 638 const std::string& content = GetContentScriptJS(); 639 CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData( 640 const_cast<char*>(content.data()), content.size()); 641 callback->Continue(stream); 642 return true; 643 } 644 645 EXPECT_FALSE(true); // Not reached. 646 return false; 647 } 648 649 protected: GetTabsApiJS() const650 std::string GetTabsApiJS() const override { 651 return "chrome.tabs.executeScript(" + GetTargetTabId() + 652 ", {file:\"script.js\"});"; 653 } 654 OnDestroyTest()655 void OnDestroyTest() override { 656 ExecuteScriptTestHandler::OnDestroyTest(); 657 EXPECT_TRUE(got_get_extension_resource_); 658 } 659 660 private: 661 TrackCallback got_get_extension_resource_; 662 663 IMPLEMENT_REFCOUNTING(ExecuteScriptFileTestHandler); 664 DISALLOW_COPY_AND_ASSIGN(ExecuteScriptFileTestHandler); 665 }; 666 667 } // namespace 668 669 TABS_TEST_GROUP_ALL(ExecuteScriptFile, ExecuteScriptFileTestHandler) 670 671 namespace { 672 673 // Test for chrome.tabs.executeScript with a callback argument. 674 class ExecuteScriptCallbackTestHandler : public ExecuteScriptTestHandler { 675 public: ExecuteScriptCallbackTestHandler(RequestContextType request_context_type)676 explicit ExecuteScriptCallbackTestHandler( 677 RequestContextType request_context_type) 678 : ExecuteScriptTestHandler(request_context_type) {} 679 680 protected: OnMessage(CefRefPtr<CefBrowser> browser,const std::string & message)681 bool OnMessage(CefRefPtr<CefBrowser> browser, 682 const std::string& message) override { 683 if (message == "callback") { 684 EXPECT_FALSE(got_callback_message_); 685 got_callback_message_.yes(); 686 EXPECT_TRUE(browser->IsSame(extension_browser())); 687 TriggerDestroyTest(); 688 return true; 689 } 690 return ExecuteScriptTestHandler::OnMessage(browser, message); 691 } 692 GetTabsApiJS() const693 std::string GetTabsApiJS() const override { 694 return "chrome.tabs.executeScript(" + GetTargetTabId() + ", {code:\"" + 695 GetContentScriptJS() + "\"}, function(results) {" + 696 GetMessageJS("callback") + "});"; 697 } 698 TriggerDestroyTest()699 void TriggerDestroyTest() override { 700 // Only destroy the test if we got both callbacks. 701 if (got_callback_message_ && got_success_message()) { 702 ExecuteScriptTestHandler::TriggerDestroyTest(); 703 } 704 } 705 OnDestroyTest()706 void OnDestroyTest() override { 707 ExecuteScriptTestHandler::OnDestroyTest(); 708 EXPECT_TRUE(got_callback_message_); 709 } 710 711 private: 712 TrackCallback got_callback_message_; 713 714 IMPLEMENT_REFCOUNTING(ExecuteScriptCallbackTestHandler); 715 DISALLOW_COPY_AND_ASSIGN(ExecuteScriptCallbackTestHandler); 716 }; 717 718 } // namespace 719 720 TABS_TEST_GROUP_MINIMAL(ExecuteScriptCallback, ExecuteScriptCallbackTestHandler) 721 722 namespace { 723 724 // Test for chrome.tabs.executeScript with execution occuring from a separate 725 // resource script. 726 class ExecuteScriptResourceTabTestHandler : public ExecuteScriptTestHandler { 727 public: ExecuteScriptResourceTabTestHandler(RequestContextType request_context_type)728 explicit ExecuteScriptResourceTabTestHandler( 729 RequestContextType request_context_type) 730 : ExecuteScriptTestHandler(request_context_type) {} 731 732 // CefResourceRequestHandler methods: GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)733 CefRefPtr<CefResourceHandler> GetResourceHandler( 734 CefRefPtr<CefBrowser> browser, 735 CefRefPtr<CefFrame> frame, 736 CefRefPtr<CefRequest> request) override { 737 const std::string& url = request->GetURL(); 738 if (url == resource_url_) { 739 EXPECT_TRUE(browser->IsSame(extension_browser())); 740 EXPECT_FALSE(got_resource_url_request_); 741 got_resource_url_request_.yes(); 742 } 743 744 return ExecuteScriptTestHandler::GetResourceHandler(browser, frame, 745 request); 746 } 747 748 protected: OnAddExtensionResources(const std::string & origin)749 void OnAddExtensionResources(const std::string& origin) override { 750 ExecuteScriptTestHandler::OnAddExtensionResources(origin); 751 resource_url_ = origin + "resource.js"; 752 AddResource(resource_url_, GetExtensionJS(), "text/javascript"); 753 } 754 GetExtensionHTML() const755 std::string GetExtensionHTML() const override { 756 return "<html><head><script src=\"resource.js\"></script></head><body " 757 "onLoad=" + 758 GetMessageJS("extension_onload") + ">Extension</body></html>"; 759 } 760 OnDestroyTest()761 void OnDestroyTest() override { 762 ExecuteScriptTestHandler::OnDestroyTest(); 763 EXPECT_TRUE(got_resource_url_request_); 764 } 765 766 private: 767 std::string resource_url_; 768 TrackCallback got_resource_url_request_; 769 770 IMPLEMENT_REFCOUNTING(ExecuteScriptResourceTabTestHandler); 771 DISALLOW_COPY_AND_ASSIGN(ExecuteScriptResourceTabTestHandler); 772 }; 773 774 } // namespace 775 776 TABS_TEST_GROUP_MINIMAL(ExecuteScriptResource, 777 ExecuteScriptResourceTabTestHandler) 778 779 // 780 // chrome.tabs.insertCSS tests. 781 // 782 783 namespace { 784 785 // Base class for chrome.tabs.insertCSS tests. 786 class InsertCSSTestHandler : public TabsTestHandler { 787 public: InsertCSSTestHandler(RequestContextType request_context_type)788 explicit InsertCSSTestHandler(RequestContextType request_context_type) 789 : TabsTestHandler(request_context_type) {} 790 791 protected: GetMainBrowserSuccessBODY() const792 std::string GetMainBrowserSuccessBODY() const override { 793 // We can't use a MutationObserver here because insertCSS does not modify 794 // the style attribute. We could detect the change by tracking modifications 795 // to document.styleSheets but that's complicated. Use a simple timer loop 796 // implementation calling getComputedStyle instead. 797 return "<script>var interval = setInterval(function() {" 798 "if (window.getComputedStyle(document.body,null)." 799 "getPropertyValue('background-color') == 'rgb(255, 0, 0)') {" + 800 GetMessageJS(kSuccessMessage) + 801 "clearInterval(interval);}}, 100);</script>"; 802 } 803 804 // Returns the code that will be injected as a content script. GetContentScriptCSS() const805 virtual std::string GetContentScriptCSS() const { 806 return "body{background-color:red}"; 807 } 808 GetTabsApiJS() const809 std::string GetTabsApiJS() const override { 810 return "chrome.tabs.insertCSS(" + GetTargetTabId() + ", {code:\"" + 811 GetContentScriptCSS() + "\"});"; 812 } 813 }; 814 815 // Test for chrome.tabs.insertCSS with a null tabId value. 816 class InsertCSSNullTabTestHandler : public InsertCSSTestHandler { 817 public: InsertCSSNullTabTestHandler(RequestContextType request_context_type)818 explicit InsertCSSNullTabTestHandler(RequestContextType request_context_type) 819 : InsertCSSTestHandler(request_context_type) {} 820 821 private: 822 IMPLEMENT_REFCOUNTING(InsertCSSNullTabTestHandler); 823 DISALLOW_COPY_AND_ASSIGN(InsertCSSNullTabTestHandler); 824 }; 825 826 } // namespace 827 828 TABS_TEST_GROUP_ALL(InsertCSSNullTab, InsertCSSNullTabTestHandler) 829 830 namespace { 831 832 // Test for chrome.tabs.insertCSS with an explicit tabId value. 833 class InsertCSSExplicitTabTestHandler : public InsertCSSTestHandler { 834 public: InsertCSSExplicitTabTestHandler(RequestContextType request_context_type)835 explicit InsertCSSExplicitTabTestHandler( 836 RequestContextType request_context_type) 837 : InsertCSSTestHandler(request_context_type) { 838 // Create the main browser first so we can retrieve the id. 839 set_create_main_browser_first(true); 840 // When a tabId is specified we should get a call to CanAccessBrowser 841 // instead of GetActiveBrowser. 842 set_expect_get_active_browser(false); 843 } 844 845 protected: GetTargetTabId() const846 std::string GetTargetTabId() const override { 847 DCHECK(main_browser()); 848 std::stringstream ss; 849 ss << main_browser()->GetIdentifier(); 850 return ss.str(); 851 } 852 853 private: 854 IMPLEMENT_REFCOUNTING(InsertCSSExplicitTabTestHandler); 855 DISALLOW_COPY_AND_ASSIGN(InsertCSSExplicitTabTestHandler); 856 }; 857 858 } // namespace 859 860 TABS_TEST_GROUP_ALL(InsertCSSExplicitTab, InsertCSSExplicitTabTestHandler) 861 862 namespace { 863 864 // Test for chrome.tabs.insertCSS with a file argument loading a content 865 // script. 866 class InsertCSSFileTestHandler : public InsertCSSTestHandler { 867 public: InsertCSSFileTestHandler(RequestContextType request_context_type)868 explicit InsertCSSFileTestHandler(RequestContextType request_context_type) 869 : InsertCSSTestHandler(request_context_type) {} 870 871 // CefExtensionHandler methods: GetExtensionResource(CefRefPtr<CefExtension> extension,CefRefPtr<CefBrowser> browser,const CefString & file,CefRefPtr<CefGetExtensionResourceCallback> callback)872 bool GetExtensionResource( 873 CefRefPtr<CefExtension> extension, 874 CefRefPtr<CefBrowser> browser, 875 const CefString& file, 876 CefRefPtr<CefGetExtensionResourceCallback> callback) override { 877 EXPECT_TRUE(CefCurrentlyOn(TID_UI)); 878 EXPECT_TRUE(this->extension()); 879 EXPECT_TRUE(this->extension()->IsSame(extension)); 880 881 if (file == "script.css") { 882 EXPECT_FALSE(got_get_extension_resource_); 883 got_get_extension_resource_.yes(); 884 885 const std::string& content = GetContentScriptCSS(); 886 CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData( 887 const_cast<char*>(content.data()), content.size()); 888 callback->Continue(stream); 889 return true; 890 } 891 892 EXPECT_FALSE(true); // Not reached. 893 return false; 894 } 895 896 protected: GetTabsApiJS() const897 std::string GetTabsApiJS() const override { 898 return "chrome.tabs.insertCSS(" + GetTargetTabId() + 899 ", {file:\"script.css\"});"; 900 } 901 OnDestroyTest()902 void OnDestroyTest() override { 903 InsertCSSTestHandler::OnDestroyTest(); 904 EXPECT_TRUE(got_get_extension_resource_); 905 } 906 907 private: 908 TrackCallback got_get_extension_resource_; 909 910 IMPLEMENT_REFCOUNTING(InsertCSSFileTestHandler); 911 DISALLOW_COPY_AND_ASSIGN(InsertCSSFileTestHandler); 912 }; 913 914 } // namespace 915 916 TABS_TEST_GROUP_ALL(InsertCSSFile, InsertCSSFileTestHandler) 917 918 namespace { 919 920 // Test for chrome.tabs.insertCSS with a callback argument. 921 class InsertCSSCallbackTestHandler : public InsertCSSTestHandler { 922 public: InsertCSSCallbackTestHandler(RequestContextType request_context_type)923 explicit InsertCSSCallbackTestHandler(RequestContextType request_context_type) 924 : InsertCSSTestHandler(request_context_type) {} 925 926 protected: OnMessage(CefRefPtr<CefBrowser> browser,const std::string & message)927 bool OnMessage(CefRefPtr<CefBrowser> browser, 928 const std::string& message) override { 929 if (message == "callback") { 930 EXPECT_FALSE(got_callback_message_); 931 got_callback_message_.yes(); 932 EXPECT_TRUE(browser->IsSame(extension_browser())); 933 TriggerDestroyTest(); 934 return true; 935 } 936 return InsertCSSTestHandler::OnMessage(browser, message); 937 } 938 GetTabsApiJS() const939 std::string GetTabsApiJS() const override { 940 return "chrome.tabs.insertCSS(" + GetTargetTabId() + ", {code:\"" + 941 GetContentScriptCSS() + "\"}, function(results) {" + 942 GetMessageJS("callback") + "});"; 943 } 944 TriggerDestroyTest()945 void TriggerDestroyTest() override { 946 // Only destroy the test if we got both callbacks. 947 if (got_callback_message_ && got_success_message()) { 948 InsertCSSTestHandler::TriggerDestroyTest(); 949 } 950 } 951 OnDestroyTest()952 void OnDestroyTest() override { 953 InsertCSSTestHandler::OnDestroyTest(); 954 EXPECT_TRUE(got_callback_message_); 955 } 956 957 private: 958 TrackCallback got_callback_message_; 959 960 IMPLEMENT_REFCOUNTING(InsertCSSCallbackTestHandler); 961 DISALLOW_COPY_AND_ASSIGN(InsertCSSCallbackTestHandler); 962 }; 963 964 } // namespace 965 966 TABS_TEST_GROUP_MINIMAL(InsertCSSCallback, InsertCSSCallbackTestHandler) 967 968 namespace { 969 970 // Test for chrome.tabs.insertCSS with execution occuring from a separate 971 // resource script. 972 class InsertCSSResourceTabTestHandler : public InsertCSSTestHandler { 973 public: InsertCSSResourceTabTestHandler(RequestContextType request_context_type)974 explicit InsertCSSResourceTabTestHandler( 975 RequestContextType request_context_type) 976 : InsertCSSTestHandler(request_context_type) {} 977 978 // CefResourceRequestHandler methods: GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)979 CefRefPtr<CefResourceHandler> GetResourceHandler( 980 CefRefPtr<CefBrowser> browser, 981 CefRefPtr<CefFrame> frame, 982 CefRefPtr<CefRequest> request) override { 983 const std::string& url = request->GetURL(); 984 if (url == resource_url_) { 985 EXPECT_TRUE(browser->IsSame(extension_browser())); 986 EXPECT_FALSE(got_resource_url_request_); 987 got_resource_url_request_.yes(); 988 } 989 990 return InsertCSSTestHandler::GetResourceHandler(browser, frame, request); 991 } 992 993 protected: OnAddExtensionResources(const std::string & origin)994 void OnAddExtensionResources(const std::string& origin) override { 995 InsertCSSTestHandler::OnAddExtensionResources(origin); 996 resource_url_ = origin + "resource.js"; 997 AddResource(resource_url_, GetExtensionJS(), "text/javascript"); 998 } 999 GetExtensionHTML() const1000 std::string GetExtensionHTML() const override { 1001 return "<html><head><script src=\"resource.js\"></script></head><body " 1002 "onLoad=" + 1003 GetMessageJS("extension_onload") + ">Extension</body></html>"; 1004 } 1005 OnDestroyTest()1006 void OnDestroyTest() override { 1007 InsertCSSTestHandler::OnDestroyTest(); 1008 EXPECT_TRUE(got_resource_url_request_); 1009 } 1010 1011 private: 1012 std::string resource_url_; 1013 TrackCallback got_resource_url_request_; 1014 1015 IMPLEMENT_REFCOUNTING(InsertCSSResourceTabTestHandler); 1016 DISALLOW_COPY_AND_ASSIGN(InsertCSSResourceTabTestHandler); 1017 }; 1018 1019 } // namespace 1020 1021 TABS_TEST_GROUP_MINIMAL(InsertCSSResource, InsertCSSResourceTabTestHandler) 1022 1023 // 1024 // chrome.tabs.setZoom/getZoom tests. 1025 // 1026 1027 namespace { 1028 1029 // Base class for chrome.tabs.setZoom/getZoom tests. 1030 class ZoomTestHandler : public TabsTestHandler { 1031 public: ZoomTestHandler(RequestContextType request_context_type)1032 explicit ZoomTestHandler(RequestContextType request_context_type) 1033 : TabsTestHandler(request_context_type) { 1034 // We call API functions three times in this handler. 1035 set_expected_api_call_count(3); 1036 } 1037 1038 protected: GetMainBrowserSuccessHEAD() const1039 std::string GetMainBrowserSuccessHEAD() const override { 1040 return "<script>var orig_width = window.innerWidth;</script>"; 1041 } 1042 GetMainBrowserSuccessBODY() const1043 std::string GetMainBrowserSuccessBODY() const override { 1044 // We can't directly detect zoom changes, so instead we look for changes 1045 // in window.innerWidth. 1046 return "<script>var interval = setInterval(function() {" 1047 "if (window.innerWidth != orig_width) {" + 1048 GetMessageJS(kSuccessMessage) + 1049 "clearInterval(interval);}}, 100);</script>"; 1050 } 1051 GetTabsApiJS() const1052 std::string GetTabsApiJS() const override { 1053 // Results in a change to window.innerWidth. 1054 return "chrome.tabs.setZoom(" + GetTargetTabId() + ", 2.0);"; 1055 } 1056 OnMessage(CefRefPtr<CefBrowser> browser,const std::string & message)1057 bool OnMessage(CefRefPtr<CefBrowser> browser, 1058 const std::string& message) override { 1059 if (message == "restored") { 1060 EXPECT_TRUE(browser->IsSame(extension_browser())); 1061 EXPECT_FALSE(got_restored_message_); 1062 got_restored_message_.yes(); 1063 // Destroy the test for real. 1064 TabsTestHandler::TriggerDestroyTest(); 1065 return true; 1066 } 1067 return TabsTestHandler::OnMessage(browser, message); 1068 } 1069 TriggerDestroyTest()1070 void TriggerDestroyTest() override { 1071 // Before destroying the test we need to restore the zoom factor so that 1072 // it doesn't persist in the RequestContext. This also tests the callback 1073 // argument and the getZoom function so there's no need to do that 1074 // separately. 1075 extension_browser()->GetMainFrame()->ExecuteJavaScript( 1076 "chrome.tabs.setZoom(" + GetTargetTabId() + ", 1.0, function() {" + 1077 "chrome.tabs.getZoom(" + GetTargetTabId() + 1078 ", function(zoomFactor) { if (zoomFactor == 1.0) {" + 1079 GetMessageJS("restored") + "}})});", 1080 extension_url(), 0); 1081 } 1082 OnDestroyTest()1083 void OnDestroyTest() override { 1084 TabsTestHandler::OnDestroyTest(); 1085 EXPECT_TRUE(got_restored_message_); 1086 } 1087 1088 private: 1089 TrackCallback got_restored_message_; 1090 }; 1091 1092 // Test for chrome.tabs.setZoom/getZoom with a null tabId value. 1093 class ZoomNullTabTestHandler : public ZoomTestHandler { 1094 public: ZoomNullTabTestHandler(RequestContextType request_context_type)1095 explicit ZoomNullTabTestHandler(RequestContextType request_context_type) 1096 : ZoomTestHandler(request_context_type) {} 1097 1098 private: 1099 IMPLEMENT_REFCOUNTING(ZoomNullTabTestHandler); 1100 DISALLOW_COPY_AND_ASSIGN(ZoomNullTabTestHandler); 1101 }; 1102 1103 } // namespace 1104 1105 TABS_TEST_GROUP_ALL(ZoomNullTab, ZoomNullTabTestHandler) 1106 1107 namespace { 1108 1109 // Test for chrome.tabs.setZoom/getZoom with an explicit tabId value. 1110 class ZoomExplicitTabTestHandler : public ZoomTestHandler { 1111 public: ZoomExplicitTabTestHandler(RequestContextType request_context_type)1112 explicit ZoomExplicitTabTestHandler(RequestContextType request_context_type) 1113 : ZoomTestHandler(request_context_type) { 1114 // Create the main browser first so we can retrieve the id. 1115 set_create_main_browser_first(true); 1116 // When a tabId is specified we should get a call to CanAccessBrowser 1117 // instead of GetActiveBrowser. 1118 set_expect_get_active_browser(false); 1119 } 1120 1121 protected: GetTargetTabId() const1122 std::string GetTargetTabId() const override { 1123 DCHECK(main_browser()); 1124 std::stringstream ss; 1125 ss << main_browser()->GetIdentifier(); 1126 return ss.str(); 1127 } 1128 1129 private: 1130 IMPLEMENT_REFCOUNTING(ZoomExplicitTabTestHandler); 1131 DISALLOW_COPY_AND_ASSIGN(ZoomExplicitTabTestHandler); 1132 }; 1133 1134 } // namespace 1135 1136 TABS_TEST_GROUP_ALL(ZoomExplicitTab, ZoomExplicitTabTestHandler) 1137 1138 // 1139 // chrome.tabs.setZoomSettings/getZoomSettings tests. 1140 // 1141 1142 namespace { 1143 1144 // Base class for chrome.tabs.setZoomSettings/getZoomSettings tests. 1145 class ZoomSettingsTestHandler : public TabsTestHandler { 1146 public: ZoomSettingsTestHandler(RequestContextType request_context_type)1147 explicit ZoomSettingsTestHandler(RequestContextType request_context_type) 1148 : TabsTestHandler(request_context_type) { 1149 // We call API functions two times in this handler. 1150 set_expected_api_call_count(2); 1151 // Success message will be delivered in the extension browser because we 1152 // don't know how to detect zoom settings changes in the main browser. 1153 set_expect_success_in_main_browser(false); 1154 } 1155 1156 protected: GetTabsApiJS() const1157 std::string GetTabsApiJS() const override { 1158 // Set and restore the zoom settings. This also tests the callback argument 1159 // and the getZoomSettings function so there's no need to do that 1160 // separately. This is safe because zoom settings are not persisted in the 1161 // RequestContext across navigations. 1162 return "chrome.tabs.setZoomSettings(" + GetTargetTabId() + 1163 ", {mode: 'manual', scope: 'per-tab'}, function() {" + 1164 "chrome.tabs.getZoomSettings(" + GetTargetTabId() + 1165 ", function(zoomSettings) { if (zoomSettings.mode == 'manual' " 1166 "&& zoomSettings.scope == 'per-tab') {" + 1167 GetMessageJS(kSuccessMessage) + "}})});"; 1168 } 1169 }; 1170 1171 // Test for chrome.tabs.setZoomSettings/getZoomSettings with a null tabId value. 1172 class ZoomSettingsNullTabTestHandler : public ZoomSettingsTestHandler { 1173 public: ZoomSettingsNullTabTestHandler(RequestContextType request_context_type)1174 explicit ZoomSettingsNullTabTestHandler( 1175 RequestContextType request_context_type) 1176 : ZoomSettingsTestHandler(request_context_type) {} 1177 1178 private: 1179 IMPLEMENT_REFCOUNTING(ZoomSettingsNullTabTestHandler); 1180 DISALLOW_COPY_AND_ASSIGN(ZoomSettingsNullTabTestHandler); 1181 }; 1182 1183 } // namespace 1184 1185 TABS_TEST_GROUP_ALL(ZoomSettingsNullTab, ZoomSettingsNullTabTestHandler) 1186 1187 namespace { 1188 1189 // Test for chrome.tabs.setZoomSettings/getZoomSettings with an explicit tabId 1190 // value. 1191 class ZoomSettingsExplicitTabTestHandler : public ZoomSettingsTestHandler { 1192 public: ZoomSettingsExplicitTabTestHandler(RequestContextType request_context_type)1193 explicit ZoomSettingsExplicitTabTestHandler( 1194 RequestContextType request_context_type) 1195 : ZoomSettingsTestHandler(request_context_type) { 1196 // Create the main browser first so we can retrieve the id. 1197 set_create_main_browser_first(true); 1198 // When a tabId is specified we should get a call to CanAccessBrowser 1199 // instead of GetActiveBrowser. 1200 set_expect_get_active_browser(false); 1201 } 1202 1203 protected: GetTargetTabId() const1204 std::string GetTargetTabId() const override { 1205 DCHECK(main_browser()); 1206 std::stringstream ss; 1207 ss << main_browser()->GetIdentifier(); 1208 return ss.str(); 1209 } 1210 1211 private: 1212 IMPLEMENT_REFCOUNTING(ZoomSettingsExplicitTabTestHandler); 1213 DISALLOW_COPY_AND_ASSIGN(ZoomSettingsExplicitTabTestHandler); 1214 }; 1215 1216 } // namespace 1217 1218 TABS_TEST_GROUP_ALL(ZoomSettingsExplicitTab, ZoomSettingsExplicitTabTestHandler) 1219