woocommerce/plugins/woocommerce-admin/client/utils/xstate/test/url-handling.test.ts

165 lines
5.0 KiB
TypeScript
Raw Normal View History

/**
* External dependencies
*/
import * as navigation from '@woocommerce/navigation';
/**
* Internal dependencies
*/
import { updateQueryParams, createQueryParamsListener } from '../url-handling';
jest.mock( '@woocommerce/navigation', () => ( {
getHistory: jest.fn(),
getQuery: jest.fn(),
updateQueryString: jest.fn(),
} ) );
const mockedGetQuery = navigation.getQuery as jest.Mock;
const mockedUpdateQueryString = navigation.updateQueryString as jest.Mock;
const mockedGetHistory = navigation.getHistory as jest.Mock;
describe( 'updateQueryParams', () => {
beforeEach( () => {
jest.clearAllMocks();
} );
it( 'calls updateQueryString with correct changes', () => {
mockedGetQuery.mockReturnValue( {
sidebar: 'oldSidebar',
content: 'oldContent',
} );
const changes = { sidebar: 'newSidebar', content: 'newContent' };
updateQueryParams( changes );
expect( mockedUpdateQueryString ).toHaveBeenCalledWith( changes );
} );
it( 'does not call updateQueryString when new values match current ones', () => {
mockedGetQuery.mockReturnValue( {
sidebar: 'sameSidebar',
content: 'sameContent',
} );
updateQueryParams( { sidebar: 'sameSidebar', content: 'sameContent' } );
expect( mockedUpdateQueryString ).not.toHaveBeenCalled();
} );
// note that in this test and the below tests, we use .mock.lastCall and .toStrictEqual so that
// we can distinguish the difference between { content: 'bar', sidebar: undefined } and { content: 'bar }
// this is important because calling it with sidebar: undefined will unset the sidebar query parameter,
// while calling it without the sidebar key will leave the existing sidebar query parameter if any
it( 'calls updateQueryString with both parameters as undefined if passed in', () => {
mockedGetQuery.mockReturnValue( {
sidebar: 'existingSidebar',
content: 'existingContent',
} );
const changes = { sidebar: undefined, content: undefined };
updateQueryParams( changes );
expect( mockedUpdateQueryString.mock.lastCall[ 0 ] ).toStrictEqual(
changes
);
} );
it( 'correctly updates with undefined if one parameter is undefined', () => {
mockedGetQuery.mockReturnValue( {
sidebar: 'existingSidebar',
content: 'existingContent',
} );
const changes = { sidebar: 'newSidebar', content: undefined };
updateQueryParams( changes );
expect( mockedUpdateQueryString.mock.lastCall[ 0 ] ).toStrictEqual(
changes
);
} );
it( 'only updates changes that are different', () => {
mockedGetQuery.mockReturnValue( {
sidebar: 'existingSidebar',
content: 'existingContent',
} );
const changes = { sidebar: 'newSidebar', content: 'existingContent' };
updateQueryParams( changes );
expect( mockedUpdateQueryString.mock.lastCall[ 0 ] ).toStrictEqual( {
sidebar: 'newSidebar',
} );
} );
it( 'only updates changes that are passed in', () => {
mockedGetQuery.mockReturnValue( {
sidebar: 'existingSidebar',
} );
const changes = { sidebar: 'newSidebar' };
updateQueryParams( changes );
expect( mockedUpdateQueryString.mock.lastCall[ 0 ] ).toStrictEqual(
changes
);
} );
} );
describe( 'createQueryParamsListener', () => {
let unlistenMock: jest.Mock;
let sendBackMock: jest.Mock;
let historyMock: { listen: jest.Mock; location: { search: string } };
beforeEach( () => {
sendBackMock = jest.fn();
unlistenMock = jest.fn();
historyMock = {
listen: jest.fn().mockImplementation( () => {
return unlistenMock;
} ),
location: { search: '?test=sameValue' },
};
mockedGetHistory.mockReturnValue( historyMock );
} );
afterEach( () => {
jest.clearAllMocks();
} );
it( 'registers and unregisters the listener', () => {
const unlisten = createQueryParamsListener( 'test', sendBackMock );
expect( historyMock.listen ).toHaveBeenCalled();
unlisten();
expect( unlistenMock ).toHaveBeenCalled();
} );
it( 'calls sendBack when the specified query parameter changes', () => {
const paramName = 'test';
createQueryParamsListener( paramName, sendBackMock );
// Simulate a query param change
historyMock.listen.mock.calls[ 0 ][ 0 ]( {
action: 'POP',
location: { search: `?${ paramName }=newValue` },
} );
expect( sendBackMock ).toHaveBeenCalledWith( {
type: 'EXTERNAL_URL_UPDATE',
} );
} );
it( "does not call sendBack when the query parameter that changes isn't what we are listening to", () => {
const paramName = 'test';
createQueryParamsListener( paramName, sendBackMock );
// Simulate a navigation that does not change the specific query param
historyMock.listen.mock.calls[ 0 ][ 0 ]( {
action: 'POP',
location: { search: '?test=sameValue&anotherParam=different' },
} );
expect( sendBackMock ).not.toHaveBeenCalled();
} );
it( 'does not call sendBack when action is not POP', () => {
const paramName = 'test';
createQueryParamsListener( paramName, sendBackMock );
// Simulate a PUSH action
historyMock.listen.mock.calls[ 0 ][ 0 ]( {
action: 'PUSH',
location: { search: `?${ paramName }=newValue` },
} );
expect( sendBackMock ).not.toHaveBeenCalled();
} );
} );