blob: 2d5a6238a28d0b91cfa5e62823d1354ca618e085 [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"
Peter Kasting919ce652020-05-07 10:22:3621#include "content/public/test/browser_test.h"
[email protected]7d478cb2012-07-24 17:19:4222#include "content/public/test/browser_test_utils.h"
[email protected]e4452d32013-11-15 23:07:4123#include "extensions/common/extension.h"
[email protected]d42c11152013-08-22 19:36:3224#include "extensions/common/manifest.h"
[email protected]f2cb3cf2013-03-21 01:40:5325#include "net/dns/mock_host_resolver.h"
nickfa2254b2015-08-07 23:27:2926#include "net/test/embedded_test_server/embedded_test_server.h"
[email protected]a6483d22013-07-03 22:11:0027#include "url/gurl.h"
[email protected]a964e112011-04-14 21:52:5128
[email protected]1c321ee2012-05-21 03:02:3429using extensions::Extension;
30
Devlin Cronin836f545d2018-05-09 00:25:0531class ChromeAppAPITest : public extensions::ExtensionBrowserTest {
jambb11ed742017-05-01 17:27:5932 void SetUpOnMainThread() override {
Devlin Cronin836f545d2018-05-09 00:25:0533 extensions::ExtensionBrowserTest::SetUpOnMainThread();
jambb11ed742017-05-01 17:27:5934 host_resolver()->AddRule("*", "127.0.0.1");
35 ASSERT_TRUE(embedded_test_server()->Start());
36 }
37
[email protected]80675fc2011-06-21 02:05:4938 protected:
[email protected]b27c3622014-03-22 00:26:5539 bool IsAppInstalledInMainFrame() {
40 return IsAppInstalledInFrame(
41 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
42 }
43 bool IsAppInstalledInIFrame() {
44 return IsAppInstalledInFrame(GetIFrame());
45 }
46 bool IsAppInstalledInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1347 const char kGetAppIsInstalled[] =
48 "window.domAutomationController.send(window.chrome.app.isInstalled);";
[email protected]80675fc2011-06-21 02:05:4949 bool result;
[email protected]b27c3622014-03-22 00:26:5550 CHECK(content::ExecuteScriptAndExtractBool(frame,
51 kGetAppIsInstalled,
52 &result));
[email protected]f2fe87c2012-04-24 17:53:4953 return result;
54 }
55
[email protected]b27c3622014-03-22 00:26:5556 std::string InstallStateInMainFrame() {
57 return InstallStateInFrame(
58 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
59 }
60 std::string InstallStateInIFrame() {
61 return InstallStateInFrame(GetIFrame());
62 }
63 std::string InstallStateInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1364 const char kGetAppInstallState[] =
65 "window.chrome.app.installState("
66 " function(s) { window.domAutomationController.send(s); });";
[email protected]f2fe87c2012-04-24 17:53:4967 std::string result;
[email protected]b27c3622014-03-22 00:26:5568 CHECK(content::ExecuteScriptAndExtractString(frame,
69 kGetAppInstallState,
70 &result));
[email protected]f2fe87c2012-04-24 17:53:4971 return result;
72 }
73
[email protected]b27c3622014-03-22 00:26:5574 std::string RunningStateInMainFrame() {
75 return RunningStateInFrame(
76 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
77 }
78 std::string RunningStateInIFrame() {
79 return RunningStateInFrame(GetIFrame());
80 }
81 std::string RunningStateInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1382 const char kGetAppRunningState[] =
83 "window.domAutomationController.send("
84 " window.chrome.app.runningState());";
[email protected]f2fe87c2012-04-24 17:53:4985 std::string result;
[email protected]b27c3622014-03-22 00:26:5586 CHECK(content::ExecuteScriptAndExtractString(frame,
87 kGetAppRunningState,
88 &result));
[email protected]80675fc2011-06-21 02:05:4989 return result;
90 }
91
[email protected]a964e112011-04-14 21:52:5192 private:
[email protected]b27c3622014-03-22 00:26:5593 content::RenderFrameHost* GetIFrame() {
94 return content::FrameMatchingPredicate(
David Bokan2c77c33c2021-07-26 23:29:5995 browser()->tab_strip_model()->GetActiveWebContents()->GetPrimaryPage(),
Alex Turnerd9f1b0f2020-10-21 00:05:5096 base::BindRepeating(&content::FrameIsChildOfMainFrame));
[email protected]b27c3622014-03-22 00:26:5597 }
[email protected]a964e112011-04-14 21:52:5198};
99
nickfa2254b2015-08-07 23:27:29100IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalled) {
nickfa2254b2015-08-07 23:27:29101 GURL app_url =
102 embedded_test_server()->GetURL("app.com", "/extensions/test_file.html");
103 GURL non_app_url = embedded_test_server()->GetURL(
104 "nonapp.com", "/extensions/test_file.html");
[email protected]a964e112011-04-14 21:52:51105
[email protected]80675fc2011-06-21 02:05:49106 // Before the app is installed, app.com does not think that it is installed
107 ui_test_utils::NavigateToURL(browser(), app_url);
[email protected]b27c3622014-03-22 00:26:55108 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51109
110 // Load an app which includes app.com in its extent.
111 const Extension* extension = LoadExtension(
112 test_data_dir_.AppendASCII("app_dot_com_app"));
113 ASSERT_TRUE(extension);
114
[email protected]80675fc2011-06-21 02:05:49115 // Even after the app is installed, the existing app.com tab is not in an
116 // app process, so chrome.app.isInstalled should return false.
[email protected]b27c3622014-03-22 00:26:55117 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51118
119 // Test that a non-app page has chrome.app.isInstalled = false.
120 ui_test_utils::NavigateToURL(browser(), non_app_url);
[email protected]b27c3622014-03-22 00:26:55121 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51122
123 // Test that a non-app page returns null for chrome.app.getDetails().
[email protected]06bc5d92013-01-02 22:44:13124 const char kGetAppDetails[] =
125 "window.domAutomationController.send("
126 " JSON.stringify(window.chrome.app.getDetails()));";
[email protected]80675fc2011-06-21 02:05:49127 std::string result;
[email protected]a964e112011-04-14 21:52:51128 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43129 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48130 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13131 kGetAppDetails,
132 &result));
[email protected]a964e112011-04-14 21:52:51133 EXPECT_EQ("null", result);
134
135 // Check that an app page has chrome.app.isInstalled = true.
136 ui_test_utils::NavigateToURL(browser(), app_url);
[email protected]b27c3622014-03-22 00:26:55137 EXPECT_TRUE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51138
139 // Check that an app page returns the correct result for
140 // chrome.app.getDetails().
141 ui_test_utils::NavigateToURL(browser(), app_url);
142 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43143 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48144 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13145 kGetAppDetails,
146 &result));
dchengc963c7142016-04-08 03:55:22147 std::unique_ptr<base::DictionaryValue> app_details(
estadeb09312b2015-05-22 16:30:13148 static_cast<base::DictionaryValue*>(
Lei Zhang582ecd12019-02-13 20:28:54149 base::JSONReader::ReadDeprecated(result).release()));
[email protected]953620b2011-12-04 00:55:32150 // extension->manifest() does not contain the id.
Song Fangzhencdbb7062021-07-07 11:13:53151 app_details->RemoveKey("id");
[email protected]a964e112011-04-14 21:52:51152 EXPECT_TRUE(app_details.get());
[email protected]953620b2011-12-04 00:55:32153 EXPECT_TRUE(app_details->Equals(extension->manifest()->value()));
[email protected]a964e112011-04-14 21:52:51154
[email protected]9b3a5c22011-05-31 08:03:13155 // Try to change app.isInstalled. Should silently fail, so
156 // that isInstalled should have the initial value.
157 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43158 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48159 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13160 "window.domAutomationController.send("
161 " function() {"
162 " var value = window.chrome.app.isInstalled;"
163 " window.chrome.app.isInstalled = !value;"
164 " if (window.chrome.app.isInstalled == value) {"
165 " return 'true';"
166 " } else {"
167 " return 'false';"
168 " }"
169 " }()"
170 ");",
171 &result));
[email protected]9b3a5c22011-05-31 08:03:13172
173 // Should not be able to alter window.chrome.app.isInstalled from javascript";
174 EXPECT_EQ("true", result);
[email protected]a964e112011-04-14 21:52:51175}
176
Devlin Cronine97d4ed2018-06-29 01:38:50177// Test accessing app.isInstalled when the context has been invalidated (e.g.
178// by removing the frame). Regression test for https://crbug.com/855853.
179IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalledFromRemovedFrame) {
180 GURL app_url =
181 embedded_test_server()->GetURL("app.com", "/extensions/test_file.html");
182 const Extension* extension =
183 LoadExtension(test_data_dir_.AppendASCII("app_dot_com_app"));
184 ASSERT_TRUE(extension);
185 ui_test_utils::NavigateToURL(browser(), app_url);
186
187 constexpr char kScript[] =
188 R"(var i = document.createElement('iframe');
189 i.onload = function() {
190 var frameApp = i.contentWindow.chrome.app;
191 document.body.removeChild(i);
192 var isInstalled = frameApp.isInstalled;
193 window.domAutomationController.send(
194 isInstalled === undefined);
195 };
196 i.src = '%s';
197 document.body.appendChild(i);)";
198 bool result = false;
199 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
200 browser()->tab_strip_model()->GetActiveWebContents(),
201 base::StringPrintf(kScript, app_url.spec().c_str()), &result));
202 EXPECT_TRUE(result);
203}
204
[email protected]f2fe87c2012-04-24 17:53:49205IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningState) {
nickfa2254b2015-08-07 23:27:29206 GURL app_url = embedded_test_server()->GetURL(
207 "app.com", "/extensions/get_app_details_for_frame.html");
208 GURL non_app_url = embedded_test_server()->GetURL(
209 "nonapp.com", "/extensions/get_app_details_for_frame.html");
[email protected]f2fe87c2012-04-24 17:53:49210
211 // Before the app is installed, app.com does not think that it is installed
212 ui_test_utils::NavigateToURL(browser(), app_url);
213
[email protected]b27c3622014-03-22 00:26:55214 EXPECT_EQ("not_installed", InstallStateInMainFrame());
215 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
216 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49217
218 const Extension* extension = LoadExtension(
219 test_data_dir_.AppendASCII("app_dot_com_app"));
220 ASSERT_TRUE(extension);
221
[email protected]b27c3622014-03-22 00:26:55222 EXPECT_EQ("installed", InstallStateInMainFrame());
223 EXPECT_EQ("ready_to_run", RunningStateInMainFrame());
224 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49225
226 // Reloading the page should put the tab in an app process.
227 ui_test_utils::NavigateToURL(browser(), app_url);
[email protected]b27c3622014-03-22 00:26:55228 EXPECT_EQ("installed", InstallStateInMainFrame());
229 EXPECT_EQ("running", RunningStateInMainFrame());
230 EXPECT_TRUE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49231
232 // Disable the extension and verify the state.
Devlin Cronin251bd412018-05-30 00:55:42233 extensions::ExtensionService* service =
234 extensions::ExtensionSystem::Get(browser()->profile())
235 ->extension_service();
Minh X. Nguyen45479012017-08-18 21:35:36236 service->DisableExtension(
237 extension->id(),
238 extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE);
[email protected]f2fe87c2012-04-24 17:53:49239 ui_test_utils::NavigateToURL(browser(), app_url);
240
[email protected]b27c3622014-03-22 00:26:55241 EXPECT_EQ("disabled", InstallStateInMainFrame());
242 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
243 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49244
[email protected]03d25812014-06-22 19:41:55245 service->EnableExtension(extension->id());
[email protected]b27c3622014-03-22 00:26:55246 EXPECT_EQ("installed", InstallStateInMainFrame());
247 EXPECT_EQ("ready_to_run", RunningStateInMainFrame());
248 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49249
250 // The non-app URL should still not be installed or running.
251 ui_test_utils::NavigateToURL(browser(), non_app_url);
252
[email protected]b27c3622014-03-22 00:26:55253 EXPECT_EQ("not_installed", InstallStateInMainFrame());
254 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
255 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49256
[email protected]b27c3622014-03-22 00:26:55257 EXPECT_EQ("installed", InstallStateInIFrame());
258 EXPECT_EQ("cannot_run", RunningStateInIFrame());
Alex Moshchuke63b9e92017-10-14 00:27:22259
260 // With --site-per-process, the iframe on nonapp.com will currently swap
261 // processes and go into the hosted app process.
262 if (content::AreAllSitesIsolatedForTesting())
263 EXPECT_TRUE(IsAppInstalledInIFrame());
264 else
265 EXPECT_FALSE(IsAppInstalledInIFrame());
[email protected]f2fe87c2012-04-24 17:53:49266}
267
268IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningStateFrame) {
nickfa2254b2015-08-07 23:27:29269 GURL app_url = embedded_test_server()->GetURL(
270 "app.com", "/extensions/get_app_details_for_frame_reversed.html");
[email protected]f2fe87c2012-04-24 17:53:49271
272 // Check the install and running state of a non-app iframe running
273 // within an app.
274 ui_test_utils::NavigateToURL(browser(), app_url);
275
[email protected]b27c3622014-03-22 00:26:55276 EXPECT_EQ("not_installed", InstallStateInIFrame());
277 EXPECT_EQ("cannot_run", RunningStateInIFrame());
278 EXPECT_FALSE(IsAppInstalledInIFrame());
[email protected]f2fe87c2012-04-24 17:53:49279}