blob: bd68c7732f7419d6deb0f58d5193548512e65b5f [file] [log] [blame]
skyostilfe116162016-02-26 20:53:331// 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
mostynbc3d183b2016-04-04 11:02:455#include <memory>
eseckler9ef54762016-06-03 17:28:386#include <string>
7#include <vector>
mostynbc3d183b2016-04-04 11:02:458
esecklerd2869ff2017-01-19 14:46:219#include "base/base64.h"
Eric Seckler80a868a2017-10-10 22:57:4410#include "base/command_line.h"
alexclarke1a4a3bab2017-05-24 16:07:4211#include "base/json/json_writer.h"
Johannes Henkeled0e5da2018-05-30 22:55:1812#include "base/logging.h"
Gabriel Charette078e3662017-08-28 22:59:0413#include "base/run_loop.h"
Alex Clarke51a354ae2017-07-12 11:04:4414#include "base/strings/stringprintf.h"
Eric Seckler9781fb92018-03-01 15:27:3315#include "base/test/scoped_feature_list.h"
Eric Seckler82ad0e92017-07-17 15:52:2216#include "build/build_config.h"
Eric Seckler4f0eb9fa2018-03-01 11:23:2117#include "cc/base/switches.h"
Eric Seckler9781fb92018-03-01 15:27:3318#include "components/viz/common/features.h"
Eric Seckler5b74eba2018-02-21 18:41:4419#include "components/viz/common/switches.h"
Eric Seckler82ad0e92017-07-17 15:52:2220#include "content/public/browser/web_contents.h"
Eric Seckler7b9e9952017-11-14 19:08:3121#include "content/public/common/content_switches.h"
skyostilfe116162016-02-26 20:53:3322#include "content/public/test/browser_test.h"
Eric Seckler48f8a072017-06-20 14:28:3623#include "headless/lib/browser/headless_web_contents_impl.h"
Eric Seckler1cbd8e02018-04-27 03:17:3424#include "headless/public/devtools/domains/browser.h"
Alex Clarke51a354ae2017-07-12 11:04:4425#include "headless/public/devtools/domains/dom_snapshot.h"
Eric Seckler80a868a2017-10-10 22:57:4426#include "headless/public/devtools/domains/emulation.h"
27#include "headless/public/devtools/domains/headless_experimental.h"
altimineaffa8e02016-11-08 23:56:3128#include "headless/public/devtools/domains/page.h"
esecklerd2869ff2017-01-19 14:46:2129#include "headless/public/devtools/domains/runtime.h"
esecklerf2531a52016-11-17 20:20:5230#include "headless/public/devtools/domains/security.h"
Eric Seckler80a868a2017-10-10 22:57:4431#include "headless/public/devtools/domains/target.h"
skyostilfe116162016-02-26 20:53:3332#include "headless/public/headless_browser.h"
eseckler9ef54762016-06-03 17:28:3833#include "headless/public/headless_devtools_client.h"
skyostilfe116162016-02-26 20:53:3334#include "headless/public/headless_web_contents.h"
35#include "headless/test/headless_browser_test.h"
Scott Violet318a55f2018-03-30 19:08:1936#include "printing/buildflags/buildflags.h"
altiminbf875c92016-08-04 17:09:0737#include "testing/gmock/include/gmock/gmock.h"
skyostilfe116162016-02-26 20:53:3338#include "testing/gtest/include/gtest/gtest.h"
esecklerd2869ff2017-01-19 14:46:2139#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"
skyostilfe116162016-02-26 20:53:3342#include "ui/gfx/geometry/size.h"
43#include "url/gurl.h"
44
Lei Zhang48a4a5262018-04-17 20:18:4445#if BUILDFLAG(ENABLE_PRINTING)
jzfeng3d83dad2017-05-09 03:44:1846#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
alexclarkefb9a2352017-05-25 14:19:1953using testing::ElementsAre;
Alex Clarke9155a342017-09-15 10:56:5954using testing::ElementsAreArray;
55using testing::Not;
altiminbf875c92016-08-04 17:09:0756using testing::UnorderedElementsAre;
Alex Clarke9155a342017-09-15 10:56:5957using testing::UnorderedElementsAreArray;
altiminbf875c92016-08-04 17:09:0758
skyostilfe116162016-02-26 20:53:3359namespace headless {
skyostilfe116162016-02-26 20:53:3360class HeadlessWebContentsTest : public HeadlessBrowserTest {};
61
skyostilfe116162016-02-26 20:53:3362IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, Navigation) {
63 EXPECT_TRUE(embedded_test_server()->Start());
eseckler9ef54762016-06-03 17:28:3864
altiminbf875c92016-08-04 17:09:0765 HeadlessBrowserContext* browser_context =
altimin93a02402016-08-03 16:26:4366 browser()->CreateBrowserContextBuilder().Build();
67
skyostil25c2c0122016-06-09 12:54:1268 HeadlessWebContents* web_contents =
altimin93a02402016-08-03 16:26:4369 browser_context->CreateWebContentsBuilder()
skyostil25c2c0122016-06-09 12:54:1270 .SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
71 .Build();
skyostil585fa602016-04-25 16:07:5672 EXPECT_TRUE(WaitForLoad(web_contents));
altiminb6d2d1fc2016-04-21 15:23:2273
altiminbf875c92016-08-04 17:09:0774 EXPECT_THAT(browser_context->GetAllWebContents(),
75 UnorderedElementsAre(web_contents));
altiminb6d2d1fc2016-04-21 15:23:2276}
77
78IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, WindowOpen) {
79 EXPECT_TRUE(embedded_test_server()->Start());
80
altiminbf875c92016-08-04 17:09:0781 HeadlessBrowserContext* browser_context =
altimin93a02402016-08-03 16:26:4382 browser()->CreateBrowserContextBuilder().Build();
83
skyostil25c2c0122016-06-09 12:54:1284 HeadlessWebContents* web_contents =
altimin93a02402016-08-03 16:26:4385 browser_context->CreateWebContentsBuilder()
skyostil25c2c0122016-06-09 12:54:1286 .SetInitialURL(embedded_test_server()->GetURL("/window_open.html"))
87 .Build();
skyostil585fa602016-04-25 16:07:5688 EXPECT_TRUE(WaitForLoad(web_contents));
altiminb6d2d1fc2016-04-21 15:23:2289
Eric Seckler48f8a072017-06-20 14:28:3690 EXPECT_EQ(2u, browser_context->GetAllWebContents().size());
91
Johannes Henkeled0e5da2018-05-30 22:55:1892 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 Seckler48f8a072017-06-20 14:28:36102 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 Seckler82ad0e92017-07-17 15:52:22109
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 Seckler48f8a072017-06-20 14:28:36119}
120
Johannes Henkel03212fe2018-04-25 17:34:32121IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest,
122 FocusOfHeadlessWebContents_IsIndependent) {
irisu559af0912017-02-28 13:10:34123 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();
arthursonzognib3a06c1b2018-05-14 11:52:35132 WaitForLoadAndGainFocus(web_contents);
irisu559af0912017-02-28 13:10:34133
Alex Clarke1dbb6092017-10-18 16:53:34134 std::unique_ptr<runtime::EvaluateResult> has_focus =
135 EvaluateScript(web_contents, "document.hasFocus()");
136 EXPECT_TRUE(has_focus->GetResult()->GetValue()->GetBool());
irisu559af0912017-02-28 13:10:34137
138 HeadlessWebContents* web_contents2 =
139 browser_context->CreateWebContentsBuilder()
140 .SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
141 .Build();
arthursonzognib3a06c1b2018-05-14 11:52:35142 WaitForLoadAndGainFocus(web_contents2);
irisu559af0912017-02-28 13:10:34143
esecklerc09e3992017-04-03 13:10:36144 // Focus of different WebContents is independent.
Alex Clarke1dbb6092017-10-18 16:53:34145 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());
irisu559af0912017-02-28 13:10:34150}
151
sushkovfd9f2942017-05-09 04:34:36152IN_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
esecklerd2869ff2017-01-19 14:46:21168namespace {
169bool 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.
eseckler9ef54762016-06-03 17:28:38180class HeadlessWebContentsScreenshotTest
esecklerd2869ff2017-01-19 14:46:21181 : public HeadlessAsyncDevTooledBrowserTest,
182 public ::testing::WithParamInterface<bool> {
eseckler9ef54762016-06-03 17:28:38183 public:
esecklerd2869ff2017-01-19 14:46:21184 void SetUp() override {
185 EnablePixelOutput();
Sami Kyostilad99a9662017-06-06 09:09:17186 if (GetParam()) {
esecklerd2869ff2017-01-19 14:46:21187 UseSoftwareCompositing();
Sami Kyostilad99a9662017-06-06 09:09:17188 SetUpWithoutGPU();
189 } else {
190 HeadlessAsyncDevTooledBrowserTest::SetUp();
191 }
esecklerd2869ff2017-01-19 14:46:21192 }
193
eseckler9ef54762016-06-03 17:28:38194 void RunDevTooledTest() override {
esecklerd2869ff2017-01-19 14:46:21195 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),
tzikf7adad1a2018-03-10 20:31:01201 base::BindOnce(&HeadlessWebContentsScreenshotTest::OnPageSetupCompleted,
202 base::Unretained(this)));
esecklerd2869ff2017-01-19 14:46:21203 }
204
205 void OnPageSetupCompleted(std::unique_ptr<runtime::EvaluateResult> result) {
eseckler9ef54762016-06-03 17:28:38206 devtools_client_->GetPage()->GetExperimental()->CaptureScreenshot(
dvalletb7b006952017-05-24 08:04:43207 page::CaptureScreenshotParams::Builder().Build(),
tzikf7adad1a2018-03-10 20:31:01208 base::BindOnce(&HeadlessWebContentsScreenshotTest::OnScreenshotCaptured,
209 base::Unretained(this)));
eseckler9ef54762016-06-03 17:28:38210 }
211
212 void OnScreenshotCaptured(
213 std::unique_ptr<page::CaptureScreenshotResult> result) {
esecklerd2869ff2017-01-19 14:46:21214 std::string base64 = result->GetData();
jzfeng3d83dad2017-05-09 03:44:18215 EXPECT_GT(base64.length(), 0U);
esecklerd2869ff2017-01-19 14:46:21216 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);
eseckler9ef54762016-06-03 17:28:38224 FinishAsynchronousTest();
225 }
226};
227
esecklerd2869ff2017-01-19 14:46:21228HEADLESS_ASYNC_DEVTOOLED_TEST_P(HeadlessWebContentsScreenshotTest);
229
230// Instantiate test case for both software and gpu compositing modes.
231INSTANTIATE_TEST_CASE_P(HeadlessWebContentsScreenshotTests,
232 HeadlessWebContentsScreenshotTest,
233 ::testing::Bool());
eseckler9ef54762016-06-03 17:28:38234
Eric Seckler1cbd8e02018-04-27 03:17:34235// Regression test for crbug.com/832138.
236class 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
263HEADLESS_ASYNC_DEVTOOLED_TEST_P(
264 HeadlessWebContentsScreenshotWindowPositionTest);
265
266// Instantiate test case for both software and gpu compositing modes.
267INSTANTIATE_TEST_CASE_P(HeadlessWebContentsScreenshotWindowPositionTests,
268 HeadlessWebContentsScreenshotWindowPositionTest,
269 ::testing::Bool());
270
Lei Zhang48a4a5262018-04-17 20:18:44271#if BUILDFLAG(ENABLE_PRINTING)
jzfeng3d83dad2017-05-09 03:44:18272class 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 Wilson5ed06e72017-12-01 01:25:11283 base::NumberToString(kDocHeight) + "in'";
jzfeng3d83dad2017-05-09 03:44:18284 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),
tzikf7adad1a2018-03-10 20:31:01291 base::BindOnce(&HeadlessWebContentsPDFTest::OnPageSetupCompleted,
292 base::Unretained(this)));
jzfeng3d83dad2017-05-09 03:44:18293 }
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(),
tzikf7adad1a2018-03-10 20:31:01306 base::BindOnce(&HeadlessWebContentsPDFTest::OnPDFCreated,
307 base::Unretained(this)));
jzfeng3d83dad2017-05-09 03:44:18308 }
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 Zhang0b00ad42018-07-24 02:22:41316 auto pdf_span = base::as_bytes(base::make_span(pdf_data));
jzfeng3d83dad2017-05-09 03:44:18317 int num_pages;
Lei Zhang0b00ad42018-07-24 02:22:41318 EXPECT_TRUE(chrome_pdf::GetPDFDocInfo(pdf_span, &num_pages, nullptr));
jzfeng3d83dad2017-05-09 03:44:18319 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 Zhang0b00ad42018-07-24 02:22:41325 pdf_span, i, &width_in_points, &height_in_points));
jzfeng3d83dad2017-05-09 03:44:18326 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 Zhang5c500482018-04-12 07:34:16333 rect, gfx::Point(0, 0), gfx::Size(kDpi, kDpi), /*autorotate=*/true,
334 /*use_color=*/true, printing::PdfRenderSettings::Mode::NORMAL);
jzfeng3d83dad2017-05-09 03:44:18335 std::vector<uint8_t> page_bitmap_data(kColorChannels *
336 settings.area.size().GetArea());
337 EXPECT_TRUE(chrome_pdf::RenderPDFPageToBitmap(
Lei Zhang0b00ad42018-07-24 02:22:41338 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));
jzfeng3d83dad2017-05-09 03:44:18341 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
349HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessWebContentsPDFTest);
350#endif
351
esecklerf2531a52016-11-17 20:20:52352class 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());
esecklerf2531a52016-11-17 20:20:52365
eseckler76edc3b42017-01-19 14:36:05366 devtools_client_->GetSecurity()->GetExperimental()->Disable(
367 security::DisableParams::Builder().Build());
368 devtools_client_->GetSecurity()->GetExperimental()->RemoveObserver(this);
esecklerf2531a52016-11-17 20:20:52369 FinishAsynchronousTest();
370 }
371};
372
Eric Secklerea51c9c2017-07-18 20:47:56373// Regression test for https://crbug.com/733569.
374class HeadlessWebContentsRequestStorageQuotaTest
375 : public HeadlessAsyncDevTooledBrowserTest,
376 public runtime::Observer {
377 public:
378 void RunDevTooledTest() override {
379 EXPECT_TRUE(embedded_test_server()->Start());
380
Gabriel Charette60404392017-11-09 15:52:40381 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
Eric Secklerea51c9c2017-07-18 20:47:56382 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
397HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessWebContentsRequestStorageQuotaTest);
398
Luca Versari4128efc2017-08-04 13:33:22399IN_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
418IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, BrowserOpenInTab) {
419 EXPECT_TRUE(embedded_test_server()->Start());
420
421 HeadlessBrowserContext* browser_context =
422 browser()->CreateBrowserContextBuilder().Build();
423
Luca Versari4128efc2017-08-04 13:33:22424 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 Versari4128efc2017-08-04 13:33:22440}
Alex Clarke9155a342017-09-15 10:56:59441
Eric Seckler80a868a2017-10-10 22:57:44442// BeginFrameControl is not supported on MacOS.
443#if !defined(OS_MACOSX)
444
445class HeadlessWebContentsBeginFrameControlTest
446 : public HeadlessBrowserTest,
447 public headless_experimental::ExperimentalObserver,
448 public page::Observer {
449 public:
Eric Seckler4948f932018-08-28 14:51:22450 HeadlessWebContentsBeginFrameControlTest() {}
Eric Seckler80a868a2017-10-10 22:57:44451
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 Seckler4948f932018-08-28 14:51:22464 browser_devtools_client_ = HeadlessDevToolsClient::Create();
465 devtools_client_ = HeadlessDevToolsClient::Create();
Eric Seckler80a868a2017-10-10 22:57:44466 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(),
tzikf7adad1a2018-03-10 20:31:01480 base::BindOnce(
Eric Seckler80a868a2017-10-10 22:57:44481 &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 Seckler4f0eb9fa2018-03-01 11:23:21492 // See bit.ly/headless-rendering for why we use these flags.
Eric Seckler5b74eba2018-02-21 18:41:44493 command_line->AppendSwitch(switches::kRunAllCompositorStagesBeforeDraw);
Eric Seckler7b9e9952017-11-14 19:08:31494 command_line->AppendSwitch(switches::kDisableNewContentRenderingTimeout);
Eric Seckler4f0eb9fa2018-03-01 11:23:21495 command_line->AppendSwitch(cc::switches::kDisableCheckerImaging);
496 command_line->AppendSwitch(cc::switches::kDisableThreadedAnimation);
497 command_line->AppendSwitch(switches::kDisableThreadedScrolling);
Eric Seckler9781fb92018-03-01 15:27:33498
499 scoped_feature_list_.InitAndEnableFeature(
500 features::kEnableSurfaceSynchronization);
Eric Seckler80a868a2017-10-10 22:57:44501 }
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(),
tzikf7adad1a2018-03-10 20:31:01516 base::BindOnce(
517 &HeadlessWebContentsBeginFrameControlTest::LoadingStopped,
518 base::Unretained(this)));
Eric Seckler80a868a2017-10-10 22:57:44519 }
520
521 void LoadingStopped(std::unique_ptr<page::StopLoadingResult>) {
522 devtools_client_->GetPage()->AddObserver(this);
tzikf7adad1a2018-03-10 20:31:01523 devtools_client_->GetPage()->Enable(base::BindOnce(
524 &HeadlessWebContentsBeginFrameControlTest::PageDomainEnabled,
525 base::Unretained(this)));
Eric Seckler80a868a2017-10-10 22:57:44526 }
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 Seckler4f0eb9fa2018-03-01 11:23:21557 // 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 Seckler80a868a2017-10-10 22:57:44562 OnNeedsBeginFrame();
563 }
564
Eric Seckler80a868a2017-10-10 22:57:44565 void BeginFrame(bool screenshot) {
Eric Seckler4f0eb9fa2018-03-01 11:23:21566 // With full-pipeline mode and surface sync, the needs_begin_frame signal
567 // should always be true.
568 EXPECT_TRUE(needs_begin_frames_);
Eric Seckler80a868a2017-10-10 22:57:44569
570 frame_in_flight_ = true;
Eric Seckler4f0eb9fa2018-03-01 11:23:21571 num_begin_frames_++;
Eric Seckler80a868a2017-10-10 22:57:44572
573 auto builder = headless_experimental::BeginFrameParams::Builder();
574 if (screenshot) {
Eric Seckler80a868a2017-10-10 22:57:44575 builder.SetScreenshot(
576 headless_experimental::ScreenshotParams::Builder().Build());
577 }
578
579 devtools_client_->GetHeadlessExperimental()->GetExperimental()->BeginFrame(
580 builder.Build(),
tzikf7adad1a2018-03-10 20:31:01581 base::BindOnce(&HeadlessWebContentsBeginFrameControlTest::FrameFinished,
582 base::Unretained(this)));
Eric Seckler80a868a2017-10-10 22:57:44583 }
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 Seckler9781fb92018-03-01 15:27:33619 base::test::ScopedFeatureList scoped_feature_list_;
620
Eric Seckler80a868a2017-10-10 22:57:44621 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 Seckler4f0eb9fa2018-03-01 11:23:21627 int num_begin_frames_ = 0;
Eric Seckler80a868a2017-10-10 22:57:44628 std::unique_ptr<HeadlessDevToolsClient> browser_devtools_client_;
629 std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
630};
631
632class HeadlessWebContentsBeginFrameControlBasicTest
633 : public HeadlessWebContentsBeginFrameControlTest {
634 public:
Chris Watkins6e89eee2017-11-29 06:01:18635 HeadlessWebContentsBeginFrameControlBasicTest() = default;
Eric Seckler80a868a2017-10-10 22:57:44636
637 protected:
638 std::string GetTestHtmlFile() override {
639 // Blue background.
640 return "/blue_page.html";
641 }
642
Eric Seckler4f0eb9fa2018-03-01 11:23:21643 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 Seckler80a868a2017-10-10 22:57:44648
649 void OnFrameFinished(std::unique_ptr<headless_experimental::BeginFrameResult>
650 result) override {
Eric Seckler4f0eb9fa2018-03-01 11:23:21651 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 Seckler80a868a2017-10-10 22:57:44658 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 Seckler4f0eb9fa2018-03-01 11:23:21672 } 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 Seckler80a868a2017-10-10 22:57:44678
Eric Seckler4f0eb9fa2018-03-01 11:23:21679 if (num_begin_frames_ < 3) {
680 // Capture a screenshot in second but not third BeginFrame.
681 BeginFrame(num_begin_frames_ == 1);
682 } else {
Eric Seckler80a868a2017-10-10 22:57:44683 // Post completion to avoid deleting the WebContents on the same callstack
684 // as frame finished callback.
685 PostFinishAsynchronousTest();
686 }
687 }
Eric Seckler80a868a2017-10-10 22:57:44688};
689
690HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessWebContentsBeginFrameControlBasicTest);
691
Eric Seckler80a868a2017-10-10 22:57:44692class HeadlessWebContentsBeginFrameControlViewportTest
693 : public HeadlessWebContentsBeginFrameControlTest {
694 public:
Chris Watkins6e89eee2017-11-29 06:01:18695 HeadlessWebContentsBeginFrameControlViewportTest() = default;
Eric Seckler80a868a2017-10-10 22:57:44696
697 protected:
698 std::string GetTestHtmlFile() override {
699 // Draws a 100x100px blue box at 200x200px.
700 return "/blue_box.html";
701 }
702
Eric Seckler4f0eb9fa2018-03-01 11:23:21703 void OnNeedsBeginFrame() override {
704 // Send a first BeginFrame to initialize the surface.
705 BeginFrame(false);
Eric Seckler80a868a2017-10-10 22:57:44706 }
707
708 void SetUpViewport() {
Eric Seckler80a868a2017-10-10 22:57:44709 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 Seckler4f0eb9fa2018-03-01 11:23:21722 .SetScale(3)
Eric Seckler80a868a2017-10-10 22:57:44723 .Build())
Eric Secklerdc6d5992017-11-15 14:50:11724 .Build(),
tzikf7adad1a2018-03-10 20:31:01725 base::BindOnce(&HeadlessWebContentsBeginFrameControlViewportTest::
726 SetDeviceMetricsOverrideDone,
727 base::Unretained(this)));
Eric Seckler7b9e9952017-11-14 19:08:31728 }
729
Eric Secklerdc6d5992017-11-15 14:50:11730 void SetDeviceMetricsOverrideDone(
731 std::unique_ptr<emulation::SetDeviceMetricsOverrideResult> result) {
Eric Seckler7b9e9952017-11-14 19:08:31732 EXPECT_TRUE(result);
Saman Sami33be507c2018-03-02 22:33:08733 // Take a screenshot in the second BeginFrame.
734 BeginFrame(true);
Eric Seckler80a868a2017-10-10 22:57:44735 }
736
Eric Seckler4f0eb9fa2018-03-01 11:23:21737 void OnFrameFinished(std::unique_ptr<headless_experimental::BeginFrameResult>
738 result) override {
739 if (num_begin_frames_ == 1) {
Eric Seckler4f0eb9fa2018-03-01 11:23:21740 SetUpViewport();
741 return;
Eric Seckler4f0eb9fa2018-03-01 11:23:21742 }
743
Saman Sami33be507c2018-03-02 22:33:08744 DCHECK_EQ(2, num_begin_frames_);
Eric Seckler4f0eb9fa2018-03-01 11:23:21745 // 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 Seckler80a868a2017-10-10 22:57:44775};
776
777HEADLESS_ASYNC_DEVTOOLED_TEST_F(
778 HeadlessWebContentsBeginFrameControlViewportTest);
779
780#endif // !defined(OS_MACOSX)
781
Alex Clarke61c3cd72017-10-17 09:31:22782class 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",
tzikf7adad1a2018-03-10 20:31:01798 base::BindOnce(&CookiesEnabled::OnResult, base::Unretained(this)));
Alex Clarke61c3cd72017-10-17 09:31:22799 }
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 Clarke61c3cd72017-10-17 09:31:22808};
809
810HEADLESS_ASYNC_DEVTOOLED_TEST_F(CookiesEnabled);
811
Alex Clarke6bd0fd52018-02-12 16:08:25812namespace {
813const char* kPageWhichOpensAWindow = R"(
814<html>
815<body>
816<script>
817window.open('/page2.html');
818</script>
819</body>
820</html>
821)";
822
823const char* kPage2 = R"(
824<html>
825<body>
826Page 2.
827</body>
828</html>
829)";
830} // namespace
831
832class WebContentsOpenTest : public page::Observer,
833 public HeadlessAsyncDevTooledBrowserTest {
834 public:
835 void RunDevTooledTest() override {
Alex Clarke6bd0fd52018-02-12 16:08:25836 devtools_client_->GetPage()->AddObserver(this);
Andrey Kosyakov8846844e2018-07-10 00:49:22837 interceptor_->InsertResponse("http://foo.com/index.html",
838 {kPageWhichOpensAWindow, "text/html"});
839 interceptor_->InsertResponse("http://foo.com/page2.html",
840 {kPage2, "text/html"});
Alex Clarke6bd0fd52018-02-12 16:08:25841
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 Clarke6bd0fd52018-02-12 16:08:25848};
849
850class 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 Kosyakov8846844e2018-07-10 00:49:22859 interceptor_->urls_requested(),
Alex Clarke6bd0fd52018-02-12 16:08:25860 ElementsAre("http://foo.com/index.html", "http://foo.com/page2.html"));
861 FinishAsynchronousTest();
862 }
863};
864
865HEADLESS_ASYNC_DEVTOOLED_TEST_F(DontBlockWebContentsOpenTest);
866
867class 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 Kosyakov8846844e2018-07-10 00:49:22875 EXPECT_THAT(interceptor_->urls_requested(),
Alex Clarke6bd0fd52018-02-12 16:08:25876 ElementsAre("http://foo.com/index.html"));
877 FinishAsynchronousTest();
878 }
879};
880
881HEADLESS_ASYNC_DEVTOOLED_TEST_F(BlockWebContentsOpenTest);
882
skyostilfe116162016-02-26 20:53:33883} // namespace headless