blob: b382c0637433f9d2dabba508d7308756a05e5ff7 [file] [log] [blame]
// Copyright 2014 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 "content/shell/browser/layout_test/layout_test_devtools_bindings.h"
#include "base/command_line.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/shell/browser/layout_test/blink_test_controller.h"
#include "content/shell/browser/shell.h"
#include "content/shell/common/layout_test/layout_test_switches.h"
#include "net/base/filename_util.h"
namespace {
GURL GetInspectedPageURL(const GURL& test_url) {
std::string spec = test_url.spec();
std::string test_query_param = "&test=";
std::string test_script_url =
spec.substr(spec.find(test_query_param) + test_query_param.length());
std::string inspected_page_url = test_script_url.replace(
test_script_url.find("/devtools/"), std::string::npos,
"/devtools/resources/inspected-page.html");
return GURL(inspected_page_url);
}
} // namespace
namespace content {
class LayoutTestDevToolsBindings::SecondaryObserver
: public WebContentsObserver {
public:
explicit SecondaryObserver(LayoutTestDevToolsBindings* bindings)
: WebContentsObserver(bindings->inspected_contents()),
bindings_(bindings) {}
// WebContentsObserver implementation.
void DocumentAvailableInMainFrame() override {
if (bindings_)
bindings_->NavigateDevToolsFrontend();
bindings_ = nullptr;
}
// WebContentsObserver implementation.
void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
BlinkTestController::Get()->HandleNewRenderFrameHost(render_frame_host);
}
private:
LayoutTestDevToolsBindings* bindings_;
DISALLOW_COPY_AND_ASSIGN(SecondaryObserver);
};
// static.
GURL LayoutTestDevToolsBindings::GetDevToolsPathAsURL(
const std::string& frontend_url) {
if (!frontend_url.empty())
return GURL(frontend_url);
base::FilePath dir_exe;
if (!PathService::Get(base::DIR_EXE, &dir_exe)) {
NOTREACHED();
return GURL();
}
#if defined(OS_MACOSX)
// On Mac, the executable is in
// out/Release/Content Shell.app/Contents/MacOS/Content Shell.
// We need to go up 3 directories to get to out/Release.
dir_exe = dir_exe.AppendASCII("../../..");
#endif
base::FilePath dev_tools_path;
bool is_debug_dev_tools = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDebugDevTools);
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kCustomDevToolsFrontend)) {
dev_tools_path = base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
switches::kCustomDevToolsFrontend);
} else {
std::string folder = is_debug_dev_tools ? "debug/" : "";
dev_tools_path = dir_exe.AppendASCII("resources/inspector/" + folder);
}
GURL result = net::FilePathToFileURL(
dev_tools_path.AppendASCII("integration_test_runner.html"));
std::string url_string =
base::StringPrintf("%s?experiments=true", result.spec().c_str());
if (is_debug_dev_tools)
url_string += "&debugFrontend=true";
return GURL(url_string);
}
// static.
GURL LayoutTestDevToolsBindings::MapTestURLIfNeeded(const GURL& test_url,
bool* is_devtools_js_test) {
std::string spec = test_url.spec();
bool is_js_test =
base::EndsWith(spec, ".js", base::CompareCase::INSENSITIVE_ASCII);
*is_devtools_js_test =
spec.find("/devtools/") != std::string::npos && is_js_test;
if (!*is_devtools_js_test)
return test_url;
std::string url_string = GetDevToolsPathAsURL(std::string()).spec();
url_string += "&test=" + spec;
return GURL(url_string);
}
void LayoutTestDevToolsBindings::NavigateDevToolsFrontend() {
GURL devtools_url = GetDevToolsPathAsURL(frontend_url_.spec());
NavigationController::LoadURLParams params(devtools_url);
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
web_contents()->GetController().LoadURLWithParams(params);
web_contents()->Focus();
}
void LayoutTestDevToolsBindings::EvaluateInFrontend(int call_id,
const std::string& script) {
if (!ready_for_test_) {
pending_evaluations_.push_back(std::make_pair(call_id, script));
return;
}
std::string encoded_script;
base::JSONWriter::Write(base::Value(script), &encoded_script);
std::string source =
base::StringPrintf("DevToolsAPI.evaluateForTestInFrontend(%d, %s);",
call_id, encoded_script.c_str());
web_contents()->GetMainFrame()->ExecuteJavaScriptForTests(
base::UTF8ToUTF16(source));
}
LayoutTestDevToolsBindings::LayoutTestDevToolsBindings(
WebContents* devtools_contents,
WebContents* inspected_contents,
const std::string& settings,
const GURL& frontend_url,
bool new_harness)
: ShellDevToolsBindings(devtools_contents, inspected_contents, nullptr),
frontend_url_(frontend_url) {
SetPreferences(settings);
if (new_harness) {
secondary_observer_ = base::MakeUnique<SecondaryObserver>(this);
NavigationController::LoadURLParams params(
GetInspectedPageURL(frontend_url));
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
inspected_contents->GetController().LoadURLWithParams(params);
} else {
NavigateDevToolsFrontend();
}
}
LayoutTestDevToolsBindings::~LayoutTestDevToolsBindings() {}
void LayoutTestDevToolsBindings::HandleMessageFromDevToolsFrontend(
const std::string& message) {
std::string method;
base::DictionaryValue* dict = nullptr;
std::unique_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
if (parsed_message && parsed_message->GetAsDictionary(&dict) &&
dict->GetString("method", &method) && method == "readyForTest") {
ready_for_test_ = true;
for (const auto& pair : pending_evaluations_)
EvaluateInFrontend(pair.first, pair.second);
pending_evaluations_.clear();
return;
}
ShellDevToolsBindings::HandleMessageFromDevToolsFrontend(message);
}
void LayoutTestDevToolsBindings::RenderProcessGone(
base::TerminationStatus status) {
BlinkTestController::Get()->DevToolsProcessCrashed();
}
void LayoutTestDevToolsBindings::RenderFrameCreated(
RenderFrameHost* render_frame_host) {
BlinkTestController::Get()->HandleNewRenderFrameHost(render_frame_host);
}
} // namespace content