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