blob: 573d306cd848895eb20d27a1d86cab56dc8d899e [file] [log] [blame]
[email protected]f2fe87c2012-04-24 17:53:491// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]a964e112011-04-14 21:52:512// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
dchengc963c7142016-04-08 03:55:225#include <memory>
[email protected]a964e112011-04-14 21:52:516#include <string>
7
Sebastien Marchandf1349f52019-01-25 03:16:418#include "base/bind.h"
[email protected]a964e112011-04-14 21:52:519#include "base/command_line.h"
10#include "base/json/json_reader.h"
[email protected]3ea1b182013-02-08 22:38:4111#include "base/strings/string_number_conversions.h"
Lei Zhangfe5b86932019-02-01 17:26:5912#include "base/strings/stringprintf.h"
[email protected]a964e112011-04-14 21:52:5113#include "base/values.h"
14#include "chrome/browser/extensions/extension_browsertest.h"
[email protected]f2fe87c2012-04-24 17:53:4915#include "chrome/browser/extensions/extension_service.h"
16#include "chrome/browser/profiles/profile.h"
[email protected]a964e112011-04-14 21:52:5117#include "chrome/browser/ui/browser.h"
[email protected]47ae23372013-01-29 01:50:4818#include "chrome/browser/ui/tabs/tab_strip_model.h"
[email protected]af44e7fb2011-07-29 18:32:3219#include "chrome/test/base/ui_test_utils.h"
[email protected]4ca15302012-01-03 05:53:2020#include "content/public/browser/web_contents.h"
[email protected]7d478cb2012-07-24 17:19:4221#include "content/public/test/browser_test_utils.h"
[email protected]e4452d32013-11-15 23:07:4122#include "extensions/common/extension.h"
[email protected]d42c11152013-08-22 19:36:3223#include "extensions/common/manifest.h"
[email protected]f2cb3cf2013-03-21 01:40:5324#include "net/dns/mock_host_resolver.h"
nickfa2254b2015-08-07 23:27:2925#include "net/test/embedded_test_server/embedded_test_server.h"
[email protected]a6483d22013-07-03 22:11:0026#include "url/gurl.h"
[email protected]a964e112011-04-14 21:52:5127
[email protected]1c321ee2012-05-21 03:02:3428using extensions::Extension;
29
Devlin Cronin836f545d2018-05-09 00:25:0530class ChromeAppAPITest : public extensions::ExtensionBrowserTest {
jambb11ed742017-05-01 17:27:5931 void SetUpOnMainThread() override {
Devlin Cronin836f545d2018-05-09 00:25:0532 extensions::ExtensionBrowserTest::SetUpOnMainThread();
jambb11ed742017-05-01 17:27:5933 host_resolver()->AddRule("*", "127.0.0.1");
34 ASSERT_TRUE(embedded_test_server()->Start());
35 }
36
[email protected]80675fc2011-06-21 02:05:4937 protected:
[email protected]b27c3622014-03-22 00:26:5538 bool IsAppInstalledInMainFrame() {
39 return IsAppInstalledInFrame(
40 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
41 }
42 bool IsAppInstalledInIFrame() {
43 return IsAppInstalledInFrame(GetIFrame());
44 }
45 bool IsAppInstalledInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1346 const char kGetAppIsInstalled[] =
47 "window.domAutomationController.send(window.chrome.app.isInstalled);";
[email protected]80675fc2011-06-21 02:05:4948 bool result;
[email protected]b27c3622014-03-22 00:26:5549 CHECK(content::ExecuteScriptAndExtractBool(frame,
50 kGetAppIsInstalled,
51 &result));
[email protected]f2fe87c2012-04-24 17:53:4952 return result;
53 }
54
[email protected]b27c3622014-03-22 00:26:5555 std::string InstallStateInMainFrame() {
56 return InstallStateInFrame(
57 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
58 }
59 std::string InstallStateInIFrame() {
60 return InstallStateInFrame(GetIFrame());
61 }
62 std::string InstallStateInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1363 const char kGetAppInstallState[] =
64 "window.chrome.app.installState("
65 " function(s) { window.domAutomationController.send(s); });";
[email protected]f2fe87c2012-04-24 17:53:4966 std::string result;
[email protected]b27c3622014-03-22 00:26:5567 CHECK(content::ExecuteScriptAndExtractString(frame,
68 kGetAppInstallState,
69 &result));
[email protected]f2fe87c2012-04-24 17:53:4970 return result;
71 }
72
[email protected]b27c3622014-03-22 00:26:5573 std::string RunningStateInMainFrame() {
74 return RunningStateInFrame(
75 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
76 }
77 std::string RunningStateInIFrame() {
78 return RunningStateInFrame(GetIFrame());
79 }
80 std::string RunningStateInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1381 const char kGetAppRunningState[] =
82 "window.domAutomationController.send("
83 " window.chrome.app.runningState());";
[email protected]f2fe87c2012-04-24 17:53:4984 std::string result;
[email protected]b27c3622014-03-22 00:26:5585 CHECK(content::ExecuteScriptAndExtractString(frame,
86 kGetAppRunningState,
87 &result));
[email protected]80675fc2011-06-21 02:05:4988 return result;
89 }
90
[email protected]a964e112011-04-14 21:52:5191 private:
[email protected]b27c3622014-03-22 00:26:5592 content::RenderFrameHost* GetIFrame() {
93 return content::FrameMatchingPredicate(
94 browser()->tab_strip_model()->GetActiveWebContents(),
95 base::Bind(&content::FrameIsChildOfMainFrame));
96 }
[email protected]a964e112011-04-14 21:52:5197};
98
nickfa2254b2015-08-07 23:27:2999IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalled) {
nickfa2254b2015-08-07 23:27:29100 GURL app_url =
101 embedded_test_server()->GetURL("app.com", "/extensions/test_file.html");
102 GURL non_app_url = embedded_test_server()->GetURL(
103 "nonapp.com", "/extensions/test_file.html");
[email protected]a964e112011-04-14 21:52:51104
[email protected]80675fc2011-06-21 02:05:49105 // Before the app is installed, app.com does not think that it is installed
106 ui_test_utils::NavigateToURL(browser(), app_url);
[email protected]b27c3622014-03-22 00:26:55107 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51108
109 // Load an app which includes app.com in its extent.
110 const Extension* extension = LoadExtension(
111 test_data_dir_.AppendASCII("app_dot_com_app"));
112 ASSERT_TRUE(extension);
113
[email protected]80675fc2011-06-21 02:05:49114 // Even after the app is installed, the existing app.com tab is not in an
115 // app process, so chrome.app.isInstalled should return false.
[email protected]b27c3622014-03-22 00:26:55116 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51117
118 // Test that a non-app page has chrome.app.isInstalled = false.
119 ui_test_utils::NavigateToURL(browser(), non_app_url);
[email protected]b27c3622014-03-22 00:26:55120 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51121
122 // Test that a non-app page returns null for chrome.app.getDetails().
[email protected]06bc5d92013-01-02 22:44:13123 const char kGetAppDetails[] =
124 "window.domAutomationController.send("
125 " JSON.stringify(window.chrome.app.getDetails()));";
[email protected]80675fc2011-06-21 02:05:49126 std::string result;
[email protected]a964e112011-04-14 21:52:51127 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43128 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48129 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13130 kGetAppDetails,
131 &result));
[email protected]a964e112011-04-14 21:52:51132 EXPECT_EQ("null", result);
133
134 // Check that an app page has chrome.app.isInstalled = true.
135 ui_test_utils::NavigateToURL(browser(), app_url);
[email protected]b27c3622014-03-22 00:26:55136 EXPECT_TRUE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51137
138 // Check that an app page returns the correct result for
139 // chrome.app.getDetails().
140 ui_test_utils::NavigateToURL(browser(), app_url);
141 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43142 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48143 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13144 kGetAppDetails,
145 &result));
dchengc963c7142016-04-08 03:55:22146 std::unique_ptr<base::DictionaryValue> app_details(
estadeb09312b2015-05-22 16:30:13147 static_cast<base::DictionaryValue*>(
Lei Zhang582ecd12019-02-13 20:28:54148 base::JSONReader::ReadDeprecated(result).release()));
[email protected]953620b2011-12-04 00:55:32149 // extension->manifest() does not contain the id.
[email protected]a964e112011-04-14 21:52:51150 app_details->Remove("id", NULL);
151 EXPECT_TRUE(app_details.get());
[email protected]953620b2011-12-04 00:55:32152 EXPECT_TRUE(app_details->Equals(extension->manifest()->value()));
[email protected]a964e112011-04-14 21:52:51153
[email protected]9b3a5c22011-05-31 08:03:13154 // Try to change app.isInstalled. Should silently fail, so
155 // that isInstalled should have the initial value.
156 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43157 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48158 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13159 "window.domAutomationController.send("
160 " function() {"
161 " var value = window.chrome.app.isInstalled;"
162 " window.chrome.app.isInstalled = !value;"
163 " if (window.chrome.app.isInstalled == value) {"
164 " return 'true';"
165 " } else {"
166 " return 'false';"
167 " }"
168 " }()"
169 ");",
170 &result));
[email protected]9b3a5c22011-05-31 08:03:13171
172 // Should not be able to alter window.chrome.app.isInstalled from javascript";
173 EXPECT_EQ("true", result);
[email protected]a964e112011-04-14 21:52:51174}
175
Devlin Cronine97d4ed2018-06-29 01:38:50176// Test accessing app.isInstalled when the context has been invalidated (e.g.
177// by removing the frame). Regression test for https://crbug.com/855853.
178IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalledFromRemovedFrame) {
179 GURL app_url =
180 embedded_test_server()->GetURL("app.com", "/extensions/test_file.html");
181 const Extension* extension =
182 LoadExtension(test_data_dir_.AppendASCII("app_dot_com_app"));
183 ASSERT_TRUE(extension);
184 ui_test_utils::NavigateToURL(browser(), app_url);
185
186 constexpr char kScript[] =
187 R"(var i = document.createElement('iframe');
188 i.onload = function() {
189 var frameApp = i.contentWindow.chrome.app;
190 document.body.removeChild(i);
191 var isInstalled = frameApp.isInstalled;
192 window.domAutomationController.send(
193 isInstalled === undefined);
194 };
195 i.src = '%s';
196 document.body.appendChild(i);)";
197 bool result = false;
198 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
199 browser()->tab_strip_model()->GetActiveWebContents(),
200 base::StringPrintf(kScript, app_url.spec().c_str()), &result));
201 EXPECT_TRUE(result);
202}
203
[email protected]f2fe87c2012-04-24 17:53:49204IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningState) {
nickfa2254b2015-08-07 23:27:29205 GURL app_url = embedded_test_server()->GetURL(
206 "app.com", "/extensions/get_app_details_for_frame.html");
207 GURL non_app_url = embedded_test_server()->GetURL(
208 "nonapp.com", "/extensions/get_app_details_for_frame.html");
[email protected]f2fe87c2012-04-24 17:53:49209
210 // Before the app is installed, app.com does not think that it is installed
211 ui_test_utils::NavigateToURL(browser(), app_url);
212
[email protected]b27c3622014-03-22 00:26:55213 EXPECT_EQ("not_installed", InstallStateInMainFrame());
214 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
215 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49216
217 const Extension* extension = LoadExtension(
218 test_data_dir_.AppendASCII("app_dot_com_app"));
219 ASSERT_TRUE(extension);
220
[email protected]b27c3622014-03-22 00:26:55221 EXPECT_EQ("installed", InstallStateInMainFrame());
222 EXPECT_EQ("ready_to_run", RunningStateInMainFrame());
223 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49224
225 // Reloading the page should put the tab in an app process.
226 ui_test_utils::NavigateToURL(browser(), app_url);
[email protected]b27c3622014-03-22 00:26:55227 EXPECT_EQ("installed", InstallStateInMainFrame());
228 EXPECT_EQ("running", RunningStateInMainFrame());
229 EXPECT_TRUE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49230
231 // Disable the extension and verify the state.
Devlin Cronin251bd412018-05-30 00:55:42232 extensions::ExtensionService* service =
233 extensions::ExtensionSystem::Get(browser()->profile())
234 ->extension_service();
Minh X. Nguyen45479012017-08-18 21:35:36235 service->DisableExtension(
236 extension->id(),
237 extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE);
[email protected]f2fe87c2012-04-24 17:53:49238 ui_test_utils::NavigateToURL(browser(), app_url);
239
[email protected]b27c3622014-03-22 00:26:55240 EXPECT_EQ("disabled", InstallStateInMainFrame());
241 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
242 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49243
[email protected]03d25812014-06-22 19:41:55244 service->EnableExtension(extension->id());
[email protected]b27c3622014-03-22 00:26:55245 EXPECT_EQ("installed", InstallStateInMainFrame());
246 EXPECT_EQ("ready_to_run", RunningStateInMainFrame());
247 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49248
249 // The non-app URL should still not be installed or running.
250 ui_test_utils::NavigateToURL(browser(), non_app_url);
251
[email protected]b27c3622014-03-22 00:26:55252 EXPECT_EQ("not_installed", InstallStateInMainFrame());
253 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
254 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49255
[email protected]b27c3622014-03-22 00:26:55256 EXPECT_EQ("installed", InstallStateInIFrame());
257 EXPECT_EQ("cannot_run", RunningStateInIFrame());
Alex Moshchuke63b9e92017-10-14 00:27:22258
259 // With --site-per-process, the iframe on nonapp.com will currently swap
260 // processes and go into the hosted app process.
261 if (content::AreAllSitesIsolatedForTesting())
262 EXPECT_TRUE(IsAppInstalledInIFrame());
263 else
264 EXPECT_FALSE(IsAppInstalledInIFrame());
[email protected]f2fe87c2012-04-24 17:53:49265}
266
267IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningStateFrame) {
nickfa2254b2015-08-07 23:27:29268 GURL app_url = embedded_test_server()->GetURL(
269 "app.com", "/extensions/get_app_details_for_frame_reversed.html");
[email protected]f2fe87c2012-04-24 17:53:49270
271 // Check the install and running state of a non-app iframe running
272 // within an app.
273 ui_test_utils::NavigateToURL(browser(), app_url);
274
[email protected]b27c3622014-03-22 00:26:55275 EXPECT_EQ("not_installed", InstallStateInIFrame());
276 EXPECT_EQ("cannot_run", RunningStateInIFrame());
277 EXPECT_FALSE(IsAppInstalledInIFrame());
[email protected]f2fe87c2012-04-24 17:53:49278}