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.
7 #include "base/command_line.h"
8 #include "base/json/json_reader.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/values.h"
12 #include "chrome/browser/extensions/extension_browsertest.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/test/base/ui_test_utils.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/test/browser_test_utils.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/manifest.h"
23 #include "net/dns/mock_host_resolver.h"
26 using extensions::Extension
;
28 class ChromeAppAPITest
: public ExtensionBrowserTest
{
30 bool IsAppInstalledInMainFrame() {
31 return IsAppInstalledInFrame(
32 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
34 bool IsAppInstalledInIFrame() {
35 return IsAppInstalledInFrame(GetIFrame());
37 bool IsAppInstalledInFrame(content::RenderFrameHost
* frame
) {
38 const char kGetAppIsInstalled
[] =
39 "window.domAutomationController.send(window.chrome.app.isInstalled);";
41 CHECK(content::ExecuteScriptAndExtractBool(frame
,
47 std::string
InstallStateInMainFrame() {
48 return InstallStateInFrame(
49 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
51 std::string
InstallStateInIFrame() {
52 return InstallStateInFrame(GetIFrame());
54 std::string
InstallStateInFrame(content::RenderFrameHost
* frame
) {
55 const char kGetAppInstallState
[] =
56 "window.chrome.app.installState("
57 " function(s) { window.domAutomationController.send(s); });";
59 CHECK(content::ExecuteScriptAndExtractString(frame
,
65 std::string
RunningStateInMainFrame() {
66 return RunningStateInFrame(
67 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
69 std::string
RunningStateInIFrame() {
70 return RunningStateInFrame(GetIFrame());
72 std::string
RunningStateInFrame(content::RenderFrameHost
* frame
) {
73 const char kGetAppRunningState
[] =
74 "window.domAutomationController.send("
75 " window.chrome.app.runningState());";
77 CHECK(content::ExecuteScriptAndExtractString(frame
,
84 content::RenderFrameHost
* GetIFrame() {
85 return content::FrameMatchingPredicate(
86 browser()->tab_strip_model()->GetActiveWebContents(),
87 base::Bind(&content::FrameIsChildOfMainFrame
));
90 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
91 ExtensionBrowserTest::SetUpCommandLine(command_line
);
92 command_line
->AppendSwitchASCII(switches::kAppsCheckoutURL
,
93 "http://checkout.com:");
97 // Flaky http://crbug.com/238674
99 #define MAYBE_IsInstalled DISABLED_IsInstalled
101 #define MAYBE_IsInstalled IsInstalled
103 IN_PROC_BROWSER_TEST_F(ChromeAppAPITest
, MAYBE_IsInstalled
) {
104 static const char kAppHost
[] = "app.com";
105 static const char kNonAppHost
[] = "nonapp.com";
107 host_resolver()->AddRule(kAppHost
, "127.0.0.1");
108 host_resolver()->AddRule(kNonAppHost
, "127.0.0.1");
109 ASSERT_TRUE(test_server()->Start());
111 GURL
test_file_url(test_server()->GetURL("extensions/test_file.html"));
112 GURL::Replacements replace_host
;
114 replace_host
.SetHostStr(kAppHost
);
115 GURL
app_url(test_file_url
.ReplaceComponents(replace_host
));
117 replace_host
.SetHostStr(kNonAppHost
);
118 GURL
non_app_url(test_file_url
.ReplaceComponents(replace_host
));
120 // Before the app is installed, app.com does not think that it is installed
121 ui_test_utils::NavigateToURL(browser(), app_url
);
122 EXPECT_FALSE(IsAppInstalledInMainFrame());
124 // Load an app which includes app.com in its extent.
125 const Extension
* extension
= LoadExtension(
126 test_data_dir_
.AppendASCII("app_dot_com_app"));
127 ASSERT_TRUE(extension
);
129 // Even after the app is installed, the existing app.com tab is not in an
130 // app process, so chrome.app.isInstalled should return false.
131 EXPECT_FALSE(IsAppInstalledInMainFrame());
133 // Test that a non-app page has chrome.app.isInstalled = false.
134 ui_test_utils::NavigateToURL(browser(), non_app_url
);
135 EXPECT_FALSE(IsAppInstalledInMainFrame());
137 // Test that a non-app page returns null for chrome.app.getDetails().
138 const char kGetAppDetails
[] =
139 "window.domAutomationController.send("
140 " JSON.stringify(window.chrome.app.getDetails()));";
143 content::ExecuteScriptAndExtractString(
144 browser()->tab_strip_model()->GetActiveWebContents(),
147 EXPECT_EQ("null", result
);
149 // Check that an app page has chrome.app.isInstalled = true.
150 ui_test_utils::NavigateToURL(browser(), app_url
);
151 EXPECT_TRUE(IsAppInstalledInMainFrame());
153 // Check that an app page returns the correct result for
154 // chrome.app.getDetails().
155 ui_test_utils::NavigateToURL(browser(), app_url
);
157 content::ExecuteScriptAndExtractString(
158 browser()->tab_strip_model()->GetActiveWebContents(),
161 scoped_ptr
<base::DictionaryValue
> app_details(
162 static_cast<base::DictionaryValue
*>(
163 base::JSONReader::DeprecatedRead(result
)));
164 // extension->manifest() does not contain the id.
165 app_details
->Remove("id", NULL
);
166 EXPECT_TRUE(app_details
.get());
167 EXPECT_TRUE(app_details
->Equals(extension
->manifest()->value()));
169 // Try to change app.isInstalled. Should silently fail, so
170 // that isInstalled should have the initial value.
172 content::ExecuteScriptAndExtractString(
173 browser()->tab_strip_model()->GetActiveWebContents(),
174 "window.domAutomationController.send("
176 " var value = window.chrome.app.isInstalled;"
177 " window.chrome.app.isInstalled = !value;"
178 " if (window.chrome.app.isInstalled == value) {"
187 // Should not be able to alter window.chrome.app.isInstalled from javascript";
188 EXPECT_EQ("true", result
);
191 IN_PROC_BROWSER_TEST_F(ChromeAppAPITest
, GetDetailsForFrame
) {
192 const char kAppHost
[] = "app.com";
193 const char kNonAppHost
[] = "nonapp.com";
194 const char kCheckoutHost
[] = "checkout.com";
196 host_resolver()->AddRule(kAppHost
, "127.0.0.1");
197 host_resolver()->AddRule(kNonAppHost
, "127.0.0.1");
198 host_resolver()->AddRule(kCheckoutHost
, "127.0.0.1");
199 ASSERT_TRUE(test_server()->Start());
201 GURL
test_file_url(test_server()->GetURL(
202 "files/extensions/get_app_details_for_frame.html"));
203 GURL::Replacements replace_host
;
205 replace_host
.SetHostStr(kCheckoutHost
);
206 GURL
checkout_url(test_file_url
.ReplaceComponents(replace_host
));
208 replace_host
.SetHostStr(kAppHost
);
209 GURL
app_url(test_file_url
.ReplaceComponents(replace_host
));
211 // Load an app which includes app.com in its extent.
212 const Extension
* extension
= LoadExtension(
213 test_data_dir_
.AppendASCII("app_dot_com_app"));
214 ASSERT_TRUE(extension
);
216 // Test that normal pages (even apps) cannot use getDetailsForFrame().
217 ui_test_utils::NavigateToURL(browser(), app_url
);
218 const char kTestUnsuccessfulAccess
[] =
219 "window.domAutomationController.send(window.testUnsuccessfulAccess())";
222 content::ExecuteScriptAndExtractBool(
223 browser()->tab_strip_model()->GetActiveWebContents(),
224 kTestUnsuccessfulAccess
,
228 // Test that checkout can use getDetailsForFrame() and that it works
230 ui_test_utils::NavigateToURL(browser(), checkout_url
);
231 const char kGetDetailsForFrame
[] =
232 "window.domAutomationController.send("
233 " JSON.stringify(chrome.app.getDetailsForFrame(frames[0])))";
236 content::ExecuteScriptAndExtractString(
237 browser()->tab_strip_model()->GetActiveWebContents(),
241 scoped_ptr
<base::DictionaryValue
> app_details(
242 static_cast<base::DictionaryValue
*>(
243 base::JSONReader::DeprecatedRead(json
)));
244 // extension->manifest() does not contain the id.
245 app_details
->Remove("id", NULL
);
246 EXPECT_TRUE(app_details
.get());
247 EXPECT_TRUE(app_details
->Equals(extension
->manifest()->value()));
251 IN_PROC_BROWSER_TEST_F(ChromeAppAPITest
, InstallAndRunningState
) {
252 static const char kAppHost
[] = "app.com";
253 static const char kNonAppHost
[] = "nonapp.com";
255 host_resolver()->AddRule(kAppHost
, "127.0.0.1");
256 host_resolver()->AddRule(kNonAppHost
, "127.0.0.1");
257 ASSERT_TRUE(test_server()->Start());
259 GURL
test_file_url(test_server()->GetURL(
260 "files/extensions/get_app_details_for_frame.html"));
261 GURL::Replacements replace_host
;
263 replace_host
.SetHostStr(kAppHost
);
264 GURL
app_url(test_file_url
.ReplaceComponents(replace_host
));
266 replace_host
.SetHostStr(kNonAppHost
);
267 GURL
non_app_url(test_file_url
.ReplaceComponents(replace_host
));
269 // Before the app is installed, app.com does not think that it is installed
270 ui_test_utils::NavigateToURL(browser(), app_url
);
272 EXPECT_EQ("not_installed", InstallStateInMainFrame());
273 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
274 EXPECT_FALSE(IsAppInstalledInMainFrame());
276 const Extension
* extension
= LoadExtension(
277 test_data_dir_
.AppendASCII("app_dot_com_app"));
278 ASSERT_TRUE(extension
);
280 EXPECT_EQ("installed", InstallStateInMainFrame());
281 EXPECT_EQ("ready_to_run", RunningStateInMainFrame());
282 EXPECT_FALSE(IsAppInstalledInMainFrame());
284 // Reloading the page should put the tab in an app process.
285 ui_test_utils::NavigateToURL(browser(), app_url
);
286 EXPECT_EQ("installed", InstallStateInMainFrame());
287 EXPECT_EQ("running", RunningStateInMainFrame());
288 EXPECT_TRUE(IsAppInstalledInMainFrame());
290 // Disable the extension and verify the state.
291 ExtensionService
* service
= extensions::ExtensionSystem::Get(
292 browser()->profile())->extension_service();
293 service
->DisableExtension(extension
->id(),
294 Extension::DISABLE_PERMISSIONS_INCREASE
);
295 ui_test_utils::NavigateToURL(browser(), app_url
);
297 EXPECT_EQ("disabled", InstallStateInMainFrame());
298 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
299 EXPECT_FALSE(IsAppInstalledInMainFrame());
301 service
->EnableExtension(extension
->id());
302 EXPECT_EQ("installed", InstallStateInMainFrame());
303 EXPECT_EQ("ready_to_run", RunningStateInMainFrame());
304 EXPECT_FALSE(IsAppInstalledInMainFrame());
306 // The non-app URL should still not be installed or running.
307 ui_test_utils::NavigateToURL(browser(), non_app_url
);
309 EXPECT_EQ("not_installed", InstallStateInMainFrame());
310 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
311 EXPECT_FALSE(IsAppInstalledInMainFrame());
313 EXPECT_EQ("installed", InstallStateInIFrame());
314 EXPECT_EQ("cannot_run", RunningStateInIFrame());
315 EXPECT_FALSE(IsAppInstalledInIFrame());
318 IN_PROC_BROWSER_TEST_F(ChromeAppAPITest
, InstallAndRunningStateFrame
) {
319 static const char kAppHost
[] = "app.com";
320 static const char kNonAppHost
[] = "nonapp.com";
322 host_resolver()->AddRule(kAppHost
, "127.0.0.1");
323 host_resolver()->AddRule(kNonAppHost
, "127.0.0.1");
324 ASSERT_TRUE(test_server()->Start());
326 GURL
test_file_url(test_server()->GetURL(
327 "files/extensions/get_app_details_for_frame_reversed.html"));
328 GURL::Replacements replace_host
;
330 replace_host
.SetHostStr(kAppHost
);
331 GURL
app_url(test_file_url
.ReplaceComponents(replace_host
));
333 replace_host
.SetHostStr(kNonAppHost
);
334 GURL
non_app_url(test_file_url
.ReplaceComponents(replace_host
));
336 // Check the install and running state of a non-app iframe running
338 ui_test_utils::NavigateToURL(browser(), app_url
);
340 EXPECT_EQ("not_installed", InstallStateInIFrame());
341 EXPECT_EQ("cannot_run", RunningStateInIFrame());
342 EXPECT_FALSE(IsAppInstalledInIFrame());