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

[Autofill Assistant] Send failing step

This CL adds reporting for which web-action failed. This
is useful for actions that execute in multiple steps, e.g.
|ClickAction|:

* WaitForDocumentToBecomeInteractive
* ScrollIntoView
* ClickOrTap

Bug: b/169924567
Change-Id: I644178737fc21039767670ffcb5853d794ab754b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2475115
Commit-Queue: Sandro Maggi <sandromaggi@google.com>
Reviewed-by: default avatarStephane Zermatten <szermatt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#818373}
parent 7501f245
...@@ -108,6 +108,36 @@ TEST_F(ActionDelegateUtilTest, FindElementAndExecuteMultipleActions) { ...@@ -108,6 +108,36 @@ TEST_F(ActionDelegateUtilTest, FindElementAndExecuteMultipleActions) {
base::Unretained(this))); base::Unretained(this)));
} }
TEST_F(ActionDelegateUtilTest,
FindElementAndExecuteMultipleActionsAbortsOnError) {
InSequence sequence;
Selector expected_selector({"#element"});
auto expected_element =
test_util::MockFindElement(mock_action_delegate_, expected_selector);
EXPECT_CALL(*this, MockIndexedAction(1, EqualsElement(expected_element), _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(*this, MockIndexedAction(2, EqualsElement(expected_element), _))
.WillOnce(RunOnceCallback<2>(ClientStatus(UNEXPECTED_JS_ERROR)));
EXPECT_CALL(*this, MockIndexedAction(3, EqualsElement(expected_element), _))
.Times(0);
EXPECT_CALL(*this, MockDone(EqualsStatus(ClientStatus(UNEXPECTED_JS_ERROR))));
auto actions = std::make_unique<ElementActionVector>();
actions->emplace_back(base::BindOnce(
&ActionDelegateUtilTest::MockIndexedAction, base::Unretained(this), 1));
actions->emplace_back(base::BindOnce(
&ActionDelegateUtilTest::MockIndexedAction, base::Unretained(this), 2));
actions->emplace_back(base::BindOnce(
&ActionDelegateUtilTest::MockIndexedAction, base::Unretained(this), 3));
FindElementAndPerformAll(&mock_action_delegate_, expected_selector,
std::move(actions),
base::BindOnce(&ActionDelegateUtilTest::MockDone,
base::Unretained(this)));
}
TEST_F(ActionDelegateUtilTest, ActionDelegateDeletedDuringExecution) { TEST_F(ActionDelegateUtilTest, ActionDelegateDeletedDuringExecution) {
InSequence sequence; InSequence sequence;
......
...@@ -650,6 +650,9 @@ message ProcessedActionStatusDetailsProto { ...@@ -650,6 +650,9 @@ message ProcessedActionStatusDetailsProto {
// More information included for |SetFormFieldValueProto| related errors. // More information included for |SetFormFieldValueProto| related errors.
optional SetFormFieldErrorInfoProto form_field_error_info = 4; optional SetFormFieldErrorInfoProto form_field_error_info = 4;
// Additional information from the |WebController|.
optional WebControllerErrorInfoProto web_controller_error_info = 5;
} }
message NavigationInfoProto { message NavigationInfoProto {
...@@ -761,6 +764,63 @@ message SetFormFieldErrorInfoProto { ...@@ -761,6 +764,63 @@ message SetFormFieldErrorInfoProto {
optional int32 invalid_keypress_index = 1; optional int32 invalid_keypress_index = 1;
} }
// Message to report errors related to WebController execution.
message WebControllerErrorInfoProto {
enum WebAction {
UNSPECIFIED_WEB_ACTION = 0;
// Scroll an element into view by centering it on the page. This uses
// native JS functionality.
SCROLL_INTO_VIEW = 1;
// Waiting for the document ready state to be interactive.
WAIT_FOR_DOCUMENT_TO_BECOME_INTERACTIVE = 2;
// Send a click or tap event to an element.
CLICK_OR_TAP_ELEMENT = 3;
// Select an option from an HTML dropdown.
SELECT_OPTION = 4;
// Set the element's style to be highlighted by adding a BoxShadow to the
// element.
HIGHLIGHT_ELEMENT = 5;
// Scroll the element into view with padding. This does not use native JS
// functionality but calculates the scrolling manually.
SCROLL_INTO_VIEW_WITH_PADDING = 6;
// Get the |value| attribute of an element.
GET_FIELD_VALUE = 7;
// Get any attribute of an element.
GET_STRING_ATTRIBUTE = 8;
// Select an element's value. This does only work for text elements.
SELECT_FIELD_VALUE = 9;
// Set the |value| attribute of an element.
SET_VALUE_ATTRIBUTE = 10;
// Set any attribute of an element.
SET_ATTRIBUTE = 11;
// Send a series of keystroke inputs. This requires an element to have
// focus to receive them.
SEND_KEYBOARD_INPUT = 12;
// Get the outer HTML of an element.
GET_OUTER_HTML = 13;
// Get the tag of an element.
GET_ELEMENT_TAG = 14;
}
// The web-action that failed. This is usually a step in an execution chain
// for an action.
optional WebAction failed_web_action = 1;
}
// The pseudo type values come from // The pseudo type values come from
// https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-PseudoType. // https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-PseudoType.
enum PseudoType { enum PseudoType {
......
...@@ -259,6 +259,32 @@ void OnWaitForDocumentReadyState( ...@@ -259,6 +259,32 @@ void OnWaitForDocumentReadyState(
std::move(callback).Run(status, static_cast<DocumentReadyState>(ready_state)); std::move(callback).Run(status, static_cast<DocumentReadyState>(ready_state));
} }
void DecorateWebControllerStatus(
WebControllerErrorInfoProto::WebAction web_action,
base::OnceCallback<void(const ClientStatus&)> callback,
const ClientStatus& status) {
ClientStatus copy = status;
if (!status.ok()) {
VLOG(1) << web_action << " failed with status: " << status;
FillWebControllerErrorInfo(web_action, &copy);
}
std::move(callback).Run(copy);
}
template <typename T>
void DecorateControllerStatusWithValue(
WebControllerErrorInfoProto::WebAction web_action,
base::OnceCallback<void(const ClientStatus&, const T&)> callback,
const ClientStatus& status,
const T& result) {
ClientStatus copy = status;
if (!status.ok()) {
VLOG(1) << web_action << " failed with status: " << status;
FillWebControllerErrorInfo(web_action, &copy);
}
std::move(callback).Run(copy, result);
}
} // namespace } // namespace
// static // static
...@@ -334,8 +360,11 @@ void WebController::ScrollIntoView( ...@@ -334,8 +360,11 @@ void WebController::ScrollIntoView(
.SetReturnByValue(true) .SetReturnByValue(true)
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResult, base::BindOnce(
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); &WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&DecorateWebControllerStatus,
WebControllerErrorInfoProto::SCROLL_INTO_VIEW,
std::move(callback))));
} }
void WebController::WaitForDocumentToBecomeInteractive( void WebController::WaitForDocumentToBecomeInteractive(
...@@ -348,11 +377,65 @@ void WebController::WaitForDocumentToBecomeInteractive( ...@@ -348,11 +377,65 @@ void WebController::WaitForDocumentToBecomeInteractive(
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
void WebController::InternalWaitForDocumentToBecomeInteractive(
int remaining_rounds,
const std::string& object_id,
const std::string& node_frame_id,
base::OnceCallback<void(bool)> callback) {
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(object_id)
.SetFunctionDeclaration(std::string(kIsDocumentReadyForInteract))
.SetReturnByValue(true)
.Build(),
node_frame_id,
base::BindOnce(
&WebController::OnInternalWaitForDocumentToBecomeInteractive,
weak_ptr_factory_.GetWeakPtr(), remaining_rounds, object_id,
node_frame_id, std::move(callback)));
}
void WebController::OnInternalWaitForDocumentToBecomeInteractive(
int remaining_rounds,
const std::string& object_id,
const std::string& node_frame_id,
base::OnceCallback<void(bool)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok() || remaining_rounds <= 0) {
VLOG(1) << __func__
<< " Failed to wait for the document to become interactive with "
"remaining_rounds: "
<< remaining_rounds;
std::move(callback).Run(false);
return;
}
bool ready;
if (SafeGetBool(result->GetResult(), &ready) && ready) {
std::move(callback).Run(true);
return;
}
content::GetUIThreadTaskRunner({})->PostDelayedTask(
FROM_HERE,
base::BindOnce(&WebController::InternalWaitForDocumentToBecomeInteractive,
weak_ptr_factory_.GetWeakPtr(), --remaining_rounds,
object_id, node_frame_id, std::move(callback)),
settings_->document_ready_check_interval);
}
void WebController::OnWaitForDocumentToBecomeInteractive( void WebController::OnWaitForDocumentToBecomeInteractive(
base::OnceCallback<void(const ClientStatus&)> callback, base::OnceCallback<void(const ClientStatus&)> callback,
bool result) { bool result) {
if (!result) { if (!result) {
std::move(callback).Run(ClientStatus(TIMED_OUT)); ClientStatus error_status(TIMED_OUT);
FillWebControllerErrorInfo(
WebControllerErrorInfoProto::WAIT_FOR_DOCUMENT_TO_BECOME_INTERACTIVE,
&error_status);
std::move(callback).Run(error_status);
return; return;
} }
std::move(callback).Run(OkClientStatus()); std::move(callback).Run(OkClientStatus());
...@@ -375,9 +458,11 @@ void WebController::ClickOrTapElement( ...@@ -375,9 +458,11 @@ void WebController::ClickOrTapElement(
.SetFunctionDeclaration(kClickElement) .SetFunctionDeclaration(kClickElement)
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResult, base::BindOnce(
weak_ptr_factory_.GetWeakPtr(), &WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
std::move(wrapped_callback))); base::BindOnce(&DecorateWebControllerStatus,
WebControllerErrorInfoProto::CLICK_OR_TAP_ELEMENT,
std::move(wrapped_callback))));
return; return;
} }
...@@ -388,9 +473,13 @@ void WebController::ClickOrTapElement( ...@@ -388,9 +473,13 @@ void WebController::ClickOrTapElement(
pending_workers_.emplace_back(std::move(getter)); pending_workers_.emplace_back(std::move(getter));
ptr->Start( ptr->Start(
element.container_frame_host, element.object_id, element.container_frame_host, element.object_id,
base::BindOnce(&WebController::TapOrClickOnCoordinates, base::BindOnce(
&WebController::TapOrClickOnCoordinates,
weak_ptr_factory_.GetWeakPtr(), ptr, element.node_frame_id, weak_ptr_factory_.GetWeakPtr(), ptr, element.node_frame_id,
click_type, std::move(wrapped_callback))); click_type,
base::BindOnce(&DecorateWebControllerStatus,
WebControllerErrorInfoProto::CLICK_OR_TAP_ELEMENT,
std::move(wrapped_callback))));
} }
void WebController::TapOrClickOnCoordinates( void WebController::TapOrClickOnCoordinates(
...@@ -849,7 +938,10 @@ void WebController::SelectOption( ...@@ -849,7 +938,10 @@ void WebController::SelectOption(
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(&WebController::OnSelectOption, base::BindOnce(&WebController::OnSelectOption,
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&DecorateWebControllerStatus,
WebControllerErrorInfoProto::SELECT_OPTION,
std::move(callback))));
} }
void WebController::OnSelectOption( void WebController::OnSelectOption(
...@@ -891,8 +983,11 @@ void WebController::HighlightElement( ...@@ -891,8 +983,11 @@ void WebController::HighlightElement(
.SetReturnByValue(true) .SetReturnByValue(true)
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResult, base::BindOnce(
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); &WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&DecorateWebControllerStatus,
WebControllerErrorInfoProto::HIGHLIGHT_ELEMENT,
std::move(callback))));
} }
void WebController::FocusElement( void WebController::FocusElement(
...@@ -911,8 +1006,12 @@ void WebController::FocusElement( ...@@ -911,8 +1006,12 @@ void WebController::FocusElement(
.SetReturnByValue(true) .SetReturnByValue(true)
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResult, base::BindOnce(
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); &WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(
&DecorateWebControllerStatus,
WebControllerErrorInfoProto::SCROLL_INTO_VIEW_WITH_PADDING,
std::move(callback))));
} }
void WebController::GetFieldValue( void WebController::GetFieldValue(
...@@ -942,8 +1041,12 @@ void WebController::OnFindElementForGetFieldValue( ...@@ -942,8 +1041,12 @@ void WebController::OnFindElementForGetFieldValue(
.SetReturnByValue(true) .SetReturnByValue(true)
.Build(), .Build(),
element_result->node_frame_id, element_result->node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResultForString, base::BindOnce(
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); &WebController::OnJavaScriptResultForString,
weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&DecorateControllerStatusWithValue<std::string>,
WebControllerErrorInfoProto::GET_FIELD_VALUE,
std::move(callback))));
} }
void WebController::GetStringAttribute( void WebController::GetStringAttribute(
...@@ -955,7 +1058,10 @@ void WebController::GetStringAttribute( ...@@ -955,7 +1058,10 @@ void WebController::GetStringAttribute(
<< "]"; << "]";
if (attributes.empty()) { if (attributes.empty()) {
std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__), ""); ClientStatus error_status = UnexpectedErrorStatus(__FILE__, __LINE__);
FillWebControllerErrorInfo(
WebControllerErrorInfoProto::GET_STRING_ATTRIBUTE, &error_status);
std::move(callback).Run(error_status, "");
return; return;
} }
base::Value::ListStorage attribute_values; base::Value::ListStorage attribute_values;
...@@ -973,8 +1079,12 @@ void WebController::GetStringAttribute( ...@@ -973,8 +1079,12 @@ void WebController::GetStringAttribute(
.SetReturnByValue(true) .SetReturnByValue(true)
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResultForString, base::BindOnce(
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); &WebController::OnJavaScriptResultForString,
weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&DecorateControllerStatusWithValue<std::string>,
WebControllerErrorInfoProto::GET_STRING_ATTRIBUTE,
std::move(callback))));
} }
void WebController::SelectFieldValue( void WebController::SelectFieldValue(
...@@ -986,8 +1096,93 @@ void WebController::SelectFieldValue( ...@@ -986,8 +1096,93 @@ void WebController::SelectFieldValue(
.SetFunctionDeclaration(std::string(kSelectFieldValue)) .SetFunctionDeclaration(std::string(kSelectFieldValue))
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(
&WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&DecorateWebControllerStatus,
WebControllerErrorInfoProto::SELECT_FIELD_VALUE,
std::move(callback))));
}
void WebController::SetValueAttribute(
const ElementFinder::Result& element,
const std::string& value,
base::OnceCallback<void(const ClientStatus&)> callback) {
std::vector<std::unique_ptr<runtime::CallArgument>> argument;
AddRuntimeCallArgument(value, &argument);
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(element.object_id)
.SetArguments(std::move(argument))
.SetFunctionDeclaration(std::string(kSetValueAttributeScript))
.Build(),
element.node_frame_id,
base::BindOnce(
&WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&DecorateWebControllerStatus,
WebControllerErrorInfoProto::SET_VALUE_ATTRIBUTE,
std::move(callback))));
}
void WebController::SetAttribute(
const ElementFinder::Result& element,
const std::vector<std::string>& attributes,
const std::string& value,
base::OnceCallback<void(const ClientStatus&)> callback) {
DVLOG(3) << __func__ << " attributes=[" << base::JoinString(attributes, ",")
<< "], value=" << value;
if (attributes.empty()) {
ClientStatus error_status = UnexpectedErrorStatus(__FILE__, __LINE__);
FillWebControllerErrorInfo(WebControllerErrorInfoProto::SET_ATTRIBUTE,
&error_status);
std::move(callback).Run(error_status);
return;
}
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);
AddRuntimeCallArgument(value, &arguments);
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(element.object_id)
.SetArguments(std::move(arguments))
.SetFunctionDeclaration(std::string(kSetAttributeScript))
.Build(),
element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResult, base::BindOnce(&WebController::OnJavaScriptResult,
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&DecorateWebControllerStatus,
WebControllerErrorInfoProto::SET_ATTRIBUTE,
std::move(callback))));
}
void WebController::SendKeyboardInput(
const ElementFinder::Result& element,
const std::vector<UChar32>& codepoints,
const int delay_in_millisecond,
base::OnceCallback<void(const ClientStatus&)> callback) {
if (VLOG_IS_ON(3)) {
std::string input_str;
if (!UnicodeToUTF8(codepoints, &input_str)) {
input_str.assign("<invalid input>");
}
#ifdef NDEBUG
VLOG(3) << __func__ << " input=(redacted)";
#else
DVLOG(3) << __func__ << " input=" << input_str;
#endif
}
DispatchKeyboardTextDownEvent(
element.node_frame_id, codepoints, 0,
/* delay= */ false, delay_in_millisecond,
base::BindOnce(&DecorateWebControllerStatus,
WebControllerErrorInfoProto::SEND_KEYBOARD_INPUT,
std::move(callback)));
} }
void WebController::DispatchKeyboardTextDownEvent( void WebController::DispatchKeyboardTextDownEvent(
...@@ -1073,76 +1268,6 @@ auto WebController::CreateKeyEventParamsForCharacter( ...@@ -1073,76 +1268,6 @@ auto WebController::CreateKeyEventParamsForCharacter(
return params; return params;
} }
void WebController::SetValueAttribute(
const ElementFinder::Result& element,
const std::string& value,
base::OnceCallback<void(const ClientStatus&)> callback) {
std::vector<std::unique_ptr<runtime::CallArgument>> argument;
AddRuntimeCallArgument(value, &argument);
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(element.object_id)
.SetArguments(std::move(argument))
.SetFunctionDeclaration(std::string(kSetValueAttributeScript))
.Build(),
element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResult,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WebController::SetAttribute(
const ElementFinder::Result& element,
const std::vector<std::string>& attributes,
const std::string& value,
base::OnceCallback<void(const ClientStatus&)> callback) {
DVLOG(3) << __func__ << " attributes=[" << base::JoinString(attributes, ",")
<< "], value=" << value;
if (attributes.empty()) {
std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
return;
}
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);
AddRuntimeCallArgument(value, &arguments);
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(element.object_id)
.SetArguments(std::move(arguments))
.SetFunctionDeclaration(std::string(kSetAttributeScript))
.Build(),
element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResult,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WebController::SendKeyboardInput(
const ElementFinder::Result& element,
const std::vector<UChar32>& codepoints,
const int delay_in_millisecond,
base::OnceCallback<void(const ClientStatus&)> callback) {
if (VLOG_IS_ON(3)) {
std::string input_str;
if (!UnicodeToUTF8(codepoints, &input_str)) {
input_str.assign("<invalid input>");
}
#ifdef NDEBUG
VLOG(3) << __func__ << " input=(redacted)";
#else
DVLOG(3) << __func__ << " input=" << input_str;
#endif
}
DispatchKeyboardTextDownEvent(element.node_frame_id, codepoints, 0,
/* delay= */ false, delay_in_millisecond,
std::move(callback));
}
void WebController::GetVisualViewport( void WebController::GetVisualViewport(
base::OnceCallback<void(const ClientStatus&, const RectF&)> callback) { base::OnceCallback<void(const ClientStatus&, const RectF&)> callback) {
devtools_client_->GetRuntime()->Evaluate( devtools_client_->GetRuntime()->Evaluate(
...@@ -1237,8 +1362,12 @@ void WebController::GetOuterHtml( ...@@ -1237,8 +1362,12 @@ void WebController::GetOuterHtml(
.SetReturnByValue(true) .SetReturnByValue(true)
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResultForString, base::BindOnce(
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); &WebController::OnJavaScriptResultForString,
weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&DecorateControllerStatusWithValue<std::string>,
WebControllerErrorInfoProto::GET_OUTER_HTML,
std::move(callback))));
} }
void WebController::GetElementTag( void WebController::GetElementTag(
...@@ -1252,58 +1381,12 @@ void WebController::GetElementTag( ...@@ -1252,58 +1381,12 @@ void WebController::GetElementTag(
.SetReturnByValue(true) .SetReturnByValue(true)
.Build(), .Build(),
element.node_frame_id, element.node_frame_id,
base::BindOnce(&WebController::OnJavaScriptResultForString,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WebController::InternalWaitForDocumentToBecomeInteractive(
int remaining_rounds,
const std::string& object_id,
const std::string& node_frame_id,
base::OnceCallback<void(bool)> callback) {
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(object_id)
.SetFunctionDeclaration(std::string(kIsDocumentReadyForInteract))
.SetReturnByValue(true)
.Build(),
node_frame_id,
base::BindOnce( base::BindOnce(
&WebController::OnInternalWaitForDocumentToBecomeInteractive, &WebController::OnJavaScriptResultForString,
weak_ptr_factory_.GetWeakPtr(), remaining_rounds, object_id, weak_ptr_factory_.GetWeakPtr(),
node_frame_id, std::move(callback))); base::BindOnce(&DecorateControllerStatusWithValue<std::string>,
} WebControllerErrorInfoProto::GET_ELEMENT_TAG,
std::move(callback))));
void WebController::OnInternalWaitForDocumentToBecomeInteractive(
int remaining_rounds,
const std::string& object_id,
const std::string& node_frame_id,
base::OnceCallback<void(bool)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok() || remaining_rounds <= 0) {
VLOG(1) << __func__
<< " Failed to wait for the document to become interactive with "
"remaining_rounds: "
<< remaining_rounds;
std::move(callback).Run(false);
return;
}
bool ready;
if (SafeGetBool(result->GetResult(), &ready) && ready) {
std::move(callback).Run(true);
return;
}
content::GetUIThreadTaskRunner({})->PostDelayedTask(
FROM_HERE,
base::BindOnce(&WebController::InternalWaitForDocumentToBecomeInteractive,
weak_ptr_factory_.GetWeakPtr(), --remaining_rounds,
object_id, node_frame_id, std::move(callback)),
settings_->document_ready_check_interval);
} }
WebController::ScopedAssistantActionStateRunning:: WebController::ScopedAssistantActionStateRunning::
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "components/autofill_assistant/browser/web/web_controller_util.h" #include "components/autofill_assistant/browser/web/web_controller_util.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h" #include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
#include "components/autofill_assistant/browser/service.pb.h"
namespace autofill_assistant { namespace autofill_assistant {
...@@ -56,6 +57,14 @@ ClientStatus FillAutofillErrorStatus(ClientStatus status) { ...@@ -56,6 +57,14 @@ ClientStatus FillAutofillErrorStatus(ClientStatus status) {
return status; return status;
} }
void FillWebControllerErrorInfo(
WebControllerErrorInfoProto::WebAction failed_web_action,
ClientStatus* status) {
status->mutable_details()
->mutable_web_controller_error_info()
->set_failed_web_action(failed_web_action);
}
bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out) { bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out) {
if (result && result->HasObjectId()) { if (result && result->HasObjectId()) {
*out = result->GetObjectId(); *out = result->GetObjectId();
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "components/autofill_assistant/browser/client_status.h" #include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h" #include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
#include "components/autofill_assistant/browser/devtools/devtools_client.h" #include "components/autofill_assistant/browser/devtools/devtools_client.h"
#include "components/autofill_assistant/browser/service.pb.h"
namespace autofill_assistant { namespace autofill_assistant {
...@@ -57,6 +58,11 @@ ClientStatus CheckJavaScriptResult( ...@@ -57,6 +58,11 @@ ClientStatus CheckJavaScriptResult(
// Fills a ClientStatus with appropriate details for a Chrome Autofill error. // Fills a ClientStatus with appropriate details for a Chrome Autofill error.
ClientStatus FillAutofillErrorStatus(ClientStatus status); ClientStatus FillAutofillErrorStatus(ClientStatus status);
// Fills a ClientStatus with appropriate details from the
void FillWebControllerErrorInfo(
WebControllerErrorInfoProto::WebAction failed_web_action,
ClientStatus* status);
// Safely gets an object id from a RemoteObject // Safely gets an object id from a RemoteObject
bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out); bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out);
......
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