woocommerce/plugins/woocommerce-admin/client/customize-store/design-without-ai/tests/state-machine.test.ts

338 lines
8.9 KiB
TypeScript
Raw Normal View History

/**
* External dependencies
*/
import { interpret } from 'xstate';
import { waitFor } from 'xstate/lib/waitFor';
/**
* Internal dependencies
*/
import { designWithNoAiStateMachineDefinition } from '../state-machine';
const createMockMachine = ( {
services,
guards,
actions,
}: Parameters<
typeof designWithNoAiStateMachineDefinition.withConfig
>[ 0 ] ) => {
const machineWithConfig = designWithNoAiStateMachineDefinition.withConfig( {
services,
guards,
actions,
} );
return machineWithConfig;
};
jest.mock( '@wordpress/api-fetch', () => jest.fn() );
jest.mock(
'@wordpress/edit-site/build-module/components/global-styles/global-styles-provider',
() => jest.fn()
);
describe( 'Design Without AI state machine', () => {
beforeEach( () => {
jest.clearAllMocks();
} );
describe( 'navigate state', () => {
it( 'should start with the navigate state', async () => {
const expectedValue = 'navigate';
const actualState =
designWithNoAiStateMachineDefinition.initialState;
expect( actualState.matches( expectedValue ) ).toBeTruthy();
} );
it( 'should check the url', () => {
const hasStepInUrl = jest.fn( () => true );
const machine = designWithNoAiStateMachineDefinition.withConfig( {
guards: {
hasStepInUrl,
},
} );
const machineInterpret = interpret( machine ).start();
expect( hasStepInUrl ).toBeCalled();
machineInterpret.stop();
} );
it( 'should transit to preAssembleSite state when the url is /design', () => {
const hasStepInUrl = jest.fn( () => true );
const machine = designWithNoAiStateMachineDefinition.withConfig( {
guards: {
hasStepInUrl,
},
} );
const machineInterpret = interpret( machine ).start();
expect(
machineInterpret.getSnapshot().matches( 'preAssembleSite' )
).toBeTruthy();
machineInterpret.stop();
} );
it( "should not transit to preAssembleSite state when the url isn't /design", () => {
const hasStepInUrl = jest.fn( () => false );
const machine = designWithNoAiStateMachineDefinition.withConfig( {
guards: {
hasStepInUrl,
},
} );
const machineInterpret = interpret( machine ).start();
expect(
machineInterpret.getSnapshot().matches( 'preAssembleSite' )
).toBeFalsy();
} );
} );
describe( 'preAssembleSite state', () => {
it( 'should invoke `redirectToIntroWithError` when `installAndActivateTheme` service fails', async () => {
const initialState =
'preAssembleSite.preApiCallLoader.installAndActivateTheme';
const installAndActivateThemeMock = jest.fn( () =>
Promise.reject()
);
const assembleSiteMock = jest.fn( () => Promise.resolve() );
const createProductsMock = jest.fn( () =>
Promise.resolve( {
success: true,
} )
);
const redirectToIntroWithErrorMock = jest.fn();
const machine = createMockMachine( {
services: {
installAndActivateTheme: installAndActivateThemeMock,
assembleSite: assembleSiteMock,
createProducts: createProductsMock,
},
actions: {
redirectToIntroWithError: redirectToIntroWithErrorMock,
},
} );
const state = machine.getInitialState( initialState );
const actor = interpret( machine ).start( state );
await waitFor( actor, ( currentState ) => {
return currentState.matches(
'preAssembleSite.preApiCallLoader.installAndActivateTheme.pending'
);
} );
expect( installAndActivateThemeMock ).toHaveBeenCalled();
expect( redirectToIntroWithErrorMock ).toHaveBeenCalled();
} );
it( 'should invoke `installAndActivateTheme` service', async () => {
const initialState =
'preAssembleSite.preApiCallLoader.installAndActivateTheme';
const installAndActivateThemeMock = jest.fn( () =>
Promise.resolve()
);
const assembleSiteMock = jest.fn( () => Promise.resolve() );
const createProductsMock = jest.fn( () =>
Promise.resolve( {
success: true,
} )
);
const machine = createMockMachine( {
services: {
installAndActivateTheme: installAndActivateThemeMock,
assembleSite: assembleSiteMock,
createProducts: createProductsMock,
},
} );
const state = machine.getInitialState( initialState );
const actor = interpret( machine ).start( state );
await waitFor( actor, ( currentState ) => {
return currentState.matches(
'preAssembleSite.preApiCallLoader.installAndActivateTheme.pending'
);
} );
expect( installAndActivateThemeMock ).toHaveBeenCalled();
const finalState = await waitFor( actor, ( currentState ) => {
return currentState.matches(
'preAssembleSite.preApiCallLoader.installAndActivateTheme.success'
);
} );
expect(
finalState.matches(
'preAssembleSite.preApiCallLoader.installAndActivateTheme.success'
)
).toBeTruthy();
} );
it( 'should invoke `redirectToIntroWithError` when `assembleSite` service fails', async () => {
const initialState = 'preAssembleSite.assembleSite';
const assembleSiteMock = jest.fn( () => Promise.reject() );
const createProductsMock = jest.fn( () => {
return Promise.resolve( {
success: true,
} );
} );
const installAndActivateThemeMock = jest.fn( () =>
Promise.resolve()
);
const redirectToIntroWithErrorMock = jest.fn();
const machine = createMockMachine( {
services: {
assembleSite: assembleSiteMock,
createProducts: createProductsMock,
installAndActivateTheme: installAndActivateThemeMock,
},
actions: {
redirectToIntroWithError: redirectToIntroWithErrorMock,
},
} );
const state = machine.getInitialState( initialState );
const actor = interpret( machine ).start( state );
await waitFor( actor, ( currentState ) => {
return currentState.matches(
'preAssembleSite.assembleSite.pending'
);
} );
expect( assembleSiteMock ).toHaveBeenCalled();
expect( redirectToIntroWithErrorMock ).toHaveBeenCalled();
} );
it( 'should invoke `assembleSite` service', async () => {
const initialState = 'preAssembleSite.assembleSite';
const assembleSiteMock = jest.fn( () => Promise.resolve() );
const installAndActivateThemeMock = jest.fn( () =>
Promise.resolve()
);
const createProductsMock = jest.fn( () =>
Promise.resolve( {
success: true,
} )
);
const machine = createMockMachine( {
services: {
assembleSite: assembleSiteMock,
createProducts: createProductsMock,
installAndActivateTheme: installAndActivateThemeMock,
},
actions: {
redirectToAssemblerHub: jest.fn(),
},
} );
const state = machine.getInitialState( initialState );
const actor = interpret( machine ).start( state );
const finalState = await waitFor( actor, ( currentState ) => {
return currentState.matches( 'showAssembleHub' );
} );
expect( assembleSiteMock ).toHaveBeenCalled();
expect( finalState.matches( 'showAssembleHub' ) ).toBeTruthy();
} );
it( 'should invoke `redirectToIntroWithError` when `createProducts` service fails', async () => {
const initialState =
'preAssembleSite.preApiCallLoader.createProducts';
const createProductsMock = jest.fn( () => Promise.reject() );
const assembleSiteMock = jest.fn( () => Promise.resolve() );
const installAndActivateThemeMock = jest.fn( () =>
Promise.resolve()
);
const redirectToIntroWithErrorMock = jest.fn();
const machine = createMockMachine( {
services: {
createProducts: createProductsMock,
assembleSite: assembleSiteMock,
installAndActivateTheme: installAndActivateThemeMock,
},
actions: {
redirectToIntroWithError: redirectToIntroWithErrorMock,
},
} );
const state = machine.getInitialState( initialState );
const actor = interpret( machine ).start( state );
await waitFor( actor, ( currentState ) => {
return currentState.matches(
'preAssembleSite.preApiCallLoader.createProducts.pending'
);
} );
expect( createProductsMock ).toHaveBeenCalled();
expect( redirectToIntroWithErrorMock ).toHaveBeenCalled();
} );
it( 'should invoke `createProducts` service', async () => {
const initialState =
'preAssembleSite.preApiCallLoader.createProducts';
const createProductsMock = jest.fn( () =>
Promise.resolve( {
success: true,
} )
);
const machine = createMockMachine( {
services: {
createProducts: createProductsMock,
},
} );
const state = machine.getInitialState( initialState );
const actor = interpret( machine ).start( state );
await waitFor( actor, ( currentState ) => {
return currentState.matches(
'preAssembleSite.preApiCallLoader.createProducts.pending'
);
} );
expect( createProductsMock ).toHaveBeenCalled();
const finalState = await waitFor( actor, ( currentState ) => {
return currentState.matches(
'preAssembleSite.preApiCallLoader.createProducts.success'
);
} );
expect(
finalState.matches(
'preAssembleSite.preApiCallLoader.createProducts.success'
)
).toBeTruthy();
} );
} );
} );