blob: e0ffd0578d4155a3c81598ed6ff541f55a7642e8 [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"
[email protected]a964e112011-04-14 21:52:5112#include "base/values.h"
13#include "chrome/browser/extensions/extension_browsertest.h"
[email protected]f2fe87c2012-04-24 17:53:4914#include "chrome/browser/extensions/extension_service.h"
15#include "chrome/browser/profiles/profile.h"
[email protected]a964e112011-04-14 21:52:5116#include "chrome/browser/ui/browser.h"
[email protected]47ae23372013-01-29 01:50:4817#include "chrome/browser/ui/tabs/tab_strip_model.h"
[email protected]af44e7fb2011-07-29 18:32:3218#include "chrome/test/base/ui_test_utils.h"
[email protected]4ca15302012-01-03 05:53:2019#include "content/public/browser/web_contents.h"
[email protected]7d478cb2012-07-24 17:19:4220#include "content/public/test/browser_test_utils.h"
[email protected]e4452d32013-11-15 23:07:4121#include "extensions/common/extension.h"
[email protected]d42c11152013-08-22 19:36:3222#include "extensions/common/manifest.h"
[email protected]f2cb3cf2013-03-21 01:40:5323#include "net/dns/mock_host_resolver.h"
nickfa2254b2015-08-07 23:27:2924#include "net/test/embedded_test_server/embedded_test_server.h"
[email protected]a6483d22013-07-03 22:11:0025#include "url/gurl.h"
[email protected]a964e112011-04-14 21:52:5126
[email protected]1c321ee2012-05-21 03:02:3427using extensions::Extension;
28
Devlin Cronin836f545d2018-05-09 00:25:0529class ChromeAppAPITest : public extensions::ExtensionBrowserTest {
jambb11ed742017-05-01 17:27:5930 void SetUpOnMainThread() override {
Devlin Cronin836f545d2018-05-09 00:25:0531 extensions::ExtensionBrowserTest::SetUpOnMainThread();
jambb11ed742017-05-01 17:27:5932 host_resolver()->AddRule("*", "127.0.0.1");
33 ASSERT_TRUE(embedded_test_server()->Start());
34 }
35
[email protected]80675fc2011-06-21 02:05:4936 protected:
[email protected]b27c3622014-03-22 00:26:5537 bool IsAppInstalledInMainFrame() {
38 return IsAppInstalledInFrame(
39 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
40 }
41 bool IsAppInstalledInIFrame() {
42 return IsAppInstalledInFrame(GetIFrame());
43 }
44 bool IsAppInstalledInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1345 const char kGetAppIsInstalled[] =
46 "window.domAutomationController.send(window.chrome.app.isInstalled);";
[email protected]80675fc2011-06-21 02:05:4947 bool result;
[email protected]b27c3622014-03-22 00:26:5548 CHECK(content::ExecuteScriptAndExtractBool(frame,
49 kGetAppIsInstalled,
50 &result));
[email protected]f2fe87c2012-04-24 17:53:4951 return result;
52 }
53
[email protected]b27c3622014-03-22 00:26:5554 std::string InstallStateInMainFrame() {
55 return InstallStateInFrame(
56 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
57 }
58 std::string InstallStateInIFrame() {
59 return InstallStateInFrame(GetIFrame());
60 }
61 std::string InstallStateInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1362 const char kGetAppInstallState[] =
63 "window.chrome.app.installState("
64 " function(s) { window.domAutomationController.send(s); });";
[email protected]f2fe87c2012-04-24 17:53:4965 std::string result;
[email protected]b27c3622014-03-22 00:26:5566 CHECK(content::ExecuteScriptAndExtractString(frame,
67 kGetAppInstallState,
68 &result));
[email protected]f2fe87c2012-04-24 17:53:4969 return result;
70 }
71
[email protected]b27c3622014-03-22 00:26:5572 std::string RunningStateInMainFrame() {
73 return RunningStateInFrame(
74 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
75 }
76 std::string RunningStateInIFrame() {
77 return RunningStateInFrame(GetIFrame());
78 }
79 std::string RunningStateInFrame(content::RenderFrameHost* frame) {
[email protected]06bc5d92013-01-02 22:44:1380 const char kGetAppRunningState[] =
81 "window.domAutomationController.send("
82 " window.chrome.app.runningState());";
[email protected]f2fe87c2012-04-24 17:53:4983 std::string result;
[email protected]b27c3622014-03-22 00:26:5584 CHECK(content::ExecuteScriptAndExtractString(frame,
85 kGetAppRunningState,
86 &result));
[email protected]80675fc2011-06-21 02:05:4987 return result;
88 }
89
[email protected]a964e112011-04-14 21:52:5190 private:
[email protected]b27c3622014-03-22 00:26:5591 content::RenderFrameHost* GetIFrame() {
92 return content::FrameMatchingPredicate(
93 browser()->tab_strip_model()->GetActiveWebContents(),
94 base::Bind(&content::FrameIsChildOfMainFrame));
95 }
[email protected]a964e112011-04-14 21:52:5196};
97
nickfa2254b2015-08-07 23:27:2998IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalled) {
nickfa2254b2015-08-07 23:27:2999 GURL app_url =
100 embedded_test_server()->GetURL("app.com", "/extensions/test_file.html");
101 GURL non_app_url = embedded_test_server()->GetURL(
102 "nonapp.com", "/extensions/test_file.html");
[email protected]a964e112011-04-14 21:52:51103
[email protected]80675fc2011-06-21 02:05:49104 // Before the app is installed, app.com does not think that it is installed
105 ui_test_utils::NavigateToURL(browser(), app_url);
[email protected]b27c3622014-03-22 00:26:55106 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51107
108 // Load an app which includes app.com in its extent.
109 const Extension* extension = LoadExtension(
110 test_data_dir_.AppendASCII("app_dot_com_app"));
111 ASSERT_TRUE(extension);
112
[email protected]80675fc2011-06-21 02:05:49113 // Even after the app is installed, the existing app.com tab is not in an
114 // app process, so chrome.app.isInstalled should return false.
[email protected]b27c3622014-03-22 00:26:55115 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51116
117 // Test that a non-app page has chrome.app.isInstalled = false.
118 ui_test_utils::NavigateToURL(browser(), non_app_url);
[email protected]b27c3622014-03-22 00:26:55119 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51120
121 // Test that a non-app page returns null for chrome.app.getDetails().
[email protected]06bc5d92013-01-02 22:44:13122 const char kGetAppDetails[] =
123 "window.domAutomationController.send("
124 " JSON.stringify(window.chrome.app.getDetails()));";
[email protected]80675fc2011-06-21 02:05:49125 std::string result;
[email protected]a964e112011-04-14 21:52:51126 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43127 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48128 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13129 kGetAppDetails,
130 &result));
[email protected]a964e112011-04-14 21:52:51131 EXPECT_EQ("null", result);
132
133 // Check that an app page has chrome.app.isInstalled = true.
134 ui_test_utils::NavigateToURL(browser(), app_url);
[email protected]b27c3622014-03-22 00:26:55135 EXPECT_TRUE(IsAppInstalledInMainFrame());
[email protected]a964e112011-04-14 21:52:51136
137 // Check that an app page returns the correct result for
138 // chrome.app.getDetails().
139 ui_test_utils::NavigateToURL(browser(), app_url);
140 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43141 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48142 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13143 kGetAppDetails,
144 &result));
dchengc963c7142016-04-08 03:55:22145 std::unique_ptr<base::DictionaryValue> app_details(
estadeb09312b2015-05-22 16:30:13146 static_cast<base::DictionaryValue*>(
olli.raula4d364162015-09-10 06:39:40147 base::JSONReader::Read(result).release()));
[email protected]953620b2011-12-04 00:55:32148 // extension->manifest() does not contain the id.
[email protected]a964e112011-04-14 21:52:51149 app_details->Remove("id", NULL);
150 EXPECT_TRUE(app_details.get());
[email protected]953620b2011-12-04 00:55:32151 EXPECT_TRUE(app_details->Equals(extension->manifest()->value()));
[email protected]a964e112011-04-14 21:52:51152
[email protected]9b3a5c22011-05-31 08:03:13153 // Try to change app.isInstalled. Should silently fail, so
154 // that isInstalled should have the initial value.
155 ASSERT_TRUE(
[email protected]b6987e02013-01-04 18:30:43156 content::ExecuteScriptAndExtractString(
[email protected]47ae23372013-01-29 01:50:48157 browser()->tab_strip_model()->GetActiveWebContents(),
[email protected]06bc5d92013-01-02 22:44:13158 "window.domAutomationController.send("
159 " function() {"
160 " var value = window.chrome.app.isInstalled;"
161 " window.chrome.app.isInstalled = !value;"
162 " if (window.chrome.app.isInstalled == value) {"
163 " return 'true';"
164 " } else {"
165 " return 'false';"
166 " }"
167 " }()"
168 ");",
169 &result));
[email protected]9b3a5c22011-05-31 08:03:13170
171 // Should not be able to alter window.chrome.app.isInstalled from javascript";
172 EXPECT_EQ("true", result);
[email protected]a964e112011-04-14 21:52:51173}
174
Devlin Cronine97d4ed2018-06-29 01:38:50175// Test accessing app.isInstalled when the context has been invalidated (e.g.
176// by removing the frame). Regression test for https://crbug.com/855853.
177IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalledFromRemovedFrame) {
178 GURL app_url =
179 embedded_test_server()->GetURL("app.com", "/extensions/test_file.html");
180 const Extension* extension =
181 LoadExtension(test_data_dir_.AppendASCII("app_dot_com_app"));
182 ASSERT_TRUE(extension);
183 ui_test_utils::NavigateToURL(browser(), app_url);
184
185 constexpr char kScript[] =
186 R"(var i = document.createElement('iframe');
187 i.onload = function() {
188 var frameApp = i.contentWindow.chrome.app;
189 document.body.removeChild(i);
190 var isInstalled = frameApp.isInstalled;
191 window.domAutomationController.send(
192 isInstalled === undefined);
193 };
194 i.src = '%s';
195 document.body.appendChild(i);)";
196 bool result = false;
197 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
198 browser()->tab_strip_model()->GetActiveWebContents(),
199 base::StringPrintf(kScript, app_url.spec().c_str()), &result));
200 EXPECT_TRUE(result);
201}
202
[email protected]f2fe87c2012-04-24 17:53:49203IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningState) {
nickfa2254b2015-08-07 23:27:29204 GURL app_url = embedded_test_server()->GetURL(
205 "app.com", "/extensions/get_app_details_for_frame.html");
206 GURL non_app_url = embedded_test_server()->GetURL(
207 "nonapp.com", "/extensions/get_app_details_for_frame.html");
[email protected]f2fe87c2012-04-24 17:53:49208
209 // Before the app is installed, app.com does not think that it is installed
210 ui_test_utils::NavigateToURL(browser(), app_url);
211
[email protected]b27c3622014-03-22 00:26:55212 EXPECT_EQ("not_installed", InstallStateInMainFrame());
213 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
214 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49215
216 const Extension* extension = LoadExtension(
217 test_data_dir_.AppendASCII("app_dot_com_app"));
218 ASSERT_TRUE(extension);
219
[email protected]b27c3622014-03-22 00:26:55220 EXPECT_EQ("installed", InstallStateInMainFrame());
221 EXPECT_EQ("ready_to_run", RunningStateInMainFrame());
222 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49223
224 // Reloading the page should put the tab in an app process.
225 ui_test_utils::NavigateToURL(browser(), app_url);
[email protected]b27c3622014-03-22 00:26:55226 EXPECT_EQ("installed", InstallStateInMainFrame());
227 EXPECT_EQ("running", RunningStateInMainFrame());
228 EXPECT_TRUE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49229
230 // Disable the extension and verify the state.
Devlin Cronin251bd412018-05-30 00:55:42231 extensions::ExtensionService* service =
232 extensions::ExtensionSystem::Get(browser()->profile())
233 ->extension_service();
Minh X. Nguyen45479012017-08-18 21:35:36234 service->DisableExtension(
235 extension->id(),
236 extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE);
[email protected]f2fe87c2012-04-24 17:53:49237 ui_test_utils::NavigateToURL(browser(), app_url);
238
[email protected]b27c3622014-03-22 00:26:55239 EXPECT_EQ("disabled", InstallStateInMainFrame());
240 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
241 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49242
[email protected]03d25812014-06-22 19:41:55243 service->EnableExtension(extension->id());
[email protected]b27c3622014-03-22 00:26:55244 EXPECT_EQ("installed", InstallStateInMainFrame());
245 EXPECT_EQ("ready_to_run", RunningStateInMainFrame());
246 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49247
248 // The non-app URL should still not be installed or running.
249 ui_test_utils::NavigateToURL(browser(), non_app_url);
250
[email protected]b27c3622014-03-22 00:26:55251 EXPECT_EQ("not_installed", InstallStateInMainFrame());
252 EXPECT_EQ("cannot_run", RunningStateInMainFrame());
253 EXPECT_FALSE(IsAppInstalledInMainFrame());
[email protected]f2fe87c2012-04-24 17:53:49254
[email protected]b27c3622014-03-22 00:26:55255 EXPECT_EQ("installed", InstallStateInIFrame());
256 EXPECT_EQ("cannot_run", RunningStateInIFrame());
Alex Moshchuke63b9e92017-10-14 00:27:22257
258 // With --site-per-process, the iframe on nonapp.com will currently swap
259 // processes and go into the hosted app process.
260 if (content::AreAllSitesIsolatedForTesting())
261 EXPECT_TRUE(IsAppInstalledInIFrame());
262 else
263 EXPECT_FALSE(IsAppInstalledInIFrame());
[email protected]f2fe87c2012-04-24 17:53:49264}
265
266IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningStateFrame) {
nickfa2254b2015-08-07 23:27:29267 GURL app_url = embedded_test_server()->GetURL(
268 "app.com", "/extensions/get_app_details_for_frame_reversed.html");
[email protected]f2fe87c2012-04-24 17:53:49269
270 // Check the install and running state of a non-app iframe running
271 // within an app.
272 ui_test_utils::NavigateToURL(browser(), app_url);
273
[email protected]b27c3622014-03-22 00:26:55274 EXPECT_EQ("not_installed", InstallStateInIFrame());
275 EXPECT_EQ("cannot_run", RunningStateInIFrame());
276 EXPECT_FALSE(IsAppInstalledInIFrame());
[email protected]f2fe87c2012-04-24 17:53:49277}