// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.autofill.settings;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.test.filters.MediumTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.chromium.base.ThreadUtils;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.chrome.browser.autofill.AutofillEditorBase;
import org.chromium.chrome.browser.autofill.AutofillTestHelper;
import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.autofill.PersonalDataManager.Iban;
import org.chromium.chrome.browser.autofill.PersonalDataManagerFactory;
import org.chromium.chrome.browser.settings.SettingsActivity;
import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.R;
import org.chromium.components.autofill.IbanRecordType;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.test.util.modaldialog.FakeModalDialogManager;
// TODO(b/309163597): Add Robolectric tests to test the local editor behavior.
@RunWith(ChromeJUnit4ClassRunner.class)
public class AutofillLocalIbanEditorTest {
@Rule public final AutofillTestRule rule = new AutofillTestRule();
@Rule
public final SettingsActivityTestRule<AutofillLocalIbanEditor> mSettingsActivityTestRule =
new SettingsActivityTestRule<>(AutofillLocalIbanEditor.class);
@Mock private ObservableSupplierImpl<ModalDialogManager> mModalDialogManagerSupplierMock;
@Mock private PersonalDataManager mPersonalDataManagerMock;
private AutofillTestHelper mAutofillTestHelper;
private Bundle fragmentArgs(String guid) {
Bundle args = new Bundle();
args.putString(AutofillEditorBase.AUTOFILL_GUID, guid);
return args;
}
private static final Iban VALID_BELGIUM_IBAN =
new Iban.Builder()
.setLabel("")
.setNickname("My IBAN")
.setRecordType(IbanRecordType.UNKNOWN)
.setValue("BE71096123456769")
.build();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mAutofillTestHelper = new AutofillTestHelper();
}
private AutofillLocalIbanEditor setUpDefaultAutofillLocalIbanEditorFragment() {
SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
AutofillLocalIbanEditor autofillLocalIbanEditorFragment =
(AutofillLocalIbanEditor) activity.getMainFragment();
assertThat(autofillLocalIbanEditorFragment.mDoneButton.isEnabled()).isFalse();
return autofillLocalIbanEditorFragment;
}
private void setNicknameInEditor(
AutofillLocalIbanEditor autofillLocalIbanEditorFragment, String nickname) {
ThreadUtils.runOnUiThreadBlocking(
() -> {
try {
autofillLocalIbanEditorFragment.mNickname.setText(nickname);
} catch (Exception e) {
Assert.fail("Failed to set Nickname");
}
});
}
private void setValueInEditor(
AutofillLocalIbanEditor autofillLocalIbanEditorFragment, String value) {
ThreadUtils.runOnUiThreadBlocking(
() -> {
try {
autofillLocalIbanEditorFragment.mValue.setText(value);
} catch (Exception e) {
Assert.fail("Failed to set IBAN");
}
});
}
private void openDeletePaymentMethodConfirmationDialog(
AutofillLocalIbanEditor autofillLocalIbanEditorFragment,
ModalDialogManager modalDialogManager) {
when(mModalDialogManagerSupplierMock.get()).thenReturn(modalDialogManager);
autofillLocalIbanEditorFragment.setModalDialogManagerSupplier(
mModalDialogManagerSupplierMock);
MenuItem deleteButton = mock(MenuItem.class);
when(deleteButton.getItemId()).thenReturn(R.id.delete_menu_id);
ThreadUtils.runOnUiThreadBlocking(
() -> {
autofillLocalIbanEditorFragment.onOptionsItemSelected(deleteButton);
});
}
@Test
@MediumTest
public void testValidIbanValueEnablesSaveButton() throws Exception {
AutofillLocalIbanEditor autofillLocalIbanEditorFragment =
setUpDefaultAutofillLocalIbanEditorFragment();
// Valid Russia IBAN value.
setValueInEditor(
autofillLocalIbanEditorFragment, /* value= */ "RU0204452560040702810412345678901");
assertThat(autofillLocalIbanEditorFragment.mDoneButton.isEnabled()).isTrue();
}
@Test
@MediumTest
public void testInvalidIbanValueDoesNotEnableSaveButton() throws Exception {
AutofillLocalIbanEditor autofillLocalIbanEditorFragment =
setUpDefaultAutofillLocalIbanEditorFragment();
// Invalid Russia IBAN value.
setValueInEditor(
autofillLocalIbanEditorFragment, /* value= */ "RU0204452560040702810412345678902");
assertThat(autofillLocalIbanEditorFragment.mDoneButton.isEnabled()).isFalse();
}
@Test
@MediumTest
public void testEditIban_whenIbanIsNotEdited_keepsSaveButtonDisabled() throws Exception {
String guid = mAutofillTestHelper.addOrUpdateLocalIban(VALID_BELGIUM_IBAN);
SettingsActivity activity =
mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
AutofillLocalIbanEditor autofillLocalIbanEditorFragment =
(AutofillLocalIbanEditor) activity.getMainFragment();
assertThat(autofillLocalIbanEditorFragment.mNickname.getText().toString())
.isEqualTo("My IBAN");
assertThat(autofillLocalIbanEditorFragment.mValue.getText().toString())
.isEqualTo("BE71096123456769");
// If neither the value nor the nickname is modified, the Done button should remain
// disabled.
assertThat(autofillLocalIbanEditorFragment.mDoneButton.isEnabled()).isFalse();
}
@Test
@MediumTest
public void testEditIban_whenIbanValueIsEditedFromValidToInvalid_disablesSaveButton()
throws Exception {
String guid = mAutofillTestHelper.addOrUpdateLocalIban(VALID_BELGIUM_IBAN);
SettingsActivity activity =
mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
AutofillLocalIbanEditor autofillLocalIbanEditorFragment =
(AutofillLocalIbanEditor) activity.getMainFragment();
// Change IBAN value from valid to invalid.
setValueInEditor(autofillLocalIbanEditorFragment, /* value= */ "BE710961234567600");
assertThat(autofillLocalIbanEditorFragment.mDoneButton.isEnabled()).isFalse();
}
@Test
@MediumTest
public void testEditIban_whenIbanValueIsEditedToAnotherValidValue_enablesSaveButton()
throws Exception {
String guid = mAutofillTestHelper.addOrUpdateLocalIban(VALID_BELGIUM_IBAN);
SettingsActivity activity =
mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
AutofillLocalIbanEditor autofillLocalIbanEditorFragment =
(AutofillLocalIbanEditor) activity.getMainFragment();
setValueInEditor(
autofillLocalIbanEditorFragment, /* value= */ "GB82 WEST 1234 5698 7654 32");
assertThat(autofillLocalIbanEditorFragment.mDoneButton.isEnabled()).isTrue();
}
@Test
@MediumTest
public void testEditIban_whenIbanNicknameIsEdited_enablesSaveButton() throws Exception {
String guid = mAutofillTestHelper.addOrUpdateLocalIban(VALID_BELGIUM_IBAN);
SettingsActivity activity =
mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
AutofillLocalIbanEditor autofillLocalIbanEditorFragment =
(AutofillLocalIbanEditor) activity.getMainFragment();
setNicknameInEditor(autofillLocalIbanEditorFragment, /* nickname= */ "My doctor's IBAN");
assertThat(autofillLocalIbanEditorFragment.mDoneButton.isEnabled()).isTrue();
}
@Test
@MediumTest
public void deleteIbanConfirmationDialog_deleteEntryCanceled_dialogDismissed()
throws Exception {
String guid = mAutofillTestHelper.addOrUpdateLocalIban(VALID_BELGIUM_IBAN);
SettingsActivity activity =
mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
AutofillLocalIbanEditor autofillLocalIbanEditorFragment =
(AutofillLocalIbanEditor) activity.getMainFragment();
PersonalDataManagerFactory.setInstanceForTesting(mPersonalDataManagerMock);
FakeModalDialogManager fakeModalDialogManager =
new FakeModalDialogManager(ModalDialogManager.ModalDialogType.APP);
openDeletePaymentMethodConfirmationDialog(
autofillLocalIbanEditorFragment, fakeModalDialogManager);
// Verify the dialog is open.
Assert.assertNotNull(fakeModalDialogManager.getShownDialogModel());
ThreadUtils.runOnUiThreadBlocking(() -> fakeModalDialogManager.clickNegativeButton());
// Verify the dialog is closed.
Assert.assertNull(fakeModalDialogManager.getShownDialogModel());
// Verify the IBAN entry is not deleted.
verify(mPersonalDataManagerMock, never()).deleteIban(guid);
}
@Test
@MediumTest
public void deleteIbanConfirmationDialog_deleteEntryConfirmed_dialogDismissedAndEntryDeleted()
throws Exception {
String guid = mAutofillTestHelper.addOrUpdateLocalIban(VALID_BELGIUM_IBAN);
SettingsActivity activity =
mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
AutofillLocalIbanEditor autofillLocalIbanEditorFragment =
(AutofillLocalIbanEditor) activity.getMainFragment();
PersonalDataManagerFactory.setInstanceForTesting(mPersonalDataManagerMock);
FakeModalDialogManager fakeModalDialogManager =
new FakeModalDialogManager(ModalDialogManager.ModalDialogType.APP);
openDeletePaymentMethodConfirmationDialog(
autofillLocalIbanEditorFragment, fakeModalDialogManager);
// Verify the dialog is open.
Assert.assertNotNull(fakeModalDialogManager.getShownDialogModel());
ThreadUtils.runOnUiThreadBlocking(() -> fakeModalDialogManager.clickPositiveButton());
// Verify the dialog is closed.
Assert.assertNull(fakeModalDialogManager.getShownDialogModel());
// Verify the IBAN entry is deleted.
verify(mPersonalDataManagerMock, times(1)).deleteIban(guid);
}
}