197 lines
5.4 KiB
TypeScript
197 lines
5.4 KiB
TypeScript
/**
|
|
* External dependencies
|
|
*/
|
|
import { dispatch, select } from '@wordpress/data';
|
|
import { previewCart } from '@woocommerce/resource-previews';
|
|
import { Cart } from '@woocommerce/types';
|
|
import { camelCaseKeys } from '@woocommerce/base-utils';
|
|
|
|
/**
|
|
* Internal dependencies
|
|
*/
|
|
import { notifyQuantityChanges } from '../notify-quantity-changes';
|
|
|
|
// Deep clone an object to avoid mutating it later.
|
|
const cloneObject = ( obj ) => JSON.parse( JSON.stringify( obj ) );
|
|
|
|
jest.mock( '@wordpress/data' );
|
|
|
|
const mockedCreateInfoNotice = jest.fn();
|
|
dispatch.mockImplementation( ( store ) => {
|
|
if ( store === 'core/notices' ) {
|
|
return {
|
|
createInfoNotice: mockedCreateInfoNotice,
|
|
};
|
|
}
|
|
} );
|
|
|
|
select.mockImplementation( () => {
|
|
return {
|
|
hasFinishedResolution() {
|
|
return true;
|
|
},
|
|
};
|
|
} );
|
|
|
|
/**
|
|
* Clones the preview cart and turns it into a `Cart`.
|
|
*/
|
|
const getFreshCarts = (): { oldCart: Cart; newCart: Cart } => {
|
|
const oldCart = camelCaseKeys( cloneObject( previewCart ) ) as Cart;
|
|
const newCart = camelCaseKeys( cloneObject( previewCart ) ) as Cart;
|
|
return { oldCart, newCart };
|
|
};
|
|
|
|
describe( 'notifyQuantityChanges', () => {
|
|
afterEach( () => {
|
|
jest.clearAllMocks();
|
|
} );
|
|
it( 'shows notices when the quantity limits of an item change', () => {
|
|
const { oldCart, newCart } = getFreshCarts();
|
|
newCart.items[ 0 ].quantity_limits.minimum = 50;
|
|
notifyQuantityChanges( {
|
|
oldCart,
|
|
newCart,
|
|
cartItemsPendingQuantity: [],
|
|
} );
|
|
expect( mockedCreateInfoNotice ).toHaveBeenLastCalledWith(
|
|
'The quantity of "Beanie" was increased to 50. This is the minimum required quantity.',
|
|
{
|
|
context: 'wc/cart',
|
|
speak: true,
|
|
type: 'snackbar',
|
|
id: '1-quantity-update',
|
|
}
|
|
);
|
|
|
|
newCart.items[ 0 ].quantity_limits.minimum = 1;
|
|
newCart.items[ 0 ].quantity_limits.maximum = 10;
|
|
// Quantity needs to be outside the limits for the notice to show.
|
|
newCart.items[ 0 ].quantity = 11;
|
|
notifyQuantityChanges( {
|
|
oldCart,
|
|
newCart,
|
|
cartItemsPendingQuantity: [],
|
|
} );
|
|
expect( mockedCreateInfoNotice ).toHaveBeenLastCalledWith(
|
|
'The quantity of "Beanie" was decreased to 10. This is the maximum allowed quantity.',
|
|
{
|
|
context: 'wc/cart',
|
|
speak: true,
|
|
type: 'snackbar',
|
|
id: '1-quantity-update',
|
|
}
|
|
);
|
|
newCart.items[ 0 ].quantity = 10;
|
|
oldCart.items[ 0 ].quantity = 10;
|
|
newCart.items[ 0 ].quantity_limits.multiple_of = 6;
|
|
notifyQuantityChanges( {
|
|
oldCart,
|
|
newCart,
|
|
cartItemsPendingQuantity: [],
|
|
} );
|
|
expect( mockedCreateInfoNotice ).toHaveBeenLastCalledWith(
|
|
'The quantity of "Beanie" was changed to 6. You must purchase this product in groups of 6.',
|
|
{
|
|
context: 'wc/cart',
|
|
speak: true,
|
|
type: 'snackbar',
|
|
id: '1-quantity-update',
|
|
}
|
|
);
|
|
} );
|
|
it( 'does not show notices if the quantity limit changes, and the quantity is within limits', () => {
|
|
const { oldCart, newCart } = getFreshCarts();
|
|
newCart.items[ 0 ].quantity = 5;
|
|
oldCart.items[ 0 ].quantity = 5;
|
|
newCart.items[ 0 ].quantity_limits.maximum = 10;
|
|
notifyQuantityChanges( {
|
|
oldCart,
|
|
newCart,
|
|
cartItemsPendingQuantity: [],
|
|
} );
|
|
expect( mockedCreateInfoNotice ).not.toHaveBeenCalled();
|
|
|
|
newCart.items[ 0 ].quantity_limits.minimum = 4;
|
|
notifyQuantityChanges( {
|
|
oldCart,
|
|
newCart,
|
|
cartItemsPendingQuantity: [],
|
|
} );
|
|
expect( mockedCreateInfoNotice ).not.toHaveBeenCalled();
|
|
} );
|
|
it( 'shows notices when the quantity of an item changes', () => {
|
|
const { oldCart, newCart } = getFreshCarts();
|
|
newCart.items[ 0 ].quantity = 50;
|
|
notifyQuantityChanges( {
|
|
oldCart,
|
|
newCart,
|
|
cartItemsPendingQuantity: [],
|
|
} );
|
|
expect( mockedCreateInfoNotice ).toHaveBeenLastCalledWith(
|
|
'The quantity of "Beanie" was changed to 50.',
|
|
{
|
|
context: 'wc/cart',
|
|
speak: true,
|
|
type: 'snackbar',
|
|
id: '1-quantity-update',
|
|
}
|
|
);
|
|
} );
|
|
it( 'does not show notices when the item is the one being updated', () => {
|
|
const { oldCart, newCart } = getFreshCarts();
|
|
newCart.items[ 0 ].quantity = 5;
|
|
newCart.items[ 0 ].quantity_limits.maximum = 10;
|
|
notifyQuantityChanges( {
|
|
oldCart,
|
|
newCart,
|
|
cartItemsPendingQuantity: [ '1' ],
|
|
} );
|
|
expect( mockedCreateInfoNotice ).not.toHaveBeenCalled();
|
|
} );
|
|
it( 'does not show notices when a deleted item is the one being removed', () => {
|
|
const { oldCart, newCart } = getFreshCarts();
|
|
|
|
// Remove both items from the new cart.
|
|
delete newCart.items[ 0 ];
|
|
delete newCart.items[ 1 ];
|
|
notifyQuantityChanges( {
|
|
oldCart,
|
|
newCart,
|
|
// This means the user is only actively removing item with key '1'. The second item is "unexpected" so we
|
|
// expect exactly one notification to be shown.
|
|
cartItemsPendingDelete: [ '1' ],
|
|
} );
|
|
// Check it was called for item 2, but not item 1.
|
|
expect( mockedCreateInfoNotice ).toHaveBeenCalledTimes( 1 );
|
|
} );
|
|
|
|
it( 'shows a notice when an item is unexpectedly removed', () => {
|
|
const { oldCart, newCart } = getFreshCarts();
|
|
delete newCart.items[ 0 ];
|
|
notifyQuantityChanges( {
|
|
oldCart,
|
|
newCart,
|
|
} );
|
|
expect( mockedCreateInfoNotice ).toHaveBeenLastCalledWith(
|
|
'"Beanie" was removed from your cart.',
|
|
{
|
|
context: 'wc/cart',
|
|
speak: true,
|
|
type: 'snackbar',
|
|
id: '1-removed',
|
|
}
|
|
);
|
|
} );
|
|
it( 'does not show notices if the cart has not finished resolving', () => {
|
|
select.mockImplementation( () => {
|
|
return {
|
|
hasFinishedResolution() {
|
|
return false;
|
|
},
|
|
};
|
|
} );
|
|
expect( mockedCreateInfoNotice ).not.toHaveBeenCalled();
|
|
} );
|
|
} );
|