1 // Copyright 2014 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/files/file_path.h"
6 #include "base/files/file_util.h"
7 #include "base/path_service.h"
8 #include "base/values.h"
9 #include "chrome/browser/extensions/extension_apitest.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/common/chrome_paths.h"
13 #include "chrome/test/base/ui_test_utils.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/test/browser_test_utils.h"
17 #include "extensions/browser/event_router.h"
18 #include "extensions/common/api/test.h"
19 #include "extensions/common/extension.h"
20 #include "extensions/test/extension_test_message_listener.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 namespace extensions
{
25 namespace OnMessage
= api::test::OnMessage
;
29 // Tests running extension APIs on WebUI.
30 class ExtensionWebUITest
: public ExtensionApiTest
{
32 testing::AssertionResult
RunTest(const char* name
,
34 const GURL
& frame_url
,
35 bool expected_result
) {
36 // Tests are located in chrome/test/data/extensions/webui/$(name).
38 PathService::Get(chrome::DIR_TEST_DATA
, &path
);
40 path
.AppendASCII("extensions").AppendASCII("webui").AppendASCII(name
);
43 if (!base::PathExists(path
))
44 return testing::AssertionFailure() << "Couldn't find " << path
.value();
46 base::ReadFileToString(path
, &script
);
47 script
= "(function(){'use strict';" + script
+ "}());";
50 bool actual_result
= false;
51 content::RenderFrameHost
* webui
= NavigateToWebUI(page_url
, frame_url
);
53 return testing::AssertionFailure() << "Failed to navigate to WebUI";
54 CHECK(content::ExecuteScriptAndExtractBool(webui
, script
, &actual_result
));
55 return (expected_result
== actual_result
)
56 ? testing::AssertionSuccess()
57 : (testing::AssertionFailure() << "Check console output");
60 testing::AssertionResult
RunTestOnExtensionsFrame(const char* name
) {
61 // In the current extension WebUI design, the content is actually hosted in
62 // an iframe at chrome://extensions-frame.
64 GURL("chrome://extensions"),
65 GURL("chrome://extensions-frame"),
66 true); // tests on chrome://extensions-frame should succeed
69 testing::AssertionResult
RunTestOnChromeExtensionsFrame(const char* name
) {
70 // Like RunTestOnExtensionsFrame, but chrome://extensions is an alias for
71 // chrome://chrome/extensions so test it explicitly.
73 GURL("chrome://chrome/extensions"),
74 GURL("chrome://extensions-frame"),
75 true); // tests on chrome://extensions-frame should succeed
78 testing::AssertionResult
RunTestOnChromeExtensions(const char* name
) {
79 // Despite the extensions page being hosted in an iframe, also test the
80 // top-level chrome://extensions page (which actually loads
81 // chrome://chrome/extensions). In the past there was a bug where top-level
82 // extension WebUI bindings weren't correctly set up.
84 GURL("chrome://chrome/extensions"),
85 GURL("chrome://chrome/extensions"),
86 true); // tests on chrome://chrome/extensions should succeed
89 testing::AssertionResult
RunTestOnAbout(const char* name
) {
90 // chrome://about is an innocuous page that doesn't have any bindings.
93 GURL("chrome://about"),
94 GURL("chrome://about"),
95 false); // tests on chrome://about should fail
99 // Navigates the browser to a WebUI page and returns the RenderFrameHost for
101 content::RenderFrameHost
* NavigateToWebUI(const GURL
& page_url
,
102 const GURL
& frame_url
) {
103 ui_test_utils::NavigateToURL(browser(), page_url
);
105 content::WebContents
* active_web_contents
=
106 browser()->tab_strip_model()->GetActiveWebContents();
108 if (active_web_contents
->GetLastCommittedURL() == frame_url
)
109 return active_web_contents
->GetMainFrame();
111 return FrameMatchingPredicate(
113 base::Bind(&content::FrameHasSourceUrl
, frame_url
));
117 IN_PROC_BROWSER_TEST_F(ExtensionWebUITest
, SanityCheckAvailableAPIsInFrame
) {
118 ASSERT_TRUE(RunTestOnExtensionsFrame("sanity_check_available_apis.js"));
121 IN_PROC_BROWSER_TEST_F(ExtensionWebUITest
,
122 SanityCheckAvailableAPIsInChromeFrame
) {
123 ASSERT_TRUE(RunTestOnChromeExtensionsFrame("sanity_check_available_apis.js"));
126 IN_PROC_BROWSER_TEST_F(ExtensionWebUITest
, SanityCheckAvailableAPIsInToplevel
) {
127 ASSERT_TRUE(RunTestOnChromeExtensions("sanity_check_available_apis.js"));
130 IN_PROC_BROWSER_TEST_F(ExtensionWebUITest
, SanityCheckUnavailableAPIs
) {
131 ASSERT_TRUE(RunTestOnAbout("sanity_check_available_apis.js"));
134 // Tests chrome.test.sendMessage, which exercises WebUI making a
135 // function call and receiving a response.
136 IN_PROC_BROWSER_TEST_F(ExtensionWebUITest
, SendMessage
) {
137 scoped_ptr
<ExtensionTestMessageListener
> listener(
138 new ExtensionTestMessageListener("ping", true));
140 ASSERT_TRUE(RunTestOnExtensionsFrame("send_message.js"));
142 ASSERT_TRUE(listener
->WaitUntilSatisfied());
143 listener
->Reply("pong");
145 listener
.reset(new ExtensionTestMessageListener(false));
146 ASSERT_TRUE(listener
->WaitUntilSatisfied());
147 EXPECT_EQ("true", listener
->message());
150 // Tests chrome.runtime.onMessage, which exercises WebUI registering and
151 // receiving an event.
152 IN_PROC_BROWSER_TEST_F(ExtensionWebUITest
, OnMessage
) {
153 ASSERT_TRUE(RunTestOnExtensionsFrame("on_message.js"));
155 OnMessage::Info info
;
157 info
.last_message
= true;
158 EventRouter::Get(profile())->BroadcastEvent(make_scoped_ptr(
159 new Event(events::RUNTIME_ON_MESSAGE
, OnMessage::kEventName
,
160 OnMessage::Create(info
))));
162 scoped_ptr
<ExtensionTestMessageListener
> listener(
163 new ExtensionTestMessageListener(false));
164 ASSERT_TRUE(listener
->WaitUntilSatisfied());
165 EXPECT_EQ("true", listener
->message());
168 // Tests chrome.runtime.lastError, which exercises WebUI accessing a property
169 // on an API which it doesn't actually have access to. A bindings test really.
170 IN_PROC_BROWSER_TEST_F(ExtensionWebUITest
, RuntimeLastError
) {
171 scoped_ptr
<ExtensionTestMessageListener
> listener(
172 new ExtensionTestMessageListener("ping", true));
174 ASSERT_TRUE(RunTestOnExtensionsFrame("runtime_last_error.js"));
176 ASSERT_TRUE(listener
->WaitUntilSatisfied());
177 listener
->ReplyWithError("unknown host");
179 listener
.reset(new ExtensionTestMessageListener(false));
180 ASSERT_TRUE(listener
->WaitUntilSatisfied());
181 EXPECT_EQ("true", listener
->message());
184 IN_PROC_BROWSER_TEST_F(ExtensionWebUITest
, CanEmbedExtensionOptions
) {
185 scoped_ptr
<ExtensionTestMessageListener
> listener(
186 new ExtensionTestMessageListener("ready", true));
188 const Extension
* extension
=
189 LoadExtension(test_data_dir_
.AppendASCII("extension_options")
190 .AppendASCII("embed_self"));
191 ASSERT_TRUE(extension
);
193 ASSERT_TRUE(RunTestOnExtensionsFrame("can_embed_extension_options.js"));
195 ASSERT_TRUE(listener
->WaitUntilSatisfied());
196 listener
->Reply(extension
->id());
197 listener
.reset(new ExtensionTestMessageListener("load", false));
198 ASSERT_TRUE(listener
->WaitUntilSatisfied());
201 IN_PROC_BROWSER_TEST_F(ExtensionWebUITest
, ReceivesExtensionOptionsOnClose
) {
202 scoped_ptr
<ExtensionTestMessageListener
> listener(
203 new ExtensionTestMessageListener("ready", true));
205 const Extension
* extension
=
206 InstallExtension(test_data_dir_
.AppendASCII("extension_options")
207 .AppendASCII("close_self"), 1);
208 ASSERT_TRUE(extension
);
211 RunTestOnExtensionsFrame("receives_extension_options_on_close.js"));
213 ASSERT_TRUE(listener
->WaitUntilSatisfied());
214 listener
->Reply(extension
->id());
215 listener
.reset(new ExtensionTestMessageListener("onclose received", false));
216 ASSERT_TRUE(listener
->WaitUntilSatisfied());
219 // Regression test for crbug.com/414526.
221 // Same setup as CanEmbedExtensionOptions but disable the extension before
223 IN_PROC_BROWSER_TEST_F(ExtensionWebUITest
, EmbedDisabledExtension
) {
224 scoped_ptr
<ExtensionTestMessageListener
> listener(
225 new ExtensionTestMessageListener("ready", true));
227 std::string extension_id
;
229 const Extension
* extension
=
230 LoadExtension(test_data_dir_
.AppendASCII("extension_options")
231 .AppendASCII("embed_self"));
232 ASSERT_TRUE(extension
);
233 extension_id
= extension
->id();
234 DisableExtension(extension_id
);
237 ASSERT_TRUE(RunTestOnExtensionsFrame("can_embed_extension_options.js"));
239 ASSERT_TRUE(listener
->WaitUntilSatisfied());
240 listener
->Reply(extension_id
);
241 listener
.reset(new ExtensionTestMessageListener("createfailed", false));
242 ASSERT_TRUE(listener
->WaitUntilSatisfied());
247 } // namespace extensions