/**
* External dependencies
*/
import {
act,
render,
screen,
queryByText,
waitFor,
waitForElementToBeRemoved,
} from '@testing-library/react';
import { previewCart } from '@woocommerce/resource-previews';
import { dispatch } from '@wordpress/data';
import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data';
import { SlotFillProvider } from '@woocommerce/blocks-checkout';
import { default as fetchMock } from 'jest-fetch-mock';
import userEvent from '@testing-library/user-event';
/**
* Internal dependencies
*/
import Block from '../block';
import { defaultCartState } from '../../../data/cart/default-state';
const MiniCartBlock = ( props ) => (
);
const mockEmptyCart = () => {
fetchMock.mockResponse( ( req ) => {
if ( req.url.match( /wc\/store\/v1\/cart/ ) ) {
return Promise.resolve(
JSON.stringify( defaultCartState.cartData )
);
}
return Promise.resolve( '' );
} );
};
const mockFullCart = () => {
fetchMock.mockResponse( ( req ) => {
if ( req.url.match( /wc\/store\/v1\/cart/ ) ) {
return Promise.resolve( JSON.stringify( previewCart ) );
}
return Promise.resolve( '' );
} );
};
const initializeLocalStorage = () => {
Object.defineProperty( window, 'localStorage', {
value: {
setItem: jest.fn(),
},
writable: true,
} );
};
describe( 'Testing Mini-Cart', () => {
beforeEach( () => {
act( () => {
mockFullCart();
// need to clear the store resolution state between tests.
dispatch( storeKey ).invalidateResolutionForStore();
dispatch( storeKey ).receiveCart( defaultCartState.cartData );
} );
} );
afterEach( () => {
fetchMock.resetMocks();
} );
it( 'shows Mini-Cart count badge when there are items in the cart', async () => {
render( );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
await waitFor( () =>
expect( screen.getByText( '3' ) ).toBeInTheDocument()
);
} );
it( "doesn't show Mini-Cart count badge when cart is empty", async () => {
mockEmptyCart();
render( );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
const badgeWith0Count = screen.queryByText( '0' );
expect( badgeWith0Count ).toBeNull();
} );
it( 'opens Mini-Cart drawer when clicking on button', async () => {
const user = userEvent.setup();
render( );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
await act( async () => {
await user.click( screen.getByLabelText( /items/i ) );
} );
await waitFor( () =>
expect( screen.getByText( /your cart/i ) ).toBeInTheDocument()
);
// The opening of the drawer uses deprecated ReactDOM.render.
expect( console ).toHaveErroredWith(
`Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot%s`,
// The stack trace
expect.any( String )
);
} );
it( 'closes the drawer when clicking on the close button', async () => {
const user = userEvent.setup();
render( );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
// Open drawer.
await act( async () => {
await user.click( screen.getByLabelText( /items/i ) );
} );
// Close drawer.
let closeButton = null;
await waitFor( () => {
closeButton = screen.getByLabelText( /close/i );
} );
if ( closeButton ) {
await act( async () => {
await user.click( closeButton );
} );
}
await waitFor( () => {
expect(
screen.queryByText( /your cart/i )
).not.toBeInTheDocument();
} );
// The opening of the drawer uses deprecated ReactDOM.render.
expect( console ).toHaveErroredWith(
`Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot%s`,
// The stack trace
expect.any( String )
);
} );
it( 'renders empty cart if there are no items in the cart', async () => {
const user = userEvent.setup();
mockEmptyCart();
render( );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
await act( async () => {
await user.click( screen.getByLabelText( /items/i ) );
} );
expect( fetchMock ).toHaveBeenCalledTimes( 1 );
// The opening of the drawer uses deprecated ReactDOM.render.
expect( console ).toHaveErroredWith(
`Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot%s`,
// The stack trace
expect.any( String )
);
} );
it( 'updates contents when removed from cart event is triggered', async () => {
render( );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
mockEmptyCart();
// eslint-disable-next-line no-undef
const removedFromCartEvent = new Event( 'wc-blocks_removed_from_cart' );
act( () => {
document.body.dispatchEvent( removedFromCartEvent );
} );
await waitForElementToBeRemoved( () =>
screen.queryByLabelText( /3 items in cart/i )
);
await waitFor( () =>
expect(
screen.getByLabelText( /0 items in cart/i )
).toBeInTheDocument()
);
} );
it( 'updates contents when added to cart event is triggered', async () => {
mockEmptyCart();
render( );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
mockFullCart();
// eslint-disable-next-line no-undef
const addedToCartEvent = new Event( 'wc-blocks_added_to_cart' );
act( () => {
document.body.dispatchEvent( addedToCartEvent );
} );
await waitForElementToBeRemoved( () =>
screen.queryByLabelText( /0 items in cart/i )
);
await waitFor( () =>
expect(
screen.getByLabelText( /3 items in cart/i )
).toBeInTheDocument()
);
} );
it( 'updates local storage when cart finishes loading', async () => {
initializeLocalStorage();
mockFullCart();
render( );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
// Assert we saved the values returned to the localStorage.
await waitFor( () =>
expect(
JSON.parse( window.localStorage.setItem.mock.calls[ 0 ][ 1 ] )
.itemsCount
).toEqual( 3 )
);
} );
it( 'renders cart price if "Hide Cart Price" setting is not enabled', async () => {
mockEmptyCart();
render( );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
await waitFor( () =>
expect( screen.getByText( '$0.00' ) ).toBeInTheDocument()
);
} );
it( 'does not render cart price if "Hide Cart Price" setting is enabled', async () => {
mockEmptyCart();
const { container } = render( );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
await waitFor( () =>
expect( queryByText( container, '$0.00' ) ).not.toBeInTheDocument()
);
} );
} );