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
31class AutomationProxy;
32class BrowserProxy;
33class GURL;
34class TabProxy;
35
36namespace base {
37class DictionaryValue;
38class 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.
46class 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
333class 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
421std::ostream& operator<<(std::ostream& out, const std::wstring& wstr);
422
423template<typename T>
424std::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