diff --git a/locales/en/index.yml b/locales/en/index.yml index f6f9424d41c..39b9ed94064 100644 --- a/locales/en/index.yml +++ b/locales/en/index.yml @@ -1894,7 +1894,7 @@ wallet: defaultName: Gestore pspTitle: Gestore pspSortButton: Ordina - featuredReason: Perché sei già cliente + featuredReason: Sei già cliente continueButton: Continua sortBottomSheet: default: Default diff --git a/locales/it/index.yml b/locales/it/index.yml index 1525b138425..d4e93d9deca 100644 --- a/locales/it/index.yml +++ b/locales/it/index.yml @@ -1894,7 +1894,7 @@ wallet: defaultName: Gestore pspTitle: Gestore pspSortButton: Ordina - featuredReason: Perché sei già cliente + featuredReason: Sei già cliente continueButton: Continua sortBottomSheet: default: Default diff --git a/ts/features/payments/checkout/screens/WalletPaymentPickPspScreen.tsx b/ts/features/payments/checkout/screens/WalletPaymentPickPspScreen.tsx index e57dd8b0ba2..f2bf971658f 100644 --- a/ts/features/payments/checkout/screens/WalletPaymentPickPspScreen.tsx +++ b/ts/features/payments/checkout/screens/WalletPaymentPickPspScreen.tsx @@ -154,6 +154,7 @@ const WalletPaymentPickPspScreen = () => { () => ({ type: "buttonLink", componentProps: { + testID: "wallet-payment-pick-psp-sort-button", label: I18n.t("wallet.payment.psp.pspSortButton"), accessibilityLabel: I18n.t("wallet.payment.psp.pspSortButton"), onPress: present diff --git a/ts/features/payments/checkout/screens/__tests__/WalletPaymentPickPspScreen.test.tsx b/ts/features/payments/checkout/screens/__tests__/WalletPaymentPickPspScreen.test.tsx new file mode 100644 index 00000000000..c2f3010be45 --- /dev/null +++ b/ts/features/payments/checkout/screens/__tests__/WalletPaymentPickPspScreen.test.tsx @@ -0,0 +1,154 @@ +import { View } from "react-native"; +import React from "react"; +import { fireEvent } from "@testing-library/react-native"; +import { createStore } from "redux"; +import configureMockStore from "redux-mock-store"; +import { appReducer } from "../../../../../store/reducers"; +import { applicationChangeState } from "../../../../../store/actions/application"; +import { GlobalState } from "../../../../../store/reducers/types"; +import { RptId } from "../../../../../../definitions/pagopa/ecommerce/RptId"; +import { renderScreenWithNavigationStoreContext } from "../../../../../utils/testWrapper"; +import { PaymentsCheckoutRoutes } from "../../navigation/routes"; +import { paymentsCalculatePaymentFeesAction } from "../../store/actions/networking"; +import { useIOBottomSheetAutoresizableModal } from "../../../../../utils/hooks/bottomSheet"; +import { WalletPaymentPickPspScreen } from "../WalletPaymentPickPspScreen"; +import { Bundle } from "../../../../../../definitions/pagopa/ecommerce/Bundle"; +import { PaymentMethodStatusEnum } from "../../../../../../definitions/pagopa/ecommerce/PaymentMethodStatus"; +import I18n from "../../../../../i18n"; + +jest.mock("../../analytics"); +jest.mock("../../../../../utils/hooks/bottomSheet"); + +const mockNavigation = { + navigate: jest.fn(), + setOptions: jest.fn() +}; + +jest.mock("@react-navigation/native", () => ({ + ...jest.requireActual("@react-navigation/native"), + useNavigation: () => mockNavigation, + useRoute: () => ({ + params: { rptId: "1234567890" as RptId } + }) +})); + +const CHEAPER_VALUE = 123; +const MIDDLE_VALUE = 456; +const EXPENSIVE_VALUE = 789; +const MOCKED_PSP_LIST: ReadonlyArray = [ + { + idPsp: "1", + abi: "01010", + pspBusinessName: "BANCO di NAPOLI", + taxPayerFee: CHEAPER_VALUE, + primaryCiIncurredFee: CHEAPER_VALUE, + idBundle: "A" + }, + { + idPsp: "2", + abi: "01015", + pspBusinessName: "Banco di Sardegna", + taxPayerFee: MIDDLE_VALUE, + primaryCiIncurredFee: MIDDLE_VALUE, + idBundle: "B", + onUs: true + }, + { + idPsp: "3", + abi: "03015", + pspBusinessName: "FINECO", + taxPayerFee: EXPENSIVE_VALUE, + primaryCiIncurredFee: EXPENSIVE_VALUE, + idBundle: "C" + } +]; + +const globalState = appReducer(undefined, applicationChangeState("active")); +const mockStore = configureMockStore(); +const mockModal = { + present: jest.fn(), + dismiss: jest.fn(), + bottomSheet: +}; +const mockedUseIOBottomSheetAutoresizableModal = + useIOBottomSheetAutoresizableModal as jest.Mock; +mockedUseIOBottomSheetAutoresizableModal.mockReturnValue(mockModal); + +describe("WalletPaymentPickPspScreen", () => { + const renderComponent = () => { + const state = mockStore(globalState); + const store = createStore(appReducer, state as any); + return { + ...renderScreenWithNavigationStoreContext( + WalletPaymentPickPspScreen, + PaymentsCheckoutRoutes.PAYMENT_CHECKOUT_MAKE, + {}, + store + ), + store + }; + }; + + it("renders the main content with the list content if psp list is available", () => { + const { getAllByText, store } = renderComponent(); + + store.dispatch( + paymentsCalculatePaymentFeesAction.success({ + bundles: MOCKED_PSP_LIST, + asset: "MOCK", + paymentMethodDescription: "MOCK", + paymentMethodName: "MOCK", + paymentMethodStatus: PaymentMethodStatusEnum.ENABLED + }) + ); + + expect(getAllByText("BANCO di NAPOLI")).toBeTruthy(); + }); + + it("shows the featured reason if there is a psp with the onUs flag", () => { + const { getByText, store } = renderComponent(); + store.dispatch( + paymentsCalculatePaymentFeesAction.success({ + bundles: MOCKED_PSP_LIST, + asset: "MOCK", + paymentMethodDescription: "MOCK", + paymentMethodName: "MOCK", + paymentMethodStatus: PaymentMethodStatusEnum.ENABLED + }) + ); + expect(getByText(I18n.t("wallet.payment.psp.featuredReason"))).toBeTruthy(); + }); + + it("doesn't show the featured reason if there is not a psp with the onUs flag", () => { + const { queryByText, store } = renderComponent(); + store.dispatch( + paymentsCalculatePaymentFeesAction.success({ + bundles: MOCKED_PSP_LIST.map(psp => { + const { onUs, ...rest } = psp; + return rest; + }), + asset: "MOCK", + paymentMethodDescription: "MOCK", + paymentMethodName: "MOCK", + paymentMethodStatus: PaymentMethodStatusEnum.ENABLED + }) + ); + expect(queryByText(I18n.t("wallet.payment.psp.featuredReason"))).toBeNull(); + }); + + it("presents bottom sheet press the sort button", () => { + const { getByTestId, store } = renderComponent(); + store.dispatch( + paymentsCalculatePaymentFeesAction.success({ + bundles: MOCKED_PSP_LIST, + asset: "MOCK", + paymentMethodDescription: "MOCK", + paymentMethodName: "MOCK", + paymentMethodStatus: PaymentMethodStatusEnum.ENABLED + }) + ); + const sortButton = getByTestId("wallet-payment-pick-psp-sort-button"); + fireEvent.press(sortButton); + expect(mockModal.present).toHaveBeenCalled(); + }); +}); diff --git a/ts/features/payments/checkout/store/reducers/index.ts b/ts/features/payments/checkout/store/reducers/index.ts index 61f742e1daf..fc170b5303a 100644 --- a/ts/features/payments/checkout/store/reducers/index.ts +++ b/ts/features/payments/checkout/store/reducers/index.ts @@ -192,9 +192,9 @@ const reducer = ( // Bundles are stored sorted by default sort rule const sortedBundles = getSortedPspList(bundles, "default"); - // Automatically select PSP if only 1 received or with `onUs` property + // Automatically select PSP if only 1 received const preselectedPsp = - sortedBundles.length === 1 || sortedBundles[0]?.onUs + sortedBundles.length === 1 ? O.some(sortedBundles[0]) : state.selectedPsp; diff --git a/ts/features/payments/common/utils/__tests__/index.test.ts b/ts/features/payments/common/utils/__tests__/index.test.ts index 9dbc10b3273..f82822a9668 100644 --- a/ts/features/payments/common/utils/__tests__/index.test.ts +++ b/ts/features/payments/common/utils/__tests__/index.test.ts @@ -1,5 +1,6 @@ import { format } from "date-fns"; -import { isPaymentMethodExpired } from ".."; +import { getSortedPspList, isPaymentMethodExpired } from ".."; +import { Bundle } from "../../../../../../definitions/pagopa/ecommerce/Bundle"; describe("isPaymentMethodExpired", () => { it("should return true if payment method is expired", () => { @@ -23,3 +24,64 @@ describe("isPaymentMethodExpired", () => { expect(result).toBeFalsy(); }); }); + +describe("getSortedPspList", () => { + const CHEAPER_VALUE = 123; + const MIDDLE_VALUE = 456; + const EXPENSIVE_VALUE = 789; + const MOCKED_PSP_LIST: ReadonlyArray = [ + { + idPsp: "1", + abi: "01010", + pspBusinessName: "BANCO di NAPOLI", + taxPayerFee: CHEAPER_VALUE, + primaryCiIncurredFee: CHEAPER_VALUE, + idBundle: "A" + }, + { + idPsp: "2", + abi: "01015", + pspBusinessName: "Banco di Sardegna", + taxPayerFee: MIDDLE_VALUE, + primaryCiIncurredFee: MIDDLE_VALUE, + idBundle: "B", + onUs: true + }, + { + idPsp: "3", + abi: "03015", + pspBusinessName: "FINECO", + taxPayerFee: EXPENSIVE_VALUE, + primaryCiIncurredFee: EXPENSIVE_VALUE, + idBundle: "C" + } + ]; + + it("should return as first element the element with onUs flag if default sorting", () => { + const result = getSortedPspList(MOCKED_PSP_LIST, "default"); + expect(result[0].onUs).toBe(true); + }); + + it("should return the list by amount from the cheaper to the more expensive if amount sorting", () => { + const result = getSortedPspList(MOCKED_PSP_LIST, "amount"); + expect(result[0].taxPayerFee).toBe(CHEAPER_VALUE); + expect(result[1].taxPayerFee).toBe(MIDDLE_VALUE); + expect(result[2].taxPayerFee).toBe(EXPENSIVE_VALUE); + }); + + it("should return the list sorted by name if name sorting", () => { + const result = getSortedPspList(MOCKED_PSP_LIST, "name"); + expect(result[0].pspBusinessName).toBe("BANCO di NAPOLI"); + expect(result[1].pspBusinessName).toBe("Banco di Sardegna"); + expect(result[2].pspBusinessName).toBe("FINECO"); + }); + + it("should return the exact same list if default sorting and not present the onUs flag", () => { + const MOCKED_PSP_LIST_WITHOUT_ONUS = MOCKED_PSP_LIST.map(psp => { + const { onUs, ...rest } = psp; + return rest; + }); + const result = getSortedPspList(MOCKED_PSP_LIST_WITHOUT_ONUS, "default"); + expect(result).toEqual(MOCKED_PSP_LIST_WITHOUT_ONUS); + }); +}); diff --git a/ts/features/payments/common/utils/index.ts b/ts/features/payments/common/utils/index.ts index a2b1a36fe6c..dfcb76cf360 100644 --- a/ts/features/payments/common/utils/index.ts +++ b/ts/features/payments/common/utils/index.ts @@ -153,7 +153,7 @@ export const getSortedPspList = ( return _.orderBy( pspList, ["onUs", "taxPayerFee", "pspBusinessName"], - ["desc", "asc", "asc"] + ["asc", "asc", "asc"] ); } };