chromium/chrome/browser/commerce/price_insights/android/javatests/src/org/chromium/chrome/browser/price_insights/PriceInsightsBottomSheetCoordinatorTest.java

// 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.price_insights;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.annotation.IdRes;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.content.ContextCompat;
import androidx.test.filters.SmallTest;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import org.chromium.base.ThreadUtils;
import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.test.util.Batch;
import org.chromium.chrome.browser.commerce.ShoppingServiceFactory;
import org.chromium.chrome.browser.price_insights.PriceInsightsBottomSheetCoordinator.PriceInsightsDelegate;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.test.ChromeBrowserTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.commerce.core.ShoppingService;
import org.chromium.components.commerce.core.ShoppingService.PriceInsightsInfo;
import org.chromium.components.commerce.core.ShoppingService.PriceInsightsInfoCallback;
import org.chromium.components.commerce.core.ShoppingService.PricePoint;
import org.chromium.ui.test.util.BlankUiTestActivityTestCase;
import org.chromium.url.JUnitTestGURLs;

import java.util.Arrays;
import java.util.Optional;

/** Tests for {@link PriceInsightsBottomSheetCoordinator}. */
@RunWith(ChromeJUnit4ClassRunner.class)
@Batch(Batch.PER_CLASS)
public class PriceInsightsBottomSheetCoordinatorTest extends BlankUiTestActivityTestCase {
    @Rule public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();

    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();

    @Mock private BottomSheetController mMockBottomSheetController;
    @Mock private Tab mMockTab;
    @Mock private TabModelSelector mMockTabModelSelector;
    @Mock private ShoppingService mMockShoppingService;
    @Mock private Profile mMockProfile;
    @Mock private PriceInsightsDelegate mMockPriceInsightsDelegate;
    @Mock private ObservableSupplier<Boolean> mMockPriceTrackingStateSupplier;

    @Captor private ArgumentCaptor<PriceInsightsBottomSheetContent> mBottomSheetContentCaptor;

    private static final String PRODUCT_TITLE = "Testing Sneaker";
    private static final String PRICE_TRACKING_DESCRIPTION =
            "Get alerts when the price drops on any site across the web";
    private static final String PRICE_TRACKING_DISABLED_BUTTON_TEXT = "Track";
    private static final String PRICE_HISTORY_TITLE = "Price history across the web";
    private static final String OPEN_URL_TITLE = "Search buying options";
    private static final PriceInsightsInfo PRICE_INSIGHTS_INFO =
            new PriceInsightsInfo(
                    Optional.empty(),
                    "USD",
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Arrays.asList(new PricePoint("08-08-2024", 65000000L)),
                    Optional.of(JUnitTestGURLs.EXAMPLE_URL),
                    0,
                    false);

    private Activity mActivity;
    private View mMockPriceHistoryChart;
    private PriceInsightsBottomSheetCoordinator mPriceInsightsCoordinator;

    @Before
    public void setUp() {
        mActivity = getActivity();
        doReturn(mMockProfile).when(mMockTab).getProfile();
        doReturn(PRODUCT_TITLE).when(mMockTab).getTitle();
        setShoppingServiceGetPriceInsightsInfoForUrl();
        ShoppingServiceFactory.setShoppingServiceForTesting(mMockShoppingService);
        mMockPriceHistoryChart = new View(mActivity);
        doReturn(mMockPriceHistoryChart)
                .when(mMockPriceInsightsDelegate)
                .getPriceHistoryChartForPriceInsightsInfo(PRICE_INSIGHTS_INFO);
        doReturn(false).when(mMockPriceTrackingStateSupplier).get();
        doReturn(mMockPriceTrackingStateSupplier)
                .when(mMockPriceInsightsDelegate)
                .getPriceTrackingStateSupplier(mMockTab);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mPriceInsightsCoordinator =
                            new PriceInsightsBottomSheetCoordinator(
                                    mActivity,
                                    mMockBottomSheetController,
                                    mMockTab,
                                    mMockTabModelSelector,
                                    mMockShoppingService,
                                    mMockPriceInsightsDelegate);
                });
    }

    @After
    public void tearDown() {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mPriceInsightsCoordinator.closeContent();
                });
    }

    @Test
    @SmallTest
    public void testRequestShowContent() {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mPriceInsightsCoordinator.requestShowContent();
                });
        verify(mMockBottomSheetController, times(1))
                .requestShowContent(mBottomSheetContentCaptor.capture(), eq(true));
        ScrollView scrollView = (ScrollView) getView(R.id.scroll_view);
        TextView priceTrackingTitle = (TextView) getView(R.id.price_tracking_title);
        TextView priceTrackingDescription = (TextView) getView(R.id.price_tracking_description);
        TextView priceTrackingButton = (TextView) getView(R.id.price_tracking_button);
        Drawable priceTrackingButtonDrawable =
                priceTrackingButton.getCompoundDrawablesRelative()[0];
        TextView priceHistoryTitleView = (TextView) getView(R.id.price_history_title);
        TextView openUrlButton = (TextView) getView(R.id.open_jackpot_url_button);
        Drawable openUrlButtonDrawable = openUrlButton.getCompoundDrawablesRelative()[2];

        assertNotNull(scrollView);
        assertEquals(PRODUCT_TITLE, priceTrackingTitle.getText());
        assertEquals(PRICE_TRACKING_DESCRIPTION, priceTrackingDescription.getText());
        assertEquals(PRICE_TRACKING_DISABLED_BUTTON_TEXT, priceTrackingButton.getText());
        assertNotNull(priceTrackingButtonDrawable);
        assertEquals(
                ContextCompat.getColor(
                        mActivity,
                        R.color
                                .price_insights_sheet_price_tracking_ineligible_button_foreground_color),
                priceTrackingButton.getCurrentTextColor());
        assertEquals(
                AppCompatResources.getColorStateList(
                                mActivity,
                                R.color
                                        .price_insights_sheet_price_tracking_ineligible_button_foreground_color)
                        .getDefaultColor(),
                priceTrackingButton.getCompoundDrawableTintList().getDefaultColor());
        assertEquals(
                AppCompatResources.getColorStateList(
                                mActivity,
                                R.color
                                        .price_insights_sheet_price_tracking_ineligible_button_bg_color)
                        .getDefaultColor(),
                priceTrackingButton.getBackgroundTintList().getDefaultColor());
        assertEquals(PRICE_HISTORY_TITLE, priceHistoryTitleView.getText());
        assertEquals(View.VISIBLE, openUrlButton.getVisibility());
        assertEquals(OPEN_URL_TITLE, openUrlButton.getText());
        assertNotNull(openUrlButtonDrawable);
    }

    @Test
    @SmallTest
    public void testCloseContent() {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mPriceInsightsCoordinator.requestShowContent();
                });
        mPriceInsightsCoordinator.closeContent();
        verify(mMockBottomSheetController, times(1))
                .hideContent(mBottomSheetContentCaptor.capture(), eq(true));
    }

    private View getView(@IdRes int viewId) {
        View view = mBottomSheetContentCaptor.getValue().getContentView();
        assertNotNull(view);
        return view.findViewById(viewId);
    }

    private void setShoppingServiceGetPriceInsightsInfoForUrl() {
        doAnswer(
                        (InvocationOnMock invocation) -> {
                            ((PriceInsightsInfoCallback) invocation.getArgument(1))
                                    .onResult(JUnitTestGURLs.EXAMPLE_URL, PRICE_INSIGHTS_INFO);
                            return null;
                        })
                .when(mMockShoppingService)
                .getPriceInsightsInfoForUrl(any(), any());
    }
}