chromium/components/payments/content/android/javatests/src/org/chromium/components/payments/AndroidPaymentAppUnitTest.java

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

package org.chromium.components.payments;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
import org.chromium.payments.mojom.PaymentCurrencyAmount;
import org.chromium.payments.mojom.PaymentDetailsModifier;
import org.chromium.payments.mojom.PaymentItem;
import org.chromium.payments.mojom.PaymentMethodData;
import org.chromium.payments.mojom.PaymentOptions;
import org.chromium.payments.mojom.PaymentShippingOption;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/** Tests for the native Android payment app finder. */
@RunWith(BaseJUnit4ClassRunner.class)
@Batch(Batch.UNIT_TESTS)
public class AndroidPaymentAppUnitTest {
    @Mock private AndroidPaymentApp.Launcher mLauncherMock;

    private String mErrorMessage;
    private String mPaymentMethodName;
    private String mPaymentDetails;
    private boolean mReadyToPayResponse;
    private boolean mReadyToPayQueryFinished;
    private boolean mInvokePaymentAppFinished;

    @Before
    public void setUp() {
        NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess();
    }

    @SmallTest
    @Test
    @UiThreadTest
    public void testSuccessfulPaymentWithoutIsReadyToPayService() throws Exception {
        runTest(Activity.RESULT_OK);
        Assert.assertNull(mErrorMessage);
        Assert.assertEquals("https://company.com/pay", mPaymentMethodName);
        Assert.assertEquals("{}", mPaymentDetails);
    }

    @SmallTest
    @Test
    @UiThreadTest
    public void testCancelledPaymentWithoutIsReadyToPayService() throws Exception {
        runTest(Activity.RESULT_CANCELED);
        Assert.assertEquals(
                "Payment app returned RESULT_CANCELED code. This is how payment apps "
                        + "can close their activity programmatically.",
                mErrorMessage);
        Assert.assertNull(mPaymentMethodName);
        Assert.assertNull(mPaymentDetails);
    }

    private void runTest(int resultCode) throws Exception {
        MockitoAnnotations.initMocks(this);

        // Reset test results.
        mErrorMessage = null;
        mPaymentMethodName = null;
        mPaymentDetails = null;
        mReadyToPayResponse = false;
        mReadyToPayQueryFinished = false;
        mInvokePaymentAppFinished = false;

        AndroidPaymentApp app =
                new AndroidPaymentApp(
                        mLauncherMock,
                        "com.company.app",
                        "com.company.app.PaymentActivity",
                        /* isReadyToPayService= */ null,
                        "App Label",
                        /* icon= */ null,
                        /* isIncognito= */ false,
                        /* appToHide= */ null,
                        new SupportedDelegations());
        app.addMethodName("https://company.com/pay");

        Map<String, PaymentMethodData> methods = new HashMap<>();
        methods.put("https://company.com/pay", new PaymentMethodData());

        Map<String, PaymentDetailsModifier> modifiers = new HashMap<>();

        app.maybeQueryIsReadyToPayService(
                methods,
                "https://merchant.com",
                "https://psp.com",
                /* certificateChain= */ null,
                modifiers,
                new AndroidPaymentApp.IsReadyToPayCallback() {
                    @Override
                    public void onIsReadyToPayResponse(
                            AndroidPaymentApp app, boolean isReadyToPay) {
                        mReadyToPayQueryFinished = true;
                        mReadyToPayResponse = isReadyToPay;
                    }
                });
        CriteriaHelper.pollUiThreadNested(() -> mReadyToPayQueryFinished);
        Assert.assertTrue("Payment app should be ready to pay", mReadyToPayResponse);

        PaymentItem total = new PaymentItem();
        total.amount = new PaymentCurrencyAmount();
        total.amount.currency = "USD";
        total.amount.value = "1.00";
        total.label = "Total";
        app.invokePaymentApp(
                "request-id",
                "Merchant Name",
                "https://merchant.com",
                "https://psp.com",
                /* certificateChain= */ null,
                methods,
                total,
                /* displayItems= */ new ArrayList<PaymentItem>(),
                modifiers,
                new PaymentOptions(),
                new ArrayList<PaymentShippingOption>(),
                new PaymentApp.InstrumentDetailsCallback() {
                    @Override
                    public void onInstrumentDetailsReady(
                            String methodName, String stringifiedDetails, PayerData payerData) {
                        mPaymentMethodName = methodName;
                        mPaymentDetails = stringifiedDetails;
                        mInvokePaymentAppFinished = true;
                    }

                    @Override
                    public void onInstrumentDetailsError(String errorMessage) {
                        mErrorMessage = errorMessage;
                        mInvokePaymentAppFinished = true;
                    }
                });
        AndroidPaymentApp.IntentResult intentResult = new AndroidPaymentApp.IntentResult();
        intentResult.resultCode = resultCode;
        intentResult.data = new Intent();
        Bundle extras = new Bundle();
        extras.putString("methodName", "https://company.com/pay");
        extras.putString("details", "{}");
        intentResult.data.putExtras(extras);
        app.onIntentCompletedForTesting(intentResult);

        CriteriaHelper.pollUiThreadNested(() -> mInvokePaymentAppFinished);
    }
}