/** * External dependencies */ import { act, render, screen, waitFor } from '@testing-library/react'; import { previewCart } from '@woocommerce/resource-previews'; import * as wpDataFunctions from '@wordpress/data'; import { CART_STORE_KEY, PAYMENT_STORE_KEY } from '@woocommerce/block-data'; import { default as fetchMock } from 'jest-fetch-mock'; import { registerPaymentMethod, __experimentalDeRegisterPaymentMethod, } from '@woocommerce/blocks-registry'; import userEvent from '@testing-library/user-event'; import { dispatch } from '@wordpress/data'; /** * Internal dependencies */ import PaymentMethods from '../payment-methods'; jest.mock( '../saved-payment-method-options', () => ( { onChange } ) => { return ( <> Saved payment method options ); } ); jest.mock( '@woocommerce/base-components/radio-control-accordion', () => ( { onChange } ) => ( <> Payment method options ) ); const originalSelect = jest.requireActual( '@wordpress/data' ).select; const selectMock = jest .spyOn( wpDataFunctions, 'select' ) .mockImplementation( ( storeName ) => { const originalStore = originalSelect( storeName ); if ( storeName === PAYMENT_STORE_KEY ) { return { ...originalStore, getState: () => { const originalState = originalStore.getState(); return { ...originalState, savedPaymentMethods: {}, availablePaymentMethods: {}, paymentMethodsInitialized: true, }; }, }; } return originalStore; } ); const registerMockPaymentMethods = () => { [ 'cod', 'credit-card' ].forEach( ( name ) => { registerPaymentMethod( { name, label: name, content:
A payment method
, edit:
A payment method
, icons: null, canMakePayment: () => true, supports: { showSavedCards: true, showSaveOption: true, features: [ 'products' ], }, ariaLabel: name, } ); } ); dispatch( PAYMENT_STORE_KEY ).__internalUpdateAvailablePaymentMethods(); }; const resetMockPaymentMethods = () => { [ 'cod', 'credit-card' ].forEach( ( name ) => { __experimentalDeRegisterPaymentMethod( name ); } ); }; describe( 'PaymentMethods', () => { beforeEach( () => { fetchMock.mockResponse( ( req ) => { if ( req.url.match( /wc\/store\/v1\/cart/ ) ) { return Promise.resolve( JSON.stringify( previewCart ) ); } return Promise.resolve( '' ); } ); // need to clear the store resolution state between tests. wpDataFunctions .dispatch( CART_STORE_KEY ) .invalidateResolutionForStore(); wpDataFunctions.dispatch( CART_STORE_KEY ).receiveCart( { ...previewCart, payment_methods: [ 'cod', 'credit-card' ], } ); } ); afterEach( () => { fetchMock.resetMocks(); } ); test( 'should show no payment methods component when there are no payment methods', async () => { render( ); await waitFor( () => { const noPaymentMethods = screen.queryAllByText( /no payment methods available/ ); // We might get more than one match because the `speak()` function // creates an extra `div` with the notice contents used for a11y. expect( noPaymentMethods.length ).toBeGreaterThanOrEqual( 1 ); // Reset the mock back to how it was because we don't need it anymore after this test. selectMock.mockRestore(); } ); } ); test( 'selecting new payment method', async () => { const ShowActivePaymentMethod = () => { const { activePaymentMethod, activeSavedToken } = wpDataFunctions.useSelect( ( select ) => { const store = select( PAYMENT_STORE_KEY ); return { activePaymentMethod: store.getActivePaymentMethod(), activeSavedToken: store.getActiveSavedToken(), }; } ); return ( <>
{ 'Active Payment Method: ' + activePaymentMethod }
{ 'Active Saved Token: ' + activeSavedToken }
); }; act( () => { registerMockPaymentMethods(); } ); // Wait for the payment methods to finish loading before rendering. await waitFor( () => { expect( wpDataFunctions .select( PAYMENT_STORE_KEY ) .getActivePaymentMethod() ).toBe( 'cod' ); } ); render( <> ); await waitFor( () => { const savedPaymentMethodOptions = screen.queryByText( /Saved payment method options/ ); expect( savedPaymentMethodOptions ).not.toBeNull(); } ); await waitFor( () => { const paymentMethodOptions = screen.queryByText( /Payment method options/ ); expect( paymentMethodOptions ).not.toBeNull(); } ); await waitFor( () => { const savedToken = screen.queryByText( /Active Payment Method: credit-card/ ); expect( savedToken ).toBeNull(); } ); userEvent.click( screen.getByText( 'Select new payment' ) ); await waitFor( () => { const activePaymentMethod = screen.queryByText( /Active Payment Method: credit-card/ ); expect( activePaymentMethod ).not.toBeNull(); } ); act( () => resetMockPaymentMethods() ); } ); } );