Home | History | Annotate | Download | only in ui
      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