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