blob: 20e78dedc31e3fc5ecd1a61422e95fa708576004 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/content/browser/content_autofill_driver.h"
#include <stdint.h>
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/gmock_move_support.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/content/browser/content_autofill_driver_factory_test_api.h"
#include "components/autofill/content/browser/content_autofill_driver_test_api.h"
#include "components/autofill/content/browser/content_autofill_router.h"
#include "components/autofill/content/browser/content_autofill_router_test_api.h"
#include "components/autofill/content/browser/test_autofill_client_injector.h"
#include "components/autofill/content/browser/test_autofill_driver_injector.h"
#include "components/autofill/content/browser/test_autofill_manager_injector.h"
#include "components/autofill/content/browser/test_content_autofill_client.h"
#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/browser_autofill_manager.h"
#include "components/autofill/core/browser/test_autofill_driver.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/mock_navigation_handle.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "net/base/net_errors.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
namespace autofill {
using ::testing::_;
using ::testing::AllOf;
using ::testing::DoAll;
using ::testing::ElementsAre;
using ::testing::Field;
using ::testing::Gt;
using ::testing::Invoke;
using ::testing::IsEmpty;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SizeIs;
using ::testing::WithArg;
namespace {
const char kAppLocale[] = "en-US";
ContentAutofillRouterTestApi test_api(ContentAutofillRouter* cad) {
return ContentAutofillRouterTestApi(cad);
}
ContentAutofillDriverTestApi test_api(ContentAutofillDriver* cad) {
return ContentAutofillDriverTestApi(cad);
}
class FakeAutofillAgent : public mojom::AutofillAgent {
public:
FakeAutofillAgent()
: called_clear_section_(false), called_clear_previewed_form_(false) {}
~FakeAutofillAgent() override {}
void BindPendingReceiver(mojo::ScopedInterfaceEndpointHandle handle) {
receivers_.Add(this, mojo::PendingAssociatedReceiver<mojom::AutofillAgent>(
std::move(handle)));
}
void SetQuitLoopClosure(base::OnceClosure closure) {
quit_closure_ = std::move(closure);
}
// Returns the id and formdata received via
// mojo interface method mojom::AutofillAgent::FillOrPreviewForm().
bool GetAutofillFillFormMessage(FormData* results) {
if (!fill_form_form_)
return false;
if (results)
*results = *fill_form_form_;
return true;
}
// Returns the id and formdata received via
// mojo interface method mojom::AutofillAgent::PreviewForm().
bool GetAutofillPreviewFormMessage(FormData* results) {
if (!preview_form_form_)
return false;
if (results)
*results = *preview_form_form_;
return true;
}
// Returns data received via mojo interface method
// mojom::AutofillAent::FieldTypePredictionsAvailable().
bool GetFieldTypePredictionsAvailable(
std::vector<FormDataPredictions>* predictions) {
if (!predictions_)
return false;
if (predictions)
*predictions = *predictions_;
return true;
}
// Returns whether mojo interface method mojom::AutofillAgent::ClearForm() got
// called.
bool GetCalledClearSection() { return called_clear_section_; }
// Returns whether mojo interface method
// mojom::AutofillAgent::ClearPreviewedForm() got called.
bool GetCalledClearPreviewedForm() { return called_clear_previewed_form_; }
// Returns data received via mojo interface method
// mojom::AutofillAgent::FillFieldWithValue().
bool GetString16FillFieldWithValue(const FieldGlobalId& field,
std::u16string* value) {
if (!value_fill_field_ || value_renderer_id_ != field.renderer_id)
return false;
if (value)
*value = *value_fill_field_;
return true;
}
// Returns data received via mojo interface method
// mojom::AutofillAgent::PreviewFieldWithValue().
bool GetString16PreviewFieldWithValue(const FieldGlobalId field,
std::u16string* value) {
if (!value_preview_field_ || value_renderer_id_ != field.renderer_id)
return false;
if (value)
*value = *value_preview_field_;
return true;
}
// Returns data received via mojo interface method
// mojom::AutofillAgent::AcceptDataListSuggestion().
bool GetString16AcceptDataListSuggestion(FieldGlobalId field,
std::u16string* value) {
if (!value_accept_data_ || value_renderer_id_ != field.renderer_id)
return false;
if (value)
*value = *value_accept_data_;
return true;
}
// mojom::AutofillAgent:
MOCK_METHOD(void,
TriggerFormExtractionWithResponse,
(base::OnceCallback<void(bool)>),
(override));
MOCK_METHOD(void,
GetPotentialLastFourCombinationsForStandaloneCvc,
(base::OnceCallback<void(const std::vector<std::string>&)>),
(override));
private:
void CallDone() {
if (!quit_closure_.is_null())
std::move(quit_closure_).Run();
}
// mojom::AutofillAgent:
void TriggerFormExtraction() override {}
void FillOrPreviewForm(const FormData& form,
mojom::RendererFormDataAction action) override {
if (action == mojom::RendererFormDataAction::kPreview) {
preview_form_form_ = form;
} else {
fill_form_form_ = form;
}
CallDone();
}
void FieldTypePredictionsAvailable(
const std::vector<FormDataPredictions>& forms) override {
predictions_ = forms;
CallDone();
}
void ClearSection() override {
called_clear_section_ = true;
CallDone();
}
void ClearPreviewedForm() override {
called_clear_previewed_form_ = true;
CallDone();
}
void FillFieldWithValue(FieldRendererId field,
const std::u16string& value) override {
value_renderer_id_ = field;
value_fill_field_ = value;
CallDone();
}
void PreviewFieldWithValue(FieldRendererId field,
const std::u16string& value) override {
value_renderer_id_ = field;
value_preview_field_ = value;
CallDone();
}
void SetSuggestionAvailability(FieldRendererId field,
const mojom::AutofillState state) override {
value_renderer_id_ = field;
if (state == mojom::AutofillState::kAutofillAvailable)
suggestions_available_ = true;
else if (state == mojom::AutofillState::kNoSuggestions)
suggestions_available_ = false;
CallDone();
}
void AcceptDataListSuggestion(FieldRendererId field,
const std::u16string& value) override {
value_renderer_id_ = field;
value_accept_data_ = value;
CallDone();
}
void EnableHeavyFormDataScraping() override {}
void FillPasswordSuggestion(const std::u16string& username,
const std::u16string& password) override {}
void PreviewPasswordSuggestion(const std::u16string& username,
const std::u16string& password) override {}
void PreviewPasswordGenerationSuggestion(
const std::u16string& password) override {}
void SetUserGestureRequired(bool required) override {}
void SetSecureContextRequired(bool required) override {}
void SetFocusRequiresScroll(bool require) override {}
void SetQueryPasswordSuggestion(bool query) override {}
void SetFieldsEligibleForManualFilling(
const std::vector<FieldRendererId>& fields) override {}
mojo::AssociatedReceiverSet<mojom::AutofillAgent> receivers_;
base::OnceClosure quit_closure_;
// Records data received from FillOrPreviewForm() call.
absl::optional<FormData> fill_form_form_;
absl::optional<FormData> preview_form_form_;
// Records data received from FieldTypePredictionsAvailable() call.
absl::optional<std::vector<FormDataPredictions>> predictions_;
// Records whether ClearSection() got called.
bool called_clear_section_;
// Records whether ClearPreviewedForm() got called.
bool called_clear_previewed_form_;
// Records the ID received from FillFieldWithValue(), PreviewFieldWithValue(),
// SetSuggestionAvailability(), or AcceptDataListSuggestion().
absl::optional<FieldRendererId> value_renderer_id_;
// Records string received from FillFieldWithValue() call.
absl::optional<std::u16string> value_fill_field_;
// Records string received from PreviewFieldWithValue() call.
absl::optional<std::u16string> value_preview_field_;
// Records string received from AcceptDataListSuggestion() call.
absl::optional<std::u16string> value_accept_data_;
// Records bool received from SetSuggestionAvailability() call.
bool suggestions_available_;
};
} // namespace
class MockBrowserAutofillManager : public BrowserAutofillManager {
public:
MockBrowserAutofillManager(AutofillDriver* driver, AutofillClient* client)
: BrowserAutofillManager(driver, client, kAppLocale) {}
~MockBrowserAutofillManager() override = default;
MOCK_METHOD(void, Reset, (), (override));
MOCK_METHOD(bool, ShouldParseForms, (), ());
MOCK_METHOD(void,
OnFormsSeen,
(const std::vector<FormData>& updated_forms,
const std::vector<FormGlobalId>& removed_forms),
());
};
class ContentAutofillDriverTest : public content::RenderViewHostTestHarness,
public ::testing::WithParamInterface<bool> {
public:
enum class NavigationType {
kNormal,
kSameDocument,
kServedFromBackForwardCache,
kPrerenderedPageActivation,
};
ContentAutofillDriverTest() : autofill_across_iframes_(GetParam()) {
std::vector<base::test::FeatureRef> enabled;
std::vector<base::test::FeatureRef> disabled;
(autofill_across_iframes_ ? enabled : disabled)
.push_back(features::kAutofillAcrossIframes);
scoped_feature_list_.InitWithFeatures(enabled, disabled);
}
void SetUp() override {
content::RenderViewHostTestHarness::SetUp();
// This needed to keep the WebContentsObserverConsistencyChecker checks
// happy for when AppendChild is called.
NavigateAndCommit(GURL("about:blank"));
blink::AssociatedInterfaceProvider* remote_interfaces =
web_contents()->GetPrimaryMainFrame()->GetRemoteAssociatedInterfaces();
remote_interfaces->OverrideBinderForTesting(
mojom::AutofillAgent::Name_,
base::BindRepeating(&FakeAutofillAgent::BindPendingReceiver,
base::Unretained(&fake_agent_)));
}
void Navigate(NavigationType type) {
content::MockNavigationHandle navigation_handle(GURL(), main_rfh());
navigation_handle.set_has_committed(true);
switch (type) {
case NavigationType::kNormal:
break;
case NavigationType::kSameDocument:
navigation_handle.set_is_same_document(true);
break;
case NavigationType::kServedFromBackForwardCache:
navigation_handle.set_is_served_from_bfcache(true);
break;
case NavigationType::kPrerenderedPageActivation:
navigation_handle.set_is_prerendered_page_activation(true);
break;
}
factory()->DidFinishNavigation(&navigation_handle);
}
protected:
FormData SeeAddressFormData() {
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> augmented_forms;
EXPECT_CALL(*manager(), OnFormsSeen(_, _))
.WillOnce(DoAll(SaveArg<0>(&augmented_forms)));
driver()->renderer_events().FormsSeen(/*updated_forms=*/{form},
/*removed_forms=*/{});
return augmented_forms.front();
}
TestContentAutofillClient* client() {
return autofill_client_injector_[web_contents()];
}
ContentAutofillDriverFactory* factory() {
return client()->GetAutofillDriverFactory();
}
ContentAutofillRouter& router() {
return ContentAutofillDriverFactoryTestApi(factory()).router();
}
ContentAutofillDriver* driver() {
return autofill_driver_injector_[web_contents()];
}
MockBrowserAutofillManager* manager() {
return static_cast<MockBrowserAutofillManager*>(
driver()->autofill_manager());
}
LocalFrameToken frame_token() {
return LocalFrameToken(
web_contents()->GetPrimaryMainFrame()->GetFrameToken().value());
}
bool autofill_across_iframes_ = false;
base::test::ScopedFeatureList scoped_feature_list_;
test::AutofillUnitTestEnvironment autofill_test_environment_;
TestAutofillClientInjector<TestContentAutofillClient>
autofill_client_injector_;
TestAutofillDriverInjector<ContentAutofillDriver> autofill_driver_injector_;
TestAutofillManagerInjector<MockBrowserAutofillManager>
autofill_manager_injector_;
FakeAutofillAgent fake_agent_;
};
TEST_P(ContentAutofillDriverTest, NavigatedMainFrameDifferentDocument) {
EXPECT_CALL(*manager(), Reset());
Navigate(NavigationType::kNormal);
}
TEST_P(ContentAutofillDriverTest, NavigatedMainFrameSameDocument) {
EXPECT_CALL(*manager(), Reset()).Times(0);
Navigate(NavigationType::kSameDocument);
}
TEST_P(ContentAutofillDriverTest, NavigatedMainFrameFromBackForwardCache) {
EXPECT_CALL(*manager(), Reset()).Times(0);
Navigate(NavigationType::kServedFromBackForwardCache);
}
TEST_P(ContentAutofillDriverTest, NavigatedMainFramePrerenderedPageActivation) {
EXPECT_CALL(*manager(), Reset()).Times(0);
Navigate(NavigationType::kPrerenderedPageActivation);
}
TEST_P(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfForm) {
NavigateAndCommit(GURL("https://username:password@hostname/path?query#hash"));
FormData form;
form.fields.emplace_back();
FormData form2 = test_api(driver()).GetFormWithFrameAndFormMetaData(form);
test_api(driver()).SetFrameAndFormMetaData(form, nullptr);
EXPECT_EQ(form.host_frame, frame_token());
EXPECT_EQ(form.url, GURL("https://hostname/path"));
EXPECT_EQ(form.full_url, GURL());
EXPECT_EQ(form.main_frame_origin,
web_contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin());
EXPECT_EQ(form.main_frame_origin,
url::Origin::CreateFromNormalizedTuple("https", "hostname", 443));
ASSERT_EQ(form.fields.size(), 1u);
EXPECT_EQ(form.fields.front().host_frame, frame_token());
EXPECT_EQ(form2.host_frame, form.host_frame);
EXPECT_EQ(form2.url, form.url);
EXPECT_EQ(form2.full_url, form.full_url);
EXPECT_EQ(form2.main_frame_origin, form.main_frame_origin);
ASSERT_EQ(form2.fields.size(), 1u);
EXPECT_EQ(form2.fields.front().host_frame, form2.fields.front().host_frame);
}
// Test that forms in "about:" without parents have an empty FormData::url.
TEST_P(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfForm_AboutScheme) {
NavigateAndCommit(GURL("about:blank"));
ASSERT_TRUE(main_rfh()->GetLastCommittedURL().IsAboutBlank());
FormData form;
test_api(driver()).SetFrameAndFormMetaData(form, nullptr);
EXPECT_TRUE(form.url.is_empty());
}
// Tests that the FormData::version of forms passed to AutofillManager
// increases.
TEST_P(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfForm_Version) {
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> augmented_forms;
EXPECT_CALL(*manager(), OnFormsSeen(_, _))
.WillOnce(DoAll(SaveArg<0>(&augmented_forms)));
driver()->renderer_events().FormsSeen(/*updated_forms=*/{form},
/*removed_forms=*/{});
ASSERT_EQ(augmented_forms.size(), 1u);
FormVersion previous_version = augmented_forms[0].version;
EXPECT_CALL(*manager(), OnFormsSeen(ElementsAre(Field("FormData::version",
&FormData::version,
Gt(previous_version))),
_));
driver()->renderer_events().FormsSeen(/*updated_forms=*/{form},
/*removed_forms=*/{});
}
// Test that forms in "about:" subframes inherit the URL of their next
// non-"about:" ancestor in FormData::url.
TEST_P(ContentAutofillDriverTest,
SetFrameAndFormMetaDataOfForm_AboutSchemeInheritsFromGrandParent) {
NavigateAndCommit(GURL("https://username:password@hostname/path?query#hash"));
content::RenderFrameHost* child_rfh =
content::NavigationSimulator::NavigateAndCommitFromDocument(
GURL("about:blank"), content::RenderFrameHostTester::For(main_rfh())
->AppendChild("child"));
content::RenderFrameHost* grandchild_rfh =
content::NavigationSimulator::NavigateAndCommitFromDocument(
GURL("about:blank"),
content::RenderFrameHostTester::For(child_rfh)->AppendChild(
"grandchild"));
// Unlike `autofill_driver_injector_[grandchild_rfh]`, GetForRenderFrameHost()
// creates a driver (if none exists).
ContentAutofillDriver* grandchild_driver =
ContentAutofillDriver::GetForRenderFrameHost(grandchild_rfh);
autofill_driver_injector_[grandchild_rfh];
ASSERT_TRUE(child_rfh->GetLastCommittedURL().IsAboutBlank());
ASSERT_TRUE(grandchild_rfh->GetLastCommittedURL().IsAboutBlank());
FormData form;
test_api(grandchild_driver).SetFrameAndFormMetaData(form, nullptr);
EXPECT_EQ(form.url, GURL("https://hostname"));
}
TEST_P(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfField) {
NavigateAndCommit(GURL("https://username:password@hostname/path?query#hash"));
// We test that `SetFrameAndFormMetaData(form, &field) sets the meta data not
// just of |form|'s fields but also of an additional individual |field|.
FormData form;
form.fields.emplace_back();
FormFieldData field = form.fields.back();
FormSignature signature_without_meta_data = CalculateFormSignature(form);
test_api(driver()).SetFrameAndFormMetaData(form, &field);
EXPECT_NE(signature_without_meta_data, CalculateFormSignature(form));
EXPECT_EQ(field.host_frame, frame_token());
EXPECT_EQ(field.host_form_id, form.unique_renderer_id);
EXPECT_EQ(field.host_form_signature, CalculateFormSignature(form));
EXPECT_EQ(field.host_frame, form.fields.front().host_frame);
EXPECT_EQ(field.host_form_id, form.fields.front().host_form_id);
EXPECT_EQ(field.host_form_signature, form.fields.front().host_form_signature);
}
// Tests that FormsSeen() for an updated form arrives in the AutofillManager.
// Does not test multiple frames.
TEST_P(ContentAutofillDriverTest, FormsSeen_UpdatedForm) {
FormData form;
test::CreateTestAddressFormData(&form);
EXPECT_CALL(*manager(),
OnFormsSeen(ElementsAre(AllOf(
// The received form has some frame-specific meta
// data set, which we don't test here.
Field("FormData::frame_token",
&FormData::host_frame, frame_token()),
Field("FormData::unique_renderer_id",
&FormData::unique_renderer_id,
form.unique_renderer_id),
Field("FormData::fields", &FormData::fields,
SizeIs(form.fields.size())))),
IsEmpty()));
driver()->renderer_events().FormsSeen(/*updated_forms=*/{form},
/*removed_forms=*/{});
}
// Tests that FormsSeen() for a removed form arrives in the AutofillManager.
// Does not test multiple frames.
TEST_P(ContentAutofillDriverTest, FormsSeen_RemovedForm) {
FormRendererId form_renderer_id = test::MakeFormRendererId();
EXPECT_CALL(*manager(),
OnFormsSeen(IsEmpty(), ElementsAre(FormGlobalId(
frame_token(), form_renderer_id))));
driver()->renderer_events().FormsSeen(/*updated_forms=*/{},
/*removed_forms=*/{form_renderer_id});
}
// Tests that FormsSeen() for one updated and one removed form arrives in the
// AutofillManager.
// Does not test multiple frames.
TEST_P(ContentAutofillDriverTest, FormsSeen_UpdatedAndRemovedForm) {
FormData form;
test::CreateTestAddressFormData(&form);
FormRendererId other_form_renderer_id = test::MakeFormRendererId();
EXPECT_CALL(
*manager(),
OnFormsSeen(
ElementsAre(AllOf(
// The received form has some frame-specific meta data set, which
// we don't test here.
Field("FormData::frame_token", &FormData::host_frame,
frame_token()),
Field("FormData::unique_renderer_id",
&FormData::unique_renderer_id, form.unique_renderer_id),
Field("FormData::fields", &FormData::fields,
SizeIs(form.fields.size())))),
ElementsAre(FormGlobalId(frame_token(), other_form_renderer_id))));
driver()->renderer_events().FormsSeen(
/*updated_forms=*/{form},
/*removed_forms=*/{other_form_renderer_id});
}
TEST_P(ContentAutofillDriverTest, FormDataSentToRenderer_FillForm) {
url::Origin triggered_origin;
FormData input_form_data = SeeAddressFormData();
for (FormFieldData& field : input_form_data.fields) {
field.origin = triggered_origin;
field.value = u"dummy_value";
}
base::RunLoop run_loop;
fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver()->browser_events().FillOrPreviewForm(
mojom::RendererFormDataAction::kFill, input_form_data, triggered_origin,
{});
run_loop.RunUntilIdle();
FormData output_form_data;
EXPECT_FALSE(fake_agent_.GetAutofillPreviewFormMessage(&output_form_data));
EXPECT_TRUE(fake_agent_.GetAutofillFillFormMessage(&output_form_data));
EXPECT_TRUE(test::WithoutUnserializedData(input_form_data)
.SameFormAs(output_form_data));
}
TEST_P(ContentAutofillDriverTest, FormDataSentToRenderer_PreviewForm) {
url::Origin triggered_origin;
FormData input_form_data = SeeAddressFormData();
for (FormFieldData& field : input_form_data.fields) {
field.origin = triggered_origin;
field.value = u"dummy_value";
}
ASSERT_TRUE(base::ranges::all_of(input_form_data.fields,
base::not_fn(&std::u16string::empty),
&FormFieldData::value));
base::RunLoop run_loop;
fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver()->browser_events().FillOrPreviewForm(
mojom::RendererFormDataAction::kPreview, input_form_data,
triggered_origin, {});
run_loop.RunUntilIdle();
FormData output_form_data;
EXPECT_FALSE(fake_agent_.GetAutofillFillFormMessage(&output_form_data));
EXPECT_TRUE(fake_agent_.GetAutofillPreviewFormMessage(&output_form_data));
EXPECT_TRUE(test::WithoutUnserializedData(input_form_data)
.SameFormAs(output_form_data));
}
TEST_P(ContentAutofillDriverTest, TypePredictionsSentToRendererWhenEnabled) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kShowAutofillTypePredictions);
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> augmented_forms;
EXPECT_CALL(*manager(), OnFormsSeen(_, _))
.WillOnce(DoAll(SaveArg<0>(&augmented_forms)));
driver()->renderer_events().FormsSeen(/*updated_forms=*/{form},
/*removed_forms=*/{});
test_api(driver()).SetFrameAndFormMetaData(form, nullptr);
ASSERT_EQ(augmented_forms.size(), 1u);
EXPECT_TRUE(augmented_forms.front().SameFormAs(form));
FormStructure form_structure(form);
std::vector<FormStructure*> form_structures(1, &form_structure);
std::vector<FormDataPredictions> expected_type_predictions =
FormStructure::GetFieldTypePredictions(form_structures);
base::RunLoop run_loop;
fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver()->browser_events().SendAutofillTypePredictionsToRenderer(
form_structures);
run_loop.RunUntilIdle();
std::vector<FormDataPredictions> output_type_predictions;
EXPECT_TRUE(
fake_agent_.GetFieldTypePredictionsAvailable(&output_type_predictions));
EXPECT_EQ(expected_type_predictions, output_type_predictions);
}
TEST_P(ContentAutofillDriverTest, AcceptDataListSuggestion) {
FieldGlobalId field = SeeAddressFormData().fields.front().global_id();
std::u16string input_value(u"barfoo");
std::u16string output_value;
base::RunLoop run_loop;
fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver()->browser_events().RendererShouldAcceptDataListSuggestion(
field, input_value);
run_loop.RunUntilIdle();
EXPECT_TRUE(
fake_agent_.GetString16AcceptDataListSuggestion(field, &output_value));
EXPECT_EQ(input_value, output_value);
}
TEST_P(ContentAutofillDriverTest, ClearFilledSectionSentToRenderer) {
SeeAddressFormData();
base::RunLoop run_loop;
fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver()->browser_events().RendererShouldClearFilledSection();
run_loop.RunUntilIdle();
EXPECT_TRUE(fake_agent_.GetCalledClearSection());
}
TEST_P(ContentAutofillDriverTest, ClearPreviewedFormSentToRenderer) {
SeeAddressFormData();
base::RunLoop run_loop;
fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver()->browser_events().RendererShouldClearPreviewedForm();
run_loop.RunUntilIdle();
EXPECT_TRUE(fake_agent_.GetCalledClearPreviewedForm());
}
TEST_P(ContentAutofillDriverTest, FillFieldWithValue) {
FieldGlobalId field = SeeAddressFormData().fields.front().global_id();
std::u16string input_value(u"barqux");
std::u16string output_value;
base::RunLoop run_loop;
fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver()->browser_events().RendererShouldFillFieldWithValue(field,
input_value);
run_loop.RunUntilIdle();
EXPECT_TRUE(fake_agent_.GetString16FillFieldWithValue(field, &output_value));
EXPECT_EQ(input_value, output_value);
}
TEST_P(ContentAutofillDriverTest, PreviewFieldWithValue) {
FieldGlobalId field = SeeAddressFormData().fields.front().global_id();
std::u16string input_value(u"barqux");
std::u16string output_value;
base::RunLoop run_loop;
fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver()->browser_events().RendererShouldPreviewFieldWithValue(field,
input_value);
run_loop.RunUntilIdle();
EXPECT_TRUE(
fake_agent_.GetString16PreviewFieldWithValue(field, &output_value));
EXPECT_EQ(input_value, output_value);
}
TEST_P(ContentAutofillDriverTest, SetShouldSuppressKeyboard) {
ASSERT_FALSE(test_api(driver()).should_suppress_keyboard());
test_api(&router()).set_last_queried_source(driver());
driver()->SetShouldSuppressKeyboard(true);
EXPECT_TRUE(test_api(driver()).should_suppress_keyboard());
}
TEST_P(ContentAutofillDriverTest, TriggerFormExtractionInAllFrames) {
base::RunLoop run_loop;
fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
base::OnceCallback<void(bool)> form_extraction_finished_callback;
EXPECT_CALL(fake_agent_, TriggerFormExtractionWithResponse)
.WillOnce(MoveArg<0>(&form_extraction_finished_callback));
driver()->browser_events().TriggerFormExtractionInAllFrames(base::BindOnce(
[](base::RunLoop* run_loop, bool success) { run_loop->Quit(); },
&run_loop));
run_loop.RunUntilIdle();
EXPECT_FALSE(form_extraction_finished_callback.is_null());
std::move(form_extraction_finished_callback).Run(true);
}
TEST_P(ContentAutofillDriverTest, GetFourDigitCombinationsFromDOM_NoMatches) {
base::RunLoop run_loop;
auto cb =
[](base::OnceCallback<void(const std::vector<std::string>&)> callback) {
std::vector<std::string> matches;
std::move(callback).Run(matches);
};
EXPECT_CALL(fake_agent_, GetPotentialLastFourCombinationsForStandaloneCvc)
.WillOnce(WithArg<0>(Invoke(cb)));
std::vector<std::string> matches = {"dummy data"};
driver()->browser_events().GetFourDigitCombinationsFromDOM(
base::BindLambdaForTesting([&](const std::vector<std::string>& result) {
matches = result;
run_loop.Quit();
}));
run_loop.Run();
EXPECT_TRUE(matches.empty());
}
TEST_P(ContentAutofillDriverTest,
GetFourDigitCombinationsFromDOM_SuccessfulMatches) {
base::RunLoop run_loop;
auto cb =
[](base::OnceCallback<void(const std::vector<std::string>&)> callback) {
std::vector<std::string> matches = {"1234"};
std::move(callback).Run(matches);
};
EXPECT_CALL(fake_agent_, GetPotentialLastFourCombinationsForStandaloneCvc)
.WillOnce(WithArg<0>(Invoke(cb)));
std::vector<std::string> matches;
driver()->browser_events().GetFourDigitCombinationsFromDOM(
base::BindLambdaForTesting([&](const std::vector<std::string>& result) {
matches = result;
run_loop.Quit();
}));
run_loop.Run();
EXPECT_THAT(matches, ElementsAre("1234"));
}
INSTANTIATE_TEST_SUITE_P(ContentAutofillDriverTest,
ContentAutofillDriverTest,
testing::Bool());
} // namespace autofill