skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 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 | |
mostynb | c3d183b | 2016-04-04 11:02:45 | [diff] [blame] | 5 | #include <memory> |
eseckler | 9ef5476 | 2016-06-03 17:28:38 | [diff] [blame] | 6 | #include <string> |
| 7 | #include <vector> |
mostynb | c3d183b | 2016-04-04 11:02:45 | [diff] [blame] | 8 | |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 9 | #include "base/base64.h" |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 10 | #include "base/command_line.h" |
alexclarke | 1a4a3bab | 2017-05-24 16:07:42 | [diff] [blame] | 11 | #include "base/json/json_writer.h" |
Johannes Henkel | ed0e5da | 2018-05-30 22:55:18 | [diff] [blame] | 12 | #include "base/logging.h" |
Gabriel Charette | 078e366 | 2017-08-28 22:59:04 | [diff] [blame] | 13 | #include "base/run_loop.h" |
Alex Clarke | 51a354ae | 2017-07-12 11:04:44 | [diff] [blame] | 14 | #include "base/strings/stringprintf.h" |
Eric Seckler | 9781fb9 | 2018-03-01 15:27:33 | [diff] [blame] | 15 | #include "base/test/scoped_feature_list.h" |
Eric Seckler | 82ad0e9 | 2017-07-17 15:52:22 | [diff] [blame] | 16 | #include "build/build_config.h" |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 17 | #include "cc/base/switches.h" |
Eric Seckler | 9781fb9 | 2018-03-01 15:27:33 | [diff] [blame] | 18 | #include "components/viz/common/features.h" |
Eric Seckler | 5b74eba | 2018-02-21 18:41:44 | [diff] [blame] | 19 | #include "components/viz/common/switches.h" |
Eric Seckler | 82ad0e9 | 2017-07-17 15:52:22 | [diff] [blame] | 20 | #include "content/public/browser/web_contents.h" |
Eric Seckler | 7b9e995 | 2017-11-14 19:08:31 | [diff] [blame] | 21 | #include "content/public/common/content_switches.h" |
skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 22 | #include "content/public/test/browser_test.h" |
Eric Seckler | 48f8a07 | 2017-06-20 14:28:36 | [diff] [blame] | 23 | #include "headless/lib/browser/headless_web_contents_impl.h" |
Eric Seckler | 1cbd8e0 | 2018-04-27 03:17:34 | [diff] [blame] | 24 | #include "headless/public/devtools/domains/browser.h" |
Alex Clarke | 51a354ae | 2017-07-12 11:04:44 | [diff] [blame] | 25 | #include "headless/public/devtools/domains/dom_snapshot.h" |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 26 | #include "headless/public/devtools/domains/emulation.h" |
| 27 | #include "headless/public/devtools/domains/headless_experimental.h" |
altimin | eaffa8e0 | 2016-11-08 23:56:31 | [diff] [blame] | 28 | #include "headless/public/devtools/domains/page.h" |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 29 | #include "headless/public/devtools/domains/runtime.h" |
eseckler | f2531a5 | 2016-11-17 20:20:52 | [diff] [blame] | 30 | #include "headless/public/devtools/domains/security.h" |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 31 | #include "headless/public/devtools/domains/target.h" |
skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 32 | #include "headless/public/headless_browser.h" |
eseckler | 9ef5476 | 2016-06-03 17:28:38 | [diff] [blame] | 33 | #include "headless/public/headless_devtools_client.h" |
skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 34 | #include "headless/public/headless_web_contents.h" |
| 35 | #include "headless/test/headless_browser_test.h" |
Scott Violet | 318a55f | 2018-03-30 19:08:19 | [diff] [blame] | 36 | #include "printing/buildflags/buildflags.h" |
altimin | bf875c9 | 2016-08-04 17:09:07 | [diff] [blame] | 37 | #include "testing/gmock/include/gmock/gmock.h" |
skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 38 | #include "testing/gtest/include/gtest/gtest.h" |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 39 | #include "third_party/skia/include/core/SkBitmap.h" |
| 40 | #include "third_party/skia/include/core/SkColor.h" |
| 41 | #include "ui/gfx/codec/png_codec.h" |
skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 42 | #include "ui/gfx/geometry/size.h" |
| 43 | #include "url/gurl.h" |
| 44 | |
Lei Zhang | 48a4a526 | 2018-04-17 20:18:44 | [diff] [blame] | 45 | #if BUILDFLAG(ENABLE_PRINTING) |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 46 | #include "base/strings/string_number_conversions.h" |
| 47 | #include "pdf/pdf.h" |
| 48 | #include "printing/pdf_render_settings.h" |
| 49 | #include "printing/units.h" |
| 50 | #include "ui/gfx/geometry/rect.h" |
| 51 | #endif |
| 52 | |
alexclarke | fb9a235 | 2017-05-25 14:19:19 | [diff] [blame] | 53 | using testing::ElementsAre; |
Alex Clarke | 9155a34 | 2017-09-15 10:56:59 | [diff] [blame] | 54 | using testing::ElementsAreArray; |
| 55 | using testing::Not; |
altimin | bf875c9 | 2016-08-04 17:09:07 | [diff] [blame] | 56 | using testing::UnorderedElementsAre; |
Alex Clarke | 9155a34 | 2017-09-15 10:56:59 | [diff] [blame] | 57 | using testing::UnorderedElementsAreArray; |
altimin | bf875c9 | 2016-08-04 17:09:07 | [diff] [blame] | 58 | |
skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 59 | namespace headless { |
skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 60 | class HeadlessWebContentsTest : public HeadlessBrowserTest {}; |
| 61 | |
skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 62 | IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, Navigation) { |
| 63 | EXPECT_TRUE(embedded_test_server()->Start()); |
eseckler | 9ef5476 | 2016-06-03 17:28:38 | [diff] [blame] | 64 | |
altimin | bf875c9 | 2016-08-04 17:09:07 | [diff] [blame] | 65 | HeadlessBrowserContext* browser_context = |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 66 | browser()->CreateBrowserContextBuilder().Build(); |
| 67 | |
skyostil | 25c2c012 | 2016-06-09 12:54:12 | [diff] [blame] | 68 | HeadlessWebContents* web_contents = |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 69 | browser_context->CreateWebContentsBuilder() |
skyostil | 25c2c012 | 2016-06-09 12:54:12 | [diff] [blame] | 70 | .SetInitialURL(embedded_test_server()->GetURL("/hello.html")) |
| 71 | .Build(); |
skyostil | 585fa60 | 2016-04-25 16:07:56 | [diff] [blame] | 72 | EXPECT_TRUE(WaitForLoad(web_contents)); |
altimin | b6d2d1fc | 2016-04-21 15:23:22 | [diff] [blame] | 73 | |
altimin | bf875c9 | 2016-08-04 17:09:07 | [diff] [blame] | 74 | EXPECT_THAT(browser_context->GetAllWebContents(), |
| 75 | UnorderedElementsAre(web_contents)); |
altimin | b6d2d1fc | 2016-04-21 15:23:22 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, WindowOpen) { |
| 79 | EXPECT_TRUE(embedded_test_server()->Start()); |
| 80 | |
altimin | bf875c9 | 2016-08-04 17:09:07 | [diff] [blame] | 81 | HeadlessBrowserContext* browser_context = |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 82 | browser()->CreateBrowserContextBuilder().Build(); |
| 83 | |
skyostil | 25c2c012 | 2016-06-09 12:54:12 | [diff] [blame] | 84 | HeadlessWebContents* web_contents = |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 85 | browser_context->CreateWebContentsBuilder() |
skyostil | 25c2c012 | 2016-06-09 12:54:12 | [diff] [blame] | 86 | .SetInitialURL(embedded_test_server()->GetURL("/window_open.html")) |
| 87 | .Build(); |
skyostil | 585fa60 | 2016-04-25 16:07:56 | [diff] [blame] | 88 | EXPECT_TRUE(WaitForLoad(web_contents)); |
altimin | b6d2d1fc | 2016-04-21 15:23:22 | [diff] [blame] | 89 | |
Eric Seckler | 48f8a07 | 2017-06-20 14:28:36 | [diff] [blame] | 90 | EXPECT_EQ(2u, browser_context->GetAllWebContents().size()); |
| 91 | |
Johannes Henkel | ed0e5da | 2018-05-30 22:55:18 | [diff] [blame] | 92 | HeadlessWebContentsImpl* child = nullptr; |
| 93 | HeadlessWebContentsImpl* parent = nullptr; |
| 94 | for (HeadlessWebContents* c : browser_context->GetAllWebContents()) { |
| 95 | HeadlessWebContentsImpl* impl = HeadlessWebContentsImpl::From(c); |
| 96 | if (impl->window_id() == 1) |
| 97 | parent = impl; |
| 98 | else if (impl->window_id() == 2) |
| 99 | child = impl; |
| 100 | } |
| 101 | |
Eric Seckler | 48f8a07 | 2017-06-20 14:28:36 | [diff] [blame] | 102 | EXPECT_NE(nullptr, parent); |
| 103 | EXPECT_NE(nullptr, child); |
| 104 | EXPECT_NE(parent, child); |
| 105 | |
| 106 | // Mac doesn't have WindowTreeHosts. |
| 107 | if (parent && child && parent->window_tree_host()) |
| 108 | EXPECT_NE(parent->window_tree_host(), child->window_tree_host()); |
Eric Seckler | 82ad0e9 | 2017-07-17 15:52:22 | [diff] [blame] | 109 | |
| 110 | gfx::Rect expected_bounds(0, 0, 200, 100); |
| 111 | #if !defined(OS_MACOSX) |
| 112 | EXPECT_EQ(expected_bounds, child->web_contents()->GetViewBounds()); |
| 113 | EXPECT_EQ(expected_bounds, child->web_contents()->GetContainerBounds()); |
| 114 | #else // !defined(OS_MACOSX) |
| 115 | // Mac does not support GetViewBounds() and view positions are random. |
| 116 | EXPECT_EQ(expected_bounds.size(), |
| 117 | child->web_contents()->GetContainerBounds().size()); |
| 118 | #endif // !defined(OS_MACOSX) |
Eric Seckler | 48f8a07 | 2017-06-20 14:28:36 | [diff] [blame] | 119 | } |
| 120 | |
Johannes Henkel | 03212fe | 2018-04-25 17:34:32 | [diff] [blame] | 121 | IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, |
| 122 | FocusOfHeadlessWebContents_IsIndependent) { |
irisu | 559af091 | 2017-02-28 13:10:34 | [diff] [blame] | 123 | EXPECT_TRUE(embedded_test_server()->Start()); |
| 124 | |
| 125 | HeadlessBrowserContext* browser_context = |
| 126 | browser()->CreateBrowserContextBuilder().Build(); |
| 127 | |
| 128 | HeadlessWebContents* web_contents = |
| 129 | browser_context->CreateWebContentsBuilder() |
| 130 | .SetInitialURL(embedded_test_server()->GetURL("/hello.html")) |
| 131 | .Build(); |
arthursonzogni | b3a06c1b | 2018-05-14 11:52:35 | [diff] [blame] | 132 | WaitForLoadAndGainFocus(web_contents); |
irisu | 559af091 | 2017-02-28 13:10:34 | [diff] [blame] | 133 | |
Alex Clarke | 1dbb609 | 2017-10-18 16:53:34 | [diff] [blame] | 134 | std::unique_ptr<runtime::EvaluateResult> has_focus = |
| 135 | EvaluateScript(web_contents, "document.hasFocus()"); |
| 136 | EXPECT_TRUE(has_focus->GetResult()->GetValue()->GetBool()); |
irisu | 559af091 | 2017-02-28 13:10:34 | [diff] [blame] | 137 | |
| 138 | HeadlessWebContents* web_contents2 = |
| 139 | browser_context->CreateWebContentsBuilder() |
| 140 | .SetInitialURL(embedded_test_server()->GetURL("/hello.html")) |
| 141 | .Build(); |
arthursonzogni | b3a06c1b | 2018-05-14 11:52:35 | [diff] [blame] | 142 | WaitForLoadAndGainFocus(web_contents2); |
irisu | 559af091 | 2017-02-28 13:10:34 | [diff] [blame] | 143 | |
eseckler | c09e399 | 2017-04-03 13:10:36 | [diff] [blame] | 144 | // Focus of different WebContents is independent. |
Alex Clarke | 1dbb609 | 2017-10-18 16:53:34 | [diff] [blame] | 145 | has_focus = EvaluateScript(web_contents, "document.hasFocus()"); |
| 146 | EXPECT_TRUE(has_focus->GetResult()->GetValue()->GetBool()); |
| 147 | |
| 148 | has_focus = EvaluateScript(web_contents2, "document.hasFocus()"); |
| 149 | EXPECT_TRUE(has_focus->GetResult()->GetValue()->GetBool()); |
irisu | 559af091 | 2017-02-28 13:10:34 | [diff] [blame] | 150 | } |
| 151 | |
sushkov | fd9f294 | 2017-05-09 04:34:36 | [diff] [blame] | 152 | IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, HandleSSLError) { |
| 153 | net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| 154 | https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED); |
| 155 | ASSERT_TRUE(https_server.Start()); |
| 156 | |
| 157 | HeadlessBrowserContext* browser_context = |
| 158 | browser()->CreateBrowserContextBuilder().Build(); |
| 159 | |
| 160 | HeadlessWebContents* web_contents = |
| 161 | browser_context->CreateWebContentsBuilder() |
| 162 | .SetInitialURL(https_server.GetURL("/hello.html")) |
| 163 | .Build(); |
| 164 | |
| 165 | EXPECT_FALSE(WaitForLoad(web_contents)); |
| 166 | } |
| 167 | |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 168 | namespace { |
| 169 | bool DecodePNG(std::string base64_data, SkBitmap* bitmap) { |
| 170 | std::string png_data; |
| 171 | if (!base::Base64Decode(base64_data, &png_data)) |
| 172 | return false; |
| 173 | return gfx::PNGCodec::Decode( |
| 174 | reinterpret_cast<unsigned const char*>(png_data.data()), png_data.size(), |
| 175 | bitmap); |
| 176 | } |
| 177 | } // namespace |
| 178 | |
| 179 | // Parameter specifies whether --disable-gpu should be used. |
eseckler | 9ef5476 | 2016-06-03 17:28:38 | [diff] [blame] | 180 | class HeadlessWebContentsScreenshotTest |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 181 | : public HeadlessAsyncDevTooledBrowserTest, |
| 182 | public ::testing::WithParamInterface<bool> { |
eseckler | 9ef5476 | 2016-06-03 17:28:38 | [diff] [blame] | 183 | public: |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 184 | void SetUp() override { |
| 185 | EnablePixelOutput(); |
Sami Kyostila | d99a966 | 2017-06-06 09:09:17 | [diff] [blame] | 186 | if (GetParam()) { |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 187 | UseSoftwareCompositing(); |
Sami Kyostila | d99a966 | 2017-06-06 09:09:17 | [diff] [blame] | 188 | SetUpWithoutGPU(); |
| 189 | } else { |
| 190 | HeadlessAsyncDevTooledBrowserTest::SetUp(); |
| 191 | } |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 192 | } |
| 193 | |
eseckler | 9ef5476 | 2016-06-03 17:28:38 | [diff] [blame] | 194 | void RunDevTooledTest() override { |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 195 | std::unique_ptr<runtime::EvaluateParams> params = |
| 196 | runtime::EvaluateParams::Builder() |
| 197 | .SetExpression("document.body.style.background = '#0000ff'") |
| 198 | .Build(); |
| 199 | devtools_client_->GetRuntime()->Evaluate( |
| 200 | std::move(params), |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 201 | base::BindOnce(&HeadlessWebContentsScreenshotTest::OnPageSetupCompleted, |
| 202 | base::Unretained(this))); |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 203 | } |
| 204 | |
| 205 | void OnPageSetupCompleted(std::unique_ptr<runtime::EvaluateResult> result) { |
eseckler | 9ef5476 | 2016-06-03 17:28:38 | [diff] [blame] | 206 | devtools_client_->GetPage()->GetExperimental()->CaptureScreenshot( |
dvallet | b7b00695 | 2017-05-24 08:04:43 | [diff] [blame] | 207 | page::CaptureScreenshotParams::Builder().Build(), |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 208 | base::BindOnce(&HeadlessWebContentsScreenshotTest::OnScreenshotCaptured, |
| 209 | base::Unretained(this))); |
eseckler | 9ef5476 | 2016-06-03 17:28:38 | [diff] [blame] | 210 | } |
| 211 | |
| 212 | void OnScreenshotCaptured( |
| 213 | std::unique_ptr<page::CaptureScreenshotResult> result) { |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 214 | std::string base64 = result->GetData(); |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 215 | EXPECT_GT(base64.length(), 0U); |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 216 | SkBitmap result_bitmap; |
| 217 | EXPECT_TRUE(DecodePNG(base64, &result_bitmap)); |
| 218 | |
| 219 | EXPECT_EQ(800, result_bitmap.width()); |
| 220 | EXPECT_EQ(600, result_bitmap.height()); |
| 221 | SkColor actual_color = result_bitmap.getColor(400, 300); |
| 222 | SkColor expected_color = SkColorSetRGB(0x00, 0x00, 0xff); |
| 223 | EXPECT_EQ(expected_color, actual_color); |
eseckler | 9ef5476 | 2016-06-03 17:28:38 | [diff] [blame] | 224 | FinishAsynchronousTest(); |
| 225 | } |
| 226 | }; |
| 227 | |
eseckler | d2869ff | 2017-01-19 14:46:21 | [diff] [blame] | 228 | HEADLESS_ASYNC_DEVTOOLED_TEST_P(HeadlessWebContentsScreenshotTest); |
| 229 | |
| 230 | // Instantiate test case for both software and gpu compositing modes. |
| 231 | INSTANTIATE_TEST_CASE_P(HeadlessWebContentsScreenshotTests, |
| 232 | HeadlessWebContentsScreenshotTest, |
| 233 | ::testing::Bool()); |
eseckler | 9ef5476 | 2016-06-03 17:28:38 | [diff] [blame] | 234 | |
Eric Seckler | 1cbd8e0 | 2018-04-27 03:17:34 | [diff] [blame] | 235 | // Regression test for crbug.com/832138. |
| 236 | class HeadlessWebContentsScreenshotWindowPositionTest |
| 237 | : public HeadlessWebContentsScreenshotTest { |
| 238 | public: |
| 239 | void RunDevTooledTest() override { |
| 240 | browser_devtools_client_->GetBrowser()->GetExperimental()->SetWindowBounds( |
| 241 | browser::SetWindowBoundsParams::Builder() |
| 242 | .SetWindowId( |
| 243 | HeadlessWebContentsImpl::From(web_contents_)->window_id()) |
| 244 | .SetBounds(browser::Bounds::Builder() |
| 245 | .SetLeft(600) |
| 246 | .SetTop(100) |
| 247 | .SetWidth(800) |
| 248 | .SetHeight(600) |
| 249 | .Build()) |
| 250 | .Build(), |
| 251 | base::BindOnce( |
| 252 | &HeadlessWebContentsScreenshotWindowPositionTest::OnWindowBoundsSet, |
| 253 | base::Unretained(this))); |
| 254 | } |
| 255 | |
| 256 | void OnWindowBoundsSet( |
| 257 | std::unique_ptr<browser::SetWindowBoundsResult> result) { |
| 258 | EXPECT_TRUE(result); |
| 259 | HeadlessWebContentsScreenshotTest::RunDevTooledTest(); |
| 260 | } |
| 261 | }; |
| 262 | |
| 263 | HEADLESS_ASYNC_DEVTOOLED_TEST_P( |
| 264 | HeadlessWebContentsScreenshotWindowPositionTest); |
| 265 | |
| 266 | // Instantiate test case for both software and gpu compositing modes. |
| 267 | INSTANTIATE_TEST_CASE_P(HeadlessWebContentsScreenshotWindowPositionTests, |
| 268 | HeadlessWebContentsScreenshotWindowPositionTest, |
| 269 | ::testing::Bool()); |
| 270 | |
Lei Zhang | 48a4a526 | 2018-04-17 20:18:44 | [diff] [blame] | 271 | #if BUILDFLAG(ENABLE_PRINTING) |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 272 | class HeadlessWebContentsPDFTest : public HeadlessAsyncDevTooledBrowserTest { |
| 273 | public: |
| 274 | const double kPaperWidth = 10; |
| 275 | const double kPaperHeight = 15; |
| 276 | const double kDocHeight = 50; |
| 277 | // Number of color channels in a BGRA bitmap. |
| 278 | const int kColorChannels = 4; |
| 279 | const int kDpi = 300; |
| 280 | |
| 281 | void RunDevTooledTest() override { |
| 282 | std::string height_expression = "document.body.style.height = '" + |
Brett Wilson | 5ed06e7 | 2017-12-01 01:25:11 | [diff] [blame] | 283 | base::NumberToString(kDocHeight) + "in'"; |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 284 | std::unique_ptr<runtime::EvaluateParams> params = |
| 285 | runtime::EvaluateParams::Builder() |
| 286 | .SetExpression("document.body.style.background = '#123456';" + |
| 287 | height_expression) |
| 288 | .Build(); |
| 289 | devtools_client_->GetRuntime()->Evaluate( |
| 290 | std::move(params), |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 291 | base::BindOnce(&HeadlessWebContentsPDFTest::OnPageSetupCompleted, |
| 292 | base::Unretained(this))); |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 293 | } |
| 294 | |
| 295 | void OnPageSetupCompleted(std::unique_ptr<runtime::EvaluateResult> result) { |
| 296 | devtools_client_->GetPage()->GetExperimental()->PrintToPDF( |
| 297 | page::PrintToPDFParams::Builder() |
| 298 | .SetPrintBackground(true) |
| 299 | .SetPaperHeight(kPaperHeight) |
| 300 | .SetPaperWidth(kPaperWidth) |
| 301 | .SetMarginTop(0) |
| 302 | .SetMarginBottom(0) |
| 303 | .SetMarginLeft(0) |
| 304 | .SetMarginRight(0) |
| 305 | .Build(), |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 306 | base::BindOnce(&HeadlessWebContentsPDFTest::OnPDFCreated, |
| 307 | base::Unretained(this))); |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 308 | } |
| 309 | |
| 310 | void OnPDFCreated(std::unique_ptr<page::PrintToPDFResult> result) { |
| 311 | std::string base64 = result->GetData(); |
| 312 | EXPECT_GT(base64.length(), 0U); |
| 313 | std::string pdf_data; |
| 314 | EXPECT_TRUE(base::Base64Decode(base64, &pdf_data)); |
| 315 | |
Lei Zhang | 0b00ad4 | 2018-07-24 02:22:41 | [diff] [blame] | 316 | auto pdf_span = base::as_bytes(base::make_span(pdf_data)); |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 317 | int num_pages; |
Lei Zhang | 0b00ad4 | 2018-07-24 02:22:41 | [diff] [blame] | 318 | EXPECT_TRUE(chrome_pdf::GetPDFDocInfo(pdf_span, &num_pages, nullptr)); |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 319 | EXPECT_EQ(std::ceil(kDocHeight / kPaperHeight), num_pages); |
| 320 | |
| 321 | for (int i = 0; i < num_pages; i++) { |
| 322 | double width_in_points; |
| 323 | double height_in_points; |
| 324 | EXPECT_TRUE(chrome_pdf::GetPDFPageSizeByIndex( |
Lei Zhang | 0b00ad4 | 2018-07-24 02:22:41 | [diff] [blame] | 325 | pdf_span, i, &width_in_points, &height_in_points)); |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 326 | EXPECT_EQ(static_cast<int>(width_in_points), |
| 327 | static_cast<int>(kPaperWidth * printing::kPointsPerInch)); |
| 328 | EXPECT_EQ(static_cast<int>(height_in_points), |
| 329 | static_cast<int>(kPaperHeight * printing::kPointsPerInch)); |
| 330 | |
| 331 | gfx::Rect rect(kPaperWidth * kDpi, kPaperHeight * kDpi); |
| 332 | printing::PdfRenderSettings settings( |
Lei Zhang | 5c50048 | 2018-04-12 07:34:16 | [diff] [blame] | 333 | rect, gfx::Point(0, 0), gfx::Size(kDpi, kDpi), /*autorotate=*/true, |
| 334 | /*use_color=*/true, printing::PdfRenderSettings::Mode::NORMAL); |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 335 | std::vector<uint8_t> page_bitmap_data(kColorChannels * |
| 336 | settings.area.size().GetArea()); |
| 337 | EXPECT_TRUE(chrome_pdf::RenderPDFPageToBitmap( |
Lei Zhang | 0b00ad4 | 2018-07-24 02:22:41 | [diff] [blame] | 338 | pdf_span, i, page_bitmap_data.data(), settings.area.size().width(), |
| 339 | settings.area.size().height(), settings.dpi.width(), |
| 340 | settings.dpi.height(), settings.autorotate, settings.use_color)); |
jzfeng | 3d83dad | 2017-05-09 03:44:18 | [diff] [blame] | 341 | EXPECT_EQ(0x56, page_bitmap_data[0]); // B |
| 342 | EXPECT_EQ(0x34, page_bitmap_data[1]); // G |
| 343 | EXPECT_EQ(0x12, page_bitmap_data[2]); // R |
| 344 | } |
| 345 | FinishAsynchronousTest(); |
| 346 | } |
| 347 | }; |
| 348 | |
| 349 | HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessWebContentsPDFTest); |
| 350 | #endif |
| 351 | |
eseckler | f2531a5 | 2016-11-17 20:20:52 | [diff] [blame] | 352 | class HeadlessWebContentsSecurityTest |
| 353 | : public HeadlessAsyncDevTooledBrowserTest, |
| 354 | public security::ExperimentalObserver { |
| 355 | public: |
| 356 | void RunDevTooledTest() override { |
| 357 | devtools_client_->GetSecurity()->GetExperimental()->AddObserver(this); |
| 358 | devtools_client_->GetSecurity()->GetExperimental()->Enable( |
| 359 | security::EnableParams::Builder().Build()); |
| 360 | } |
| 361 | |
| 362 | void OnSecurityStateChanged( |
| 363 | const security::SecurityStateChangedParams& params) override { |
| 364 | EXPECT_EQ(security::SecurityState::NEUTRAL, params.GetSecurityState()); |
eseckler | f2531a5 | 2016-11-17 20:20:52 | [diff] [blame] | 365 | |
eseckler | 76edc3b4 | 2017-01-19 14:36:05 | [diff] [blame] | 366 | devtools_client_->GetSecurity()->GetExperimental()->Disable( |
| 367 | security::DisableParams::Builder().Build()); |
| 368 | devtools_client_->GetSecurity()->GetExperimental()->RemoveObserver(this); |
eseckler | f2531a5 | 2016-11-17 20:20:52 | [diff] [blame] | 369 | FinishAsynchronousTest(); |
| 370 | } |
| 371 | }; |
| 372 | |
Eric Seckler | ea51c9c | 2017-07-18 20:47:56 | [diff] [blame] | 373 | // Regression test for https://crbug.com/733569. |
| 374 | class HeadlessWebContentsRequestStorageQuotaTest |
| 375 | : public HeadlessAsyncDevTooledBrowserTest, |
| 376 | public runtime::Observer { |
| 377 | public: |
| 378 | void RunDevTooledTest() override { |
| 379 | EXPECT_TRUE(embedded_test_server()->Start()); |
| 380 | |
Gabriel Charette | 6040439 | 2017-11-09 15:52:40 | [diff] [blame] | 381 | base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); |
Eric Seckler | ea51c9c | 2017-07-18 20:47:56 | [diff] [blame] | 382 | devtools_client_->GetRuntime()->AddObserver(this); |
| 383 | devtools_client_->GetRuntime()->Enable(run_loop.QuitClosure()); |
| 384 | run_loop.Run(); |
| 385 | |
| 386 | // Should not crash and call console.log() if quota request succeeds. |
| 387 | devtools_client_->GetPage()->Navigate( |
| 388 | embedded_test_server()->GetURL("/request_storage_quota.html").spec()); |
| 389 | } |
| 390 | |
| 391 | void OnConsoleAPICalled( |
| 392 | const runtime::ConsoleAPICalledParams& params) override { |
| 393 | FinishAsynchronousTest(); |
| 394 | } |
| 395 | }; |
| 396 | |
| 397 | HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessWebContentsRequestStorageQuotaTest); |
| 398 | |
Luca Versari | 4128efc | 2017-08-04 13:33:22 | [diff] [blame] | 399 | IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, BrowserTabChangeContent) { |
| 400 | EXPECT_TRUE(embedded_test_server()->Start()); |
| 401 | |
| 402 | HeadlessBrowserContext* browser_context = |
| 403 | browser()->CreateBrowserContextBuilder().Build(); |
| 404 | |
| 405 | HeadlessWebContents* web_contents = |
| 406 | browser_context->CreateWebContentsBuilder().Build(); |
| 407 | EXPECT_TRUE(WaitForLoad(web_contents)); |
| 408 | |
| 409 | std::string script = "window.location = '" + |
| 410 | embedded_test_server()->GetURL("/hello.html").spec() + |
| 411 | "';"; |
| 412 | EXPECT_FALSE(EvaluateScript(web_contents, script)->HasExceptionDetails()); |
| 413 | |
| 414 | // This will time out if the previous script did not work. |
| 415 | EXPECT_TRUE(WaitForLoad(web_contents)); |
| 416 | } |
| 417 | |
| 418 | IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, BrowserOpenInTab) { |
| 419 | EXPECT_TRUE(embedded_test_server()->Start()); |
| 420 | |
| 421 | HeadlessBrowserContext* browser_context = |
| 422 | browser()->CreateBrowserContextBuilder().Build(); |
| 423 | |
Luca Versari | 4128efc | 2017-08-04 13:33:22 | [diff] [blame] | 424 | HeadlessWebContents* web_contents = |
| 425 | browser_context->CreateWebContentsBuilder() |
| 426 | .SetInitialURL(embedded_test_server()->GetURL("/link.html")) |
| 427 | .Build(); |
| 428 | EXPECT_TRUE(WaitForLoad(web_contents)); |
| 429 | |
| 430 | EXPECT_EQ(1u, browser_context->GetAllWebContents().size()); |
| 431 | // Simulates a middle-button click on a link to ensure that the |
| 432 | // link is opened in a new tab by the browser and not by the renderer. |
| 433 | std::string script = |
| 434 | "var event = new MouseEvent('click', {'button': 1});" |
| 435 | "document.getElementsByTagName('a')[0].dispatchEvent(event);"; |
| 436 | EXPECT_FALSE(EvaluateScript(web_contents, script)->HasExceptionDetails()); |
| 437 | |
| 438 | // Check that we have a new tab. |
| 439 | EXPECT_EQ(2u, browser_context->GetAllWebContents().size()); |
Luca Versari | 4128efc | 2017-08-04 13:33:22 | [diff] [blame] | 440 | } |
Alex Clarke | 9155a34 | 2017-09-15 10:56:59 | [diff] [blame] | 441 | |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 442 | // BeginFrameControl is not supported on MacOS. |
| 443 | #if !defined(OS_MACOSX) |
| 444 | |
| 445 | class HeadlessWebContentsBeginFrameControlTest |
| 446 | : public HeadlessBrowserTest, |
| 447 | public headless_experimental::ExperimentalObserver, |
| 448 | public page::Observer { |
| 449 | public: |
Eric Seckler | 4948f93 | 2018-08-28 14:51:22 | [diff] [blame] | 450 | HeadlessWebContentsBeginFrameControlTest() {} |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 451 | |
| 452 | void SetUp() override { |
| 453 | EnablePixelOutput(); |
| 454 | HeadlessBrowserTest::SetUp(); |
| 455 | } |
| 456 | |
| 457 | protected: |
| 458 | virtual std::string GetTestHtmlFile() = 0; |
| 459 | virtual void OnNeedsBeginFrame() {} |
| 460 | virtual void OnFrameFinished( |
| 461 | std::unique_ptr<headless_experimental::BeginFrameResult> result) {} |
| 462 | |
| 463 | void RunTest() { |
Eric Seckler | 4948f93 | 2018-08-28 14:51:22 | [diff] [blame] | 464 | browser_devtools_client_ = HeadlessDevToolsClient::Create(); |
| 465 | devtools_client_ = HeadlessDevToolsClient::Create(); |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 466 | browser_context_ = browser()->CreateBrowserContextBuilder().Build(); |
| 467 | browser()->SetDefaultBrowserContext(browser_context_); |
| 468 | browser()->GetDevToolsTarget()->AttachClient( |
| 469 | browser_devtools_client_.get()); |
| 470 | |
| 471 | EXPECT_TRUE(embedded_test_server()->Start()); |
| 472 | |
| 473 | browser_devtools_client_->GetTarget()->GetExperimental()->CreateTarget( |
| 474 | target::CreateTargetParams::Builder() |
| 475 | .SetUrl("about://blank") |
| 476 | .SetWidth(200) |
| 477 | .SetHeight(200) |
| 478 | .SetEnableBeginFrameControl(true) |
| 479 | .Build(), |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 480 | base::BindOnce( |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 481 | &HeadlessWebContentsBeginFrameControlTest::OnCreateTargetResult, |
| 482 | base::Unretained(this))); |
| 483 | |
| 484 | RunAsynchronousTest(); |
| 485 | |
| 486 | browser()->GetDevToolsTarget()->DetachClient( |
| 487 | browser_devtools_client_.get()); |
| 488 | } |
| 489 | |
| 490 | void SetUpCommandLine(base::CommandLine* command_line) override { |
| 491 | HeadlessBrowserTest::SetUpCommandLine(command_line); |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 492 | // See bit.ly/headless-rendering for why we use these flags. |
Eric Seckler | 5b74eba | 2018-02-21 18:41:44 | [diff] [blame] | 493 | command_line->AppendSwitch(switches::kRunAllCompositorStagesBeforeDraw); |
Eric Seckler | 7b9e995 | 2017-11-14 19:08:31 | [diff] [blame] | 494 | command_line->AppendSwitch(switches::kDisableNewContentRenderingTimeout); |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 495 | command_line->AppendSwitch(cc::switches::kDisableCheckerImaging); |
| 496 | command_line->AppendSwitch(cc::switches::kDisableThreadedAnimation); |
| 497 | command_line->AppendSwitch(switches::kDisableThreadedScrolling); |
Eric Seckler | 9781fb9 | 2018-03-01 15:27:33 | [diff] [blame] | 498 | |
| 499 | scoped_feature_list_.InitAndEnableFeature( |
| 500 | features::kEnableSurfaceSynchronization); |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 501 | } |
| 502 | |
| 503 | void OnCreateTargetResult( |
| 504 | std::unique_ptr<target::CreateTargetResult> result) { |
| 505 | web_contents_ = HeadlessWebContentsImpl::From( |
| 506 | browser()->GetWebContentsForDevToolsAgentHostId(result->GetTargetId())); |
| 507 | |
| 508 | web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); |
| 509 | devtools_client_->GetHeadlessExperimental()->GetExperimental()->AddObserver( |
| 510 | this); |
| 511 | devtools_client_->GetHeadlessExperimental()->GetExperimental()->Enable( |
| 512 | headless_experimental::EnableParams::Builder().Build()); |
| 513 | |
| 514 | devtools_client_->GetPage()->GetExperimental()->StopLoading( |
| 515 | page::StopLoadingParams::Builder().Build(), |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 516 | base::BindOnce( |
| 517 | &HeadlessWebContentsBeginFrameControlTest::LoadingStopped, |
| 518 | base::Unretained(this))); |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 519 | } |
| 520 | |
| 521 | void LoadingStopped(std::unique_ptr<page::StopLoadingResult>) { |
| 522 | devtools_client_->GetPage()->AddObserver(this); |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 523 | devtools_client_->GetPage()->Enable(base::BindOnce( |
| 524 | &HeadlessWebContentsBeginFrameControlTest::PageDomainEnabled, |
| 525 | base::Unretained(this))); |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 526 | } |
| 527 | |
| 528 | void PageDomainEnabled() { |
| 529 | devtools_client_->GetPage()->Navigate( |
| 530 | page::NavigateParams::Builder() |
| 531 | .SetUrl(embedded_test_server()->GetURL(GetTestHtmlFile()).spec()) |
| 532 | .Build()); |
| 533 | } |
| 534 | |
| 535 | // page::Observer implementation: |
| 536 | void OnLoadEventFired(const page::LoadEventFiredParams& params) override { |
| 537 | TRACE_EVENT0("headless", |
| 538 | "HeadlessWebContentsBeginFrameControlTest::OnLoadEventFired"); |
| 539 | devtools_client_->GetPage()->Disable(); |
| 540 | devtools_client_->GetPage()->RemoveObserver(this); |
| 541 | page_ready_ = true; |
| 542 | if (needs_begin_frames_) { |
| 543 | DCHECK(!frame_in_flight_); |
| 544 | OnNeedsBeginFrame(); |
| 545 | } |
| 546 | } |
| 547 | |
| 548 | // headless_experimental::ExperimentalObserver implementation: |
| 549 | void OnNeedsBeginFramesChanged( |
| 550 | const headless_experimental::NeedsBeginFramesChangedParams& params) |
| 551 | override { |
| 552 | TRACE_EVENT1( |
| 553 | "headless", |
| 554 | "HeadlessWebContentsBeginFrameControlTest::OnNeedsBeginFramesChanged", |
| 555 | "needs_begin_frames", params.GetNeedsBeginFrames()); |
| 556 | needs_begin_frames_ = params.GetNeedsBeginFrames(); |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 557 | // With full-pipeline mode and surface sync, the needs_begin_frame signal |
| 558 | // should become and then always stay true. |
| 559 | EXPECT_TRUE(needs_begin_frames_); |
| 560 | EXPECT_FALSE(frame_in_flight_); |
| 561 | if (page_ready_) |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 562 | OnNeedsBeginFrame(); |
| 563 | } |
| 564 | |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 565 | void BeginFrame(bool screenshot) { |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 566 | // With full-pipeline mode and surface sync, the needs_begin_frame signal |
| 567 | // should always be true. |
| 568 | EXPECT_TRUE(needs_begin_frames_); |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 569 | |
| 570 | frame_in_flight_ = true; |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 571 | num_begin_frames_++; |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 572 | |
| 573 | auto builder = headless_experimental::BeginFrameParams::Builder(); |
| 574 | if (screenshot) { |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 575 | builder.SetScreenshot( |
| 576 | headless_experimental::ScreenshotParams::Builder().Build()); |
| 577 | } |
| 578 | |
| 579 | devtools_client_->GetHeadlessExperimental()->GetExperimental()->BeginFrame( |
| 580 | builder.Build(), |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 581 | base::BindOnce(&HeadlessWebContentsBeginFrameControlTest::FrameFinished, |
| 582 | base::Unretained(this))); |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 583 | } |
| 584 | |
| 585 | void FrameFinished( |
| 586 | std::unique_ptr<headless_experimental::BeginFrameResult> result) { |
| 587 | TRACE_EVENT2("headless", |
| 588 | "HeadlessWebContentsBeginFrameControlTest::FrameFinished", |
| 589 | "has_damage", result->GetHasDamage(), "has_screenshot_data", |
| 590 | result->HasScreenshotData()); |
| 591 | |
| 592 | // Post OnFrameFinished call so that any pending OnNeedsBeginFramesChanged |
| 593 | // call will be executed first. |
| 594 | browser()->BrowserMainThread()->PostTask( |
| 595 | FROM_HERE, |
| 596 | base::BindOnce( |
| 597 | &HeadlessWebContentsBeginFrameControlTest::NotifyOnFrameFinished, |
| 598 | base::Unretained(this), std::move(result))); |
| 599 | } |
| 600 | |
| 601 | void NotifyOnFrameFinished( |
| 602 | std::unique_ptr<headless_experimental::BeginFrameResult> result) { |
| 603 | frame_in_flight_ = false; |
| 604 | OnFrameFinished(std::move(result)); |
| 605 | } |
| 606 | |
| 607 | void PostFinishAsynchronousTest() { |
| 608 | devtools_client_->GetHeadlessExperimental() |
| 609 | ->GetExperimental() |
| 610 | ->RemoveObserver(this); |
| 611 | |
| 612 | browser()->BrowserMainThread()->PostTask( |
| 613 | FROM_HERE, |
| 614 | base::BindOnce( |
| 615 | &HeadlessWebContentsBeginFrameControlTest::FinishAsynchronousTest, |
| 616 | base::Unretained(this))); |
| 617 | } |
| 618 | |
Eric Seckler | 9781fb9 | 2018-03-01 15:27:33 | [diff] [blame] | 619 | base::test::ScopedFeatureList scoped_feature_list_; |
| 620 | |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 621 | HeadlessBrowserContext* browser_context_ = nullptr; // Not owned. |
| 622 | HeadlessWebContentsImpl* web_contents_ = nullptr; // Not owned. |
| 623 | |
| 624 | bool page_ready_ = false; |
| 625 | bool needs_begin_frames_ = false; |
| 626 | bool frame_in_flight_ = false; |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 627 | int num_begin_frames_ = 0; |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 628 | std::unique_ptr<HeadlessDevToolsClient> browser_devtools_client_; |
| 629 | std::unique_ptr<HeadlessDevToolsClient> devtools_client_; |
| 630 | }; |
| 631 | |
| 632 | class HeadlessWebContentsBeginFrameControlBasicTest |
| 633 | : public HeadlessWebContentsBeginFrameControlTest { |
| 634 | public: |
Chris Watkins | 6e89eee | 2017-11-29 06:01:18 | [diff] [blame] | 635 | HeadlessWebContentsBeginFrameControlBasicTest() = default; |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 636 | |
| 637 | protected: |
| 638 | std::string GetTestHtmlFile() override { |
| 639 | // Blue background. |
| 640 | return "/blue_page.html"; |
| 641 | } |
| 642 | |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 643 | void OnNeedsBeginFrame() override { |
| 644 | // Try to capture a screenshot in first frame. This should fail because the |
| 645 | // surface doesn't exist yet. |
| 646 | BeginFrame(true); |
| 647 | } |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 648 | |
| 649 | void OnFrameFinished(std::unique_ptr<headless_experimental::BeginFrameResult> |
| 650 | result) override { |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 651 | if (num_begin_frames_ == 1) { |
| 652 | // First BeginFrame should have caused damage. |
| 653 | EXPECT_TRUE(result->GetHasDamage()); |
| 654 | // But the screenshot should have failed (see above). |
| 655 | EXPECT_FALSE(result->HasScreenshotData()); |
| 656 | } else if (num_begin_frames_ == 2) { |
| 657 | // Expect a valid screenshot in second BeginFrame. |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 658 | EXPECT_TRUE(result->GetHasDamage()); |
| 659 | EXPECT_TRUE(result->HasScreenshotData()); |
| 660 | if (result->HasScreenshotData()) { |
| 661 | std::string base64 = result->GetScreenshotData(); |
| 662 | EXPECT_LT(0u, base64.length()); |
| 663 | SkBitmap result_bitmap; |
| 664 | EXPECT_TRUE(DecodePNG(base64, &result_bitmap)); |
| 665 | |
| 666 | EXPECT_EQ(200, result_bitmap.width()); |
| 667 | EXPECT_EQ(200, result_bitmap.height()); |
| 668 | SkColor expected_color = SkColorSetRGB(0x00, 0x00, 0xff); |
| 669 | SkColor actual_color = result_bitmap.getColor(100, 100); |
| 670 | EXPECT_EQ(expected_color, actual_color); |
| 671 | } |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 672 | } else { |
| 673 | DCHECK_EQ(3, num_begin_frames_); |
| 674 | // Can't guarantee that the last BeginFrame didn't have damage, but it |
| 675 | // should not have a screenshot. |
| 676 | EXPECT_FALSE(result->HasScreenshotData()); |
| 677 | } |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 678 | |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 679 | if (num_begin_frames_ < 3) { |
| 680 | // Capture a screenshot in second but not third BeginFrame. |
| 681 | BeginFrame(num_begin_frames_ == 1); |
| 682 | } else { |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 683 | // Post completion to avoid deleting the WebContents on the same callstack |
| 684 | // as frame finished callback. |
| 685 | PostFinishAsynchronousTest(); |
| 686 | } |
| 687 | } |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 688 | }; |
| 689 | |
| 690 | HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessWebContentsBeginFrameControlBasicTest); |
| 691 | |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 692 | class HeadlessWebContentsBeginFrameControlViewportTest |
| 693 | : public HeadlessWebContentsBeginFrameControlTest { |
| 694 | public: |
Chris Watkins | 6e89eee | 2017-11-29 06:01:18 | [diff] [blame] | 695 | HeadlessWebContentsBeginFrameControlViewportTest() = default; |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 696 | |
| 697 | protected: |
| 698 | std::string GetTestHtmlFile() override { |
| 699 | // Draws a 100x100px blue box at 200x200px. |
| 700 | return "/blue_box.html"; |
| 701 | } |
| 702 | |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 703 | void OnNeedsBeginFrame() override { |
| 704 | // Send a first BeginFrame to initialize the surface. |
| 705 | BeginFrame(false); |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 706 | } |
| 707 | |
| 708 | void SetUpViewport() { |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 709 | devtools_client_->GetEmulation() |
| 710 | ->GetExperimental() |
| 711 | ->SetDeviceMetricsOverride( |
| 712 | emulation::SetDeviceMetricsOverrideParams::Builder() |
| 713 | .SetWidth(0) |
| 714 | .SetHeight(0) |
| 715 | .SetDeviceScaleFactor(0) |
| 716 | .SetMobile(false) |
| 717 | .SetViewport(page::Viewport::Builder() |
| 718 | .SetX(200) |
| 719 | .SetY(200) |
| 720 | .SetWidth(100) |
| 721 | .SetHeight(100) |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 722 | .SetScale(3) |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 723 | .Build()) |
Eric Seckler | dc6d599 | 2017-11-15 14:50:11 | [diff] [blame] | 724 | .Build(), |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 725 | base::BindOnce(&HeadlessWebContentsBeginFrameControlViewportTest:: |
| 726 | SetDeviceMetricsOverrideDone, |
| 727 | base::Unretained(this))); |
Eric Seckler | 7b9e995 | 2017-11-14 19:08:31 | [diff] [blame] | 728 | } |
| 729 | |
Eric Seckler | dc6d599 | 2017-11-15 14:50:11 | [diff] [blame] | 730 | void SetDeviceMetricsOverrideDone( |
| 731 | std::unique_ptr<emulation::SetDeviceMetricsOverrideResult> result) { |
Eric Seckler | 7b9e995 | 2017-11-14 19:08:31 | [diff] [blame] | 732 | EXPECT_TRUE(result); |
Saman Sami | 33be507c | 2018-03-02 22:33:08 | [diff] [blame] | 733 | // Take a screenshot in the second BeginFrame. |
| 734 | BeginFrame(true); |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 735 | } |
| 736 | |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 737 | void OnFrameFinished(std::unique_ptr<headless_experimental::BeginFrameResult> |
| 738 | result) override { |
| 739 | if (num_begin_frames_ == 1) { |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 740 | SetUpViewport(); |
| 741 | return; |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 742 | } |
| 743 | |
Saman Sami | 33be507c | 2018-03-02 22:33:08 | [diff] [blame] | 744 | DCHECK_EQ(2, num_begin_frames_); |
Eric Seckler | 4f0eb9fa | 2018-03-01 11:23:21 | [diff] [blame] | 745 | // Second BeginFrame should have a screenshot of the configured viewport and |
| 746 | // of the correct size. |
| 747 | EXPECT_TRUE(result->GetHasDamage()); |
| 748 | EXPECT_TRUE(result->HasScreenshotData()); |
| 749 | if (result->HasScreenshotData()) { |
| 750 | std::string base64 = result->GetScreenshotData(); |
| 751 | EXPECT_LT(0u, base64.length()); |
| 752 | SkBitmap result_bitmap; |
| 753 | EXPECT_TRUE(DecodePNG(base64, &result_bitmap)); |
| 754 | |
| 755 | EXPECT_EQ(300, result_bitmap.width()); |
| 756 | EXPECT_EQ(300, result_bitmap.height()); |
| 757 | SkColor expected_color = SkColorSetRGB(0x00, 0x00, 0xff); |
| 758 | |
| 759 | SkColor actual_color = result_bitmap.getColor(100, 100); |
| 760 | EXPECT_EQ(expected_color, actual_color); |
| 761 | actual_color = result_bitmap.getColor(0, 0); |
| 762 | EXPECT_EQ(expected_color, actual_color); |
| 763 | actual_color = result_bitmap.getColor(0, 299); |
| 764 | EXPECT_EQ(expected_color, actual_color); |
| 765 | actual_color = result_bitmap.getColor(299, 0); |
| 766 | EXPECT_EQ(expected_color, actual_color); |
| 767 | actual_color = result_bitmap.getColor(299, 299); |
| 768 | EXPECT_EQ(expected_color, actual_color); |
| 769 | } |
| 770 | |
| 771 | // Post completion to avoid deleting the WebContents on the same callstack |
| 772 | // as frame finished callback. |
| 773 | PostFinishAsynchronousTest(); |
| 774 | } |
Eric Seckler | 80a868a | 2017-10-10 22:57:44 | [diff] [blame] | 775 | }; |
| 776 | |
| 777 | HEADLESS_ASYNC_DEVTOOLED_TEST_F( |
| 778 | HeadlessWebContentsBeginFrameControlViewportTest); |
| 779 | |
| 780 | #endif // !defined(OS_MACOSX) |
| 781 | |
Alex Clarke | 61c3cd7 | 2017-10-17 09:31:22 | [diff] [blame] | 782 | class CookiesEnabled : public HeadlessAsyncDevTooledBrowserTest, |
| 783 | page::Observer { |
| 784 | public: |
| 785 | void RunDevTooledTest() override { |
| 786 | devtools_client_->GetPage()->AddObserver(this); |
| 787 | devtools_client_->GetPage()->Enable(); |
| 788 | |
| 789 | EXPECT_TRUE(embedded_test_server()->Start()); |
| 790 | devtools_client_->GetPage()->Navigate( |
| 791 | embedded_test_server()->GetURL("/cookie.html").spec()); |
| 792 | } |
| 793 | |
| 794 | // page::Observer implementation: |
| 795 | void OnLoadEventFired(const page::LoadEventFiredParams& params) override { |
| 796 | devtools_client_->GetRuntime()->Evaluate( |
| 797 | "window.test_result", |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 798 | base::BindOnce(&CookiesEnabled::OnResult, base::Unretained(this))); |
Alex Clarke | 61c3cd7 | 2017-10-17 09:31:22 | [diff] [blame] | 799 | } |
| 800 | |
| 801 | void OnResult(std::unique_ptr<runtime::EvaluateResult> result) { |
| 802 | std::string value; |
| 803 | EXPECT_TRUE(result->GetResult()->HasValue()); |
| 804 | EXPECT_TRUE(result->GetResult()->GetValue()->GetAsString(&value)); |
| 805 | EXPECT_EQ("0", value); |
| 806 | FinishAsynchronousTest(); |
| 807 | } |
Alex Clarke | 61c3cd7 | 2017-10-17 09:31:22 | [diff] [blame] | 808 | }; |
| 809 | |
| 810 | HEADLESS_ASYNC_DEVTOOLED_TEST_F(CookiesEnabled); |
| 811 | |
Alex Clarke | 6bd0fd5 | 2018-02-12 16:08:25 | [diff] [blame] | 812 | namespace { |
| 813 | const char* kPageWhichOpensAWindow = R"( |
| 814 | <html> |
| 815 | <body> |
| 816 | <script> |
| 817 | window.open('/page2.html'); |
| 818 | </script> |
| 819 | </body> |
| 820 | </html> |
| 821 | )"; |
| 822 | |
| 823 | const char* kPage2 = R"( |
| 824 | <html> |
| 825 | <body> |
| 826 | Page 2. |
| 827 | </body> |
| 828 | </html> |
| 829 | )"; |
| 830 | } // namespace |
| 831 | |
| 832 | class WebContentsOpenTest : public page::Observer, |
| 833 | public HeadlessAsyncDevTooledBrowserTest { |
| 834 | public: |
| 835 | void RunDevTooledTest() override { |
Alex Clarke | 6bd0fd5 | 2018-02-12 16:08:25 | [diff] [blame] | 836 | devtools_client_->GetPage()->AddObserver(this); |
Andrey Kosyakov | 8846844e | 2018-07-10 00:49:22 | [diff] [blame] | 837 | interceptor_->InsertResponse("http://foo.com/index.html", |
| 838 | {kPageWhichOpensAWindow, "text/html"}); |
| 839 | interceptor_->InsertResponse("http://foo.com/page2.html", |
| 840 | {kPage2, "text/html"}); |
Alex Clarke | 6bd0fd5 | 2018-02-12 16:08:25 | [diff] [blame] | 841 | |
| 842 | base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); |
| 843 | devtools_client_->GetPage()->Enable(run_loop.QuitClosure()); |
| 844 | run_loop.Run(); |
| 845 | |
| 846 | devtools_client_->GetPage()->Navigate("http://foo.com/index.html"); |
| 847 | } |
Alex Clarke | 6bd0fd5 | 2018-02-12 16:08:25 | [diff] [blame] | 848 | }; |
| 849 | |
| 850 | class DontBlockWebContentsOpenTest : public WebContentsOpenTest { |
| 851 | public: |
| 852 | void CustomizeHeadlessBrowserContext( |
| 853 | HeadlessBrowserContext::Builder& builder) override { |
| 854 | builder.SetBlockNewWebContents(false); |
| 855 | } |
| 856 | |
| 857 | void OnLoadEventFired(const page::LoadEventFiredParams&) override { |
| 858 | EXPECT_THAT( |
Andrey Kosyakov | 8846844e | 2018-07-10 00:49:22 | [diff] [blame] | 859 | interceptor_->urls_requested(), |
Alex Clarke | 6bd0fd5 | 2018-02-12 16:08:25 | [diff] [blame] | 860 | ElementsAre("http://foo.com/index.html", "http://foo.com/page2.html")); |
| 861 | FinishAsynchronousTest(); |
| 862 | } |
| 863 | }; |
| 864 | |
| 865 | HEADLESS_ASYNC_DEVTOOLED_TEST_F(DontBlockWebContentsOpenTest); |
| 866 | |
| 867 | class BlockWebContentsOpenTest : public WebContentsOpenTest { |
| 868 | public: |
| 869 | void CustomizeHeadlessBrowserContext( |
| 870 | HeadlessBrowserContext::Builder& builder) override { |
| 871 | builder.SetBlockNewWebContents(true); |
| 872 | } |
| 873 | |
| 874 | void OnLoadEventFired(const page::LoadEventFiredParams&) override { |
Andrey Kosyakov | 8846844e | 2018-07-10 00:49:22 | [diff] [blame] | 875 | EXPECT_THAT(interceptor_->urls_requested(), |
Alex Clarke | 6bd0fd5 | 2018-02-12 16:08:25 | [diff] [blame] | 876 | ElementsAre("http://foo.com/index.html")); |
| 877 | FinishAsynchronousTest(); |
| 878 | } |
| 879 | }; |
| 880 | |
| 881 | HEADLESS_ASYNC_DEVTOOLED_TEST_F(BlockWebContentsOpenTest); |
| 882 | |
skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 883 | } // namespace headless |