chrome_app_api_browsertest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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.
4
5#include <string>
6
7#include "base/command_line.h"
8#include "base/json/json_reader.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/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/browser_tabstrip.h"
17#include "chrome/common/chrome_switches.h"
18#include "chrome/common/extensions/extension.h"
19#include "chrome/common/extensions/manifest.h"
20#include "chrome/test/base/ui_test_utils.h"
21#include "content/public/browser/web_contents.h"
22#include "content/public/test/browser_test_utils.h"
23#include "googleurl/src/gurl.h"
24#include "net/base/mock_host_resolver.h"
25
26using extensions::Extension;
27
28class ChromeAppAPITest : public ExtensionBrowserTest {
29 protected:
30  bool IsAppInstalled() { return IsAppInstalled(L""); }
31  bool IsAppInstalled(const std::wstring& frame_xpath) {
32    std::wstring get_app_is_installed =
33        L"window.domAutomationController.send(window.chrome.app.isInstalled);";
34    bool result;
35    CHECK(
36        content::ExecuteJavaScriptAndExtractBool(
37            chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
38            frame_xpath, get_app_is_installed, &result));
39    return result;
40  }
41
42  std::string InstallState() { return InstallState(L""); }
43  std::string InstallState(const std::wstring& frame_xpath) {
44    std::wstring get_app_install_state =
45        L"window.chrome.app.installState("
46        L"function(s) { window.domAutomationController.send(s); });";
47    std::string result;
48    CHECK(
49        content::ExecuteJavaScriptAndExtractString(
50            chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
51            frame_xpath, get_app_install_state, &result));
52    return result;
53  }
54
55  std::string RunningState() { return RunningState(L""); }
56  std::string RunningState(const std::wstring& frame_xpath) {
57    std::wstring get_app_install_state =
58        L"window.domAutomationController.send("
59        L"window.chrome.app.runningState());";
60    std::string result;
61    CHECK(
62        content::ExecuteJavaScriptAndExtractString(
63            chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
64            frame_xpath, get_app_install_state, &result));
65    return result;
66  }
67
68 private:
69  virtual void SetUpCommandLine(CommandLine* command_line) {
70    ExtensionBrowserTest::SetUpCommandLine(command_line);
71    command_line->AppendSwitchASCII(switches::kAppsCheckoutURL,
72                                    "http://checkout.com:");
73  }
74};
75
76IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalled) {
77  std::string app_host("app.com");
78  std::string nonapp_host("nonapp.com");
79
80  host_resolver()->AddRule(app_host, "127.0.0.1");
81  host_resolver()->AddRule(nonapp_host, "127.0.0.1");
82  ASSERT_TRUE(test_server()->Start());
83
84  GURL test_file_url(test_server()->GetURL("extensions/test_file.html"));
85  GURL::Replacements replace_host;
86
87  replace_host.SetHostStr(app_host);
88  GURL app_url(test_file_url.ReplaceComponents(replace_host));
89
90  replace_host.SetHostStr(nonapp_host);
91  GURL non_app_url(test_file_url.ReplaceComponents(replace_host));
92
93  // Before the app is installed, app.com does not think that it is installed
94  ui_test_utils::NavigateToURL(browser(), app_url);
95  EXPECT_FALSE(IsAppInstalled());
96
97  // Load an app which includes app.com in its extent.
98  const Extension* extension = LoadExtension(
99      test_data_dir_.AppendASCII("app_dot_com_app"));
100  ASSERT_TRUE(extension);
101
102  // Even after the app is installed, the existing app.com tab is not in an
103  // app process, so chrome.app.isInstalled should return false.
104  EXPECT_FALSE(IsAppInstalled());
105
106  // Test that a non-app page has chrome.app.isInstalled = false.
107  ui_test_utils::NavigateToURL(browser(), non_app_url);
108  EXPECT_FALSE(IsAppInstalled());
109
110  // Test that a non-app page returns null for chrome.app.getDetails().
111  std::wstring get_app_details =
112      L"window.domAutomationController.send("
113      L"    JSON.stringify(window.chrome.app.getDetails()));";
114  std::string result;
115  ASSERT_TRUE(
116      content::ExecuteJavaScriptAndExtractString(
117          chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
118          L"", get_app_details, &result));
119  EXPECT_EQ("null", result);
120
121  // Check that an app page has chrome.app.isInstalled = true.
122  ui_test_utils::NavigateToURL(browser(), app_url);
123  EXPECT_TRUE(IsAppInstalled());
124
125  // Check that an app page returns the correct result for
126  // chrome.app.getDetails().
127  ui_test_utils::NavigateToURL(browser(), app_url);
128  ASSERT_TRUE(
129      content::ExecuteJavaScriptAndExtractString(
130          chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
131          L"", get_app_details, &result));
132  scoped_ptr<DictionaryValue> app_details(
133      static_cast<DictionaryValue*>(base::JSONReader::Read(result)));
134  // extension->manifest() does not contain the id.
135  app_details->Remove("id", NULL);
136  EXPECT_TRUE(app_details.get());
137  EXPECT_TRUE(app_details->Equals(extension->manifest()->value()));
138
139  // Try to change app.isInstalled.  Should silently fail, so
140  // that isInstalled should have the initial value.
141  ASSERT_TRUE(
142      content::ExecuteJavaScriptAndExtractString(
143          chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
144          L"",
145          L"window.domAutomationController.send("
146          L"    function() {"
147          L"        var value = window.chrome.app.isInstalled;"
148          L"        window.chrome.app.isInstalled = !value;"
149          L"        if (window.chrome.app.isInstalled == value) {"
150          L"            return 'true';"
151          L"        } else {"
152          L"            return 'false';"
153          L"        }"
154          L"    }()"
155          L");",
156         &result));
157
158  // Should not be able to alter window.chrome.app.isInstalled from javascript";
159  EXPECT_EQ("true", result);
160}
161
162IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, GetDetailsForFrame) {
163  std::string app_host("app.com");
164  std::string nonapp_host("nonapp.com");
165  std::string checkout_host("checkout.com");
166
167  host_resolver()->AddRule(app_host, "127.0.0.1");
168  host_resolver()->AddRule(nonapp_host, "127.0.0.1");
169  host_resolver()->AddRule(checkout_host, "127.0.0.1");
170  ASSERT_TRUE(test_server()->Start());
171
172  GURL test_file_url(test_server()->GetURL(
173      "files/extensions/get_app_details_for_frame.html"));
174  GURL::Replacements replace_host;
175
176  replace_host.SetHostStr(checkout_host);
177  GURL checkout_url(test_file_url.ReplaceComponents(replace_host));
178
179  replace_host.SetHostStr(app_host);
180  GURL app_url(test_file_url.ReplaceComponents(replace_host));
181
182  // Load an app which includes app.com in its extent.
183  const Extension* extension = LoadExtension(
184      test_data_dir_.AppendASCII("app_dot_com_app"));
185  ASSERT_TRUE(extension);
186
187  // Test that normal pages (even apps) cannot use getDetailsForFrame().
188  ui_test_utils::NavigateToURL(browser(), app_url);
189  std::wstring test_unsuccessful_access =
190      L"window.domAutomationController.send(window.testUnsuccessfulAccess())";
191  bool result = false;
192  ASSERT_TRUE(
193      content::ExecuteJavaScriptAndExtractBool(
194          chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
195          L"", test_unsuccessful_access, &result));
196  EXPECT_TRUE(result);
197
198  // Test that checkout can use getDetailsForFrame() and that it works
199  // correctly.
200  ui_test_utils::NavigateToURL(browser(), checkout_url);
201  std::wstring get_details_for_frame =
202      L"window.domAutomationController.send("
203      L"    JSON.stringify(chrome.app.getDetailsForFrame(frames[0])))";
204  std::string json;
205  ASSERT_TRUE(
206      content::ExecuteJavaScriptAndExtractString(
207          chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
208          L"", get_details_for_frame, &json));
209
210  scoped_ptr<DictionaryValue> app_details(
211      static_cast<DictionaryValue*>(base::JSONReader::Read(json)));
212  // extension->manifest() does not contain the id.
213  app_details->Remove("id", NULL);
214  EXPECT_TRUE(app_details.get());
215  EXPECT_TRUE(app_details->Equals(extension->manifest()->value()));
216}
217
218
219IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningState) {
220  std::string app_host("app.com");
221  std::string non_app_host("nonapp.com");
222
223  host_resolver()->AddRule(app_host, "127.0.0.1");
224  host_resolver()->AddRule(non_app_host, "127.0.0.1");
225  ASSERT_TRUE(test_server()->Start());
226
227  GURL test_file_url(test_server()->GetURL(
228      "files/extensions/get_app_details_for_frame.html"));
229  GURL::Replacements replace_host;
230
231  replace_host.SetHostStr(app_host);
232  GURL app_url(test_file_url.ReplaceComponents(replace_host));
233
234  replace_host.SetHostStr(non_app_host);
235  GURL non_app_url(test_file_url.ReplaceComponents(replace_host));
236
237  // Before the app is installed, app.com does not think that it is installed
238  ui_test_utils::NavigateToURL(browser(), app_url);
239
240  EXPECT_EQ("not_installed", InstallState());
241  EXPECT_EQ("cannot_run", RunningState());
242  EXPECT_FALSE(IsAppInstalled());
243
244  const Extension* extension = LoadExtension(
245      test_data_dir_.AppendASCII("app_dot_com_app"));
246  ASSERT_TRUE(extension);
247
248  EXPECT_EQ("installed", InstallState());
249  EXPECT_EQ("ready_to_run", RunningState());
250  EXPECT_FALSE(IsAppInstalled());
251
252  // Reloading the page should put the tab in an app process.
253  ui_test_utils::NavigateToURL(browser(), app_url);
254  EXPECT_EQ("installed", InstallState());
255  EXPECT_EQ("running", RunningState());
256  EXPECT_TRUE(IsAppInstalled());
257
258  // Disable the extension and verify the state.
259  browser()->profile()->GetExtensionService()->DisableExtension(
260      extension->id(), Extension::DISABLE_PERMISSIONS_INCREASE);
261  ui_test_utils::NavigateToURL(browser(), app_url);
262
263  EXPECT_EQ("disabled", InstallState());
264  EXPECT_EQ("cannot_run", RunningState());
265  EXPECT_FALSE(IsAppInstalled());
266
267  browser()->profile()->GetExtensionService()->EnableExtension(extension->id());
268  EXPECT_EQ("installed", InstallState());
269  EXPECT_EQ("ready_to_run", RunningState());
270  EXPECT_FALSE(IsAppInstalled());
271
272  // The non-app URL should still not be installed or running.
273  ui_test_utils::NavigateToURL(browser(), non_app_url);
274
275  EXPECT_EQ("not_installed", InstallState());
276  EXPECT_EQ("cannot_run", RunningState());
277  EXPECT_FALSE(IsAppInstalled());
278
279  EXPECT_EQ("installed", InstallState(L"//html/iframe[1]"));
280  EXPECT_EQ("cannot_run", RunningState(L"//html/iframe[1]"));
281  EXPECT_FALSE(IsAppInstalled(L"//html/iframe[1]"));
282
283}
284
285IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, InstallAndRunningStateFrame) {
286  std::string app_host("app.com");
287  std::string non_app_host("nonapp.com");
288
289  host_resolver()->AddRule(app_host, "127.0.0.1");
290  host_resolver()->AddRule(non_app_host, "127.0.0.1");
291  ASSERT_TRUE(test_server()->Start());
292
293  GURL test_file_url(test_server()->GetURL(
294      "files/extensions/get_app_details_for_frame_reversed.html"));
295  GURL::Replacements replace_host;
296
297  replace_host.SetHostStr(app_host);
298  GURL app_url(test_file_url.ReplaceComponents(replace_host));
299
300  replace_host.SetHostStr(non_app_host);
301  GURL non_app_url(test_file_url.ReplaceComponents(replace_host));
302
303  // Check the install and running state of a non-app iframe running
304  // within an app.
305  ui_test_utils::NavigateToURL(browser(), app_url);
306
307  EXPECT_EQ("not_installed", InstallState(L"//html/iframe[1]"));
308  EXPECT_EQ("cannot_run", RunningState(L"//html/iframe[1]"));
309  EXPECT_FALSE(IsAppInstalled(L"//html/iframe[1]"));
310}
311