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