Commit ef59ff7e authored by Mathias Carlen's avatar Mathias Carlen Committed by Commit Bot

[Autofill Assistant] Implement select option.

R=gogerald@chromium.org

Bug: 806868
Change-Id: I7515c9fb448b9324b81dec958e0c212192741188
Reviewed-on: https://chromium-review.googlesource.com/1228059
Commit-Queue: Mathias Carlen <mcarlen@chromium.org>
Reviewed-by: default avatarGanggui Tang <gogerald@chromium.org>
Cr-Commit-Position: refs/heads/master@{#592772}
parent a7544fa3
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_util.h"
#include "components/autofill/content/browser/content_autofill_driver.h" #include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_data.h"
...@@ -27,6 +28,31 @@ const char* const kScrollIntoViewScript = ...@@ -27,6 +28,31 @@ const char* const kScrollIntoViewScript =
}\ }\
node.scrollIntoViewIfNeeded();\ node.scrollIntoViewIfNeeded();\
}"; }";
// Javascript where $1 will be replaced with the option value. Also fires a
// "change" event to trigger any listeners. Changing the index directly does not
// trigger this.
const char* const kSelectOptionScript =
R"(function() {
const value = '$1'.toUpperCase();
var found = false;
for (var i = 0; i < this.options.length; ++i) {
const label = this.options[i].label.toUpperCase();
if (label.length > 0 && label.startsWith(value)) {
this.options.selectedIndex = i;
found = true;
break;
}
}
if (!found) {
return { result: false };
}
const e = document.createEvent('HTMLEvents');
e.initEvent('change', true, true);
this.dispatchEvent(e);
return { result: true };
})";
} // namespace } // namespace
// static // static
...@@ -488,8 +514,51 @@ void WebController::FillCardForm(const std::string& guid, ...@@ -488,8 +514,51 @@ void WebController::FillCardForm(const std::string& guid,
void WebController::SelectOption(const std::vector<std::string>& selectors, void WebController::SelectOption(const std::vector<std::string>& selectors,
const std::string& selected_option, const std::string& selected_option,
base::OnceCallback<void(bool)> callback) { base::OnceCallback<void(bool)> callback) {
// TODO(crbug.com/806868): Implement select option operation. FindElement(selectors,
std::move(callback).Run(true); base::BindOnce(&WebController::OnFindElementForSelectOption,
weak_ptr_factory_.GetWeakPtr(), selected_option,
std::move(callback)));
}
void WebController::OnFindElementForSelectOption(
const std::string& selected_option,
base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> element_result) {
const std::string object_id = element_result->object_id;
if (object_id.empty()) {
DLOG(ERROR) << "Failed to find the element to select an option.";
OnResult(false, std::move(callback));
return;
}
std::string select_option_script = base::ReplaceStringPlaceholders(
kSelectOptionScript, {selected_option}, nullptr);
std::vector<std::unique_ptr<runtime::CallArgument>> argument;
argument.emplace_back(
runtime::CallArgument::Builder().SetObjectId(object_id).Build());
devtools_client_->GetRuntime()->Enable();
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(object_id)
.SetArguments(std::move(argument))
.SetFunctionDeclaration(std::string(select_option_script))
.SetReturnByValue(true)
.Build(),
base::BindOnce(&WebController::OnSelectOption,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WebController::OnSelectOption(
base::OnceCallback<void(bool)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
devtools_client_->GetRuntime()->Disable();
if (!result || result->HasExceptionDetails()) {
DLOG(ERROR) << "Failed to select option.";
OnResult(false, std::move(callback));
return;
}
OnResult(true, std::move(callback));
} }
void WebController::FocusElement(const std::vector<std::string>& selectors, void WebController::FocusElement(const std::vector<std::string>& selectors,
...@@ -512,4 +581,4 @@ void WebController::GetFieldsValue( ...@@ -512,4 +581,4 @@ void WebController::GetFieldsValue(
std::move(callback).Run(values); std::move(callback).Run(values);
} }
} // namespace autofill_assistant. } // namespace autofill_assistant
...@@ -181,6 +181,12 @@ class WebController { ...@@ -181,6 +181,12 @@ class WebController {
std::unique_ptr<FindElementResult> element_result); std::unique_ptr<FindElementResult> element_result);
void OnFocusElement(base::OnceCallback<void(bool)> callback, void OnFocusElement(base::OnceCallback<void(bool)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result); std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForSelectOption(
const std::string& selected_option,
base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> element_result);
void OnSelectOption(base::OnceCallback<void(bool)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
// Weak pointer is fine here since it must outlive this web controller, which // Weak pointer is fine here since it must outlive this web controller, which
// is guaranteed by the owner of this object. // is guaranteed by the owner of this object.
......
...@@ -98,6 +98,21 @@ class WebControllerBrowserTest : public content::ContentBrowserTest { ...@@ -98,6 +98,21 @@ class WebControllerBrowserTest : public content::ContentBrowserTest {
std::move(done_callback).Run(); std::move(done_callback).Run();
} }
void SelectOption(const std::vector<std::string>& selectors,
const std::string& option) {
base::RunLoop run_loop;
web_controller_->SelectOption(
selectors, option,
base::BindOnce(&WebControllerBrowserTest::OnSelectOption,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
}
void OnSelectOption(base::Closure done_callback, bool result) {
ASSERT_TRUE(result);
std::move(done_callback).Run();
}
void FindElement(const std::vector<std::string>& selectors, void FindElement(const std::vector<std::string>& selectors,
size_t expected_index, size_t expected_index,
bool is_main_frame) { bool is_main_frame) {
...@@ -265,4 +280,34 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FocusElement) { ...@@ -265,4 +280,34 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FocusElement) {
)"; )";
EXPECT_EQ(true, content::EvalJsWithManualReply(shell(), checkVisibleScript)); EXPECT_EQ(true, content::EvalJsWithManualReply(shell(), checkVisibleScript));
} }
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, SelectOption) {
std::vector<std::string> selectors;
selectors.emplace_back("#select");
SelectOption(selectors, "two");
const std::string javascript = R"(
let select = document.querySelector("#select");
select.options[select.selectedIndex].label;
)";
EXPECT_EQ("Two", content::EvalJs(shell(), javascript));
SelectOption(selectors, "one");
EXPECT_EQ("One", content::EvalJs(shell(), javascript));
}
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, SelectOptionInIframe) {
std::vector<std::string> selectors;
selectors.emplace_back("#iframe");
selectors.emplace_back("select[name=state]");
SelectOption(selectors, "NY");
const std::string javascript = R"(
let iframe = document.querySelector("iframe").contentDocument;
let select = iframe.querySelector("select[name=state]");
select.options[select.selectedIndex].label;
)";
EXPECT_EQ("NY", content::EvalJs(shell(), javascript));
}
} // namespace } // namespace
...@@ -41,6 +41,14 @@ found in the LICENSE file. ...@@ -41,6 +41,14 @@ found in the LICENSE file.
<br> <br>
</div> </div>
<div>
<select id="select">
<option value="one">One</option>
<option value="two">Two</option>
<option value="three">Three</option>
</select>
</div>
<iframe id="iframe" name="test_iframe" width="100%" height="500" src= <iframe id="iframe" name="test_iframe" width="100%" height="500" src=
"autofill_assistant_target_website_iframe_one.html"></iframe> "autofill_assistant_target_website_iframe_one.html"></iframe>
</body> </body>
......
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