0

Move AutofillProviderBrowserTest to AwAutofillTest

It is hard to move AutofillProviderBrowserTest to
android_autofill components.

This patch basically re-implement the tests in
AwAutofillTest.



Bug: 1200511
Change-Id: I2018f31edb844a8a043892eb0b804b7d7a3a03d5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2914959
Reviewed-by: Dominic Battré <battre@chromium.org>
Commit-Queue: Michael Bai <michaelbai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#886441}
This commit is contained in:
Michael Bai
2021-05-25 20:18:52 +00:00
committed by Chromium LUCI CQ
parent 2ef96b65c0
commit a053472234
9 changed files with 139 additions and 449 deletions

@ -15,6 +15,7 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Bundle;
@ -2764,6 +2765,144 @@ public class AwAutofillTest {
assertEquals("\"password\"", value1);
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
public void testFrameDetachedOnFormSubmission() throws Throwable {
final String mainFrame = "<html><body>"
+ "<script>"
+ "function receiveMessage(event) {"
+ " var address_iframe = document.getElementById('address_iframe');"
+ " address_iframe.parentNode.removeChild(address_iframe);"
+ " setTimeout(delayedUpload, 0);"
+ "}"
+ "window.addEventListener('message', receiveMessage, false);"
+ "</script>"
+ "<iframe src='inner_frame_address_form.html' id='address_iframe'"
+ " name='address_iframe'>"
+ "</iframe>"
+ "</body></html>";
final String url = mWebServer.setResponse(FILE, mainFrame, null);
final String subFrame = "<html><body>"
+ "<script>"
+ "function send_post() {"
+ " window.parent.postMessage('SubmitComplete', '*');"
+ "}"
+ "</script>"
+ "<form action='inner_frame_address_form.html' id='deleting_form'"
+ " onsubmit='send_post(); return false;'>"
+ " <input type='text' id='address_field' name='address' autocomplete='on'>"
+ " <input type='submit' id='submit_button' name='submit_button'>"
+ "</form>"
+ "</body></html>";
final String subFrameURL =
mWebServer.setResponse("/inner_frame_address_form.html", subFrame, null);
assertTrue(Uri.parse(subFrameURL).getPath().equals("/inner_frame_address_form.html"));
int cnt = 0;
loadUrlSync(url);
pollJavascriptResult("var iframe = document.getElementById('address_iframe');"
+ "var frame_doc = iframe.contentDocument;"
+ "frame_doc.getElementById('address_field').focus();"
+ "frame_doc.activeElement.id;",
"\"address_field\"");
dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
cnt += waitForCallbackAndVerifyTypes(cnt,
new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED,
AUTOFILL_VALUE_CHANGED});
executeJavaScriptAndWaitForResult("var iframe = document.getElementById('address_iframe');"
+ "var frame_doc = iframe.contentDocument;"
+ "frame_doc.getElementById('submit_button').click();");
waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_VALUE_CHANGED, AUTOFILL_COMMIT});
assertEquals(SubmissionSource.FORM_SUBMISSION, mSubmissionSource);
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
public void testFrameDetachedOnFormlessSubmission() throws Throwable {
final String mainFrame = "<html><body>"
+ "<script>"
+ "function receiveMessage(event) {"
+ " var address_iframe = document.getElementById('address_iframe');"
+ " address_iframe.parentNode.removeChild(address_iframe);"
+ "}"
+ "window.addEventListener('message', receiveMessage, false);"
+ "</script>"
+ "<iframe src='inner_frame_address_formless.html' id='address_iframe'"
+ " name='address_iframe'>"
+ "</iframe>"
+ "</body></html>";
final String url = mWebServer.setResponse(FILE, mainFrame, null);
final String subFrame = "<html><body>"
+ "<script>"
+ "function send_post() {"
+ " window.parent.postMessage('SubmitComplete', '*');"
+ "}"
+ "</script>"
+ "<input type='text' id='address_field' name='address' autocomplete='on'>"
+ "<input type='button' id='submit_button' name='submit_button'"
+ " onclick='send_post()'>"
+ "</body></html>";
final String subFrameURL =
mWebServer.setResponse("/inner_frame_address_formless.html", subFrame, null);
assertTrue(Uri.parse(subFrameURL).getPath().equals("/inner_frame_address_formless.html"));
int cnt = 0;
loadUrlSync(url);
pollJavascriptResult("var iframe = document.getElementById('address_iframe');"
+ "var frame_doc = iframe.contentDocument;"
+ "frame_doc.getElementById('address_field').focus();"
+ "frame_doc.activeElement.id;",
"\"address_field\"");
dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
cnt += waitForCallbackAndVerifyTypes(cnt,
new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED,
AUTOFILL_VALUE_CHANGED});
executeJavaScriptAndWaitForResult("var iframe = document.getElementById('address_iframe');"
+ "var frame_doc = iframe.contentDocument;"
+ "frame_doc.getElementById('submit_button').click();");
// The additional AUTOFILL_VIEW_EXITED event caused by 'click' of the button.
waitForCallbackAndVerifyTypes(
cnt, new Integer[] {AUTOFILL_VIEW_EXITED, AUTOFILL_VALUE_CHANGED, AUTOFILL_COMMIT});
assertEquals(SubmissionSource.FRAME_DETACHED, mSubmissionSource);
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
public void testLabelChange() throws Throwable {
final String data = "<html><head></head><body>"
+ "<form action='a.html'>"
+ "<label id='label_id'> Address </label>"
+ "<input type='text' id='address' name='address' autocomplete='on'/>"
+ "<p id='p_id'>Address 1</p>"
+ "<input type='text' name='address1' autocomplete='on'/>"
+ "<input type='submit' id='submit_button' name='submit_button'/>"
+ "</form>"
+ "</body></html>";
int cnt = 0;
final String url = mWebServer.setResponse(FILE, data, null);
loadUrlSync(url);
executeJavaScriptAndWaitForResult("document.getElementById('address').focus();");
dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
cnt += waitForCallbackAndVerifyTypes(cnt,
new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED,
AUTOFILL_VALUE_CHANGED});
// Verify label change shall trigger new session.
executeJavaScriptAndWaitForResult(
"document.getElementById('label_id').innerHTML='address change';");
executeJavaScriptAndWaitForResult("document.getElementById('address').focus();");
dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_B);
cnt += waitForCallbackAndVerifyTypes(cnt,
new Integer[] {AUTOFILL_VIEW_EXITED, AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED,
AUTOFILL_SESSION_STARTED, AUTOFILL_VALUE_CHANGED});
// Verify inferred label change won't trigger new session.
executeJavaScriptAndWaitForResult(
"document.getElementById('p_id').innerHTML='address change';");
executeJavaScriptAndWaitForResult("document.getElementById('address').focus();");
dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_B);
cnt += waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_VALUE_CHANGED});
}
private void pollJavascriptResult(String script, String expectedResult) throws Throwable {
AwActivityTestRule.pollInstrumentationThread(() -> {
try {

@ -1,5 +1,4 @@
include_rules = [
'+components/android_autofill/browser',
'+third_party/libaddressinput/chromium/chrome_metadata_source.h',
'+third_party/libaddressinput/chromium/chrome_storage_impl.h',
]

@ -1,341 +0,0 @@
// Copyright 2017 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 "base/base_switches.h"
#include "base/bind.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/android_autofill/browser/android_autofill_manager.h"
#include "components/android_autofill/browser/test_autofill_provider.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/switches.h"
using ::testing::_;
using ::testing::Invoke;
namespace autofill {
using mojom::SubmissionSource;
namespace {
class MockAutofillProvider : public TestAutofillProvider {
public:
// WebContents takes ownership of the MockAutofillProvider.
explicit MockAutofillProvider(content::WebContents* web_contents)
: TestAutofillProvider(web_contents) {}
~MockAutofillProvider() override = default;
MOCK_METHOD4(OnFormSubmitted,
void(AndroidAutofillManager* manager,
const FormData& form,
bool,
SubmissionSource));
MOCK_METHOD6(OnQueryFormFieldAutofill,
void(AndroidAutofillManager* manager,
int32_t id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
bool autoselect_first_suggestion));
void OnQueryFormFieldAutofillImpl(AndroidAutofillManager* manager,
int32_t id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
bool autoselect_first_suggestion) {
queried_form_ = form;
}
void OnFormSubmittedImpl(AndroidAutofillManager*,
const FormData& form,
bool success,
SubmissionSource source) {
submitted_form_ = form;
}
const FormData& queried_form() { return queried_form_; }
const FormData& submitted_form() { return submitted_form_; }
private:
FormData queried_form_;
FormData submitted_form_;
};
} // namespace
class AutofillProviderBrowserTest : public InProcessBrowserTest {
public:
AutofillProviderBrowserTest() {}
~AutofillProviderBrowserTest() override {}
void SetUp() override {
InProcessBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
autofill_client_ = std::make_unique<TestAutofillClient>();
// WebContents takes ownership of the MockAutofillProvider.
autofill_provider_ = new MockAutofillProvider(WebContents());
// Serve both a.com and b.com (and any other domain).
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(embedded_test_server()->Start());
}
// Necessary to avoid flakiness or failure due to input arriving
// before the first compositor commit.
void SetUpCommandLine(base::CommandLine* command_line) override {
InProcessBrowserTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(blink::switches::kAllowPreCommitInput);
}
void CreateContentAutofillDriverFactoryForSubFrame() {
content::WebContents* web_contents = WebContents();
ASSERT_TRUE(web_contents != NULL);
web_contents->RemoveUserData(
ContentAutofillDriverFactory::
kContentAutofillDriverFactoryWebContentsUserDataKey);
// Replace the ContentAutofillDriverFactory for sub frame.
ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
web_contents, autofill_client_.get(), "en-US",
BrowserAutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER,
base::BindRepeating(&AndroidAutofillManager::Create));
}
void TearDownOnMainThread() override {
testing::Mock::VerifyAndClearExpectations(autofill_provider_);
}
content::RenderFrameHost* GetMainFrame() {
return WebContents()->GetMainFrame();
}
content::WebContents* WebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
void SimulateUserTypingInFocusedField() {
content::WebContents* web_contents = WebContents();
content::SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('O'),
ui::DomCode::US_O, ui::VKEY_O, false, false,
false, false);
content::SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('R'),
ui::DomCode::US_R, ui::VKEY_R, false, false,
false, false);
content::SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('A'),
ui::DomCode::US_A, ui::VKEY_A, false, false,
false, false);
content::SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('R'),
ui::DomCode::US_R, ui::VKEY_R, false, false,
false, false);
content::SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('Y'),
ui::DomCode::US_Y, ui::VKEY_Y, false, false,
false, false);
}
void SetLabelChangeExpectationAndTriggerQuery() {
// One query for the single click, and a second query when the typing is
// simulated.
base::RunLoop run_loop;
EXPECT_CALL(*autofill_provider_, OnQueryFormFieldAutofill(_, _, _, _, _, _))
.Times(testing::Exactly(2))
.WillOnce(Invoke(autofill_provider_,
&MockAutofillProvider::OnQueryFormFieldAutofillImpl))
.WillOnce(
testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }));
EXPECT_CALL(*autofill_provider_, OnFormSubmitted)
.WillOnce(Invoke(autofill_provider_,
&MockAutofillProvider::OnFormSubmittedImpl));
ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL(
"/autofill/label_change.html"));
std::string focus("document.getElementById('address').focus();");
ASSERT_TRUE(content::ExecuteScript(GetMainFrame(), focus));
SimulateUserTypingInFocusedField();
run_loop.Run();
}
void ChangeLabelAndCheckResult(const std::string& element_id,
bool expect_forms_same) {
std::string change_label_and_submit =
"document.getElementById('" + element_id +
"').innerHTML='address change';"
"document.getElementById('submit_button').click();";
ASSERT_TRUE(
content::ExecuteScript(GetMainFrame(), change_label_and_submit));
// Need to pay attention for a message that XHR has finished since there
// is no navigation to wait for.
content::DOMMessageQueue message_queue;
std::string message;
while (message_queue.WaitForMessage(&message)) {
if (message == "\"SUBMISSION_FINISHED\"")
break;
}
EXPECT_EQ("\"SUBMISSION_FINISHED\"", message);
EXPECT_EQ(2u, autofill_provider_->queried_form().fields.size());
EXPECT_EQ(2u, autofill_provider_->submitted_form().fields.size());
EXPECT_EQ(expect_forms_same,
autofill_provider_->submitted_form().SimilarFormAs(
autofill_provider_->queried_form()));
}
protected:
MockAutofillProvider* autofill_provider_;
private:
std::unique_ptr<TestAutofillClient> autofill_client_;
};
IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTest,
FrameDetachedOnFormlessSubmission) {
CreateContentAutofillDriverFactoryForSubFrame();
EXPECT_CALL(*autofill_provider_,
OnFormSubmitted(_, _, _, SubmissionSource::FRAME_DETACHED))
.Times(1);
ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL(
"/autofill/frame_detached_on_formless_submit.html"));
// Need to pay attention for a message that XHR has finished since there
// is no navigation to wait for.
content::DOMMessageQueue message_queue;
std::string focus(
"var iframe = document.getElementById('address_iframe');"
"var frame_doc = iframe.contentDocument;"
"frame_doc.getElementById('address_field').focus();");
ASSERT_TRUE(content::ExecuteScript(GetMainFrame(), focus));
SimulateUserTypingInFocusedField();
std::string fill_and_submit =
"var iframe = document.getElementById('address_iframe');"
"var frame_doc = iframe.contentDocument;"
"frame_doc.getElementById('submit_button').click();";
ASSERT_TRUE(content::ExecuteScript(GetMainFrame(), fill_and_submit));
std::string message;
while (message_queue.WaitForMessage(&message)) {
if (message == "\"SUBMISSION_FINISHED\"")
break;
}
EXPECT_EQ("\"SUBMISSION_FINISHED\"", message);
}
IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTest,
FrameDetachedOnFormSubmission) {
CreateContentAutofillDriverFactoryForSubFrame();
EXPECT_CALL(*autofill_provider_,
OnFormSubmitted(_, _, _, SubmissionSource::FORM_SUBMISSION))
.Times(1);
ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL(
"/autofill/frame_detached_on_form_submit.html"));
// Need to pay attention for a message that XHR has finished since there
// is no navigation to wait for.
content::DOMMessageQueue message_queue;
std::string focus(
"var iframe = document.getElementById('address_iframe');"
"var frame_doc = iframe.contentDocument;"
"frame_doc.getElementById('address_field').focus();");
ASSERT_TRUE(content::ExecuteScript(GetMainFrame(), focus));
SimulateUserTypingInFocusedField();
std::string fill_and_submit =
"var iframe = document.getElementById('address_iframe');"
"var frame_doc = iframe.contentDocument;"
"frame_doc.getElementById('submit_button').click();";
ASSERT_TRUE(content::ExecuteScript(GetMainFrame(), fill_and_submit));
std::string message;
while (message_queue.WaitForMessage(&message)) {
if (message == "\"SUBMISSION_FINISHED\"")
break;
}
EXPECT_EQ("\"SUBMISSION_FINISHED\"", message);
}
class AutofillProviderBrowserTestWithSkipFlagOn
: public AutofillProviderBrowserTest {
public:
AutofillProviderBrowserTestWithSkipFlagOn() {
feature_list_.InitAndEnableFeature(
features::kAutofillSkipComparingInferredLabels);
}
private:
base::test::ScopedFeatureList feature_list_;
};
class AutofillProviderBrowserTestWithSkipFlagOff
: public AutofillProviderBrowserTest {
public:
AutofillProviderBrowserTestWithSkipFlagOff() {
feature_list_.InitAndDisableFeature(
features::kAutofillSkipComparingInferredLabels);
}
private:
base::test::ScopedFeatureList feature_list_;
};
// TODO(crbug.com/1076487): These tests are flaky on all platforms.
IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTestWithSkipFlagOn,
DISABLED_LabelTagChangeImpactFormComparing) {
SetLabelChangeExpectationAndTriggerQuery();
ChangeLabelAndCheckResult("label_id", false /*expect_forms_same*/);
}
IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTestWithSkipFlagOn,
DISABLED_InferredLabelChangeNotImpactFormComparing) {
SetLabelChangeExpectationAndTriggerQuery();
ChangeLabelAndCheckResult("p_id", true /*expect_forms_same*/);
}
IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTestWithSkipFlagOff,
DISABLED_LabelTagChangeImpactFormComparing) {
SetLabelChangeExpectationAndTriggerQuery();
ChangeLabelAndCheckResult("label_id", false /*expect_forms_same*/);
}
IN_PROC_BROWSER_TEST_F(AutofillProviderBrowserTestWithSkipFlagOff,
DISABLED_InferredLabelChangeImpactFormComparing) {
SetLabelChangeExpectationAndTriggerQuery();
ChangeLabelAndCheckResult("p_id", false /*expect_forms_same*/);
}
} // namespace autofill

@ -921,7 +921,6 @@ if (!is_android) {
"//chrome/renderer",
"//chrome/services/removable_storage_writer:lib",
"//chrome/test/data:webui_test_resources",
"//components/android_autofill/browser",
"//components/autofill/content/browser:risk_proto",
"//components/autofill/content/common/mojom",
"//components/autofill/content/renderer:test_support",
@ -1111,7 +1110,6 @@ if (!is_android) {
"../browser/autofill/autofill_autocomplete_browsertest.cc",
"../browser/autofill/autofill_browsertest.cc",
"../browser/autofill/autofill_metrics_browsertest.cc",
"../browser/autofill/autofill_provider_browsertest.cc",
"../browser/autofill/autofill_server_browsertest.cc",
"../browser/autofill/content_autofill_driver_browsertest.cc",
"../browser/autofill/form_structure_browsertest.cc",

@ -1,25 +0,0 @@
<html>
<body>
<script>
function delayedUpload() {
window.domAutomationController.send("SUBMISSION_FINISHED");
}
function receiveMessage(event) {
var address_iframe = document.getElementById('address_iframe');
address_iframe.parentNode.removeChild(address_iframe);
setTimeout(delayedUpload, 0);
}
window.addEventListener("message", receiveMessage, false);
</script>
<iframe src="inner_frame_address_form.html" id="address_iframe" name="address_iframe">
</iframe>
</body>
</html>

@ -1,25 +0,0 @@
<html>
<body>
<script>
function delayedUpload() {
window.domAutomationController.send("SUBMISSION_FINISHED");
}
function receiveMessage(event) {
var address_iframe = document.getElementById('address_iframe');
address_iframe.parentNode.removeChild(address_iframe);
setTimeout(delayedUpload, 0);
}
window.addEventListener("message", receiveMessage, false);
</script>
<iframe src="inner_frame_address_formless.html" id="address_iframe" name="address_iframe">
</iframe>
</body>
</html>

@ -1,15 +0,0 @@
<html>
<body>
<script>
function send_post() {
window.parent.postMessage("SubmitComplete", "*");
}
</script>
<form action="inner_frame_address_form.html" onsubmit="send_post(); return false;"
id="deleting_form">
<input type="text" id="address_field" name="address" autocomplete="on">
<input type="submit" id="submit_button" name="submit_button">
</form>
</body>
</html>

@ -1,12 +0,0 @@
<html>
<body>
<script>
function send_post() {
window.parent.postMessage("SubmitComplete", "*");
}
</script>
<input type="text" id="address_field" name="address" autocomplete="on">
<input type="button" id="submit_button" name="submit_button" onclick="send_post()">
</body>
</html>

@ -1,28 +0,0 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
function delayedUpload() {
window.domAutomationController.send("SUBMISSION_FINISHED");
console.log("delayedUpload")
}
function send_post() {
setTimeout(delayedUpload, 0);
}
</script>
<form action="" onsubmit="send_post(); return false;">
<label id="label_id"> Address </label>
<input type="text" id="address" name="address" autocomplete="on">
<p id="p_id">Address 1</p>
<input type="text" name="address1" autocomplete="on">
<input type="submit" id="submit_button" name="submit_button">
</form>
</body>
</html>