Commit c86e1636 authored by sandromaggi's avatar sandromaggi Committed by Commit Bot

[Autofill Assistant] Add new web-action to get attribute

This CL adds a new web-action to get the attribute of an element.
This is required for extending the |GetElementStatusAction| to
also handle the text content of an element.

The attributes can be nested.

Bug: b/169924567
Change-Id: Id5ff86d907d34d8cbf8e56aa8dfd377fe8f934bf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2463233Reviewed-by: default avatarStephane Zermatten <szermatt@chromium.org>
Reviewed-by: default avatarLuca Hunkeler <hluca@google.com>
Commit-Queue: Sandro Maggi <sandromaggi@google.com>
Cr-Commit-Position: refs/heads/master@{#816111}
parent c03f58ae
...@@ -231,6 +231,15 @@ class ActionDelegate { ...@@ -231,6 +231,15 @@ class ActionDelegate {
base::OnceCallback<void(const ClientStatus&, const std::string&)> base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) = 0; callback) = 0;
// Get the value of a nested |attribute| from an |element| and return the
// result through |callback|. If the lookup fails, the value will be empty.
// An empty result does not mean an error.
virtual void GetStringAttribute(
const std::vector<std::string>& attributes,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) = 0;
// Set the |value| of field |element| and return the result through // Set the |value| of field |element| and return the result through
// |callback|. If |simulate_key_presses| is true, the value will be set by // |callback|. If |simulate_key_presses| is true, the value will be set by
// clicking the field and then simulating key presses, otherwise the `value` // clicking the field and then simulating key presses, otherwise the `value`
......
...@@ -189,6 +189,12 @@ class MockActionDelegate : public ActionDelegate { ...@@ -189,6 +189,12 @@ class MockActionDelegate : public ActionDelegate {
base::OnceCallback<void(const ClientStatus&, base::OnceCallback<void(const ClientStatus&,
const std::string&)>& callback)); const std::string&)>& callback));
MOCK_METHOD3(GetStringAttribute,
void(const std::vector<std::string>& attributes,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&,
const std::string&)> callback));
void SetFieldValue(const std::string& value, void SetFieldValue(const std::string& value,
KeyboardValueFillStrategy fill_strategy, KeyboardValueFillStrategy fill_strategy,
int key_press_delay_in_millisecond, int key_press_delay_in_millisecond,
......
...@@ -583,6 +583,15 @@ void ScriptExecutor::GetFieldValue( ...@@ -583,6 +583,15 @@ void ScriptExecutor::GetFieldValue(
delegate_->GetWebController()->GetFieldValue(selector, std::move(callback)); delegate_->GetWebController()->GetFieldValue(selector, std::move(callback));
} }
void ScriptExecutor::GetStringAttribute(
const std::vector<std::string>& attributes,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) {
delegate_->GetWebController()->GetStringAttribute(element, attributes,
std::move(callback));
}
void ScriptExecutor::SetFieldValue( void ScriptExecutor::SetFieldValue(
const std::string& value, const std::string& value,
KeyboardValueFillStrategy fill_strategy, KeyboardValueFillStrategy fill_strategy,
......
...@@ -185,6 +185,11 @@ class ScriptExecutor : public ActionDelegate, ...@@ -185,6 +185,11 @@ class ScriptExecutor : public ActionDelegate,
const Selector& selector, const Selector& selector,
base::OnceCallback<void(const ClientStatus&, const std::string&)> base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) override; callback) override;
void GetStringAttribute(
const std::vector<std::string>& attributes,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) override;
void SetFieldValue( void SetFieldValue(
const std::string& value, const std::string& value,
KeyboardValueFillStrategy fill_strategy, KeyboardValueFillStrategy fill_strategy,
......
...@@ -77,6 +77,19 @@ class MockWebController : public WebController { ...@@ -77,6 +77,19 @@ class MockWebController : public WebController {
base::OnceCallback<void(const ClientStatus&, base::OnceCallback<void(const ClientStatus&,
const std::string&)>& callback)); const std::string&)>& callback));
void GetStringAttribute(
const ElementFinder::Result& element,
const std::vector<std::string>& attributes,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) override {
OnGetStringAttribute(element, attributes, callback);
}
MOCK_METHOD3(OnGetStringAttribute,
void(const ElementFinder::Result& element,
const std::vector<std::string>& attributes,
base::OnceCallback<void(const ClientStatus&,
const std::string&)>& callback));
void GetVisualViewport( void GetVisualViewport(
base::OnceCallback<void(bool, const RectF&)> callback) override { base::OnceCallback<void(bool, const RectF&)> callback) override {
OnGetVisualViewport(callback); OnGetVisualViewport(callback);
......
...@@ -112,6 +112,18 @@ const char* const kHighlightElementScript = ...@@ -112,6 +112,18 @@ const char* const kHighlightElementScript =
const char* const kGetValueAttributeScript = const char* const kGetValueAttributeScript =
"function () { return this.value; }"; "function () { return this.value; }";
// Javascript code to retrieve the nested |attribute| of a node.
// The function intentionally has no "has value" check, such that a bad access
// will return an error.
const char* const kGetElementAttributeScript =
R"(function (attributes) {
let it = this;
for (let i = 0; i < attributes.length; ++i) {
it = it[attributes[i]];
}
return it;
})";
// Javascript code to select the current value. // Javascript code to select the current value.
const char* const kSelectFieldValue = "function() { this.select(); }"; const char* const kSelectFieldValue = "function() { this.select(); }";
...@@ -126,6 +138,8 @@ const char* const kSetValueAttributeScript = ...@@ -126,6 +138,8 @@ const char* const kSetValueAttributeScript =
})"; })";
// Javascript code to set an attribute of a node to a given value. // Javascript code to set an attribute of a node to a given value.
// The function intentionally has no "has value" check, such that a bad access
// will return an error.
const char* const kSetAttributeScript = const char* const kSetAttributeScript =
R"(function (attribute, value) { R"(function (attribute, value) {
let receiver = this; let receiver = this;
...@@ -288,11 +302,25 @@ void WebController::OnJavaScriptResult( ...@@ -288,11 +302,25 @@ void WebController::OnJavaScriptResult(
ClientStatus status = ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__); CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) { if (!status.ok()) {
VLOG(1) << __func__ << " Failed JavaScript."; VLOG(1) << __func__ << " Failed JavaScript with status: " << status;
} }
std::move(callback).Run(status); std::move(callback).Run(status);
} }
void WebController::OnJavaScriptResultForString(
base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
std::string value;
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
VLOG(1) << __func__ << "Failed JavaScript with status: " << status;
}
SafeGetStringValue(result->GetResult(), &value);
std::move(callback).Run(status, value);
}
void WebController::ScrollIntoView( void WebController::ScrollIntoView(
const ElementFinder::Result& element, const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) { base::OnceCallback<void(const ClientStatus&)> callback) {
...@@ -902,7 +930,6 @@ void WebController::OnFindElementForGetFieldValue( ...@@ -902,7 +930,6 @@ void WebController::OnFindElementForGetFieldValue(
base::OnceCallback<void(const ClientStatus&, const std::string&)> callback, base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
const ClientStatus& status, const ClientStatus& status,
std::unique_ptr<ElementFinder::Result> element_result) { std::unique_ptr<ElementFinder::Result> element_result) {
const std::string object_id = element_result->object_id;
if (!status.ok()) { if (!status.ok()) {
std::move(callback).Run(status, ""); std::move(callback).Run(status, "");
return; return;
...@@ -910,28 +937,44 @@ void WebController::OnFindElementForGetFieldValue( ...@@ -910,28 +937,44 @@ void WebController::OnFindElementForGetFieldValue(
devtools_client_->GetRuntime()->CallFunctionOn( devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder() runtime::CallFunctionOnParams::Builder()
.SetObjectId(object_id) .SetObjectId(element_result->object_id)
.SetFunctionDeclaration(std::string(kGetValueAttributeScript)) .SetFunctionDeclaration(std::string(kGetValueAttributeScript))
.SetReturnByValue(true) .SetReturnByValue(true)
.Build(), .Build(),
element_result->node_frame_id, element_result->node_frame_id,
base::BindOnce(&WebController::OnGetValueAttribute, base::BindOnce(&WebController::OnJavaScriptResultForString,
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
void WebController::OnGetValueAttribute( void WebController::GetStringAttribute(
base::OnceCallback<void(const ClientStatus& element_status, const ElementFinder::Result& element,
const std::string&)> callback, const std::vector<std::string>& attributes,
const DevtoolsClient::ReplyStatus& reply_status, base::OnceCallback<void(const ClientStatus&, const std::string&)>
std::unique_ptr<runtime::CallFunctionOnResult> result) { callback) {
std::string value; VLOG(3) << __func__ << " attributes=[" << base::JoinString(attributes, ",")
ClientStatus status = << "]";
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
// Read the result returned from Javascript code. if (attributes.empty()) {
VLOG_IF(1, !status.ok()) << __func__ std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__), "");
<< "Failed to get attribute value: " << status; return;
SafeGetStringValue(result->GetResult(), &value); }
std::move(callback).Run(status, value); base::Value::ListStorage attribute_values;
for (const std::string& attribute : attributes) {
attribute_values.emplace_back(base::Value(attribute));
}
std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
AddRuntimeCallArgument(attribute_values, &arguments);
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(element.object_id)
.SetArguments(std::move(arguments))
.SetFunctionDeclaration(std::string(kGetElementAttributeScript))
.SetReturnByValue(true)
.Build(),
element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResultForString,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
void WebController::SetFieldValue( void WebController::SetFieldValue(
...@@ -1193,17 +1236,16 @@ void WebController::SetAttribute( ...@@ -1193,17 +1236,16 @@ void WebController::SetAttribute(
const std::vector<std::string>& attributes, const std::vector<std::string>& attributes,
const std::string& value, const std::string& value,
base::OnceCallback<void(const ClientStatus&)> callback) { base::OnceCallback<void(const ClientStatus&)> callback) {
#ifdef NDEBUG
VLOG(3) << __func__ << " attributes=(redacted), value=(redacted)";
#else
DVLOG(3) << __func__ << " attributes=[" << base::JoinString(attributes, ",") DVLOG(3) << __func__ << " attributes=[" << base::JoinString(attributes, ",")
<< "], value=" << value; << "], value=" << value;
#endif
DCHECK_GT(attributes.size(), 0u); if (attributes.empty()) {
std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
return;
}
base::Value::ListStorage attribute_values; base::Value::ListStorage attribute_values;
for (const std::string& string : attributes) { for (const std::string& attribute : attributes) {
attribute_values.emplace_back(base::Value(string)); attribute_values.emplace_back(base::Value(attribute));
} }
std::vector<std::unique_ptr<runtime::CallArgument>> arguments; std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
...@@ -1336,27 +1378,10 @@ void WebController::GetOuterHtml( ...@@ -1336,27 +1378,10 @@ void WebController::GetOuterHtml(
.SetReturnByValue(true) .SetReturnByValue(true)
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(&WebController::OnGetOuterHtml, base::BindOnce(&WebController::OnJavaScriptResultForString,
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
void WebController::OnGetOuterHtml(
base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
VLOG(2) << __func__ << " Failed to get HTML content for GetOuterHtml";
std::move(callback).Run(status, "");
return;
}
std::string value;
SafeGetStringValue(result->GetResult(), &value);
std::move(callback).Run(OkClientStatus(), value);
}
void WebController::GetElementTag( void WebController::GetElementTag(
const ElementFinder::Result& element, const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)> base::OnceCallback<void(const ClientStatus&, const std::string&)>
...@@ -1368,26 +1393,10 @@ void WebController::GetElementTag( ...@@ -1368,26 +1393,10 @@ void WebController::GetElementTag(
.SetReturnByValue(true) .SetReturnByValue(true)
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(&WebController::OnGetElementTag, base::BindOnce(&WebController::OnJavaScriptResultForString,
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
void WebController::OnGetElementTag(
base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
VLOG(2) << __func__ << " Failed to get element tag for GetElementTag";
std::move(callback).Run(status, "");
return;
}
std::string value;
SafeGetStringValue(result->GetResult(), &value);
std::move(callback).Run(OkClientStatus(), value);
}
void WebController::InternalWaitForDocumentToBecomeInteractive( void WebController::InternalWaitForDocumentToBecomeInteractive(
int remaining_rounds, int remaining_rounds,
const std::string& object_id, const std::string& object_id,
......
...@@ -151,6 +151,15 @@ class WebController { ...@@ -151,6 +151,15 @@ class WebController {
base::OnceCallback<void(const ClientStatus&, const std::string&)> base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback); callback);
// Get the value of a nested |attribute| from an |element| and return the
// result through |callback|. If the lookup fails, the value will be empty.
// An empty result does not mean an error.
virtual void GetStringAttribute(
const ElementFinder::Result& element,
const std::vector<std::string>& attributes,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback);
// Set the |value| of field |element| and return the result through // Set the |value| of field |element| and return the result through
// |callback|. The strategy used to fill the value is defined by // |callback|. The strategy used to fill the value is defined by
// |fill_strategy|, see the proto for further explanation. // |fill_strategy|, see the proto for further explanation.
...@@ -281,6 +290,11 @@ class WebController { ...@@ -281,6 +290,11 @@ class WebController {
base::OnceCallback<void(const ClientStatus&)> callback, base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status, const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result); std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnJavaScriptResultForString(
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnWaitForDocumentToBecomeInteractive( void OnWaitForDocumentToBecomeInteractive(
base::OnceCallback<void(const ClientStatus&)> callback, base::OnceCallback<void(const ClientStatus&)> callback,
bool result); bool result);
...@@ -360,11 +374,6 @@ class WebController { ...@@ -360,11 +374,6 @@ class WebController {
callback, callback,
const ClientStatus& status, const ClientStatus& status,
std::unique_ptr<ElementFinder::Result> element_result); std::unique_ptr<ElementFinder::Result> element_result);
void OnGetValueAttribute(
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnClearFieldForSetFieldValue( void OnClearFieldForSetFieldValue(
const ElementFinder::Result& element, const ElementFinder::Result& element,
const std::vector<UChar32>& codepoints, const std::vector<UChar32>& codepoints,
...@@ -420,14 +429,6 @@ class WebController { ...@@ -420,14 +429,6 @@ class WebController {
const ElementFinder::Result& element, const ElementFinder::Result& element,
const std::string& value, const std::string& value,
base::OnceCallback<void(const ClientStatus&)> callback); base::OnceCallback<void(const ClientStatus&)> callback);
void OnGetOuterHtml(base::OnceCallback<void(const ClientStatus&,
const std::string&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnGetElementTag(base::OnceCallback<void(const ClientStatus&,
const std::string&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForPosition( void OnFindElementForPosition(
base::OnceCallback<void(bool, const RectF&)> callback, base::OnceCallback<void(bool, const RectF&)> callback,
const ClientStatus& status, const ClientStatus& status,
......
...@@ -148,6 +148,19 @@ class WebControllerBrowserTest : public content::ContentBrowserTest, ...@@ -148,6 +148,19 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
std::move(done_callback).Run(); std::move(done_callback).Run();
} }
void ElementRetainingStringCallback(
std::unique_ptr<ElementFinder::Result> element,
base::OnceClosure done_callback,
ClientStatus* result_output,
std::string* result,
const ClientStatus& status,
const std::string& value) {
EXPECT_TRUE(element != nullptr);
*result_output = status;
result->assign(value);
std::move(done_callback).Run();
}
void ClickOrTapElement(const Selector& selector, ClickType click_type) { void ClickOrTapElement(const Selector& selector, ClickType click_type) {
base::RunLoop run_loop; base::RunLoop run_loop;
ClientStatus result_output; ClientStatus result_output;
...@@ -356,6 +369,7 @@ class WebControllerBrowserTest : public content::ContentBrowserTest, ...@@ -356,6 +369,7 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
html_output)); html_output));
run_loop.Run(); run_loop.Run();
EXPECT_EQ(ACTION_APPLIED, result.proto_status());
return result; return result;
} }
...@@ -369,22 +383,10 @@ class WebControllerBrowserTest : public content::ContentBrowserTest, ...@@ -369,22 +383,10 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
ASSERT_TRUE(element_result != nullptr); ASSERT_TRUE(element_result != nullptr);
web_controller_->GetOuterHtml( web_controller_->GetOuterHtml(
*element_result, *element_result,
base::BindOnce(&WebControllerBrowserTest::OnGetOuterHtml, base::BindOnce(
base::Unretained(this), std::move(done_callback), &WebControllerBrowserTest::ElementRetainingStringCallback,
result_output, html_output, std::move(element_result))); base::Unretained(this), std::move(element_result),
} std::move(done_callback), result_output, html_output));
void OnGetOuterHtml(base::OnceClosure done_callback,
ClientStatus* successful_output,
std::string* html_output,
std::unique_ptr<ElementFinder::Result> element,
const ClientStatus& status,
const std::string& html) {
EXPECT_EQ(ACTION_APPLIED, status.proto_status());
EXPECT_TRUE(element != nullptr);
*successful_output = status;
*html_output = html;
std::move(done_callback).Run();
} }
ClientStatus GetElementTag(const Selector& selector, ClientStatus GetElementTag(const Selector& selector,
...@@ -400,6 +402,7 @@ class WebControllerBrowserTest : public content::ContentBrowserTest, ...@@ -400,6 +402,7 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
element_tag_output)); element_tag_output));
run_loop.Run(); run_loop.Run();
EXPECT_EQ(ACTION_APPLIED, result.proto_status());
return result; return result;
} }
...@@ -413,23 +416,10 @@ class WebControllerBrowserTest : public content::ContentBrowserTest, ...@@ -413,23 +416,10 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
ASSERT_TRUE(element_result != nullptr); ASSERT_TRUE(element_result != nullptr);
web_controller_->GetElementTag( web_controller_->GetElementTag(
*element_result, *element_result,
base::BindOnce(&WebControllerBrowserTest::OnGetElementTag, base::BindOnce(
base::Unretained(this), std::move(done_callback), &WebControllerBrowserTest::ElementRetainingStringCallback,
result_output, element_tag_output, base::Unretained(this), std::move(element_result),
std::move(element_result))); std::move(done_callback), result_output, element_tag_output));
}
void OnGetElementTag(base::OnceClosure done_callback,
ClientStatus* successful_output,
std::string* element_tag_output,
std::unique_ptr<ElementFinder::Result> element,
const ClientStatus& status,
const std::string& element_tag) {
EXPECT_EQ(ACTION_APPLIED, status.proto_status());
ASSERT_TRUE(element != nullptr);
*successful_output = status;
*element_tag_output = element_tag;
std::move(done_callback).Run();
} }
void FindElement(const Selector& selector, void FindElement(const Selector& selector,
...@@ -491,6 +481,40 @@ class WebControllerBrowserTest : public content::ContentBrowserTest, ...@@ -491,6 +481,40 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
EXPECT_FALSE(result.object_id.empty()); EXPECT_FALSE(result.object_id.empty());
} }
ClientStatus GetStringAttribute(const Selector& selector,
const std::vector<std::string>& attributes,
std::string* value) {
base::RunLoop run_loop;
ClientStatus result;
web_controller_->FindElement(
selector, /* strict= */ true,
base::BindOnce(
&WebControllerBrowserTest::FindGetStringAttributeElementCallback,
base::Unretained(this), attributes, run_loop.QuitClosure(), &result,
value));
run_loop.Run();
return result;
}
void FindGetStringAttributeElementCallback(
const std::vector<std::string>& attributes,
base::OnceClosure done_callback,
ClientStatus* result_output,
std::string* value,
const ClientStatus& element_status,
std::unique_ptr<ElementFinder::Result> element_result) {
EXPECT_EQ(ACTION_APPLIED, element_status.proto_status());
ASSERT_TRUE(element_result != nullptr);
web_controller_->GetStringAttribute(
*element_result, attributes,
base::BindOnce(
&WebControllerBrowserTest::ElementRetainingStringCallback,
base::Unretained(this), std::move(element_result),
std::move(done_callback), result_output, value));
}
void GetFieldsValue(const std::vector<Selector>& selectors, void GetFieldsValue(const std::vector<Selector>& selectors,
const std::vector<std::string>& expected_values) { const std::vector<std::string>& expected_values) {
base::RunLoop run_loop; base::RunLoop run_loop;
...@@ -553,20 +577,11 @@ class WebControllerBrowserTest : public content::ContentBrowserTest, ...@@ -553,20 +577,11 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
web_controller_->SetFieldValue( web_controller_->SetFieldValue(
*element_result, value, fill_strategy, *element_result, value, fill_strategy,
/* key_press_delay_in_millisecond= */ 0, /* key_press_delay_in_millisecond= */ 0,
base::BindOnce(&WebControllerBrowserTest::SetFieldValueCallback, base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback,
base::Unretained(this), std::move(element_result), base::Unretained(this), std::move(element_result),
std::move(done_callback), result_output)); std::move(done_callback), result_output));
} }
void SetFieldValueCallback(std::unique_ptr<ElementFinder::Result> element,
base::OnceClosure done_callback,
ClientStatus* result_output,
const ClientStatus& status) {
EXPECT_TRUE(element != nullptr);
*result_output = status;
std::move(done_callback).Run();
}
ClientStatus SendKeyboardInput(const Selector& selector, ClientStatus SendKeyboardInput(const Selector& selector,
const std::vector<UChar32>& codepoints, const std::vector<UChar32>& codepoints,
int delay_in_milli) { int delay_in_milli) {
...@@ -2054,4 +2069,25 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ...@@ -2054,4 +2069,25 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
GetFieldsValue({selector}, {"email@example.com"}); GetFieldsValue({selector}, {"email@example.com"});
} }
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetStringAttribute) {
std::string value;
std::vector<std::string> inner_text_attribute = {"innerText"};
ASSERT_EQ(ACTION_APPLIED, GetStringAttribute(Selector({"#testOuterHtml p"}),
inner_text_attribute, &value)
.proto_status());
EXPECT_EQ("Paragraph", value);
std::vector<std::string> option_label_attribute = {"options", "2", "label"};
ASSERT_EQ(ACTION_APPLIED, GetStringAttribute(Selector({"#select"}),
option_label_attribute, &value)
.proto_status());
EXPECT_EQ("Three", value);
std::vector<std::string> bad_access = {"none", "none"};
ASSERT_EQ(UNEXPECTED_JS_ERROR,
GetStringAttribute(Selector({"#button"}), bad_access, &value)
.proto_status());
}
} // namespace autofill_assistant } // namespace autofill_assistant
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