1 // Copyright 2016 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 HEADLESS_TEST_HEADLESS_BROWSER_TEST_H_
6 #define HEADLESS_TEST_HEADLESS_BROWSER_TEST_H_
7 
8 #include <memory>
9 #include <string>
10 
11 #include "content/public/test/browser_test_base.h"
12 #include "headless/public/devtools/domains/network.h"
13 #include "headless/public/devtools/domains/page.h"
14 #include "headless/public/headless_browser.h"
15 #include "headless/public/headless_web_contents.h"
16 #include "headless/test/test_network_interceptor.h"
17 
18 namespace base {
19 class RunLoop;
20 }
21 
22 namespace headless {
23 namespace runtime {
24 class EvaluateResult;
25 }
26 class HeadlessDevToolsClient;
27 
28 // A utility class for asynchronously observing load events.
29 class LoadObserver : public page::Observer, public network::Observer {
30  public:
31   LoadObserver(HeadlessDevToolsClient* devtools_client,
32                base::OnceClosure callback);
33   ~LoadObserver() override;
34 
35   // page::Observer implementation:
36   void OnLoadEventFired(const page::LoadEventFiredParams& params) override;
37 
38   // network::Observer implementation:
39   void OnResponseReceived(
40       const network::ResponseReceivedParams& params) override;
41 
navigation_succeeded()42   bool navigation_succeeded() const { return navigation_succeeded_; }
43 
44  private:
45   base::OnceClosure callback_;
46   HeadlessDevToolsClient* devtools_client_;  // Not owned.
47 
48   bool navigation_succeeded_;
49 
50   DISALLOW_COPY_AND_ASSIGN(LoadObserver);
51 };
52 
53 // Base class for tests which require a full instance of the headless browser.
54 class HeadlessBrowserTest : public content::BrowserTestBase {
55  public:
56   // Notify that an asynchronous test is now complete and the test runner should
57   // exit.
58   void FinishAsynchronousTest();
59 
60  protected:
61   HeadlessBrowserTest();
62   ~HeadlessBrowserTest() override;
63 
64   // BrowserTestBase:
65   void SetUp() override;
66   void PreRunTestOnMainThread() override;
67   void PostRunTestOnMainThread() override;
68 
69   // Run an asynchronous test in a nested run loop. The caller should call
70   // FinishAsynchronousTest() to notify that the test should finish.
71   void RunAsynchronousTest();
72 
73   // Synchronously waits for a tab to finish loading.
74   bool WaitForLoad(HeadlessWebContents* web_contents);
75 
76   // Synchronously waits for a tab to finish loading and to gain focus.
77   void WaitForLoadAndGainFocus(HeadlessWebContents* web_contents);
78 
79   // Synchronously evaluates a script and returns the result.
80   std::unique_ptr<runtime::EvaluateResult> EvaluateScript(
81       HeadlessWebContents* web_contents,
82       const std::string& script);
83 
84  protected:
85   // Call this instead of SetUp() to run tests without GPU rendering (i.e.,
86   // without using SwiftShader or a hardware GPU).
87   void SetUpWithoutGPU();
88 
89   // Returns the browser for the test.
90   HeadlessBrowser* browser() const;
91 
92   // Returns the options used by the browser. Modify with caution, since some
93   // options only take effect if they were set before browser creation.
94   HeadlessBrowser::Options* options() const;
95 
96  private:
97   std::unique_ptr<base::RunLoop> run_loop_;
98 
99   DISALLOW_COPY_AND_ASSIGN(HeadlessBrowserTest);
100 };
101 
102 // TODO(eseckler): Make macro more sheriff-friendly.
103 #define HEADLESS_ASYNC_DEVTOOLED_TEST_F(TEST_FIXTURE_NAME)               \
104   IN_PROC_BROWSER_TEST_F(TEST_FIXTURE_NAME, RunAsyncTest) { RunTest(); } \
105   class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {}
106 
107 #define HEADLESS_ASYNC_DEVTOOLED_TEST_P(TEST_FIXTURE_NAME)               \
108   IN_PROC_BROWSER_TEST_P(TEST_FIXTURE_NAME, RunAsyncTest) { RunTest(); } \
109   class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {}
110 
111 #define DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(TEST_FIXTURE_NAME)  \
112   IN_PROC_BROWSER_TEST_F(TEST_FIXTURE_NAME, DISABLED_RunAsyncTest) { \
113     RunTest();                                                       \
114   }                                                                  \
115   class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {}
116 
117 #define DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_P(TEST_FIXTURE_NAME)  \
118   IN_PROC_BROWSER_TEST_P(TEST_FIXTURE_NAME, DISABLED_RunAsyncTest) { \
119     RunTest();                                                       \
120   }                                                                  \
121   class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {}
122 
123 // Base class for tests that require access to a DevToolsClient. Subclasses
124 // should override the RunDevTooledTest() method, which is called asynchronously
125 // when the DevToolsClient is ready.
126 class HeadlessAsyncDevTooledBrowserTest : public HeadlessBrowserTest,
127                                           public HeadlessWebContents::Observer {
128  public:
129   HeadlessAsyncDevTooledBrowserTest();
130   ~HeadlessAsyncDevTooledBrowserTest() override;
131 
132   // HeadlessWebContentsObserver implementation:
133   void DevToolsTargetReady() override;
134   void RenderProcessExited(base::TerminationStatus status,
135                            int exit_code) override;
136 
137   // Implemented by tests and used to send request(s) to DevTools. Subclasses
138   // need to ensure that FinishAsynchronousTest() is called after response(s)
139   // are processed (e.g. in a callback).
140   virtual void RunDevTooledTest() = 0;
141 
142   // Whether to enable BeginFrameControl when creating |web_contents_|.
143   virtual bool GetEnableBeginFrameControl();
144 
145   // Allows the HeadlessBrowserContext used in testing to be customized.
146   virtual void CustomizeHeadlessBrowserContext(
147       HeadlessBrowserContext::Builder& builder);
148 
149   // Allows the HeadlessWebContents used in testing to be customized.
150   virtual void CustomizeHeadlessWebContents(
151       HeadlessWebContents::Builder& builder);
152 
153  protected:
154   void RunTest();
155 
156   HeadlessBrowserContext* browser_context_;  // Not owned.
157   HeadlessWebContents* web_contents_;
158   std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
159   std::unique_ptr<HeadlessDevToolsClient> browser_devtools_client_;
160   bool render_process_exited_;
161   std::unique_ptr<TestNetworkInterceptor> interceptor_;
162 };
163 
164 }  // namespace headless
165 
166 #endif  // HEADLESS_TEST_HEADLESS_BROWSER_TEST_H_
167