Commit e9d39029 authored by John Chen's avatar John Chen Committed by Commit Bot

[ChromeDriver] Expand Capabilities for W3C compliance

This CL is one step in making InitSession command W3C compliant.
It expands Capabilities object to include all capabilities that are
specified in the W3C spec. Changes include:
* Re-ordered fields in Capabilities into W3C section and ChromeDriver
  specific section. Entries in W3C section are listed in the same
  order as they appear in W3C spec.
* Added browserName, browserVersion, and platformName capabilities.
  They will be needed for proper firstMatches handling.
* Added fields needed for timeouts capability. Parsing and using of
  these fields will be added in an upcoming CL.
* Replaced legacy name unexpected_alert_behaviour with W3C-compliant
  name unhandled_prompt_behavior.
* Modified Capabilities::Parse to accept all capability values,
  including those not yet supported by ChromeDriver. Added another
  method Capabilities::IsSupported to check for unsupported options.
  This is needed for upcoming W3C-compliant capability validation.

Bug: chromedriver:1997
Change-Id: I5f53341cf47f77a1853f40028b1efe6f0b69c611
Reviewed-on: https://chromium-review.googlesource.com/1241213
Commit-Queue: John Chen <johnchen@chromium.org>
Reviewed-by: default avatarCaleb Rouleau <crouleau@chromium.org>
Cr-Commit-Position: refs/heads/master@{#593989}
parent 6efd6eb8
...@@ -197,22 +197,26 @@ Status ParseMobileEmulation(const base::Value& option, ...@@ -197,22 +197,26 @@ Status ParseMobileEmulation(const base::Value& option,
Status ParsePageLoadStrategy(const base::Value& option, Status ParsePageLoadStrategy(const base::Value& option,
Capabilities* capabilities) { Capabilities* capabilities) {
if (!option.GetAsString(&capabilities->page_load_strategy)) if (!option.GetAsString(&capabilities->page_load_strategy))
return Status(kUnknownError, "must be a string"); return Status(kInvalidArgument, "'pageLoadStrategy' must be a string");
if (capabilities->page_load_strategy == PageLoadStrategy::kNormal || if (capabilities->page_load_strategy == PageLoadStrategy::kNone ||
capabilities->page_load_strategy == PageLoadStrategy::kNone) capabilities->page_load_strategy == PageLoadStrategy::kEager ||
capabilities->page_load_strategy == PageLoadStrategy::kNormal)
return Status(kOk); return Status(kOk);
return Status(kUnknownError, "page load strategy unsupported"); return Status(kInvalidArgument, "invalid 'pageLoadStrategy'");
} }
Status ParseUnexpectedAlertBehaviour(const base::Value& option, Status ParseUnhandledPromptBehavior(const base::Value& option,
Capabilities* capabilities) { Capabilities* capabilities) {
if (!option.GetAsString(&capabilities->unexpected_alert_behaviour)) if (!option.GetAsString(&capabilities->unhandled_prompt_behavior))
return Status(kUnknownError, "must be a string"); return Status(kInvalidArgument,
if (capabilities->unexpected_alert_behaviour == kAccept || "'unhandledPromptBehavior' must be a string");
capabilities->unexpected_alert_behaviour == kDismiss || if (capabilities->unhandled_prompt_behavior == kDismiss ||
capabilities->unexpected_alert_behaviour == kIgnore) capabilities->unhandled_prompt_behavior == kAccept ||
capabilities->unhandled_prompt_behavior == kDismissAndNotify ||
capabilities->unhandled_prompt_behavior == kAcceptAndNotify ||
capabilities->unhandled_prompt_behavior == kIgnore)
return Status(kOk); return Status(kOk);
return Status(kUnknownError, "unexpected alert behaviour unsupported"); return Status(kInvalidArgument, "invalid 'unhandledPromptBehavior'");
} }
Status ParseSwitches(const base::Value& option, Status ParseSwitches(const base::Value& option,
...@@ -669,13 +673,13 @@ PerfLoggingPrefs::PerfLoggingPrefs() ...@@ -669,13 +673,13 @@ PerfLoggingPrefs::PerfLoggingPrefs()
PerfLoggingPrefs::~PerfLoggingPrefs() {} PerfLoggingPrefs::~PerfLoggingPrefs() {}
Capabilities::Capabilities() Capabilities::Capabilities()
: android_use_running_app(false), : accept_insecure_certs(false),
page_load_strategy(PageLoadStrategy::kNormal),
android_use_running_app(false),
detach(false), detach(false),
extension_load_timeout(base::TimeDelta::FromSeconds(10)), extension_load_timeout(base::TimeDelta::FromSeconds(10)),
force_devtools_screenshot(true), force_devtools_screenshot(true),
page_load_strategy(PageLoadStrategy::kNormal),
network_emulation_enabled(false), network_emulation_enabled(false),
accept_insecure_certs(false),
use_automation_extension(true) {} use_automation_extension(true) {}
Capabilities::~Capabilities() {} Capabilities::~Capabilities() {}
...@@ -690,29 +694,44 @@ bool Capabilities::IsRemoteBrowser() const { ...@@ -690,29 +694,44 @@ bool Capabilities::IsRemoteBrowser() const {
Status Capabilities::Parse(const base::DictionaryValue& desired_caps) { Status Capabilities::Parse(const base::DictionaryValue& desired_caps) {
std::map<std::string, Parser> parser_map; std::map<std::string, Parser> parser_map;
// W3C defined capabilities.
parser_map["acceptInsecureCerts"] =
base::BindRepeating(&ParseBoolean, &accept_insecure_certs);
parser_map["browserName"] = base::BindRepeating(&ParseString, &browser_name);
parser_map["browserVersion"] =
base::BindRepeating(&ParseString, &browser_version);
parser_map["platformName"] =
base::BindRepeating(&ParseString, &platform_name);
parser_map["pageLoadStrategy"] = base::BindRepeating(&ParsePageLoadStrategy);
parser_map["proxy"] = base::BindRepeating(&ParseProxy);
// TODO(https://crbug.com/chromedriver/1997): Parse "timeouts".
// TODO(https://crbug.com/chromedriver/2596): "unexpectedAlertBehaviour" is
// legacy name of "unhandledPromptBehavior", remove when we stop supporting
// legacy mode.
parser_map["unexpectedAlertBehaviour"] =
base::BindRepeating(&ParseUnhandledPromptBehavior);
parser_map["unhandledPromptBehavior"] =
base::BindRepeating(&ParseUnhandledPromptBehavior);
// ChromeDriver specific capabilities.
// goog:chromeOptions is the current spec conformance, but chromeOptions is // goog:chromeOptions is the current spec conformance, but chromeOptions is
// still supported // still supported
if (desired_caps.GetDictionary("goog:chromeOptions", nullptr)) { if (desired_caps.GetDictionary("goog:chromeOptions", nullptr)) {
parser_map["goog:chromeOptions"] = base::Bind(&ParseChromeOptions); parser_map["goog:chromeOptions"] = base::BindRepeating(&ParseChromeOptions);
} else { } else {
parser_map["chromeOptions"] = base::Bind(&ParseChromeOptions); parser_map["chromeOptions"] = base::BindRepeating(&ParseChromeOptions);
} }
parser_map["loggingPrefs"] = base::BindRepeating(&ParseLoggingPrefs);
parser_map["loggingPrefs"] = base::Bind(&ParseLoggingPrefs);
parser_map["proxy"] = base::Bind(&ParseProxy);
parser_map["pageLoadStrategy"] = base::Bind(&ParsePageLoadStrategy);
parser_map["unexpectedAlertBehaviour"] =
base::Bind(&ParseUnexpectedAlertBehaviour);
parser_map["acceptInsecureCerts"] =
base::BindRepeating(&ParseBoolean, &accept_insecure_certs);
// Network emulation requires device mode, which is only enabled when // Network emulation requires device mode, which is only enabled when
// mobile emulation is on. // mobile emulation is on.
if (desired_caps.GetDictionary("goog:chromeOptions.mobileEmulation", if (desired_caps.GetDictionary("goog:chromeOptions.mobileEmulation",
nullptr) || nullptr) ||
desired_caps.GetDictionary("chromeOptions.mobileEmulation", nullptr)) { desired_caps.GetDictionary("chromeOptions.mobileEmulation", nullptr)) {
parser_map["networkConnectionEnabled"] = parser_map["networkConnectionEnabled"] =
base::Bind(&ParseBoolean, &network_emulation_enabled); base::BindRepeating(&ParseBoolean, &network_emulation_enabled);
} }
for (std::map<std::string, Parser>::iterator it = parser_map.begin(); for (std::map<std::string, Parser>::iterator it = parser_map.begin();
it != parser_map.end(); ++it) { it != parser_map.end(); ++it) {
const base::Value* capability = NULL; const base::Value* capability = NULL;
...@@ -750,3 +769,27 @@ Status Capabilities::Parse(const base::DictionaryValue& desired_caps) { ...@@ -750,3 +769,27 @@ Status Capabilities::Parse(const base::DictionaryValue& desired_caps) {
} }
return Status(kOk); return Status(kOk);
} }
Status Capabilities::CheckSupport() const {
// TODO(https://crbug.com/chromedriver/1902): pageLoadStrategy=eager not yet
// supported.
if (page_load_strategy.length() > 0 &&
page_load_strategy != PageLoadStrategy::kNormal &&
page_load_strategy != PageLoadStrategy::kNone) {
return Status(kInvalidArgument, "'pageLoadStrategy=" + page_load_strategy +
"' not yet supported");
}
// TODO(https://crbug.com/chromedriver/2597): Some unhandledPromptBehavior
// modes not yet supported.
if (unhandled_prompt_behavior.length() > 0 &&
unhandled_prompt_behavior != kAccept &&
unhandled_prompt_behavior != kDismiss &&
unhandled_prompt_behavior != kIgnore) {
return Status(kInvalidArgument,
"'unhandledPromptBehavior=" + unhandled_prompt_behavior +
"' not yet supported");
}
return Status(kOk);
}
...@@ -96,8 +96,40 @@ struct Capabilities { ...@@ -96,8 +96,40 @@ struct Capabilities {
// Return true if android package is specified. // Return true if android package is specified.
bool IsAndroid() const; bool IsAndroid() const;
// Accepts all W3C defined capabilities (including those not yet supported by
// ChromeDriver) and all ChromeDriver-specific extensions.
Status Parse(const base::DictionaryValue& desired_caps); Status Parse(const base::DictionaryValue& desired_caps);
// Check if all specified capabilities are supported by ChromeDriver.
// The long term goal is to support all standard capabilities, thus making
// this method unnecessary.
Status CheckSupport() const;
//
// W3C defined capabilities
//
bool accept_insecure_certs;
std::string browser_name;
std::string browser_version;
std::string platform_name;
std::string page_load_strategy;
// Data from "proxy" capability are stored in "switches" field.
// The default values for the timeout fields came from W3C spec.
base::TimeDelta script_timeout = base::TimeDelta::FromSeconds(30);
base::TimeDelta page_load_timeout = base::TimeDelta::FromSeconds(300);
base::TimeDelta implicit_wait_timeout = base::TimeDelta::FromSeconds(0);
std::string unhandled_prompt_behavior;
//
// ChromeDriver specific capabilities
//
std::string android_activity; std::string android_activity;
std::string android_device_serial; std::string android_device_serial;
...@@ -147,14 +179,8 @@ struct Capabilities { ...@@ -147,14 +179,8 @@ struct Capabilities {
// If set, enable minidump for chrome crashes and save to this directory. // If set, enable minidump for chrome crashes and save to this directory.
std::string minidump_path; std::string minidump_path;
std::string page_load_strategy;
std::string unexpected_alert_behaviour;
bool network_emulation_enabled; bool network_emulation_enabled;
bool accept_insecure_certs;
PerfLoggingPrefs perf_logging_prefs; PerfLoggingPrefs perf_logging_prefs;
std::unique_ptr<base::ListValue> devtools_events_logging_prefs; std::unique_ptr<base::ListValue> devtools_events_logging_prefs;
......
...@@ -21,7 +21,9 @@ ...@@ -21,7 +21,9 @@
#include "chrome/test/chromedriver/command_listener.h" #include "chrome/test/chromedriver/command_listener.h"
static const char kAccept[] = "accept"; static const char kAccept[] = "accept";
static const char kAcceptAndNotify[] = "accept and notify";
static const char kDismiss[] = "dismiss"; static const char kDismiss[] = "dismiss";
static const char kDismissAndNotify[] = "dismiss and notify";
static const char kIgnore[] = "ignore"; static const char kIgnore[] = "ignore";
// Controls whether ChromeDriver operates in W3C mode (when true) or legacy // Controls whether ChromeDriver operates in W3C mode (when true) or legacy
...@@ -104,7 +106,7 @@ struct Session { ...@@ -104,7 +106,7 @@ struct Session {
// |CommandListener|s might be |CommandListenerProxy|s that forward to // |CommandListener|s might be |CommandListenerProxy|s that forward to
// |DevToolsEventListener|s owned by |chrome|. // |DevToolsEventListener|s owned by |chrome|.
std::vector<std::unique_ptr<CommandListener>> command_listeners; std::vector<std::unique_ptr<CommandListener>> command_listeners;
std::string unexpected_alert_behaviour; std::string unhandled_prompt_behavior;
}; };
Session* GetThreadLocalSession(); Session* GetThreadLocalSession();
......
...@@ -134,8 +134,9 @@ std::unique_ptr<base::DictionaryValue> CreateCapabilities( ...@@ -134,8 +134,9 @@ std::unique_ptr<base::DictionaryValue> CreateCapabilities(
caps->SetBoolean("acceptInsecureCerts", capabilities.accept_insecure_certs); caps->SetBoolean("acceptInsecureCerts", capabilities.accept_insecure_certs);
caps->SetBoolean("nativeEvents", true); caps->SetBoolean("nativeEvents", true);
caps->SetBoolean("hasTouchScreen", session->chrome->HasTouchScreen()); caps->SetBoolean("hasTouchScreen", session->chrome->HasTouchScreen());
caps->SetString("unexpectedAlertBehaviour", caps->SetString(session->w3c_compliant ? "unhandledPromptBehavior"
session->unexpected_alert_behaviour); : "unexpectedAlertBehaviour",
session->unhandled_prompt_behavior);
// add setWindowRect based on whether we are desktop/android/remote // add setWindowRect based on whether we are desktop/android/remote
if (capabilities.IsAndroid() || capabilities.IsRemoteBrowser()) { if (capabilities.IsAndroid() || capabilities.IsRemoteBrowser()) {
...@@ -260,11 +261,13 @@ Status InitSessionHelper(const InitSessionParams& bound_params, ...@@ -260,11 +261,13 @@ Status InitSessionHelper(const InitSessionParams& bound_params,
Capabilities capabilities; Capabilities capabilities;
Status status = capabilities.Parse(*desired_caps); Status status = capabilities.Parse(*desired_caps);
if (status.IsError())
return status;
status = capabilities.CheckSupport();
if (status.IsError()) if (status.IsError())
return status; return status;
desired_caps->GetString("unexpectedAlertBehaviour", session->unhandled_prompt_behavior = capabilities.unhandled_prompt_behavior;
&session->unexpected_alert_behaviour);
Log::Level driver_level = Log::kWarning; Log::Level driver_level = Log::kWarning;
if (capabilities.logging_prefs.count(WebDriverLog::kDriverType)) if (capabilities.logging_prefs.count(WebDriverLog::kDriverType))
......
...@@ -249,10 +249,10 @@ Status ExecuteWindowCommand(const WindowCommand& command, ...@@ -249,10 +249,10 @@ Status ExecuteWindowCommand(const WindowCommand& command,
// Close the dialog depending on the unexpectedalert behaviour set by user // Close the dialog depending on the unexpectedalert behaviour set by user
// before returning an error, so that subsequent commands do not fail. // before returning an error, so that subsequent commands do not fail.
std::string alert_behaviour = session->unexpected_alert_behaviour; std::string prompt_behavior = session->unhandled_prompt_behavior;
if (alert_behaviour == kAccept) if (prompt_behavior == kAccept)
status = dialog_manager->HandleDialog(true, session->prompt_text.get()); status = dialog_manager->HandleDialog(true, session->prompt_text.get());
else if (alert_behaviour == kDismiss) else if (prompt_behavior == kDismiss)
status = dialog_manager->HandleDialog(false, session->prompt_text.get()); status = dialog_manager->HandleDialog(false, session->prompt_text.get());
if (status.IsError()) if (status.IsError())
return status; return status;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment