Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / extensions / api / declarative_content / declarative_content_apitest.cc
blob74eebe0fa81281e1a0306990c92b8302d6addbe9
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.
5 #include "base/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
10 #include "chrome/browser/extensions/extension_action.h"
11 #include "chrome/browser/extensions/extension_action_manager.h"
12 #include "chrome/browser/extensions/extension_action_test_util.h"
13 #include "chrome/browser/extensions/extension_apitest.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/extension_tab_util.h"
16 #include "chrome/browser/extensions/test_extension_dir.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_window.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "components/bookmarks/browser/bookmark_model.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "extensions/browser/extension_registry.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/test/extension_test_message_listener.h"
25 #include "testing/gmock/include/gmock/gmock.h"
27 namespace extensions {
28 namespace {
30 const char kDeclarativeContentManifest[] =
31 "{\n"
32 " \"name\": \"Declarative Content apitest\",\n"
33 " \"version\": \"0.1\",\n"
34 " \"manifest_version\": 2,\n"
35 " \"description\": \n"
36 " \"end-to-end browser test for the declarative Content API\",\n"
37 " \"background\": {\n"
38 " \"scripts\": [\"background.js\"]\n"
39 " },\n"
40 " \"page_action\": {},\n"
41 " \"permissions\": [\n"
42 " \"declarativeContent\", \"bookmarks\"\n"
43 " ],\n"
44 " \"incognito\": \"spanning\"\n"
45 "}\n";
47 const char kIncognitoSpecificBackground[] =
48 "var PageStateMatcher = chrome.declarativeContent.PageStateMatcher;\n"
49 "var ShowPageAction = chrome.declarativeContent.ShowPageAction;\n"
50 "var inIncognitoContext = chrome.extension.inIncognitoContext;\n"
51 "\n"
52 "var hostPrefix = chrome.extension.inIncognitoContext ?\n"
53 " 'test_split' : 'test_normal';\n"
54 "var rule = {\n"
55 " conditions: [new PageStateMatcher({\n"
56 " pageUrl: {hostPrefix: hostPrefix}})],\n"
57 " actions: [new ShowPageAction()]\n"
58 "}\n"
59 "\n"
60 "var onPageChanged = chrome.declarativeContent.onPageChanged;\n"
61 "onPageChanged.removeRules(undefined, function() {\n"
62 " onPageChanged.addRules([rule], function() {\n"
63 " chrome.test.sendMessage(\n"
64 " !inIncognitoContext ? \"ready\" : \"ready (split)\");\n"
65 " });\n"
66 "});\n";
68 const char kBackgroundHelpers[] =
69 "var PageStateMatcher = chrome.declarativeContent.PageStateMatcher;\n"
70 "var ShowPageAction = chrome.declarativeContent.ShowPageAction;\n"
71 "var onPageChanged = chrome.declarativeContent.onPageChanged;\n"
72 "var reply = window.domAutomationController.send.bind(\n"
73 " window.domAutomationController);\n"
74 "\n"
75 "function setRules(rules, responseString) {\n"
76 " onPageChanged.removeRules(undefined, function() {\n"
77 " onPageChanged.addRules(rules, function() {\n"
78 " if (chrome.runtime.lastError) {\n"
79 " reply(chrome.runtime.lastError.message);\n"
80 " return;\n"
81 " }\n"
82 " reply(responseString);\n"
83 " });\n"
84 " });\n"
85 "};\n"
86 "\n"
87 "function addRules(rules, responseString) {\n"
88 " onPageChanged.addRules(rules, function() {\n"
89 " if (chrome.runtime.lastError) {\n"
90 " reply(chrome.runtime.lastError.message);\n"
91 " return;\n"
92 " }\n"
93 " reply(responseString);\n"
94 " });\n"
95 "};\n"
96 "\n"
97 "function removeRule(id, responseString) {\n"
98 " onPageChanged.removeRules([id], function() {\n"
99 " if (chrome.runtime.lastError) {\n"
100 " reply(chrome.runtime.lastError.message);\n"
101 " return;\n"
102 " }\n"
103 " reply(responseString);\n"
104 " });\n"
105 "};\n";
107 class DeclarativeContentApiTest : public ExtensionApiTest {
108 public:
109 DeclarativeContentApiTest() {}
111 protected:
112 enum IncognitoMode { SPANNING, SPLIT };
114 // Checks that the rules are correctly evaluated for an extension in incognito
115 // mode |mode| when the extension's incognito enable state is
116 // |is_enabled_in_incognito|.
117 void CheckIncognito(IncognitoMode mode, bool is_enabled_in_incognito);
119 // Checks that the rules matching a bookmarked state of |is_bookmarked| are
120 // correctly evaluated on bookmark events.
121 void CheckBookmarkEvents(bool is_bookmarked);
123 TestExtensionDir ext_dir_;
125 private:
126 DISALLOW_COPY_AND_ASSIGN(DeclarativeContentApiTest);
129 void DeclarativeContentApiTest::CheckIncognito(IncognitoMode mode,
130 bool is_enabled_in_incognito) {
131 std::string manifest = kDeclarativeContentManifest;
132 if (mode == SPLIT) {
133 base::ReplaceSubstringsAfterOffset(
134 &manifest, 0, "\"incognito\": \"spanning\"",
135 "\"incognito\": \"split\"");
136 ASSERT_NE(kDeclarativeContentManifest, manifest);
138 ext_dir_.WriteManifest(manifest);
139 ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"),
140 kIncognitoSpecificBackground);
142 ExtensionTestMessageListener ready("ready", false);
143 ExtensionTestMessageListener ready_incognito("ready (split)", false);
145 const Extension* extension = is_enabled_in_incognito ?
146 LoadExtensionIncognito(ext_dir_.unpacked_path()) :
147 LoadExtension(ext_dir_.unpacked_path());
148 ASSERT_TRUE(extension);
150 Browser* incognito_browser = CreateIncognitoBrowser();
151 const ExtensionAction* incognito_page_action =
152 ExtensionActionManager::Get(incognito_browser->profile())->
153 GetPageAction(*extension);
154 ASSERT_TRUE(incognito_page_action);
156 ASSERT_TRUE(ready.WaitUntilSatisfied());
157 if (is_enabled_in_incognito && mode == SPLIT)
158 ASSERT_TRUE(ready_incognito.WaitUntilSatisfied());
160 content::WebContents* const incognito_tab =
161 incognito_browser->tab_strip_model()->GetWebContentsAt(0);
162 const int incognito_tab_id = ExtensionTabUtil::GetTabId(incognito_tab);
164 EXPECT_FALSE(incognito_page_action->GetIsVisible(incognito_tab_id));
166 NavigateInRenderer(incognito_tab, GURL("http://test_split/"));
167 if (mode == SPLIT) {
168 EXPECT_EQ(is_enabled_in_incognito,
169 incognito_page_action->GetIsVisible(incognito_tab_id));
170 } else {
171 EXPECT_FALSE(incognito_page_action->GetIsVisible(incognito_tab_id));
174 NavigateInRenderer(incognito_tab, GURL("http://test_normal/"));
175 if (mode != SPLIT) {
176 EXPECT_EQ(is_enabled_in_incognito,
177 incognito_page_action->GetIsVisible(incognito_tab_id));
178 } else {
179 EXPECT_FALSE(incognito_page_action->GetIsVisible(incognito_tab_id));
182 // Verify that everything works as expected in the non-incognito browser.
183 const ExtensionAction* page_action =
184 ExtensionActionManager::Get(browser()->profile())->
185 GetPageAction(*extension);
186 content::WebContents* const tab =
187 browser()->tab_strip_model()->GetWebContentsAt(0);
188 const int tab_id = ExtensionTabUtil::GetTabId(tab);
190 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
192 NavigateInRenderer(tab, GURL("http://test_normal/"));
193 EXPECT_TRUE(page_action->GetIsVisible(tab_id));
195 NavigateInRenderer(tab, GURL("http://test_split/"));
196 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
199 void DeclarativeContentApiTest::CheckBookmarkEvents(bool match_is_bookmarked) {
200 ext_dir_.WriteManifest(kDeclarativeContentManifest);
201 ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
203 content::WebContents* const tab =
204 browser()->tab_strip_model()->GetWebContentsAt(0);
205 const int tab_id = ExtensionTabUtil::GetTabId(tab);
207 const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
208 ASSERT_TRUE(extension);
209 const ExtensionAction* page_action = ExtensionActionManager::Get(
210 browser()->profile())->GetPageAction(*extension);
211 ASSERT_TRUE(page_action);
213 NavigateInRenderer(tab, GURL("http://test1/"));
214 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
216 static const char kSetIsBookmarkedRule[] =
217 "setRules([{\n"
218 " conditions: [new PageStateMatcher({isBookmarked: %s})],\n"
219 " actions: [new ShowPageAction()]\n"
220 "}], 'test_rule');\n";
222 EXPECT_EQ("test_rule", ExecuteScriptInBackgroundPage(
223 extension->id(),
224 base::StringPrintf(kSetIsBookmarkedRule,
225 match_is_bookmarked ? "true" : "false")));
226 EXPECT_EQ(!match_is_bookmarked, page_action->GetIsVisible(tab_id));
228 // Check rule evaluation on add/remove bookmark.
229 bookmarks::BookmarkModel* bookmark_model =
230 BookmarkModelFactory::GetForProfile(browser()->profile());
231 const bookmarks::BookmarkNode* node =
232 bookmark_model->AddURL(bookmark_model->other_node(), 0,
233 base::ASCIIToUTF16("title"),
234 GURL("http://test1/"));
235 EXPECT_EQ(match_is_bookmarked, page_action->GetIsVisible(tab_id));
237 bookmark_model->Remove(node);
238 EXPECT_EQ(!match_is_bookmarked, page_action->GetIsVisible(tab_id));
240 // Check rule evaluation on navigate to bookmarked and non-bookmarked URL.
241 bookmark_model->AddURL(bookmark_model->other_node(), 0,
242 base::ASCIIToUTF16("title"),
243 GURL("http://test2/"));
245 NavigateInRenderer(tab, GURL("http://test2/"));
246 EXPECT_EQ(match_is_bookmarked, page_action->GetIsVisible(tab_id));
248 NavigateInRenderer(tab, GURL("http://test3/"));
249 EXPECT_EQ(!match_is_bookmarked, page_action->GetIsVisible(tab_id));
252 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest, Overview) {
253 ext_dir_.WriteManifest(kDeclarativeContentManifest);
254 ext_dir_.WriteFile(
255 FILE_PATH_LITERAL("background.js"),
256 "var declarative = chrome.declarative;\n"
257 "\n"
258 "var PageStateMatcher = chrome.declarativeContent.PageStateMatcher;\n"
259 "var ShowPageAction = chrome.declarativeContent.ShowPageAction;\n"
260 "\n"
261 "var rule = {\n"
262 " conditions: [new PageStateMatcher({\n"
263 " pageUrl: {hostPrefix: \"test1\"}}),\n"
264 " new PageStateMatcher({\n"
265 " css: [\"input[type='password']\"]})],\n"
266 " actions: [new ShowPageAction()]\n"
267 "}\n"
268 "\n"
269 "var testEvent = chrome.declarativeContent.onPageChanged;\n"
270 "\n"
271 "testEvent.removeRules(undefined, function() {\n"
272 " testEvent.addRules([rule], function() {\n"
273 " chrome.test.sendMessage(\"ready\")\n"
274 " });\n"
275 "});\n");
276 ExtensionTestMessageListener ready("ready", false);
277 const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
278 ASSERT_TRUE(extension);
279 const ExtensionAction* page_action =
280 ExtensionActionManager::Get(browser()->profile())->
281 GetPageAction(*extension);
282 ASSERT_TRUE(page_action);
284 ASSERT_TRUE(ready.WaitUntilSatisfied());
285 content::WebContents* const tab =
286 browser()->tab_strip_model()->GetWebContentsAt(0);
287 const int tab_id = ExtensionTabUtil::GetTabId(tab);
289 NavigateInRenderer(tab, GURL("http://test1/"));
291 // The declarative API should show the page action instantly, rather
292 // than waiting for the extension to run.
293 EXPECT_TRUE(page_action->GetIsVisible(tab_id));
295 // Make sure leaving a matching page unshows the page action.
296 NavigateInRenderer(tab, GURL("http://not_checked/"));
297 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
299 // Insert a password field to make sure that's noticed.
300 // Notice that we touch offsetTop to force a synchronous layout.
301 ASSERT_TRUE(content::ExecuteScript(
302 tab, "document.body.innerHTML = '<input type=\"password\">';"
303 "document.body.offsetTop;"));
305 // Give the style match a chance to run and send back the matching-selector
306 // update.
307 ASSERT_TRUE(content::ExecuteScript(tab, std::string()));
309 EXPECT_TRUE(page_action->GetIsVisible(tab_id))
310 << "Adding a matching element should show the page action.";
312 // Remove it again to make sure that reverts the action.
313 // Notice that we touch offsetTop to force a synchronous layout.
314 ASSERT_TRUE(content::ExecuteScript(
315 tab, "document.body.innerHTML = 'Hello world';"
316 "document.body.offsetTop;"));
318 // Give the style match a chance to run and send back the matching-selector
319 // update.
320 ASSERT_TRUE(content::ExecuteScript(tab, std::string()));
322 EXPECT_FALSE(page_action->GetIsVisible(tab_id))
323 << "Removing the matching element should hide the page action again.";
326 // Tests that the rules are evaluated at the time they are added or removed.
327 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest, RulesEvaluatedOnAddRemove) {
328 ext_dir_.WriteManifest(kDeclarativeContentManifest);
329 ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
330 const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
331 ASSERT_TRUE(extension);
332 const ExtensionAction* page_action =
333 ExtensionActionManager::Get(browser()->profile())->
334 GetPageAction(*extension);
335 ASSERT_TRUE(page_action);
337 content::WebContents* const tab =
338 browser()->tab_strip_model()->GetWebContentsAt(0);
339 const int tab_id = ExtensionTabUtil::GetTabId(tab);
341 NavigateInRenderer(tab, GURL("http://test1/"));
343 const std::string kAddTestRules =
344 "addRules([{\n"
345 " id: '1',\n"
346 " conditions: [new PageStateMatcher({\n"
347 " pageUrl: {hostPrefix: \"test1\"}})],\n"
348 " actions: [new ShowPageAction()]\n"
349 "}, {\n"
350 " id: '2',\n"
351 " conditions: [new PageStateMatcher({\n"
352 " pageUrl: {hostPrefix: \"test2\"}})],\n"
353 " actions: [new ShowPageAction()]\n"
354 "}], 'add_rules');\n";
355 EXPECT_EQ("add_rules",
356 ExecuteScriptInBackgroundPage(extension->id(), kAddTestRules));
358 EXPECT_TRUE(page_action->GetIsVisible(tab_id));
360 const std::string kRemoveTestRule1 = "removeRule('1', 'remove_rule1');\n";
361 EXPECT_EQ("remove_rule1",
362 ExecuteScriptInBackgroundPage(extension->id(), kRemoveTestRule1));
364 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
366 NavigateInRenderer(tab, GURL("http://test2/"));
368 EXPECT_TRUE(page_action->GetIsVisible(tab_id));
370 const std::string kRemoveTestRule2 = "removeRule('2', 'remove_rule2');\n";
371 EXPECT_EQ("remove_rule2",
372 ExecuteScriptInBackgroundPage(extension->id(), kRemoveTestRule2));
374 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
377 // Tests that rules from manifest are added and evaluated properly.
378 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest, RulesAddedFromManifest) {
379 const char manifest[] =
380 "{\n"
381 " \"name\": \"Declarative Content apitest\",\n"
382 " \"version\": \"0.1\",\n"
383 " \"manifest_version\": 2,\n"
384 " \"page_action\": {},\n"
385 " \"permissions\": [\n"
386 " \"declarativeContent\"\n"
387 " ],\n"
388 " \"event_rules\": [{\n"
389 " \"event\": \"declarativeContent.onPageChanged\",\n"
390 " \"actions\": [{\n"
391 " \"type\": \"declarativeContent.ShowPageAction\"\n"
392 " }],\n"
393 " \"conditions\": [{\n"
394 " \"type\": \"declarativeContent.PageStateMatcher\",\n"
395 " \"pageUrl\": {\"hostPrefix\": \"test1\"}\n"
396 " }]\n"
397 " }]\n"
398 "}\n";
399 ext_dir_.WriteManifest(manifest);
400 const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
401 ASSERT_TRUE(extension);
402 const ExtensionAction* page_action =
403 ExtensionActionManager::Get(browser()->profile())
404 ->GetPageAction(*extension);
405 ASSERT_TRUE(page_action);
407 content::WebContents* const tab =
408 browser()->tab_strip_model()->GetWebContentsAt(0);
409 const int tab_id = ExtensionTabUtil::GetTabId(tab);
411 NavigateInRenderer(tab, GURL("http://blank/"));
412 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
413 NavigateInRenderer(tab, GURL("http://test1/"));
414 EXPECT_TRUE(page_action->GetIsVisible(tab_id));
415 NavigateInRenderer(tab, GURL("http://test2/"));
416 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
419 // Tests that rules are not evaluated in incognito browser windows when the
420 // extension specifies spanning incognito mode but is not enabled for incognito.
421 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
422 DisabledForSpanningIncognito) {
423 CheckIncognito(SPANNING, false);
426 // Tests that rules are evaluated in incognito browser windows when the
427 // extension specifies spanning incognito mode and is enabled for incognito.
428 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest, EnabledForSpanningIncognito) {
429 CheckIncognito(SPANNING, true);
432 // Tests that rules are not evaluated in incognito browser windows when the
433 // extension specifies split incognito mode but is not enabled for incognito.
434 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest, DisabledForSplitIncognito) {
435 CheckIncognito(SPLIT, false);
438 // Tests that rules are evaluated in incognito browser windows when the
439 // extension specifies split incognito mode and is enabled for incognito.
440 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest, EnabledForSplitIncognito) {
441 CheckIncognito(SPLIT, true);
444 // Tests that rules are evaluated for an incognito tab that exists at the time
445 // the rules are added.
446 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
447 RulesEvaluatedForExistingIncognitoTab) {
448 Browser* incognito_browser = CreateIncognitoBrowser();
449 content::WebContents* const incognito_tab =
450 incognito_browser->tab_strip_model()->GetWebContentsAt(0);
451 const int incognito_tab_id = ExtensionTabUtil::GetTabId(incognito_tab);
453 NavigateInRenderer(incognito_tab, GURL("http://test_normal/"));
455 ext_dir_.WriteManifest(kDeclarativeContentManifest);
456 ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"),
457 kIncognitoSpecificBackground);
458 ExtensionTestMessageListener ready("ready", false);
459 const Extension* extension = LoadExtensionIncognito(ext_dir_.unpacked_path());
460 ASSERT_TRUE(extension);
461 ASSERT_TRUE(ready.WaitUntilSatisfied());
463 const ExtensionAction* incognito_page_action =
464 ExtensionActionManager::Get(incognito_browser->profile())->
465 GetPageAction(*extension);
466 ASSERT_TRUE(incognito_page_action);
468 // The page action should be shown.
469 EXPECT_TRUE(incognito_page_action->GetIsVisible(incognito_tab_id));
472 // Sets up rules matching http://test1/ in a normal and incognito browser.
473 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest, PRE_RulesPersistence) {
474 ExtensionTestMessageListener ready("ready", false);
475 ExtensionTestMessageListener ready_split("ready (split)", false);
476 // An on-disk extension is required so that it can be reloaded later in the
477 // RulesPersistence test.
478 const Extension* extension =
479 LoadExtensionIncognito(test_data_dir_.AppendASCII("declarative_content")
480 .AppendASCII("persistence"));
481 ASSERT_TRUE(extension);
482 ASSERT_TRUE(ready.WaitUntilSatisfied());
484 CreateIncognitoBrowser();
485 ASSERT_TRUE(ready_split.WaitUntilSatisfied());
488 // Reloads the extension from PRE_RulesPersistence and checks that the rules
489 // continue to work as expected after being persisted and reloaded.
490 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest, RulesPersistence) {
491 ExtensionTestMessageListener ready("second run ready", false);
492 ExtensionTestMessageListener ready_split("second run ready (split)", false);
493 ASSERT_TRUE(ready.WaitUntilSatisfied());
495 ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
496 const Extension* extension =
497 GetExtensionByPath(registry->enabled_extensions(),
498 test_data_dir_.AppendASCII("declarative_content")
499 .AppendASCII("persistence"));
501 // Check non-incognito browser.
502 content::WebContents* const tab =
503 browser()->tab_strip_model()->GetWebContentsAt(0);
504 const int tab_id = ExtensionTabUtil::GetTabId(tab);
506 const ExtensionAction* page_action =
507 ExtensionActionManager::Get(browser()->profile())->
508 GetPageAction(*extension);
509 ASSERT_TRUE(page_action);
510 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
512 NavigateInRenderer(tab, GURL("http://test_normal/"));
513 EXPECT_TRUE(page_action->GetIsVisible(tab_id));
515 NavigateInRenderer(tab, GURL("http://test_split/"));
516 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
518 // Check incognito browser.
519 Browser* incognito_browser = CreateIncognitoBrowser();
520 ASSERT_TRUE(ready_split.WaitUntilSatisfied());
521 content::WebContents* const incognito_tab =
522 incognito_browser->tab_strip_model()->GetWebContentsAt(0);
523 const int incognito_tab_id = ExtensionTabUtil::GetTabId(incognito_tab);
525 const ExtensionAction* incognito_page_action =
526 ExtensionActionManager::Get(incognito_browser->profile())->
527 GetPageAction(*extension);
528 ASSERT_TRUE(incognito_page_action);
530 NavigateInRenderer(incognito_tab, GURL("http://test_split/"));
531 EXPECT_TRUE(incognito_page_action->GetIsVisible(incognito_tab_id));
533 NavigateInRenderer(incognito_tab, GURL("http://test_normal/"));
534 EXPECT_FALSE(incognito_page_action->GetIsVisible(incognito_tab_id));
537 // http://crbug.com/304373
538 #if defined(OS_WIN)
539 // Fails on XP: http://crbug.com/515717
540 #define MAYBE_UninstallWhileActivePageAction \
541 DISABLED_UninstallWhileActivePageAction
542 #else
543 #define MAYBE_UninstallWhileActivePageAction UninstallWhileActivePageAction
544 #endif
545 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
546 MAYBE_UninstallWhileActivePageAction) {
547 ext_dir_.WriteManifest(kDeclarativeContentManifest);
548 ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
549 const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
550 ASSERT_TRUE(extension);
551 const std::string extension_id = extension->id();
552 const ExtensionAction* page_action = ExtensionActionManager::Get(
553 browser()->profile())->GetPageAction(*extension);
554 ASSERT_TRUE(page_action);
556 const std::string kTestRule =
557 "setRules([{\n"
558 " conditions: [new PageStateMatcher({\n"
559 " pageUrl: {hostPrefix: \"test\"}})],\n"
560 " actions: [new ShowPageAction()]\n"
561 "}], 'test_rule');\n";
562 EXPECT_EQ("test_rule",
563 ExecuteScriptInBackgroundPage(extension_id, kTestRule));
565 content::WebContents* const tab =
566 browser()->tab_strip_model()->GetWebContentsAt(0);
567 const int tab_id = ExtensionTabUtil::GetTabId(tab);
569 NavigateInRenderer(tab, GURL("http://test/"));
571 EXPECT_TRUE(page_action->GetIsVisible(tab_id));
572 EXPECT_TRUE(WaitForPageActionVisibilityChangeTo(1));
573 EXPECT_EQ(1u, extension_action_test_util::GetVisiblePageActionCount(tab));
574 EXPECT_EQ(1u, extension_action_test_util::GetTotalPageActionCount(tab));
576 ReloadExtension(extension_id); // Invalidates page_action and extension.
577 EXPECT_EQ("test_rule",
578 ExecuteScriptInBackgroundPage(extension_id, kTestRule));
579 // TODO(jyasskin): Apply new rules to existing tabs, without waiting for a
580 // navigation.
581 NavigateInRenderer(tab, GURL("http://test/"));
582 EXPECT_TRUE(WaitForPageActionVisibilityChangeTo(1));
583 EXPECT_EQ(1u, extension_action_test_util::GetVisiblePageActionCount(tab));
584 EXPECT_EQ(1u, extension_action_test_util::GetTotalPageActionCount(tab));
586 UnloadExtension(extension_id);
587 NavigateInRenderer(tab, GURL("http://test/"));
588 EXPECT_TRUE(WaitForPageActionVisibilityChangeTo(0));
589 EXPECT_EQ(0u, extension_action_test_util::GetVisiblePageActionCount(tab));
590 EXPECT_EQ(0u, extension_action_test_util::GetTotalPageActionCount(tab));
593 // This tests against a renderer crash that was present during development.
594 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
595 DISABLED_AddExtensionMatchingExistingTabWithDeadFrames) {
596 ext_dir_.WriteManifest(kDeclarativeContentManifest);
597 ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
598 content::WebContents* const tab =
599 browser()->tab_strip_model()->GetWebContentsAt(0);
600 const int tab_id = ExtensionTabUtil::GetTabId(tab);
602 ASSERT_TRUE(content::ExecuteScript(
603 tab, "document.body.innerHTML = '<iframe src=\"http://test2\">';"));
604 // Replace the iframe to destroy its WebFrame.
605 ASSERT_TRUE(content::ExecuteScript(
606 tab, "document.body.innerHTML = '<span class=\"foo\">';"));
608 const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
609 ASSERT_TRUE(extension);
610 const ExtensionAction* page_action = ExtensionActionManager::Get(
611 browser()->profile())->GetPageAction(*extension);
612 ASSERT_TRUE(page_action);
613 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
615 EXPECT_EQ("rule0",
616 ExecuteScriptInBackgroundPage(
617 extension->id(),
618 "setRules([{\n"
619 " conditions: [new PageStateMatcher({\n"
620 " css: [\"span[class=foo]\"]})],\n"
621 " actions: [new ShowPageAction()]\n"
622 "}], 'rule0');\n"));
623 // Give the renderer a chance to apply the rules change and notify the
624 // browser. This takes one time through the Blink message loop to receive
625 // the rule change and apply the new stylesheet, and a second to dedupe the
626 // update.
627 ASSERT_TRUE(content::ExecuteScript(tab, std::string()));
628 ASSERT_TRUE(content::ExecuteScript(tab, std::string()));
630 EXPECT_FALSE(tab->IsCrashed());
631 EXPECT_TRUE(page_action->GetIsVisible(tab_id))
632 << "Loading an extension when an open page matches its rules "
633 << "should show the page action.";
635 EXPECT_EQ("removed",
636 ExecuteScriptInBackgroundPage(
637 extension->id(),
638 "onPageChanged.removeRules(undefined, function() {\n"
639 " window.domAutomationController.send('removed');\n"
640 "});\n"));
641 EXPECT_FALSE(page_action->GetIsVisible(tab_id));
644 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
645 ShowPageActionWithoutPageAction) {
646 std::string manifest_without_page_action = kDeclarativeContentManifest;
647 base::ReplaceSubstringsAfterOffset(
648 &manifest_without_page_action, 0, "\"page_action\": {},", "");
649 ASSERT_NE(kDeclarativeContentManifest, manifest_without_page_action);
650 ext_dir_.WriteManifest(manifest_without_page_action);
651 ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
652 const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
653 ASSERT_TRUE(extension);
655 EXPECT_THAT(ExecuteScriptInBackgroundPage(
656 extension->id(),
657 "setRules([{\n"
658 " conditions: [new PageStateMatcher({\n"
659 " pageUrl: {hostPrefix: \"test\"}})],\n"
660 " actions: [new ShowPageAction()]\n"
661 "}], 'test_rule');\n"),
662 testing::HasSubstr("without a page action"));
664 content::WebContents* const tab =
665 browser()->tab_strip_model()->GetWebContentsAt(0);
666 NavigateInRenderer(tab, GURL("http://test/"));
668 EXPECT_EQ(NULL,
669 ExtensionActionManager::Get(browser()->profile())->
670 GetPageAction(*extension));
671 EXPECT_EQ(0u, extension_action_test_util::GetVisiblePageActionCount(tab));
674 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
675 CanonicalizesPageStateMatcherCss) {
676 ext_dir_.WriteManifest(kDeclarativeContentManifest);
677 ext_dir_.WriteFile(
678 FILE_PATH_LITERAL("background.js"),
679 "var PageStateMatcher = chrome.declarativeContent.PageStateMatcher;\n"
680 "function Return(obj) {\n"
681 " window.domAutomationController.send('' + obj);\n"
682 "}\n");
683 const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
684 ASSERT_TRUE(extension);
686 EXPECT_EQ("input[type=\"password\"]",
687 ExecuteScriptInBackgroundPage(
688 extension->id(),
689 "var psm = new PageStateMatcher(\n"
690 " {css: [\"input[type='password']\"]});\n"
691 "Return(psm.css);"));
693 EXPECT_THAT(ExecuteScriptInBackgroundPage(
694 extension->id(),
695 "try {\n"
696 " new PageStateMatcher({css: 'Not-an-array'});\n"
697 " Return('Failed to throw');\n"
698 "} catch (e) {\n"
699 " Return(e.message);\n"
700 "}\n"),
701 testing::ContainsRegex("css.*Expected 'array'"));
702 EXPECT_THAT(ExecuteScriptInBackgroundPage(
703 extension->id(),
704 "try {\n"
705 " new PageStateMatcher({css: [null]});\n" // Not a string.
706 " Return('Failed to throw');\n"
707 "} catch (e) {\n"
708 " Return(e.message);\n"
709 "}\n"),
710 testing::ContainsRegex("css\\.0.*Expected 'string'"));
711 EXPECT_THAT(ExecuteScriptInBackgroundPage(
712 extension->id(),
713 "try {\n"
714 // Invalid CSS:
715 " new PageStateMatcher({css: [\"input''\"]});\n"
716 " Return('Failed to throw');\n"
717 "} catch (e) {\n"
718 " Return(e.message);\n"
719 "}\n"),
720 testing::ContainsRegex("valid.*: input''$"));
721 EXPECT_THAT(ExecuteScriptInBackgroundPage(
722 extension->id(),
723 "try {\n"
724 // "Complex" selector:
725 " new PageStateMatcher({css: ['div input']});\n"
726 " Return('Failed to throw');\n"
727 "} catch (e) {\n"
728 " Return(e.message);\n"
729 "}\n"),
730 testing::ContainsRegex("compound selector.*: div input$"));
733 // Tests that the rules with isBookmarked: true are evaluated when handling
734 // bookmarking events.
735 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
736 IsBookmarkedRulesEvaluatedOnBookmarkEvents) {
737 CheckBookmarkEvents(true);
740 // Tests that the rules with isBookmarked: false are evaluated when handling
741 // bookmarking events.
742 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
743 NotBookmarkedRulesEvaluatedOnBookmarkEvents) {
744 CheckBookmarkEvents(false);
747 // https://crbug.com/497586
748 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
749 WebContentsWithoutTabAddedNotificationAtOnLoaded) {
750 // Add a web contents to the tab strip in a way that doesn't trigger
751 // NOTIFICATION_TAB_ADDED.
752 content::WebContents* contents = content::WebContents::Create(
753 content::WebContents::CreateParams(profile()));
754 browser()->tab_strip_model()->AppendWebContents(contents, false);
756 // The actual extension contents don't matter here -- we're just looking to
757 // trigger OnExtensionLoaded.
758 ext_dir_.WriteManifest(kDeclarativeContentManifest);
759 ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
760 ASSERT_TRUE(LoadExtension(ext_dir_.unpacked_path()));
763 // https://crbug.com/501225
764 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
765 PendingWebContentsClearedOnRemoveRules) {
766 ext_dir_.WriteManifest(kDeclarativeContentManifest);
767 ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
768 const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
769 ASSERT_TRUE(extension);
770 const ExtensionAction* page_action = ExtensionActionManager::Get(
771 browser()->profile())->GetPageAction(*extension);
772 ASSERT_TRUE(page_action);
774 // Create two tabs.
775 content::WebContents* const tab1 =
776 browser()->tab_strip_model()->GetWebContentsAt(0);
778 AddTabAtIndex(1, GURL("http://test2/"), ui::PAGE_TRANSITION_LINK);
779 scoped_ptr<content::WebContents> tab2(
780 browser()->tab_strip_model()->GetWebContentsAt(1));
782 // Add a rule matching the second tab.
783 const std::string kAddTestRules =
784 "addRules([{\n"
785 " id: '1',\n"
786 " conditions: [new PageStateMatcher({\n"
787 " pageUrl: {hostPrefix: \"test1\"}})],\n"
788 " actions: [new ShowPageAction()]\n"
789 "}, {\n"
790 " id: '2',\n"
791 " conditions: [new PageStateMatcher({\n"
792 " pageUrl: {hostPrefix: \"test2\"}})],\n"
793 " actions: [new ShowPageAction()]\n"
794 "}], 'add_rules');\n";
795 EXPECT_EQ("add_rules",
796 ExecuteScriptInBackgroundPage(extension->id(), kAddTestRules));
797 EXPECT_TRUE(page_action->GetIsVisible(
798 ExtensionTabUtil::GetTabId(tab2.get())));
800 // Remove the rule.
801 const std::string kRemoveTestRule1 = "removeRule('2', 'remove_rule1');\n";
802 EXPECT_EQ("remove_rule1",
803 ExecuteScriptInBackgroundPage(extension->id(), kRemoveTestRule1));
805 // Remove the second tab, then trigger a rule evaluation for the remaining
806 // tab.
807 tab2.reset();
808 NavigateInRenderer(tab1, GURL("http://test1/"));
809 EXPECT_TRUE(page_action->GetIsVisible(ExtensionTabUtil::GetTabId(tab1)));
812 // https://crbug.com/517492
813 #if defined(OS_WIN)
814 // Fails on XP: http://crbug.com/515717
815 #define MAYBE_RemoveAllRulesAfterExtensionUninstall \
816 DISABLED_RemoveAllRulesAfterExtensionUninstall
817 #else
818 #define MAYBE_RemoveAllRulesAfterExtensionUninstall \
819 RemoveAllRulesAfterExtensionUninstall
820 #endif
821 IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
822 MAYBE_RemoveAllRulesAfterExtensionUninstall) {
823 ext_dir_.WriteManifest(kDeclarativeContentManifest);
824 ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
826 // Load the extension, add a rule, then uninstall the extension.
827 const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
828 ASSERT_TRUE(extension);
830 const std::string kAddTestRule =
831 "addRules([{\n"
832 " id: '1',\n"
833 " conditions: [],\n"
834 " actions: [new ShowPageAction()]\n"
835 "}], 'add_rule');\n";
836 EXPECT_EQ("add_rule",
837 ExecuteScriptInBackgroundPage(extension->id(), kAddTestRule));
839 ExtensionService* extension_service = extensions::ExtensionSystem::Get(
840 browser()->profile())->extension_service();
842 base::string16 error;
843 ASSERT_TRUE(extension_service->UninstallExtension(
844 extension->id(),
845 UNINSTALL_REASON_FOR_TESTING,
846 base::Bind(&base::DoNothing),
847 &error));
848 ASSERT_EQ(base::ASCIIToUTF16(""), error);
850 // Reload the extension, then add and remove a rule.
851 extension = LoadExtension(ext_dir_.unpacked_path());
852 ASSERT_TRUE(extension);
854 EXPECT_EQ("add_rule",
855 ExecuteScriptInBackgroundPage(extension->id(), kAddTestRule));
857 const std::string kRemoveTestRule1 = "removeRule('1', 'remove_rule1');\n";
858 EXPECT_EQ("remove_rule1",
859 ExecuteScriptInBackgroundPage(extension->id(), kRemoveTestRule1));
863 // TODO(wittman): Once ChromeContentRulesRegistry operates on condition and
864 // action interfaces, add a test that checks that a navigation always evaluates
865 // consistent URL state for all conditions. i.e.: if condition1 evaluates to
866 // false on url0 and true on url1, and condition2 evaluates to true on url0 and
867 // false on url1, navigate from url0 to url1 and validate that no action is
868 // triggered. Do the same when navigating back to url0. This kind of test is
869 // unfortunately not feasible with the current implementation and the existing
870 // supported conditions and actions.
872 } // namespace
873 } // namespace extensions