Skip to content

Commit

Permalink
Data: Refactor 'useDispatch' tests to use RTL (#44802)
Browse files Browse the repository at this point in the history
* Data: Refactor 'useDispatch' tests to use RTL

* Clear mock function between assertions

* Simplify userEvent setup

* Update tests to observer actual store behavior

* Remove leftover comment

* Return action call tests
  • Loading branch information
Mamaduka authored Oct 10, 2022
1 parent 82eccd4 commit b603286
Showing 1 changed file with 124 additions and 117 deletions.
241 changes: 124 additions & 117 deletions packages/data/src/components/use-dispatch/test/use-dispatch.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/**
* External dependencies
*/
import TestRenderer, { act } from 'react-test-renderer';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

/**
* Internal dependencies
Expand All @@ -11,165 +12,171 @@ import createReduxStore from '../../../redux-store';
import { createRegistry } from '../../../registry';
import { RegistryProvider } from '../../registry-provider';

jest.useRealTimers();

describe( 'useDispatch', () => {
const counterStore = {
reducer: ( state = 0, action ) => {
if ( action.type === 'INC' ) {
return state + 1;
}

return state;
},
actions: {
inc: () => ( { type: 'INC' } ),
},
selectors: {
get: ( state ) => state,
},
};

let registry;
beforeEach( () => {
registry = createRegistry();
} );

it( 'returns dispatch function from store with no store name provided', () => {
registry.registerStore( 'demoStore', {
reducer: ( state ) => state,
actions: {
foo: () => 'bar',
},
} );
it( 'returns dispatch function from store with no store name provided', async () => {
const user = userEvent.setup();
registry.registerStore( 'demo', counterStore );

const TestComponent = () => {
return <div></div>;
};
const Component = () => {
const dispatch = useDispatch();
return <TestComponent dispatch={ dispatch } />;
return <button onClick={ () => dispatch( 'demo' ).inc() } />;
};

let testRenderer;
act( () => {
testRenderer = TestRenderer.create(
<RegistryProvider value={ registry }>
<Component />
</RegistryProvider>
);
} );
render(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);

const testInstance = testRenderer.root;
await user.click( screen.getByRole( 'button' ) );

expect( testInstance.findByType( TestComponent ).props.dispatch ).toBe(
registry.dispatch
);
expect( registry.select( 'demo' ).get() ).toBe( 1 );
} );
it( 'returns expected action creators from store for given storeName', () => {
const noop = () => ( { type: '__INERT__' } );
const testAction = jest.fn().mockImplementation( noop );
const store = createReduxStore( 'demoStore', {
reducer: ( state ) => state,
actions: {
foo: testAction,
},
} );

it( 'returns expected action creators from store for given storeName', async () => {
const user = userEvent.setup();
const store = createReduxStore( 'demoStore', counterStore );
registry.register( store );

const TestComponent = () => {
const { foo } = useDispatch( store );
return <button onClick={ foo } />;
const { inc } = useDispatch( store );
return <button onClick={ inc } />;
};

let testRenderer;
render(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);

act( () => {
testRenderer = TestRenderer.create(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);
} );
await user.click( screen.getByRole( 'button' ) );

const testInstance = testRenderer.root;
expect( registry.select( store ).get() ).toBe( 1 );
} );

act( () => {
testInstance.findByType( 'button' ).props.onClick();
} );
it( 'returns expected action creators from store for given store descriptor', async () => {
const user = userEvent.setup();
registry.registerStore( 'demoStore', counterStore );
const TestComponent = () => {
const { inc } = useDispatch( 'demoStore' );
return <button onClick={ inc } />;
};

render(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);

await user.click( screen.getByRole( 'button' ) );

expect( testAction ).toHaveBeenCalledTimes( 1 );
expect( registry.select( 'demoStore' ).get() ).toBe( 1 );
} );

it( 'returns expected action creators from store for given store descriptor', () => {
const noop = () => ( { type: '__INERT__' } );
const testAction = jest.fn().mockImplementation( noop );
registry.registerStore( 'demoStore', {
reducer: ( state ) => state,
actions: {
foo: testAction,
},
} );
it( 'returns dispatch from correct registry if registries change', async () => {
const user = userEvent.setup();

const firstRegistry = createRegistry();
firstRegistry.registerStore( 'demo', counterStore );

const secondRegistry = createRegistry();
secondRegistry.registerStore( 'demo', counterStore );

const TestComponent = () => {
const { foo } = useDispatch( 'demoStore' );
return <button onClick={ foo } />;
const dispatch = useDispatch();
return <button onClick={ () => dispatch( 'demo' ).inc() } />;
};

let testRenderer;
const { rerender } = render(
<RegistryProvider value={ firstRegistry }>
<TestComponent />
</RegistryProvider>
);

act( () => {
testRenderer = TestRenderer.create(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);
} );
await user.click( screen.getByRole( 'button' ) );

const testInstance = testRenderer.root;
expect( firstRegistry.select( 'demo' ).get() ).toBe( 1 );
expect( secondRegistry.select( 'demo' ).get() ).toBe( 0 );

act( () => {
testInstance.findByType( 'button' ).props.onClick();
} );
rerender(
<RegistryProvider value={ secondRegistry }>
<TestComponent />
</RegistryProvider>
);

expect( testAction ).toHaveBeenCalledTimes( 1 );
await user.click( screen.getByRole( 'button' ) );
expect( firstRegistry.select( 'demo' ).get() ).toBe( 1 );
expect( secondRegistry.select( 'demo' ).get() ).toBe( 1 );
} );

it( 'returns dispatch from correct registry if registries change', () => {
const reducer = ( state ) => state;
const noop = () => ( { type: '__INERT__' } );
const firstRegistryAction = jest.fn().mockImplementation( noop );
const secondRegistryAction = jest.fn().mockImplementation( noop );

const firstRegistry = registry;
firstRegistry.registerStore( 'demo', {
reducer,
it( 'dispatches returned actions correctly', async () => {
const user = userEvent.setup();
const fooAction = jest.fn( () => ( { type: '__INERT__' } ) );
const barAction = jest.fn( () => ( { type: '__INERT__' } ) );
const store = createReduxStore( 'demo', {
reducer: ( state ) => state,
actions: {
noop: firstRegistryAction,
foo: fooAction,
bar: barAction,
},
} );
registry.register( store );

const TestComponent = () => {
const dispatch = useDispatch();
return <button onClick={ () => dispatch( 'demo' ).noop() } />;
const { foo, bar } = useDispatch( store );
return (
<>
<button onClick={ foo }>foo</button>
<button onClick={ bar }>bar</button>
</>
);
};

let testRenderer;
act( () => {
testRenderer = TestRenderer.create(
<RegistryProvider value={ firstRegistry }>
<TestComponent />
</RegistryProvider>
);
} );
const testInstance = testRenderer.root;
render(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);

act( () => {
testInstance.findByType( 'button' ).props.onClick();
} );
await user.click(
screen.getByRole( 'button', {
name: 'foo',
} )
);

expect( firstRegistryAction ).toHaveBeenCalledTimes( 1 );
expect( secondRegistryAction ).toHaveBeenCalledTimes( 0 );
expect( fooAction ).toBeCalledTimes( 1 );
expect( barAction ).toBeCalledTimes( 0 );

const secondRegistry = createRegistry();
secondRegistry.registerStore( 'demo', {
reducer,
actions: {
noop: secondRegistryAction,
},
} );
await user.click(
screen.getByRole( 'button', {
name: 'bar',
} )
);

act( () => {
testRenderer.update(
<RegistryProvider value={ secondRegistry }>
<TestComponent />
</RegistryProvider>
);
} );
act( () => {
testInstance.findByType( 'button' ).props.onClick();
} );
expect( firstRegistryAction ).toHaveBeenCalledTimes( 1 );
expect( secondRegistryAction ).toHaveBeenCalledTimes( 1 );
expect( fooAction ).toBeCalledTimes( 1 );
expect( barAction ).toBeCalledTimes( 1 );
} );
} );

0 comments on commit b603286

Please sign in to comment.