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 #ifndef CHROME_TEST_UI_UI_TEST_H_ 6 #define CHROME_TEST_UI_UI_TEST_H_ 7 8 // This file provides a common base for running UI unit tests, which operate 9 // the entire browser application in a separate process for holistic 10 // functional testing. 11 // 12 // Tests should #include this file, subclass UITest, and use the TEST_F macro 13 // to declare individual test cases. This provides a running browser window 14 // during the test, accessible through the window_ member variable. The window 15 // will close when the test ends, regardless of whether the test passed. 16 // 17 // Tests which need to launch the browser with a particular set of command-line 18 // arguments should set the value of launch_arguments_ in their constructors. 19 20 #include <string> 21 22 #include "base/command_line.h" 23 #include "base/memory/scoped_ptr.h" 24 #include "base/message_loop/message_loop.h" 25 #include "base/process/process.h" 26 #include "base/time/time.h" 27 #include "chrome/test/automation/proxy_launcher.h" 28 #include "testing/platform_test.h" 29 #include "url/gurl.h" 30 31 class AutomationProxy; 32 class BrowserProxy; 33 class GURL; 34 class TabProxy; 35 36 namespace base { 37 class DictionaryValue; 38 class FilePath; 39 } 40 41 // Base class for UI Tests. This implements the core of the functions. 42 // This base class decouples all automation functionality from testing 43 // infrastructure, for use without gtest. 44 // If using gtest, you probably want to inherit from UITest (declared below) 45 // rather than UITestBase. 46 class UITestBase { 47 public: 48 // ********* Utility functions ********* 49 50 // Launches the browser only. 51 void LaunchBrowser(); 52 53 // Launches the browser and IPC testing connection in server mode. 54 void LaunchBrowserAndServer(); 55 56 // Launches the IPC testing connection in client mode, 57 // which then attempts to connect to a browser. 58 void ConnectToRunningBrowser(); 59 60 // Only for pyauto. 61 base::TimeDelta action_timeout(); 62 int action_timeout_ms(); 63 void set_action_timeout(base::TimeDelta timeout); 64 void set_action_timeout_ms(int timeout); 65 66 // Overridable so that derived classes can provide their own ProxyLauncher. 67 virtual ProxyLauncher* CreateProxyLauncher(); 68 69 // Closes the browser and IPC testing server. 70 void CloseBrowserAndServer(); 71 72 // Launches the browser with the given command line. 73 // TODO(phajdan.jr): Make LaunchBrowser private. 74 void LaunchBrowser(const CommandLine& cmdline, bool clear_profile); 75 76 // Exits out browser instance. 77 void QuitBrowser(); 78 79 // Tells the browser to navigate to the given URL in the active tab 80 // of the first app window. 81 // This method doesn't return until the navigation is complete. 82 void NavigateToURL(const GURL& url); 83 84 // Navigate to the given URL in the active tab of the given app window. 85 void NavigateToURL(const GURL& url, int window_index); 86 87 // Same as above, except in the given tab and window. 88 void NavigateToURL(const GURL& url, int window_index, int tab_index); 89 90 // Tells the browser to navigate to the given URL in the active tab 91 // of the first app window. 92 // This method doesn't return until the |number_of_navigations| navigations 93 // complete. 94 void NavigateToURLBlockUntilNavigationsComplete(const GURL& url, 95 int number_of_navigations); 96 97 // Same as above, except in the given tab and window. 98 void NavigateToURLBlockUntilNavigationsComplete(const GURL& url, 99 int number_of_navigations, int tab_index, int window_index); 100 101 // Returns the URL of the currently active tab. Only looks in the first 102 // window, for backward compatibility. If there is no active tab, or some 103 // other error, the returned URL will be empty. 104 GURL GetActiveTabURL() { return GetActiveTabURL(0); } 105 106 // Like above, but looks at the window at the given index. 107 GURL GetActiveTabURL(int window_index); 108 109 // Returns the title of the currently active tab. Only looks in the first 110 // window, for backward compatibility. 111 std::wstring GetActiveTabTitle() { return GetActiveTabTitle(0); } 112 113 // Like above, but looks at the window at the given index. 114 std::wstring GetActiveTabTitle(int window_index); 115 116 // Returns the tabstrip index of the currently active tab in the window at 117 // the given index, or -1 on error. Only looks in the first window, for 118 // backward compatibility. 119 int GetActiveTabIndex() { return GetActiveTabIndex(0); } 120 121 // Like above, but looks at the window at the given index. 122 int GetActiveTabIndex(int window_index); 123 124 // Returns the number of tabs in the first window. If no windows exist, 125 // causes a test failure and returns 0. 126 int GetTabCount(); 127 128 // Same as GetTabCount(), except with the window at the given index. 129 int GetTabCount(int window_index); 130 131 // Polls up to kWaitForActionMaxMsec ms to attain a specific tab count. Will 132 // assert that the tab count is valid at the end of the wait. 133 void WaitUntilTabCount(int tab_count); 134 135 // Closes the specified browser. Returns true if the browser was closed. 136 // This call is blocking. |application_closed| is set to true if this was 137 // the last browser window (and therefore as a result of it closing the 138 // browser process terminated). Note that in that case this method returns 139 // after the browser process has terminated. 140 bool CloseBrowser(BrowserProxy* browser, bool* application_closed) const; 141 142 // Gets the executable file path of the Chrome browser process. 143 const base::FilePath::CharType* GetExecutablePath(); 144 145 // Return the user data directory being used by the browser instance in 146 // UITest::SetUp(). 147 base::FilePath user_data_dir() const { 148 return launcher_->user_data_dir(); 149 } 150 151 // Called by some tests that wish to have a base profile to start from. This 152 // "user data directory" (containing one or more profiles) will be recursively 153 // copied into the user data directory for the test and the files will be 154 // evicted from the OS cache. To start with a blank profile, supply an empty 155 // string (the default). 156 const base::FilePath& template_user_data() const { return template_user_data_; } 157 void set_template_user_data(const base::FilePath& template_user_data) { 158 template_user_data_ = template_user_data; 159 } 160 161 // Get the handle of browser process connected to the automation. This 162 // function only returns a reference to the handle so the caller does not 163 // own the handle returned. 164 base::ProcessHandle process() const { return launcher_->process(); } 165 166 // Return the process id of the browser process (-1 on error). 167 base::ProcessId browser_process_id() const { return launcher_->process_id(); } 168 169 // Return the time when the browser was run. 170 base::TimeTicks browser_launch_time() const { 171 return launcher_->browser_launch_time(); 172 } 173 174 // Return how long the shutdown took. 175 base::TimeDelta browser_quit_time() const { 176 return launcher_->browser_quit_time(); 177 } 178 179 // Fetch the state which determines whether the profile will be cleared on 180 // next startup. 181 bool get_clear_profile() const { 182 return clear_profile_; 183 } 184 // Sets clear_profile_. Should be called before launching browser to have 185 // any effect. 186 void set_clear_profile(bool clear_profile) { 187 clear_profile_ = clear_profile; 188 } 189 190 // homepage_ accessor. 191 std::string homepage() { 192 return homepage_; 193 } 194 195 // Sets homepage_. Should be called before launching browser to have 196 // any effect. 197 void set_homepage(const std::string& homepage) { 198 homepage_ = homepage; 199 } 200 201 void set_test_name(const std::string& name) { 202 test_name_ = name; 203 } 204 205 // Sets the shutdown type, which defaults to WINDOW_CLOSE. 206 void set_shutdown_type(ProxyLauncher::ShutdownType value) { 207 launcher_->set_shutdown_type(value); 208 } 209 210 // Get the number of crash dumps we've logged since the test started. 211 int GetCrashCount() const; 212 213 // Returns empty string if there were no unexpected Chrome asserts or crashes, 214 // a string describing the failures otherwise. As a side effect, it will fail 215 // with EXPECT_EQ macros if this code runs within a gtest harness. 216 std::string CheckErrorsAndCrashes() const; 217 218 // Use Chromium binaries from the given directory. 219 void SetBrowserDirectory(const base::FilePath& dir); 220 221 // Appends a command-line switch (no associated value) to be passed to the 222 // browser when launched. 223 void AppendBrowserLaunchSwitch(const char* name); 224 225 // Appends a command-line switch with associated value to be passed to the 226 // browser when launched. 227 void AppendBrowserLaunchSwitch(const char* name, const char* value); 228 229 // Pass-through to AutomationProxy::BeginTracing. 230 bool BeginTracing(const std::string& category_patterns); 231 232 // Pass-through to AutomationProxy::EndTracing. 233 std::string EndTracing(); 234 235 protected: 236 // String to display when a test fails because the crash service isn't 237 // running. 238 static const wchar_t kFailedNoCrashService[]; 239 240 UITestBase(); 241 explicit UITestBase(base::MessageLoop::Type msg_loop_type); 242 243 virtual ~UITestBase(); 244 245 // Starts the browser using the arguments in launch_arguments_, and 246 // sets up member variables. 247 virtual void SetUp(); 248 249 // Closes the browser window. 250 virtual void TearDown(); 251 252 virtual AutomationProxy* automation() const; 253 254 ProxyLauncher::LaunchState DefaultLaunchState(); 255 256 // Extra command-line switches that need to be passed to the browser are 257 // added in this function. Add new command-line switches here. 258 virtual void SetLaunchSwitches(); 259 260 // Called by the ProxyLauncher just before the browser is launched, allowing 261 // setup of the profile for the runtime environment.. 262 virtual void SetUpProfile(); 263 264 // Returns the proxy for the currently active tab, or NULL if there is no 265 // tab or there was some kind of error. Only looks at the first window, for 266 // backward compatibility. The returned pointer MUST be deleted by the 267 // caller if non-NULL. 268 scoped_refptr<TabProxy> GetActiveTab(); 269 270 // Like above, but looks at the window at the given index. 271 scoped_refptr<TabProxy> GetActiveTab(int window_index); 272 273 // ********* Member variables ********* 274 275 // Path to the browser executable. 276 base::FilePath browser_directory_; 277 278 // Path to the unit test data. 279 base::FilePath test_data_directory_; 280 281 // Command to launch the browser 282 CommandLine launch_arguments_; 283 284 // The number of errors expected during the run (generally 0). 285 size_t expected_errors_; 286 287 // The number of crashes expected during the run (generally 0). 288 int expected_crashes_; 289 290 // Homepage used for testing. 291 std::string homepage_; 292 293 // Name of currently running automated test passed to Chrome process. 294 std::string test_name_; 295 296 // Wait for initial loads to complete in SetUp() before running test body. 297 bool wait_for_initial_loads_; 298 299 // This can be set to true to have the test run the dom automation case. 300 bool dom_automation_enabled_; 301 302 // This can be set to true to enable the stats collection controller JS 303 // bindings. 304 bool stats_collection_controller_enabled_; 305 306 // See set_template_user_data(). 307 base::FilePath template_user_data_; 308 309 // Determines if the window is shown or hidden. Defaults to hidden. 310 bool show_window_; 311 312 // If true the profile is cleared before launching. Default is true. 313 bool clear_profile_; 314 315 // Should we supply the testing channel id 316 // on the command line? Default is true. 317 bool include_testing_id_; 318 319 // Enable file cookies, default is true. 320 bool enable_file_cookies_; 321 322 // Launches browser and AutomationProxy. 323 scoped_ptr<ProxyLauncher> launcher_; 324 325 // PID file for websocket server. 326 base::FilePath websocket_pid_file_; 327 328 private: 329 // Time the test was started (so we can check for new crash dumps) 330 base::Time test_start_time_; 331 }; 332 333 class UITest : public UITestBase, public PlatformTest { 334 protected: 335 UITest() {} 336 explicit UITest(base::MessageLoop::Type msg_loop_type) 337 : UITestBase(), PlatformTest(), message_loop_(msg_loop_type) {} 338 339 virtual void SetUp() OVERRIDE; 340 virtual void TearDown() OVERRIDE; 341 342 virtual ProxyLauncher* CreateProxyLauncher() OVERRIDE; 343 344 // Count the number of active browser processes launched by this test. 345 // The count includes browser sub-processes. 346 bool GetBrowserProcessCount(int* count) WARN_UNUSED_RESULT; 347 348 // Returns a copy of local state preferences. The caller is responsible for 349 // deleting the returned object. Returns NULL if there is an error. 350 base::DictionaryValue* GetLocalState(); 351 352 // Returns a copy of the default profile preferences. The caller is 353 // responsible for deleting the returned object. Returns NULL if there is an 354 // error. 355 base::DictionaryValue* GetDefaultProfilePreferences(); 356 357 // Waits for the test case to finish. 358 // ASSERTS if there are test failures. 359 void WaitForFinish(const std::string &name, 360 const std::string &id, const GURL &url, 361 const std::string& test_complete_cookie, 362 const std::string& expected_cookie_value, 363 const base::TimeDelta wait_time); 364 365 // Polls the tab for a JavaScript condition and returns once one of the 366 // following conditions hold true: 367 // - The JavaScript condition evaluates to true (return true). 368 // - The browser process died (return false). 369 // - The timeout value has been exceeded (return false). 370 // 371 // The JavaScript expression is executed in the context of the frame that 372 // matches the provided xpath. 373 bool WaitUntilJavaScriptCondition(TabProxy* tab, 374 const std::wstring& frame_xpath, 375 const std::wstring& jscript, 376 base::TimeDelta timeout); 377 378 // Polls the tab for the cookie_name cookie and returns once one of the 379 // following conditions hold true: 380 // - The cookie is of expected_value. 381 // - The browser process died. 382 // - The timeout value has been exceeded. 383 bool WaitUntilCookieValue(TabProxy* tab, const GURL& url, 384 const char* cookie_name, 385 base::TimeDelta timeout, 386 const char* expected_value); 387 388 // Polls the tab for the cookie_name cookie and returns once one of the 389 // following conditions hold true: 390 // - The cookie is set to any value. 391 // - The browser process died. 392 // - The timeout value has been exceeded. 393 std::string WaitUntilCookieNonEmpty(TabProxy* tab, 394 const GURL& url, 395 const char* cookie_name, 396 base::TimeDelta timeout); 397 398 // Waits until the Find window has become fully visible (if |wait_for_open| is 399 // true) or fully hidden (if |wait_for_open| is false). This function can time 400 // out (return false) if the window doesn't appear within a specific time. 401 bool WaitForFindWindowVisibilityChange(BrowserProxy* browser, 402 bool wait_for_open); 403 404 // Terminates the browser, simulates end of session. 405 void TerminateBrowser(); 406 407 // Tells the browser to navigate to the given URL in the active tab 408 // of the first app window. 409 // Does not wait for the navigation to complete to return. 410 // To avoid intermittent test failures, use NavigateToURL instead, if 411 // possible. 412 void NavigateToURLAsync(const GURL& url); 413 414 private: 415 base::MessageLoop message_loop_; // Enables PostTask to main thread. 416 }; 417 418 // These exist only to support the gTest assertion macros, and 419 // shouldn't be used in normal program code. 420 #ifdef UNIT_TEST 421 std::ostream& operator<<(std::ostream& out, const std::wstring& wstr); 422 423 template<typename T> 424 std::ostream& operator<<(std::ostream& out, const ::scoped_ptr<T>& ptr) { 425 return out << ptr.get(); 426 } 427 #endif // UNIT_TEST 428 429 #endif // CHROME_TEST_UI_UI_TEST_H_ 430