blob: ea3fc514819ad74814e6464cf78ed557b9bfec15 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/autofill/address_bubbles_controller.h"
#include <string>
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/autofill/ui/ui_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/ui/tabs/tab_enums.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "components/autofill/core/browser/autofill_address_util.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/strings/grit/components_strings.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
namespace autofill {
using ::testing::Property;
using profile_ref = base::optional_ref<const AutofillProfile>;
class AddressBubblesControllerTest
: public BrowserWithTestWindowTest {
public:
AddressBubblesControllerTest() = default;
void SetUp() override {
BrowserWithTestWindowTest::SetUp();
AddTab(browser(), GURL("about:blank"));
}
AddressBubblesController* controller() {
return AddressBubblesController::FromWebContents(
web_contents());
}
protected:
raw_ptr<content::WebContents> web_contents() const {
return browser()->tab_strip_model()->GetActiveWebContents();
}
const std::string& app_locale() const {
return g_browser_process->GetApplicationLocale();
}
};
TEST_F(AddressBubblesControllerTest,
DialogAcceptedInvokesCallback) {
AutofillProfile profile = test::GetFullProfile();
base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback;
AddressBubblesController::SetUpAndShowSaveOrUpdateAddressBubble(
web_contents(), profile, /*original_profile=*/nullptr,
AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
callback.Get());
EXPECT_CALL(callback,
Run(AutofillClient::AddressPromptUserDecision::kAccepted,
Property(&profile_ref::has_value, false)));
controller()->OnUserDecision(
AutofillClient::AddressPromptUserDecision::kAccepted, std::nullopt);
}
TEST_F(AddressBubblesControllerTest,
DialogCancelledInvokesCallback) {
AutofillProfile profile = test::GetFullProfile();
base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback;
AddressBubblesController::SetUpAndShowSaveOrUpdateAddressBubble(
web_contents(), profile, /*original_profile=*/nullptr,
AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
callback.Get());
EXPECT_CALL(callback,
Run(AutofillClient::AddressPromptUserDecision::kDeclined,
Property(&profile_ref::has_value, false)));
controller()->OnUserDecision(
AutofillClient::AddressPromptUserDecision::kDeclined, std::nullopt);
}
// This is testing that closing all tabs (which effectively destroys the web
// contents) will trigger the save callback with kIgnored decions if the users
// hasn't interacted with the prompt already.
TEST_F(AddressBubblesControllerTest,
WebContentsDestroyedInvokesCallback) {
AutofillProfile profile = test::GetFullProfile();
base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback;
AddressBubblesController::SetUpAndShowSaveOrUpdateAddressBubble(
web_contents(), profile, /*original_profile=*/nullptr,
AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
callback.Get());
TabStripModel* tab_strip_model = browser()->tab_strip_model();
// There is only now tab open, so the active web contents, are the
// controller's web contents.
content::WebContents* controller_web_contents =
tab_strip_model->GetActiveWebContents();
// Now add another tab, and close the controller tab to make sure the window
// remains open. This should destroy the web contents of the controller and
// invoke the callback with a decision kIgnored.
AddTab(browser(), GURL("http://foo.com/"));
EXPECT_EQ(2, tab_strip_model->count());
EXPECT_CALL(callback, Run(AutofillClient::AddressPromptUserDecision::kIgnored,
Property(&profile_ref::has_value, false)));
// Close controller tab.
int previous_tab_count = browser()->tab_strip_model()->count();
browser()->tab_strip_model()->CloseWebContentsAt(
tab_strip_model->GetIndexOfWebContents(controller_web_contents),
TabCloseTypes::CLOSE_USER_GESTURE);
EXPECT_EQ(previous_tab_count - 1, browser()->tab_strip_model()->count());
}
// This is testing that when the SaveAddressProfilePromptOptions has the
// show_prompt set to true, the bubble should be visible.
TEST_F(AddressBubblesControllerTest,
BubbleShouldBeVisibleWithShowPrompt) {
AutofillProfile profile = test::GetFullProfile();
AddressBubblesController::SetUpAndShowSaveOrUpdateAddressBubble(
web_contents(), profile, /*original_profile=*/nullptr,
AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
/*address_profile_save_prompt_callback=*/base::DoNothing());
// Bubble is visible and active
EXPECT_TRUE(controller()->GetBubbleView());
EXPECT_TRUE(controller()->IsBubbleActive());
}
// This is testing that when the SaveAddressProfilePromptOptions has the
// show_prompt set to false, the bubble should be invisible.
TEST_F(AddressBubblesControllerTest,
BubbleShouldBeInvisibleWithoutShowPrompt) {
AutofillProfile profile = test::GetFullProfile();
AddressBubblesController::SetUpAndShowSaveOrUpdateAddressBubble(
web_contents(), profile, /*original_profile=*/nullptr,
AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = false},
/*address_profile_save_prompt_callback=*/base::DoNothing());
// Bubble is invisible but active
EXPECT_FALSE(controller()->GetBubbleView());
EXPECT_TRUE(controller()->IsBubbleActive());
}
// This is testing that when a second prompt comes while another prompt is
// shown, the controller will ignore it, and inform the backend that the second
// prompt has been auto declined.
TEST_F(AddressBubblesControllerTest,
SecondPromptWillBeAutoDeclinedWhileFirstIsVisible) {
AutofillProfile profile = test::GetFullProfile();
AddressBubblesController::SetUpAndShowSaveOrUpdateAddressBubble(
web_contents(), profile, /*original_profile=*/nullptr,
AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
/*address_profile_save_prompt_callback=*/base::DoNothing());
// Second prompt should be auto declined.
base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback;
EXPECT_CALL(callback,
Run(AutofillClient::AddressPromptUserDecision::kAutoDeclined,
Property(&profile_ref::has_value, false)));
AddressBubblesController::SetUpAndShowSaveOrUpdateAddressBubble(
web_contents(), profile, /*original_profile=*/nullptr,
AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
callback.Get());
}
// This is testing that when a second prompt comes while another prompt is in
// progress but not shown, the controller will inform the backend that the first
// process is ignored.
TEST_F(AddressBubblesControllerTest,
FirstHiddenPromptWillBeIgnoredWhenSecondPromptArrives) {
AutofillProfile profile = test::GetFullProfile();
base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback;
AddressBubblesController::SetUpAndShowSaveOrUpdateAddressBubble(
web_contents(), profile, /*original_profile=*/nullptr,
AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
callback.Get());
controller()->OnBubbleClosed();
// When second prompt comes, the first one will be ignored.
EXPECT_CALL(callback, Run(AutofillClient::AddressPromptUserDecision::kIgnored,
Property(&profile_ref::has_value, false)));
AddressBubblesController::SetUpAndShowSaveOrUpdateAddressBubble(
web_contents(), profile, /*original_profile=*/nullptr,
AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
/*address_profile_save_prompt_callback=*/base::DoNothing());
}
} // namespace autofill