blob: 4e16bbc9de36a1fd14022e11376226611cd89f0b [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"
Dave Tapuskad46d6fd62022-05-18 21:35:5121#include "content/public/common/content_features.h"
Peter Kasting919ce652020-05-07 10:22:3622#include "content/public/test/browser_test.h"
[email protected]7d478cb2012-07-24 17:19:4223#include "content/public/test/browser_test_utils.h"
[email protected]e4452d32013-11-15 23:07:4124#include "extensions/common/extension.h"
[email protected]d42c11152013-08-22 19:36:3225#include "extensions/common/manifest.h"
[email protected]f2cb3cf2013-03-21 01:40:5326#include "net/dns/mock_host_resolver.h"
nickfa2254b2015-08-07 23:27:2927#include "net/test/embedded_test_server/embedded_test_server.h"
Dave Tapuskad46d6fd62022-05-18 21:35:5128#include "third_party/blink/public/common/features.h"
[email protected]a6483d22013-07-03 22:11:0029#include "url/gurl.h"
[email protected]a964e112011-04-14 21:52:5130
[email protected]1c321ee2012-05-21 03:02:3431using extensions::Extension;
32
Devlin Cronin836f545d2018-05-09 00:25:0533class ChromeAppAPITest : public extensions::ExtensionBrowserTest {
Dave Tapuskad46d6fd62022-05-18 21:35:5134 protected:
jambb11ed742017-05-01 17:27:5935 void SetUpOnMainThread() override {
Devlin Cronin836f545d2018-05-09 00:25:0536 extensions::ExtensionBrowserTest::SetUpOnMainThread();
jambb11ed742017-05-01 17:27:5937 host_resolver()->AddRule("*", "127.0.0.1");
38 ASSERT_TRUE(embedded_test_server()->Start());
39 }
40
[email protected]b27c3622014-03-22 00:26:5541 bool IsAppInstalledInMainFrame() {
Dave Tapuska6aea6e22022-06-06 21:21:5142 return IsAppInstalledInFrame(browser()
43 ->tab_strip_model()
44 ->GetActiveWebContents()
45 ->GetPrimaryMainFrame());
[email protected]b27c3622014-03-22 00:26:5546 }
47 bool IsAppInstalledInIFrame() {
48 return IsAppInstalledInFrame(GetIFrame());
49 }
50 bool IsAppInstalledInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1351 const char kGetAppIsInstalled[] =
52 "window.domAutomationController.send(window.chrome.app.isInstalled);";
[email protected]80675fc2011-06-21 02:05:4953 bool result;
[email protected]b27c3622014-03-22 00:26:5554 CHECK(content::ExecuteScriptAndExtractBool(frame,
55 kGetAppIsInstalled,
56 &result));
[email protected]f2fe87c2012-04-24 17:53:4957 return result;
58 }
59
[email protected]b27c3622014-03-22 00:26:5560 std::string InstallStateInMainFrame() {
Dave Tapuska6aea6e22022-06-06 21:21:5161 return InstallStateInFrame(browser()
62 ->tab_strip_model()
63 ->GetActiveWebContents()
64 ->GetPrimaryMainFrame());
[email protected]b27c3622014-03-22 00:26:5565 }
66 std::string InstallStateInIFrame() {
67 return InstallStateInFrame(GetIFrame());
68 }
69 std::string InstallStateInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1370 const char kGetAppInstallState[] =
71 "window.chrome.app.installState("
72 " function(s) { window.domAutomationController.send(s); });";
[email protected]f2fe87c2012-04-24 17:53:4973 std::string result;
[email protected]b27c3622014-03-22 00:26:5574 CHECK(content::ExecuteScriptAndExtractString(frame,
75 kGetAppInstallState,
76 &result));
[email protected]f2fe87c2012-04-24 17:53:4977 return result;
78 }
79
[email protected]b27c3622014-03-22 00:26:5580 std::string RunningStateInMainFrame() {
Dave Tapuska6aea6e22022-06-06 21:21:5181 return RunningStateInFrame(browser()
82 ->tab_strip_model()
83 ->GetActiveWebContents()
84 ->GetPrimaryMainFrame());
[email protected]b27c3622014-03-22 00:26:5585 }
86 std::string RunningStateInIFrame() {
87 return RunningStateInFrame(GetIFrame());
88 }
89 std::string RunningStateInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1390 const char kGetAppRunningState[] =
91 "window.domAutomationController.send("
92 " window.chrome.app.runningState());";
[email protected]f2fe87c2012-04-24 17:53:4993 std::string result;
[email protected]b27c3622014-03-22 00:26:5594 CHECK(content::ExecuteScriptAndExtractString(frame,
95 kGetAppRunningState,
96 &result));
[email protected]80675fc2011-06-21 02:05:4997 return result;
98 }
99
[email protected]a964e112011-04-14 21:52:51100 private:
[email protected]b27c3622014-03-22 00:26:55101 content::RenderFrameHost* GetIFrame() {
102 return content::FrameMatchingPredicate(
David Bokan2c77c33c2021-07-26 23:29:59103 browser()->tab_strip_model()->GetActiveWebContents()->GetPrimaryPage(),
Alex Turnerd9f1b0f2020-10-21 00:05:50104 base::BindRepeating(&content::FrameIsChildOfMainFrame));
[email protected]b27c3622014-03-22 00:26:55105 }
[email protected]a964e112011-04-14 21:52:51106};
107
nickfa2254b2015-08-07 23:27:29108IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalled) {
nickfa2254b2015-08-07 23:27:29109 GURL app_url =
110 embedded_test_server()->GetURL("app.com", "/extensions/test_file.html");
111 GURL non_app_url = embedded_test_server()->GetURL(
112 "nonapp.com", "/extensions/test_file.html");
[email protected]a964e112011-04-14 21:52:51113
[email protected]80675fc2011-06-21 02:05:49114 // Before the app is installed, app.com does not think that it is installed
Lukasz Anforowiczb78290c2021-09-08 04:31:38115 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), app_url));
[email protected]b27c3622014-03-22 00:26:55116 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51117
118 // Load an app which includes app.com in its extent.
119 const Extension* extension = LoadExtension(
120 test_data_dir_.AppendASCII("app_dot_com_app"));
121 ASSERT_TRUE(extension);
122
[email protected]80675fc2011-06-21 02:05:49123 // Even after the app is installed, the existing app.com tab is not in an
124 // app process, so chrome.app.isInstalled should return false.
[email protected]b27c3622014-03-22 00:26:55125 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51126
127 // Test that a non-app page has chrome.app.isInstalled = false.
Lukasz Anforowiczb78290c2021-09-08 04:31:38128 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), non_app_url));
[email protected]b27c3622014-03-22 00:26:55129 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51130
131 // Test that a non-app page returns null for chrome.app.getDetails().
[email protected]06bc5d92013-01-02 22:44:13132 const char kGetAppDetails[] =
133 "window.domAutomationController.send("
134 " JSON.stringify(window.chrome.app.getDetails()));";
[email protected]80675fc2011-06-21 02:05:49135 std::string result;
[email protected]a964e112011-04-14 21:52:51136 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43137 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48138 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13139 kGetAppDetails,
140 &result));
[email protected]a964e112011-04-14 21:52:51141 EXPECT_EQ("null", result);
142
143 // Check that an app page has chrome.app.isInstalled = true.
Lukasz Anforowiczb78290c2021-09-08 04:31:38144 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), app_url));
[email protected]b27c3622014-03-22 00:26:55145 EXPECT_TRUE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51146
147 // Check that an app page returns the correct result for
148 // chrome.app.getDetails().
Lukasz Anforowiczb78290c2021-09-08 04:31:38149 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), app_url));
[email protected]a964e112011-04-14 21:52:51150 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43151 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48152 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13153 kGetAppDetails,
154 &result));
dchengc963c7142016-04-08 03:55:22155 std::unique_ptr<base::DictionaryValue> app_details(
estadeb09312b2015-05-22 16:30:13156 static_cast<base::DictionaryValue*>(
Lei Zhang582ecd12019-02-13 20:28:54157 base::JSONReader::ReadDeprecated(result).release()));
[email protected]953620b2011-12-04 00:55:32158 // extension->manifest() does not contain the id.
Song Fangzhencdbb7062021-07-07 11:13:53159 app_details->RemoveKey("id");
[email protected]a964e112011-04-14 21:52:51160 EXPECT_TRUE(app_details.get());
Ghazale Hosseinabadi1830ef22022-02-08 18:44:35161 EXPECT_EQ(*app_details, *extension->manifest()->value());
[email protected]a964e112011-04-14 21:52:51162
[email protected]9b3a5c22011-05-31 08:03:13163 // Try to change app.isInstalled. Should silently fail, so
164 // that isInstalled should have the initial value.
165 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43166 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48167 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13168 "window.domAutomationController.send("
169 " function() {"
170 " var value = window.chrome.app.isInstalled;"
171 " window.chrome.app.isInstalled = !value;"
172 " if (window.chrome.app.isInstalled == value) {"
173 " return 'true';"
174 " } else {"
175 " return 'false';"
176 " }"
177 " }()"
178 ");",
179 &result));
[email protected]9b3a5c22011-05-31 08:03:13180
181 // Should not be able to alter window.chrome.app.isInstalled from javascript";
182 EXPECT_EQ("true", result);
[email protected]a964e112011-04-14 21:52:51183}
184
Devlin Cronine97d4ed2018-06-29 01:38:50185// Test accessing app.isInstalled when the context has been invalidated (e.g.
186// by removing the frame). Regression test for https://crbug.com/855853.
187IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalledFromRemovedFrame) {
188 GURL app_url =
189 embedded_test_server()->GetURL("app.com", "/extensions/test_file.html");
190 const Extension* extension =
191 LoadExtension(test_data_dir_.AppendASCII("app_dot_com_app"));
192 ASSERT_TRUE(extension);
Lukasz Anforowiczb78290c2021-09-08 04:31:38193 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), app_url));
Devlin Cronine97d4ed2018-06-29 01:38:50194
195 constexpr char kScript[] =
196 R"(var i = document.createElement('iframe');
197 i.onload = function() {
198 var frameApp = i.contentWindow.chrome.app;
199 document.body.removeChild(i);
200 var isInstalled = frameApp.isInstalled;
201 window.domAutomationController.send(
202 isInstalled === undefined);
203 };
204 i.src = '%s';
205 document.body.appendChild(i);)";
206 bool result = false;
207 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
208 browser()->tab_strip_model()->GetActiveWebContents(),
209 base::StringPrintf(kScript, app_url.spec().c_str()), &result));
210 EXPECT_TRUE(result);
211}
212
[email protected]f2fe87c2012-04-24 17:53:49213IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningState) {
nickfa2254b2015-08-07 23:27:29214 GURL app_url = embedded_test_server()->GetURL(
215 "app.com", "/extensions/get_app_details_for_frame.html");
216 GURL non_app_url = embedded_test_server()->GetURL(
217 "nonapp.com", "/extensions/get_app_details_for_frame.html");
[email protected]f2fe87c2012-04-24 17:53:49218
219 // Before the app is installed, app.com does not think that it is installed
Lukasz Anforowiczb78290c2021-09-08 04:31:38220 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), app_url));
[email protected]f2fe87c2012-04-24 17:53:49221
[email protected]b27c3622014-03-22 00:26:55222 EXPECT_EQ("not_installed", InstallStateInMainFrame());
223 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
224 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49225
226 const Extension* extension = LoadExtension(
227 test_data_dir_.AppendASCII("app_dot_com_app"));
228 ASSERT_TRUE(extension);
229
[email protected]b27c3622014-03-22 00:26:55230 EXPECT_EQ("installed", InstallStateInMainFrame());
231 EXPECT_EQ("ready_to_run", RunningStateInMainFrame());
232 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49233
234 // Reloading the page should put the tab in an app process.
Lukasz Anforowiczb78290c2021-09-08 04:31:38235 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), app_url));
[email protected]b27c3622014-03-22 00:26:55236 EXPECT_EQ("installed", InstallStateInMainFrame());
237 EXPECT_EQ("running", RunningStateInMainFrame());
238 EXPECT_TRUE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49239
240 // Disable the extension and verify the state.
Devlin Cronin251bd412018-05-30 00:55:42241 extensions::ExtensionService* service =
242 extensions::ExtensionSystem::Get(browser()->profile())
243 ->extension_service();
Minh X. Nguyen45479012017-08-18 21:35:36244 service->DisableExtension(
245 extension->id(),
246 extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE);
Lukasz Anforowiczb78290c2021-09-08 04:31:38247 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), app_url));
[email protected]f2fe87c2012-04-24 17:53:49248
[email protected]b27c3622014-03-22 00:26:55249 EXPECT_EQ("disabled", InstallStateInMainFrame());
250 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
251 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49252
[email protected]03d25812014-06-22 19:41:55253 service->EnableExtension(extension->id());
[email protected]b27c3622014-03-22 00:26:55254 EXPECT_EQ("installed", InstallStateInMainFrame());
255 EXPECT_EQ("ready_to_run", RunningStateInMainFrame());
256 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49257
258 // The non-app URL should still not be installed or running.
Lukasz Anforowiczb78290c2021-09-08 04:31:38259 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), non_app_url));
[email protected]f2fe87c2012-04-24 17:53:49260
[email protected]b27c3622014-03-22 00:26:55261 EXPECT_EQ("not_installed", InstallStateInMainFrame());
262 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
263 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49264
[email protected]b27c3622014-03-22 00:26:55265 EXPECT_EQ("installed", InstallStateInIFrame());
266 EXPECT_EQ("cannot_run", RunningStateInIFrame());
Alex Moshchuke63b9e92017-10-14 00:27:22267
268 // With --site-per-process, the iframe on nonapp.com will currently swap
269 // processes and go into the hosted app process.
270 if (content::AreAllSitesIsolatedForTesting())
271 EXPECT_TRUE(IsAppInstalledInIFrame());
272 else
273 EXPECT_FALSE(IsAppInstalledInIFrame());
[email protected]f2fe87c2012-04-24 17:53:49274}
275
276IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningStateFrame) {
nickfa2254b2015-08-07 23:27:29277 GURL app_url = embedded_test_server()->GetURL(
278 "app.com", "/extensions/get_app_details_for_frame_reversed.html");
[email protected]f2fe87c2012-04-24 17:53:49279
280 // Check the install and running state of a non-app iframe running
281 // within an app.
Lukasz Anforowiczb78290c2021-09-08 04:31:38282 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), app_url));
[email protected]f2fe87c2012-04-24 17:53:49283
[email protected]b27c3622014-03-22 00:26:55284 EXPECT_EQ("not_installed", InstallStateInIFrame());
285 EXPECT_EQ("cannot_run", RunningStateInIFrame());
286 EXPECT_FALSE(IsAppInstalledInIFrame());
[email protected]f2fe87c2012-04-24 17:53:49287}
Dave Tapuskad46d6fd62022-05-18 21:35:51288
289class ChromeAppAPIFencedFrameTest
290 : public ChromeAppAPITest,
291 public testing::WithParamInterface<bool /* shadow_dom_fenced_frame */> {
292 public:
293 ChromeAppAPIFencedFrameTest() {
294 // kPrivacySandboxAdsAPIOverride must also be set since kFencedFrames
295 // cannot be enabled independently without it.
296 feature_list_.InitWithFeaturesAndParameters(
297 {{blink::features::kFencedFrames,
298 {{"implementation_type", GetParam() ? "shadow_dom" : "mparch"}}},
299 {features::kPrivacySandboxAdsAPIsOverride, {}}},
300 {/* disabled_features */});
301 }
302
303 ~ChromeAppAPIFencedFrameTest() override = default;
304
305 void SetUpOnMainThread() override {
306 ChromeAppAPITest::SetUpOnMainThread();
307 https_server()->AddDefaultHandlers(GetChromeTestDataDir());
308 https_server()->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
309 ASSERT_TRUE(https_server()->Start());
310 }
311
312 net::EmbeddedTestServer* https_server() { return &https_server_; }
313
314 private:
315 base::test::ScopedFeatureList feature_list_;
316 net::EmbeddedTestServer https_server_{net::EmbeddedTestServer::TYPE_HTTPS};
317};
318
319IN_PROC_BROWSER_TEST_P(ChromeAppAPIFencedFrameTest, NoInfo) {
320 GURL app_url = https_server()->GetURL(
321 "a.test", "/extensions/get_app_details_for_fenced_frame.html");
322
323 // Check the install and running state of a fenced frame running
324 // within an app.
325 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), app_url));
326
327 auto render_frame_hosts = CollectAllRenderFrameHosts(
328 browser()->tab_strip_model()->GetActiveWebContents());
329 ASSERT_EQ(2u, render_frame_hosts.size());
330
331 content::RenderFrameHost* fenced_frame = render_frame_hosts.at(1);
332 ASSERT_TRUE(fenced_frame);
333 EXPECT_EQ("cannot_run", RunningStateInFrame(fenced_frame));
334}
335
336INSTANTIATE_TEST_SUITE_P(ChromeAppAPIFencedFrameTest,
337 ChromeAppAPIFencedFrameTest,
338 testing::Bool());