chromium/chrome/android/junit/src/org/chromium/chrome/browser/autofill/save_card/AutofillSaveCardBottomSheetCoordinatorTest.java

// Copyright 2023 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.save_card;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;

import androidx.annotation.DrawableRes;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.test.filters.SmallTest;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.shadows.ShadowActivity;

import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Features.DisableFeatures;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.layouts.LayoutStateProvider;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.components.autofill.payments.AutofillSaveCardUiInfo;
import org.chromium.components.autofill.payments.CardDetail;
import org.chromium.components.autofill.payments.LegalMessageLine;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;

import java.util.List;

/** Unit tests for {@link AutofillSaveCardBottomSheetCoordinator} */
@SmallTest
@RunWith(BaseRobolectricTestRunner.class)
public final class AutofillSaveCardBottomSheetCoordinatorTest {
    @DrawableRes private static final int TEST_DRAWABLE_RES = R.drawable.arrow_up;
    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
    private Activity mActivity;
    private ShadowActivity mShadowActivity;
    @Mock private TabModel mTabModel;
    @Mock private BottomSheetController mBottomSheetController;
    @Mock private LayoutStateProvider mLayoutStateProvider;
    @Mock private AutofillSaveCardBottomSheetBridge mDelegate;
    private AutofillSaveCardBottomSheetCoordinator mCoordinator;

    @Before
    public void setUp() {
        mActivity = Robolectric.buildActivity(Activity.class).create().get();
        mShadowActivity = shadowOf(mActivity);
        mCoordinator =
                new AutofillSaveCardBottomSheetCoordinator(
                        mActivity,
                        uiInfoForTest(),
                        /* skipLoadingForFixFlow= */ false,
                        mBottomSheetController,
                        mLayoutStateProvider,
                        mTabModel,
                        mDelegate);
    }

    @Test
    public void testInitialModelValues() {
        // uiInfoForTest() is used during setUp() and the its values should be set in the model.
        assertEquals(
                uiInfoForTest().getTitleText(),
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.TITLE));
        assertEquals(
                uiInfoForTest().getDescriptionText(),
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.DESCRIPTION));
        assertEquals(
                uiInfoForTest().getLogoIcon(),
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.LOGO_ICON));
        assertEquals(
                uiInfoForTest().getCardDescription(),
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.CARD_DESCRIPTION));
        assertEquals(
                uiInfoForTest().getCardDetail().issuerIconDrawableId,
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.CARD_ICON));
        assertEquals(
                uiInfoForTest().getCardDetail().label,
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.CARD_LABEL));
        assertEquals(
                uiInfoForTest().getCardDetail().subLabel,
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.CARD_SUB_LABEL));
        assertEquals(
                uiInfoForTest().getLegalMessageLines().size(),
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.LEGAL_MESSAGE)
                        .mLines
                        .size());
        for (int i = 0; i < uiInfoForTest().getLegalMessageLines().size(); i++) {
            assertEquals(
                    uiInfoForTest().getLegalMessageLines().get(i).text,
                    mCoordinator
                            .getPropertyModelForTesting()
                            .get(AutofillSaveCardBottomSheetProperties.LEGAL_MESSAGE)
                            .mLines
                            .get(i)
                            .text);
        }
        assertEquals(
                uiInfoForTest().getConfirmText(),
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.ACCEPT_BUTTON_LABEL));
        assertEquals(
                uiInfoForTest().getCancelText(),
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.CANCEL_BUTTON_LABEL));
        assertFalse(
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.SHOW_LOADING_STATE));
        assertEquals(
                uiInfoForTest().getLoadingDescription(),
                mCoordinator
                        .getPropertyModelForTesting()
                        .get(AutofillSaveCardBottomSheetProperties.LOADING_DESCRIPTION));
    }

    @Test
    public void testRequestShowContent() {
        mCoordinator.requestShowContent();

        verify(mBottomSheetController)
                .requestShowContent(
                        any(AutofillSaveCardBottomSheetContent.class), /* animate= */ eq(true));
    }

    @Test
    public void testHide() {
        mCoordinator.requestShowContent();
        mCoordinator.hide(BottomSheetController.StateChangeReason.NONE);

        verify(mBottomSheetController)
                .hideContent(
                        any(AutofillSaveCardBottomSheetContent.class),
                        eq(true),
                        eq(BottomSheetController.StateChangeReason.NONE));
    }

    @Test
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_SAVE_CARD_LOADING_AND_CONFIRMATION})
    public void testClickAccept_withLoadingConfirmation() {
        mCoordinator.requestShowContent();
        mCoordinator.getAutofillSaveCardBottomSheetViewForTesting().mAcceptButton.performClick();

        verify(mDelegate).onUiAccepted();
        verify(mBottomSheetController, times(0)).hideContent(any(), anyBoolean(), anyInt());
    }

    @Test
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_SAVE_CARD_LOADING_AND_CONFIRMATION})
    public void testClickAccept_forLocalCard_withLoadingConfirmation() {
        // Create a coordinator for local card. `withIsForUpload` is false for local cards.
        AutofillSaveCardBottomSheetCoordinator coordinator =
                new AutofillSaveCardBottomSheetCoordinator(
                        mActivity,
                        new AutofillSaveCardUiInfo.Builder()
                                .withIsForUpload(false)
                                .withCardDetail(
                                        new CardDetail(
                                                TEST_DRAWABLE_RES, "Card label", "Card sub label"))
                                .build(),
                        /* skipLoadingForFixFlow= */ false,
                        mBottomSheetController,
                        mLayoutStateProvider,
                        mTabModel,
                        mDelegate);

        coordinator.requestShowContent();
        coordinator.getAutofillSaveCardBottomSheetViewForTesting().mAcceptButton.performClick();

        verify(mDelegate).onUiAccepted();
        verify(mBottomSheetController)
                .hideContent(
                        any(AutofillSaveCardBottomSheetContent.class),
                        /* animate= */ eq(true),
                        eq(BottomSheetController.StateChangeReason.INTERACTION_COMPLETE));
    }

    @Test
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_SAVE_CARD_LOADING_AND_CONFIRMATION})
    public void testClickAccept_whenLoadingDisabled_withLoadingConfirmation() {
        // Create a coordinator with `skipLoadingForFixFlow` set as true.
        AutofillSaveCardBottomSheetCoordinator coordinator =
                new AutofillSaveCardBottomSheetCoordinator(
                        mActivity,
                        uiInfoForTest(),
                        /* skipLoadingForFixFlow= */ true,
                        mBottomSheetController,
                        mLayoutStateProvider,
                        mTabModel,
                        mDelegate);

        coordinator.requestShowContent();
        coordinator.getAutofillSaveCardBottomSheetViewForTesting().mAcceptButton.performClick();

        verify(mDelegate).onUiAccepted();
        verify(mBottomSheetController)
                .hideContent(
                        any(AutofillSaveCardBottomSheetContent.class),
                        /* animate= */ eq(true),
                        eq(BottomSheetController.StateChangeReason.INTERACTION_COMPLETE));
    }

    @Test
    @DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_SAVE_CARD_LOADING_AND_CONFIRMATION})
    public void testClickAccept_withoutLoadingConfirmation() {
        mCoordinator.requestShowContent();
        mCoordinator.getAutofillSaveCardBottomSheetViewForTesting().mAcceptButton.performClick();

        verify(mDelegate).onUiAccepted();
        verify(mBottomSheetController)
                .hideContent(
                        any(AutofillSaveCardBottomSheetContent.class),
                        /* animate= */ eq(true),
                        eq(BottomSheetController.StateChangeReason.INTERACTION_COMPLETE));
    }

    @Test
    public void testClickCancel() {
        mCoordinator.requestShowContent();
        mCoordinator.getAutofillSaveCardBottomSheetViewForTesting().mCancelButton.performClick();

        verify(mDelegate).onUiCanceled();
        verify(mBottomSheetController)
                .hideContent(
                        any(AutofillSaveCardBottomSheetContent.class),
                        /* animate= */ eq(true),
                        eq(BottomSheetController.StateChangeReason.INTERACTION_COMPLETE));
    }

    @Test
    public void testOpenLegalMessageLink() {
        final String urlString = "https://example.test";

        mCoordinator.requestShowContent();
        mCoordinator.openLegalMessageLink(urlString);

        Intent intent = mShadowActivity.getNextStartedActivity();
        assertEquals(Uri.parse(urlString), intent.getData());
        assertEquals(Intent.ACTION_VIEW, intent.getAction());
        assertEquals(
                CustomTabsIntent.SHOW_PAGE_TITLE,
                intent.getExtras().get(CustomTabsIntent.EXTRA_TITLE_VISIBILITY_STATE));
    }

    private AutofillSaveCardUiInfo uiInfoForTest() {
        return new AutofillSaveCardUiInfo.Builder()
                .withTitleText("Title text")
                .withDescriptionText("Description text.")
                .withIsForUpload(true)
                .withLogoIcon(TEST_DRAWABLE_RES)
                .withCardDetail(new CardDetail(TEST_DRAWABLE_RES, "Card label", "Card sub label"))
                .withLegalMessageLines(List.of(new LegalMessageLine("Legal message line")))
                .withConfirmText("Confirm text")
                .withCancelText("Cancel text")
                .withLoadingDescription("Loading description")
                .build();
    }
}