blob: c9bd2827db48eb217f08b45ae019be98cd242925 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/message_loop/message_loop_current.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "headless/public/devtools/domains/emulation.h"
#include "headless/public/devtools/domains/page.h"
#include "headless/public/devtools/domains/runtime.h"
#include "headless/public/headless_browser.h"
#include "headless/public/headless_browser_context.h"
#include "headless/test/headless_browser_test.h"
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
namespace headless {
class CompositorController;
class HeadlessDevToolsClient;
class VirtualTimeController;
namespace dom_snapshot {
class GetSnapshotResult;
} // namespace dom_snapshot
// Base class for tests that render a particular page and verify the output.
class HeadlessRenderTest : public HeadlessAsyncDevTooledBrowserTest,
public page::ExperimentalObserver,
public runtime::ExperimentalObserver {
struct Navigation {
std::string url;
page::FrameScheduledNavigationReason reason;
void RunDevTooledTest() override;
// Automatically waits in destructor until callback is called.
class Sync {
Sync() {}
~Sync() {
base::MessageLoopCurrent::ScopedNestableTaskAllower nest_loop;
operator base::OnceClosure() { return run_loop.QuitClosure(); }
base::RunLoop run_loop;
struct ScreenshotOptions {
ScreenshotOptions(const std::string& golden_file_name,
int x,
int y,
int width,
int height,
double scale);
std::string golden_file_name;
int x;
int y;
int width;
int height;
double scale;
~HeadlessRenderTest() override;
// Marks that the test case reached the final conclusion.
void SetTestCompleted() { state_ = FINISHED; }
// Do necessary preparations and return a URL to render.
virtual GURL GetPageUrl(HeadlessDevToolsClient* client) = 0;
// Check if the DOM snapshot is as expected.
virtual void VerifyDom(dom_snapshot::GetSnapshotResult* dom_snapshot);
// Called when all steps needed to load and present page are done.
virtual void OnPageRenderCompleted();
// Called if page rendering wasn't completed within reasonable time.
virtual void OnTimeout();
// Override to set specific options for requests.
virtual void OverrideWebPreferences(WebPreferences* preferences);
// Determines whether a screenshot will be taken or not. If one is taken,
// ScreenshotOptions specifies the area to capture as well as a golden data
// file to compare the result to. By default, no screenshot is taken.
virtual base::Optional<ScreenshotOptions> GetScreenshotOptions();
// Returns the emulated width/height of the window. Defaults to 800x600.
virtual gfx::Size GetEmulatedWindowSize();
// Setting up the browsertest.
void SetUpCommandLine(base::CommandLine* command_line) override;
void SetUp() override;
void CustomizeHeadlessBrowserContext(
HeadlessBrowserContext::Builder& builder) override;
bool GetEnableBeginFrameControl() override;
void PostRunAsynchronousTest() override;
// page::ExperimentalObserver implementation:
void OnLoadEventFired(const page::LoadEventFiredParams& params) override;
void OnFrameStartedLoading(
const page::FrameStartedLoadingParams& params) override;
void OnFrameScheduledNavigation(
const page::FrameScheduledNavigationParams& params) override;
void OnFrameNavigated(const page::FrameNavigatedParams& params) override;
// runtime::ExperimentalObserver implementation:
void OnConsoleAPICalled(
const runtime::ConsoleAPICalledParams& params) override;
void OnExceptionThrown(const runtime::ExceptionThrownParams& params) override;
// For each frame, keep track of scheduled navigations.
// FYI: It doesn't track every navigations. For instance, it doesn't include
// the first navigation. It doesn't include HTTP redirect, but it includes
// client-side redirect.
std::map<std::string, std::vector<Navigation>> scheduled_navigations_;
std::map<std::string, std::vector<std::unique_ptr<page::Frame>>> frames_;
std::string main_frame_;
std::vector<std::string> console_log_;
std::vector<std::string> js_exceptions_;
class AdditionalVirtualTimeBudget;
void SetDeviceMetricsOverride(
std::unique_ptr<headless::page::Viewport> viewport);
void HandleVirtualTimeExhausted();
void OnGetDomSnapshotDone(
std::unique_ptr<dom_snapshot::GetSnapshotResult> result);
void CaptureScreenshot(const ScreenshotOptions& options);
void ScreenshotCaptured(const ScreenshotOptions& options,
const std::string& data);
void RenderComplete();
void HandleTimeout();
void CleanUp();
enum State {
INIT, // Setting up the client, no navigation performed yet.
STARTING, // Navigation request issued but URL not being loaded yet.
LOADING, // URL was requested but resources are not fully loaded yet.
RENDERING, // Main resources were loaded but page is still being rendered.
DONE, // Page considered to be rendered, DOM snapshot is being taken.
SCREENSHOT, // DOM snapshot has completed, screenshot is being taken.
FINISHED, // Test has finished.
State state_ = INIT;
std::unique_ptr<VirtualTimeController> virtual_time_controller_;
std::unique_ptr<CompositorController> compositor_controller_;
base::test::ScopedFeatureList scoped_feature_list_;
base::WeakPtrFactory<HeadlessRenderTest> weak_ptr_factory_;
} // namespace headless