blob: 3333384f9c9d182abb9913a1921dbcc71d8f4d84 [file] [log] [blame]
// Copyright 2013 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 <map>
#include "base/strings/utf_string_conversions.h"
#include "base/tuple.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/autofill/content/browser/autocheckout_manager.h"
#include "components/autofill/core/browser/autofill_common_test.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/test_autofill_driver.h"
#include "components/autofill/core/browser/test_autofill_manager_delegate.h"
#include "components/autofill/core/common/autofill_messages.h"
#include "components/autofill/core/common/form_data.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_thread.h"
#include "content/public/test/test_utils.h"
#include "ipc/ipc_test_sink.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::BrowserThread;
namespace autofill {
namespace {
typedef Tuple4<std::vector<FormData>,
std::vector<WebElementDescriptor>,
std::vector<WebElementDescriptor>,
WebElementDescriptor> AutofillParam;
enum ProceedElementPresence {
NO_PROCEED_ELEMENT,
HAS_PROCEED_ELEMENT,
};
FormFieldData BuildFieldWithValue(
const std::string& autocomplete_attribute,
const std::string& value) {
FormFieldData field;
field.name = ASCIIToUTF16(autocomplete_attribute);
field.value = ASCIIToUTF16(value);
field.autocomplete_attribute = autocomplete_attribute;
field.form_control_type = "text";
return field;
}
FormFieldData BuildField(const std::string& autocomplete_attribute) {
return BuildFieldWithValue(autocomplete_attribute, autocomplete_attribute);
}
scoped_ptr<FormStructure> CreateTestFormStructure(
const std::vector<ServerFieldType>& autofill_types) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.method = ASCIIToUTF16("POST");
form.origin = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.user_submitted = true;
// Add some fields, autocomplete_attribute is not important and we
// fake that server sends authoritative field mappings.
for (size_t i = 0; i < autofill_types.size(); ++i)
form.fields.push_back(BuildField("SomeField"));
scoped_ptr<FormStructure> form_structure(
new FormStructure(form, std::string()));
// Set mocked Autofill server field types.
for (size_t i = 0; i < autofill_types.size(); ++i) {
form_structure->field(i)->set_server_type(autofill_types[i]);
// Set heuristic type to make sure that server_types are used and not
// heuritic type.
form_structure->field(i)->set_heuristic_type(CREDIT_CARD_NUMBER);
}
return form_structure.Pass();
}
scoped_ptr<FormStructure> CreateTestAddressFormStructure() {
std::vector<ServerFieldType> autofill_types;
autofill_types.push_back(NAME_FULL);
autofill_types.push_back(PHONE_HOME_WHOLE_NUMBER);
autofill_types.push_back(EMAIL_ADDRESS);
autofill_types.push_back(ADDRESS_HOME_LINE1);
autofill_types.push_back(ADDRESS_HOME_CITY);
autofill_types.push_back(ADDRESS_HOME_STATE);
autofill_types.push_back(ADDRESS_HOME_COUNTRY);
autofill_types.push_back(ADDRESS_HOME_ZIP);
autofill_types.push_back(NO_SERVER_DATA);
return CreateTestFormStructure(autofill_types);
}
scoped_ptr<FormStructure> CreateTestCreditCardFormStructure() {
std::vector<ServerFieldType> autofill_types;
autofill_types.push_back(CREDIT_CARD_NAME);
autofill_types.push_back(CREDIT_CARD_NUMBER);
autofill_types.push_back(CREDIT_CARD_EXP_MONTH);
autofill_types.push_back(CREDIT_CARD_EXP_4_DIGIT_YEAR);
autofill_types.push_back(CREDIT_CARD_VERIFICATION_CODE);
autofill_types.push_back(ADDRESS_BILLING_LINE1);
autofill_types.push_back(ADDRESS_BILLING_CITY);
autofill_types.push_back(ADDRESS_BILLING_STATE);
autofill_types.push_back(ADDRESS_BILLING_COUNTRY);
autofill_types.push_back(ADDRESS_BILLING_ZIP);
return CreateTestFormStructure(autofill_types);
}
scoped_ptr<FormStructure> CreateTestFormStructureWithDefaultValues() {
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.method = ASCIIToUTF16("POST");
form.origin = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.user_submitted = true;
// Add two radio button fields.
FormFieldData male = BuildFieldWithValue("sex", "male");
male.is_checkable = true;
form.fields.push_back(male);
FormFieldData female = BuildFieldWithValue("sex", "female");
female.is_checkable = true;
form.fields.push_back(female);
FormFieldData select = BuildField("SelectField");
select.form_control_type = "select-one";
form.fields.push_back(select);
scoped_ptr<FormStructure> form_structure(
new FormStructure(form, std::string()));
// Fake server response. Set all fields as fields with default value.
form_structure->field(0)->set_server_type(FIELD_WITH_DEFAULT_VALUE);
form_structure->field(0)->set_default_value("female");
form_structure->field(1)->set_server_type(FIELD_WITH_DEFAULT_VALUE);
form_structure->field(1)->set_default_value("female");
form_structure->field(2)->set_server_type(FIELD_WITH_DEFAULT_VALUE);
form_structure->field(2)->set_default_value("Default Value");
return form_structure.Pass();
}
void PopulateClickElement(WebElementDescriptor* proceed_element,
const std::string& descriptor) {
proceed_element->descriptor = descriptor;
proceed_element->retrieval_method = WebElementDescriptor::ID;
}
scoped_ptr<AutocheckoutPageMetaData> CreateStartOfFlowMetaData() {
scoped_ptr<AutocheckoutPageMetaData> start_of_flow(
new AutocheckoutPageMetaData());
start_of_flow->current_page_number = 0;
start_of_flow->total_pages = 3;
start_of_flow->page_types[0].push_back(AUTOCHECKOUT_STEP_SHIPPING);
start_of_flow->page_types[1].push_back(AUTOCHECKOUT_STEP_DELIVERY);
start_of_flow->page_types[2].push_back(AUTOCHECKOUT_STEP_BILLING);
PopulateClickElement(&start_of_flow->proceed_element_descriptor, "#foo");
return start_of_flow.Pass();
}
scoped_ptr<AutocheckoutPageMetaData> CreateInFlowMetaData() {
scoped_ptr<AutocheckoutPageMetaData> in_flow(new AutocheckoutPageMetaData());
in_flow->current_page_number = 1;
in_flow->total_pages = 3;
PopulateClickElement(&in_flow->proceed_element_descriptor, "#foo");
return in_flow.Pass();
}
scoped_ptr<AutocheckoutPageMetaData> CreateNotInFlowMetaData() {
scoped_ptr<AutocheckoutPageMetaData> not_in_flow(
new AutocheckoutPageMetaData());
PopulateClickElement(&not_in_flow->proceed_element_descriptor, "#foo");
return not_in_flow.Pass();
}
scoped_ptr<AutocheckoutPageMetaData> CreateEndOfFlowMetaData(
ProceedElementPresence proceed_element_presence) {
scoped_ptr<AutocheckoutPageMetaData> end_of_flow(
new AutocheckoutPageMetaData());
end_of_flow->current_page_number = 2;
end_of_flow->total_pages = 3;
if (proceed_element_presence == HAS_PROCEED_ELEMENT)
PopulateClickElement(&end_of_flow->proceed_element_descriptor, "#foo");
return end_of_flow.Pass();
}
scoped_ptr<AutocheckoutPageMetaData> CreateOnePageFlowMetaData(
ProceedElementPresence proceed_element_presence) {
scoped_ptr<AutocheckoutPageMetaData> one_page_flow(
new AutocheckoutPageMetaData());
one_page_flow->current_page_number = 0;
one_page_flow->total_pages = 1;
one_page_flow->page_types[0].push_back(AUTOCHECKOUT_STEP_SHIPPING);
one_page_flow->page_types[0].push_back(AUTOCHECKOUT_STEP_DELIVERY);
one_page_flow->page_types[0].push_back(AUTOCHECKOUT_STEP_BILLING);
if (proceed_element_presence == HAS_PROCEED_ELEMENT)
PopulateClickElement(&one_page_flow->proceed_element_descriptor, "#foo");
return one_page_flow.Pass();
}
scoped_ptr<AutocheckoutPageMetaData> CreateMissingProceedMetaData() {
scoped_ptr<AutocheckoutPageMetaData> missing_proceed(
new AutocheckoutPageMetaData());
missing_proceed->current_page_number = 1;
missing_proceed->total_pages = 3;
return missing_proceed.Pass();
}
scoped_ptr<AutocheckoutPageMetaData> CreateMultiClickMetaData() {
scoped_ptr<AutocheckoutPageMetaData> metadata(new AutocheckoutPageMetaData());
metadata->current_page_number = 1;
metadata->total_pages = 3;
PopulateClickElement(&metadata->proceed_element_descriptor, "#foo");
WebElementDescriptor element;
PopulateClickElement(&element, "#before_form_fill_1");
metadata->click_elements_before_form_fill.push_back(element);
PopulateClickElement(&element, "#before_form_fill_2");
metadata->click_elements_before_form_fill.push_back(element);
PopulateClickElement(&element, "#after_form_fill");
metadata->click_elements_after_form_fill.push_back(element);
return metadata.Pass();
}
struct TestField {
const char* const field_type;
const char* const field_value;
ServerFieldType autofill_type;
};
const TestField kTestFields[] = {
{"name", "Test User", NAME_FULL},
{"tel", "650-123-9909", PHONE_HOME_WHOLE_NUMBER},
{"email", "blah@blah.com", EMAIL_ADDRESS},
{"cc-name", "Test User", CREDIT_CARD_NAME},
{"cc-number", "4444444444444448", CREDIT_CARD_NUMBER},
{"cc-exp-month", "10", CREDIT_CARD_EXP_MONTH},
{"cc-exp-year", "2020", CREDIT_CARD_EXP_4_DIGIT_YEAR},
{"cc-csc", "123", CREDIT_CARD_VERIFICATION_CODE},
{"street-address", "Fake Street", ADDRESS_HOME_LINE1},
{"locality", "Mocked City", ADDRESS_HOME_CITY},
{"region", "California", ADDRESS_HOME_STATE},
{"country", "USA", ADDRESS_HOME_COUNTRY},
{"postal-code", "49012", ADDRESS_HOME_ZIP},
{"billing-street-address", "Billing Street", ADDRESS_BILLING_LINE1},
{"billing-locality", "Billing City", ADDRESS_BILLING_CITY},
{"billing-region", "BillingState", ADDRESS_BILLING_STATE},
{"billing-country", "Canada", ADDRESS_BILLING_COUNTRY},
{"billing-postal-code", "11111", ADDRESS_BILLING_ZIP}
};
// Build Autocheckout specific form data to be consumed by
// AutofillDialogController to show the Autocheckout specific UI.
scoped_ptr<FormStructure> FakeUserSubmittedFormStructure() {
FormData formdata;
for (size_t i = 0; i < arraysize(kTestFields); i++) {
formdata.fields.push_back(
BuildFieldWithValue(kTestFields[i].field_type,
kTestFields[i].field_value));
}
scoped_ptr<FormStructure> form_structure;
form_structure.reset(new FormStructure(formdata, std::string()));
for (size_t i = 0; i < arraysize(kTestFields); ++i)
form_structure->field(i)->set_server_type(kTestFields[i].autofill_type);
return form_structure.Pass();
}
class MockAutofillManagerDelegate : public TestAutofillManagerDelegate {
public:
MockAutofillManagerDelegate()
: request_autocomplete_dialog_open_(false),
autocheckout_bubble_shown_(false),
should_autoclick_bubble_(true) {}
virtual ~MockAutofillManagerDelegate() {}
virtual void HideRequestAutocompleteDialog() OVERRIDE {
request_autocomplete_dialog_open_ = false;
}
MOCK_METHOD0(OnAutocheckoutError, void());
MOCK_METHOD0(OnAutocheckoutSuccess, void());
virtual void ShowAutocheckoutBubble(
const gfx::RectF& bounds,
bool is_google_user,
const base::Callback<void(AutocheckoutBubbleState)>& callback) OVERRIDE {
autocheckout_bubble_shown_ = true;
if (should_autoclick_bubble_)
callback.Run(AUTOCHECKOUT_BUBBLE_ACCEPTED);
}
virtual void ShowRequestAutocompleteDialog(
const FormData& form,
const GURL& source_url,
DialogType dialog_type,
const base::Callback<void(const FormStructure*,
const std::string&)>& callback) OVERRIDE {
request_autocomplete_dialog_open_ = true;
callback.Run(user_supplied_data_.get(), "google_transaction_id");
}
virtual void AddAutocheckoutStep(AutocheckoutStepType step_type) OVERRIDE {
if (autocheckout_steps_.count(step_type) == 0)
autocheckout_steps_[step_type] = AUTOCHECKOUT_STEP_UNSTARTED;
}
virtual void UpdateAutocheckoutStep(
AutocheckoutStepType step_type,
AutocheckoutStepStatus step_status) OVERRIDE {
autocheckout_steps_[step_type] = step_status;
}
void SetUserSuppliedData(scoped_ptr<FormStructure> user_supplied_data) {
user_supplied_data_.reset(user_supplied_data.release());
}
bool autocheckout_bubble_shown() const {
return autocheckout_bubble_shown_;
}
void set_autocheckout_bubble_shown(bool autocheckout_bubble_shown) {
autocheckout_bubble_shown_ = autocheckout_bubble_shown;
}
bool request_autocomplete_dialog_open() const {
return request_autocomplete_dialog_open_;
}
void set_should_autoclick_bubble(bool should_autoclick_bubble) {
should_autoclick_bubble_ = should_autoclick_bubble;
}
bool AutocheckoutStepExistsWithStatus(
AutocheckoutStepType step_type,
AutocheckoutStepStatus step_status) const {
std::map<AutocheckoutStepType, AutocheckoutStepStatus>::const_iterator it =
autocheckout_steps_.find(step_type);
return it != autocheckout_steps_.end() && it->second == step_status;
}
private:
// Whether or not ShowRequestAutocompleteDialog method has been called.
bool request_autocomplete_dialog_open_;
// Whether or not Autocheckout bubble is displayed to user.
bool autocheckout_bubble_shown_;
// Whether or not to accept the Autocheckout bubble when offered.
bool should_autoclick_bubble_;
// User specified data that would be returned to AutocheckoutManager when
// dialog is accepted.
scoped_ptr<FormStructure> user_supplied_data_;
// Step status of various Autocheckout steps in this checkout flow.
std::map<AutocheckoutStepType, AutocheckoutStepStatus> autocheckout_steps_;
};
class TestAutofillManager : public AutofillManager {
public:
explicit TestAutofillManager(AutofillDriver* driver,
AutofillManagerDelegate* delegate)
: AutofillManager(driver, delegate, NULL) {
}
virtual ~TestAutofillManager() {}
void SetFormStructure(scoped_ptr<FormStructure> form_structure) {
form_structures()->clear();
form_structures()->push_back(form_structure.release());
}
};
class MockAutofillMetrics : public AutofillMetrics {
public:
MockAutofillMetrics() {}
MOCK_CONST_METHOD1(LogAutocheckoutBubbleMetric, void(BubbleMetric));
MOCK_CONST_METHOD1(LogAutocheckoutBuyFlowMetric,
void(AutocheckoutBuyFlowMetric));
private:
DISALLOW_COPY_AND_ASSIGN(MockAutofillMetrics);
};
class TestAutocheckoutManager: public AutocheckoutManager {
public:
explicit TestAutocheckoutManager(AutofillManager* autofill_manager)
: AutocheckoutManager(autofill_manager) {
set_metric_logger(scoped_ptr<AutofillMetrics>(new MockAutofillMetrics));
}
const MockAutofillMetrics& metric_logger() const {
return static_cast<const MockAutofillMetrics&>(
AutocheckoutManager::metric_logger());
}
virtual void MaybeShowAutocheckoutBubble(
const GURL& frame_url,
const gfx::RectF& bounding_box) OVERRIDE {
AutocheckoutManager::MaybeShowAutocheckoutBubble(frame_url,
bounding_box);
// Needed for AutocheckoutManager to post task on IO thread.
content::RunAllPendingInMessageLoop(BrowserThread::IO);
}
using AutocheckoutManager::in_autocheckout_flow;
using AutocheckoutManager::should_show_bubble;
using AutocheckoutManager::MaybeShowAutocheckoutDialog;
using AutocheckoutManager::ReturnAutocheckoutData;
};
} // namespace
class AutocheckoutManagerTest : public ChromeRenderViewHostTestHarness {
protected:
virtual void SetUp() OVERRIDE {
SetThreadBundleOptions(content::TestBrowserThreadBundle::REAL_IO_THREAD);
ChromeRenderViewHostTestHarness::SetUp();
autofill_manager_delegate_.reset(new MockAutofillManagerDelegate());
autofill_driver_.reset(new TestAutofillDriver(web_contents()));
autofill_manager_.reset(new TestAutofillManager(
autofill_driver_.get(),
autofill_manager_delegate_.get()));
autocheckout_manager_.reset(
new TestAutocheckoutManager(autofill_manager_.get()));
}
virtual void TearDown() OVERRIDE {
autocheckout_manager_.reset();
autofill_manager_delegate_.reset();
autofill_manager_.reset();
autofill_driver_.reset();
ChromeRenderViewHostTestHarness::TearDown();
}
std::vector<FormData> ReadFilledForms() {
uint32 kMsgID = AutofillMsg_FillFormsAndClick::ID;
const IPC::Message* message =
process()->sink().GetFirstMessageMatching(kMsgID);
AutofillParam autofill_param;
AutofillMsg_FillFormsAndClick::Read(message, &autofill_param);
return autofill_param.a;
}
void CheckFillFormsAndClickIpc(
ProceedElementPresence proceed_element_presence) {
EXPECT_EQ(1U, process()->sink().message_count());
uint32 kMsgID = AutofillMsg_FillFormsAndClick::ID;
const IPC::Message* message =
process()->sink().GetFirstMessageMatching(kMsgID);
EXPECT_TRUE(message);
AutofillParam autofill_param;
AutofillMsg_FillFormsAndClick::Read(message, &autofill_param);
if (proceed_element_presence == HAS_PROCEED_ELEMENT) {
EXPECT_EQ(WebElementDescriptor::ID, autofill_param.d.retrieval_method);
EXPECT_EQ("#foo", autofill_param.d.descriptor);
} else {
EXPECT_EQ(WebElementDescriptor::NONE, autofill_param.d.retrieval_method);
}
ClearIpcSink();
}
void ClearIpcSink() {
process()->sink().ClearMessages();
}
void OpenRequestAutocompleteDialog() {
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_FALSE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBubbleMetric(
AutofillMetrics::BUBBLE_COULD_BE_DISPLAYED)).Times(1);
autocheckout_manager_->OnLoadedPageMetaData(CreateStartOfFlowMetaData());
// Simulate the user submitting some data via the requestAutocomplete UI.
autofill_manager_delegate_->SetUserSuppliedData(
FakeUserSubmittedFormStructure());
GURL frame_url;
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(
AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_STARTED)).Times(1);
autocheckout_manager_->MaybeShowAutocheckoutDialog(
frame_url,
AUTOCHECKOUT_BUBBLE_ACCEPTED);
CheckFillFormsAndClickIpc(HAS_PROCEED_ELEMENT);
EXPECT_TRUE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_TRUE(autocheckout_manager_->should_preserve_dialog());
EXPECT_TRUE(autofill_manager_delegate_->request_autocomplete_dialog_open());
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_SHIPPING,
AUTOCHECKOUT_STEP_STARTED));
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_DELIVERY,
AUTOCHECKOUT_STEP_UNSTARTED));
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_BILLING,
AUTOCHECKOUT_STEP_UNSTARTED));
}
void HideRequestAutocompleteDialog() {
EXPECT_TRUE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
autofill_manager_delegate_->HideRequestAutocompleteDialog();
EXPECT_FALSE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
}
// Test a multi-page Autocheckout flow end to end.
// |proceed_element_presence_on_last_page| indicates whether the last page
// of the flow should have a proceed element.
void TestFullAutocheckoutFlow(
ProceedElementPresence proceed_element_presence_on_last_page) {
// Test for progression through last page.
OpenRequestAutocompleteDialog();
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_SHIPPING,
AUTOCHECKOUT_STEP_STARTED));
// Complete the first page.
autocheckout_manager_->OnAutocheckoutPageCompleted(SUCCESS);
EXPECT_TRUE(autocheckout_manager_->should_preserve_dialog());
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_SHIPPING,
AUTOCHECKOUT_STEP_COMPLETED));
// Go to the second page.
EXPECT_CALL(*autofill_manager_delegate_, OnAutocheckoutSuccess()).Times(1);
autocheckout_manager_->OnLoadedPageMetaData(CreateInFlowMetaData());
EXPECT_TRUE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_TRUE(autocheckout_manager_->should_preserve_dialog());
CheckFillFormsAndClickIpc(HAS_PROCEED_ELEMENT);
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_DELIVERY,
AUTOCHECKOUT_STEP_STARTED));
autocheckout_manager_->OnAutocheckoutPageCompleted(SUCCESS);
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_DELIVERY,
AUTOCHECKOUT_STEP_COMPLETED));
// Go to the third page.
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(
AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_SUCCESS)).Times(1);
autocheckout_manager_->OnLoadedPageMetaData(
CreateEndOfFlowMetaData(proceed_element_presence_on_last_page));
CheckFillFormsAndClickIpc(proceed_element_presence_on_last_page);
EXPECT_TRUE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_TRUE(autocheckout_manager_->should_preserve_dialog());
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_BILLING,
AUTOCHECKOUT_STEP_STARTED));
autocheckout_manager_->OnAutocheckoutPageCompleted(SUCCESS);
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_TRUE(autocheckout_manager_->should_preserve_dialog());
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_BILLING,
AUTOCHECKOUT_STEP_COMPLETED));
EXPECT_TRUE(autofill_manager_delegate_->request_autocomplete_dialog_open());
// Go to the page after the flow.
autocheckout_manager_->OnLoadedPageMetaData(
scoped_ptr<AutocheckoutPageMetaData>());
EXPECT_EQ(proceed_element_presence_on_last_page == HAS_PROCEED_ELEMENT,
autocheckout_manager_->should_preserve_dialog());
// Go to another page and we should not preserve the dialog now.
autocheckout_manager_->OnLoadedPageMetaData(
scoped_ptr<AutocheckoutPageMetaData>());
EXPECT_FALSE(autocheckout_manager_->should_preserve_dialog());
}
// Test a signle-page Autocheckout flow. |proceed_element_presence| indicates
// whether the page should have a proceed element.
void TestSinglePageFlow(ProceedElementPresence proceed_element_presence) {
// Test one page flow.
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_FALSE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBubbleMetric(
AutofillMetrics::BUBBLE_COULD_BE_DISPLAYED)).Times(1);
EXPECT_CALL(*autofill_manager_delegate_, OnAutocheckoutSuccess()).Times(1);
autocheckout_manager_->OnLoadedPageMetaData(
CreateOnePageFlowMetaData(proceed_element_presence));
// Simulate the user submitting some data via the requestAutocomplete UI.
autofill_manager_delegate_->SetUserSuppliedData(
FakeUserSubmittedFormStructure());
GURL frame_url;
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(
AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_STARTED)).Times(1);
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(
AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_SUCCESS)).Times(1);
autocheckout_manager_->MaybeShowAutocheckoutDialog(
frame_url,
AUTOCHECKOUT_BUBBLE_ACCEPTED);
autocheckout_manager_->OnAutocheckoutPageCompleted(SUCCESS);
CheckFillFormsAndClickIpc(proceed_element_presence);
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_TRUE(autocheckout_manager_->should_preserve_dialog());
EXPECT_TRUE(autofill_manager_delegate_->request_autocomplete_dialog_open());
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_SHIPPING,
AUTOCHECKOUT_STEP_COMPLETED));
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_DELIVERY,
AUTOCHECKOUT_STEP_COMPLETED));
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_BILLING,
AUTOCHECKOUT_STEP_COMPLETED));
// Go to the page after the flow.
autocheckout_manager_->OnLoadedPageMetaData(
scoped_ptr<AutocheckoutPageMetaData>());
EXPECT_EQ(proceed_element_presence == HAS_PROCEED_ELEMENT,
autocheckout_manager_->should_preserve_dialog());
// Go to another page, and we should not preserve the dialog now.
autocheckout_manager_->OnLoadedPageMetaData(
scoped_ptr<AutocheckoutPageMetaData>());
EXPECT_FALSE(autocheckout_manager_->should_preserve_dialog());
}
protected:
scoped_ptr<TestAutofillDriver> autofill_driver_;
scoped_ptr<TestAutofillManager> autofill_manager_;
scoped_ptr<TestAutocheckoutManager> autocheckout_manager_;
scoped_ptr<MockAutofillManagerDelegate> autofill_manager_delegate_;
};
TEST_F(AutocheckoutManagerTest, TestFillForms) {
OpenRequestAutocompleteDialog();
// Test if autocheckout manager can fill the first page.
autofill_manager_->SetFormStructure(CreateTestAddressFormStructure());
autocheckout_manager_->FillForms();
std::vector<FormData> filled_forms = ReadFilledForms();
ASSERT_EQ(1U, filled_forms.size());
ASSERT_EQ(9U, filled_forms[0].fields.size());
EXPECT_EQ(ASCIIToUTF16("Test User"), filled_forms[0].fields[0].value);
EXPECT_EQ(ASCIIToUTF16("650-123-9909"), filled_forms[0].fields[1].value);
EXPECT_EQ(ASCIIToUTF16("blah@blah.com"), filled_forms[0].fields[2].value);
EXPECT_EQ(ASCIIToUTF16("Fake Street"), filled_forms[0].fields[3].value);
EXPECT_EQ(ASCIIToUTF16("Mocked City"), filled_forms[0].fields[4].value);
EXPECT_EQ(ASCIIToUTF16("California"), filled_forms[0].fields[5].value);
EXPECT_EQ(ASCIIToUTF16("United States"), filled_forms[0].fields[6].value);
EXPECT_EQ(ASCIIToUTF16("49012"), filled_forms[0].fields[7].value);
// Last field should not be filled, because there is no server mapping
// available for it.
EXPECT_EQ(ASCIIToUTF16("SomeField"), filled_forms[0].fields[8].value);
filled_forms.clear();
ClearIpcSink();
// Test if autocheckout manager can fill form on second page.
autofill_manager_->SetFormStructure(CreateTestCreditCardFormStructure());
autocheckout_manager_->FillForms();
filled_forms = ReadFilledForms();
ASSERT_EQ(1U, filled_forms.size());
ASSERT_EQ(10U, filled_forms[0].fields.size());
EXPECT_EQ(ASCIIToUTF16("Test User"), filled_forms[0].fields[0].value);
EXPECT_EQ(ASCIIToUTF16("4444444444444448"), filled_forms[0].fields[1].value);
EXPECT_EQ(ASCIIToUTF16("10"), filled_forms[0].fields[2].value);
EXPECT_EQ(ASCIIToUTF16("2020"), filled_forms[0].fields[3].value);
EXPECT_EQ(ASCIIToUTF16("123"), filled_forms[0].fields[4].value);
EXPECT_EQ(ASCIIToUTF16("Billing Street"), filled_forms[0].fields[5].value);
EXPECT_EQ(ASCIIToUTF16("Billing City"), filled_forms[0].fields[6].value);
EXPECT_EQ(ASCIIToUTF16("BillingState"), filled_forms[0].fields[7].value);
EXPECT_EQ(ASCIIToUTF16("Canada"), filled_forms[0].fields[8].value);
EXPECT_EQ(ASCIIToUTF16("11111"), filled_forms[0].fields[9].value);
filled_forms.clear();
ClearIpcSink();
// Test form with default values.
autofill_manager_->SetFormStructure(
CreateTestFormStructureWithDefaultValues());
autocheckout_manager_->FillForms();
filled_forms = ReadFilledForms();
ASSERT_EQ(1U, filled_forms.size());
ASSERT_EQ(3U, filled_forms[0].fields.size());
EXPECT_FALSE(filled_forms[0].fields[0].is_checked);
EXPECT_EQ(ASCIIToUTF16("male"), filled_forms[0].fields[0].value);
EXPECT_TRUE(filled_forms[0].fields[1].is_checked);
EXPECT_EQ(ASCIIToUTF16("female"), filled_forms[0].fields[1].value);
EXPECT_EQ(ASCIIToUTF16("Default Value"), filled_forms[0].fields[2].value);
}
TEST_F(AutocheckoutManagerTest, OnFormsSeenTest) {
GURL frame_url;
gfx::RectF bounding_box;
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBubbleMetric(
AutofillMetrics::BUBBLE_COULD_BE_DISPLAYED)).Times(1);
autocheckout_manager_->OnLoadedPageMetaData(CreateStartOfFlowMetaData());
autocheckout_manager_->MaybeShowAutocheckoutBubble(frame_url, bounding_box);
EXPECT_FALSE(autocheckout_manager_->should_show_bubble());
// OnFormsSeen resets whether or not the bubble was shown.
autocheckout_manager_->OnFormsSeen();
EXPECT_TRUE(autocheckout_manager_->should_show_bubble());
}
TEST_F(AutocheckoutManagerTest, OnClickFailedTestMissingAdvance) {
OpenRequestAutocompleteDialog();
EXPECT_CALL(*autofill_manager_delegate_, OnAutocheckoutError()).Times(1);
EXPECT_CALL(
autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(
AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_MISSING_ADVANCE_ELEMENT))
.Times(1);
autocheckout_manager_->OnAutocheckoutPageCompleted(MISSING_ADVANCE);
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_TRUE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_SHIPPING,
AUTOCHECKOUT_STEP_FAILED));
}
TEST_F(AutocheckoutManagerTest, OnClickFailedTestMissingClickBeforeFilling) {
OpenRequestAutocompleteDialog();
EXPECT_CALL(*autofill_manager_delegate_, OnAutocheckoutError()).Times(1);
EXPECT_CALL(
autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(AutofillMetrics::
AUTOCHECKOUT_BUY_FLOW_MISSING_CLICK_ELEMENT_BEFORE_FORM_FILLING))
.Times(1);
autocheckout_manager_->OnAutocheckoutPageCompleted(
MISSING_CLICK_ELEMENT_BEFORE_FORM_FILLING);
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_TRUE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
}
TEST_F(AutocheckoutManagerTest, OnClickFailedTestMissingClickAfterFilling) {
OpenRequestAutocompleteDialog();
EXPECT_CALL(*autofill_manager_delegate_, OnAutocheckoutError()).Times(1);
EXPECT_CALL(
autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(AutofillMetrics::
AUTOCHECKOUT_BUY_FLOW_MISSING_CLICK_ELEMENT_AFTER_FORM_FILLING))
.Times(1);
autocheckout_manager_->OnAutocheckoutPageCompleted(
MISSING_CLICK_ELEMENT_AFTER_FORM_FILLING);
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_TRUE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
}
TEST_F(AutocheckoutManagerTest, MaybeShowAutocheckoutBubbleTest) {
GURL frame_url;
gfx::RectF bounding_box;
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBubbleMetric(
AutofillMetrics::BUBBLE_COULD_BE_DISPLAYED)).Times(1);
autocheckout_manager_->OnLoadedPageMetaData(CreateStartOfFlowMetaData());
// MaybeShowAutocheckoutBubble shows bubble if it has not been shown.
autocheckout_manager_->MaybeShowAutocheckoutBubble(frame_url, bounding_box);
EXPECT_FALSE(autocheckout_manager_->should_show_bubble());
EXPECT_TRUE(autofill_manager_delegate_->autocheckout_bubble_shown());
// Reset |autofill_manager_delegate_|.
HideRequestAutocompleteDialog();
autofill_manager_delegate_->set_autocheckout_bubble_shown(false);
// MaybeShowAutocheckoutBubble does nothing if the bubble was already shown
// for the current page.
autocheckout_manager_->MaybeShowAutocheckoutBubble(frame_url, bounding_box);
EXPECT_FALSE(autocheckout_manager_->should_show_bubble());
EXPECT_FALSE(autofill_manager_delegate_->autocheckout_bubble_shown());
EXPECT_FALSE(autofill_manager_delegate_->request_autocomplete_dialog_open());
}
TEST_F(AutocheckoutManagerTest, OnLoadedPageMetaDataMissingMetaData) {
// Gettting no meta data after any autocheckout page is an error.
OpenRequestAutocompleteDialog();
EXPECT_CALL(*autofill_manager_delegate_, OnAutocheckoutError()).Times(1);
EXPECT_CALL(
autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(
AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_MISSING_FIELDMAPPING))
.Times(1);
autocheckout_manager_->OnLoadedPageMetaData(
scoped_ptr<AutocheckoutPageMetaData>());
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_EQ(0U, process()->sink().message_count());
EXPECT_TRUE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
}
TEST_F(AutocheckoutManagerTest, OnLoadedPageMetaDataRepeatedStartPage) {
// Getting start page twice in a row is an error.
OpenRequestAutocompleteDialog();
EXPECT_CALL(*autofill_manager_delegate_, OnAutocheckoutError()).Times(1);
EXPECT_CALL(
autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(
AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_CANNOT_PROCEED)).Times(1);
autocheckout_manager_->OnLoadedPageMetaData(CreateStartOfFlowMetaData());
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_EQ(0U, process()->sink().message_count());
EXPECT_TRUE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_SHIPPING,
AUTOCHECKOUT_STEP_FAILED));
}
TEST_F(AutocheckoutManagerTest, OnLoadedPageMetaDataRepeatedPage) {
// Repeating a page is an error.
OpenRequestAutocompleteDialog();
// Go to second page.
autocheckout_manager_->OnLoadedPageMetaData(CreateInFlowMetaData());
EXPECT_TRUE(autocheckout_manager_->in_autocheckout_flow());
CheckFillFormsAndClickIpc(HAS_PROCEED_ELEMENT);
EXPECT_CALL(*autofill_manager_delegate_, OnAutocheckoutError()).Times(1);
EXPECT_CALL(
autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(
AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_CANNOT_PROCEED)).Times(1);
autocheckout_manager_->OnLoadedPageMetaData(CreateInFlowMetaData());
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_EQ(0U, process()->sink().message_count());
EXPECT_TRUE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_DELIVERY,
AUTOCHECKOUT_STEP_FAILED));
}
TEST_F(AutocheckoutManagerTest, OnLoadedPageMetaDataNotInFlow) {
// Repeating a page is an error.
OpenRequestAutocompleteDialog();
// Go to second page.
autocheckout_manager_->OnLoadedPageMetaData(CreateInFlowMetaData());
EXPECT_TRUE(autocheckout_manager_->in_autocheckout_flow());
CheckFillFormsAndClickIpc(HAS_PROCEED_ELEMENT);
EXPECT_CALL(*autofill_manager_delegate_, OnAutocheckoutError()).Times(1);
EXPECT_CALL(
autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(
AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_MISSING_FIELDMAPPING))
.Times(1);
autocheckout_manager_->OnLoadedPageMetaData(CreateNotInFlowMetaData());
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_EQ(0U, process()->sink().message_count());
EXPECT_TRUE(
autofill_manager_delegate_->request_autocomplete_dialog_open());
EXPECT_TRUE(autofill_manager_delegate_
->AutocheckoutStepExistsWithStatus(AUTOCHECKOUT_STEP_DELIVERY,
AUTOCHECKOUT_STEP_FAILED));
}
TEST_F(AutocheckoutManagerTest,
OnLoadedPageMetaDataShouldNotFillFormsIfNotInFlow) {
// If not in flow, OnLoadedPageMetaData does not fill forms.
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBubbleMetric(
AutofillMetrics::BUBBLE_COULD_BE_DISPLAYED)).Times(1);
autocheckout_manager_->OnLoadedPageMetaData(CreateStartOfFlowMetaData());
// Go to second page.
autocheckout_manager_->OnLoadedPageMetaData(CreateInFlowMetaData());
EXPECT_EQ(0U, process()->sink().message_count());
}
TEST_F(AutocheckoutManagerTest, FullAutocheckoutFlow) {
TestFullAutocheckoutFlow(HAS_PROCEED_ELEMENT);
}
TEST_F(AutocheckoutManagerTest, FullAutocheckoutFlowNoClickOnLastPage) {
TestFullAutocheckoutFlow(NO_PROCEED_ELEMENT);
}
TEST_F(AutocheckoutManagerTest, CancelledAutocheckoutFlow) {
// Test for progression through last page.
OpenRequestAutocompleteDialog();
// Go to second page.
autocheckout_manager_->OnLoadedPageMetaData(CreateInFlowMetaData());
EXPECT_TRUE(autocheckout_manager_->in_autocheckout_flow());
CheckFillFormsAndClickIpc(HAS_PROCEED_ELEMENT);
// Cancel the flow.
autocheckout_manager_->ReturnAutocheckoutData(NULL, std::string());
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
// Go to third page.
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBuyFlowMetric(testing::_)).Times(0);
autocheckout_manager_->OnLoadedPageMetaData(
CreateEndOfFlowMetaData(HAS_PROCEED_ELEMENT));
EXPECT_EQ(0U, process()->sink().message_count());
}
TEST_F(AutocheckoutManagerTest, SinglePageFlow) {
TestSinglePageFlow(HAS_PROCEED_ELEMENT);
}
TEST_F(AutocheckoutManagerTest, SinglePageFlowNoClickElement) {
TestSinglePageFlow(NO_PROCEED_ELEMENT);
}
TEST_F(AutocheckoutManagerTest, CancelAutocheckoutBubble) {
GURL frame_url;
gfx::RectF bounding_box;
autofill_manager_delegate_->set_should_autoclick_bubble(false);
EXPECT_FALSE(autocheckout_manager_->in_autocheckout_flow());
EXPECT_FALSE(autofill_manager_delegate_->request_autocomplete_dialog_open());
EXPECT_FALSE(autocheckout_manager_->is_autocheckout_bubble_showing());
EXPECT_CALL(autocheckout_manager_->metric_logger(),
LogAutocheckoutBubbleMetric(
AutofillMetrics::BUBBLE_COULD_BE_DISPLAYED)).Times(1);
autocheckout_manager_->OnLoadedPageMetaData(CreateStartOfFlowMetaData());
autocheckout_manager_->MaybeShowAutocheckoutBubble(frame_url, bounding_box);
EXPECT_TRUE(autocheckout_manager_->is_autocheckout_bubble_showing());
autocheckout_manager_->MaybeShowAutocheckoutDialog(
frame_url,
AUTOCHECKOUT_BUBBLE_IGNORED);
EXPECT_FALSE(autocheckout_manager_->is_autocheckout_bubble_showing());
EXPECT_TRUE(autocheckout_manager_->should_show_bubble());
autocheckout_manager_->MaybeShowAutocheckoutBubble(frame_url, bounding_box);
EXPECT_TRUE(autocheckout_manager_->is_autocheckout_bubble_showing());
autocheckout_manager_->MaybeShowAutocheckoutDialog(
frame_url,
AUTOCHECKOUT_BUBBLE_CANCELED);
EXPECT_FALSE(autocheckout_manager_->is_autocheckout_bubble_showing());
EXPECT_FALSE(autocheckout_manager_->should_show_bubble());
autocheckout_manager_->MaybeShowAutocheckoutBubble(frame_url, bounding_box);
EXPECT_FALSE(autocheckout_manager_->is_autocheckout_bubble_showing());
}
} // namespace autofill