Skip to content

Instantly share code, notes, and snippets.

@kadamwhite
Created December 10, 2019 00:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kadamwhite/f4959c157389abccca80f924ff663e50 to your computer and use it in GitHub Desktop.
Save kadamwhite/f4959c157389abccca80f924ff663e50 to your computer and use it in GitHub Desktop.
TypeScript Gutenberg connected component test
import React from 'react';
import { render, cleanup, fireEvent } from '@testing-library/react';
import { useSelect, useDispatch } from '@wordpress/data';
import '@testing-library/jest-dom/extend-expect';
import { storeProvider } from '../store-provider';
describe('storeProvider', () => {
afterEach(cleanup);
it('returns a React component', () => {
const StoreWrapper = storeProvider();
const { container } = render((
<StoreWrapper />
));
expect(container.innerHTML).toBe('');
});
it('exposes store selectors to child components', () => {
const StoreWrapper = storeProvider({
'store/name': {
selectors: {
getValue: (): string => 'store content',
},
},
});
const Test: React.FC = () => {
const data = useSelect((select): { value: string } => ({
value: select('store/name').getValue(),
}));
return (
<p>{data.value}</p>
);
};
const { getByText } = render((
<StoreWrapper>
<Test />
</StoreWrapper>
));
expect(getByText('store content')).toBeInTheDocument();
});
it('exposes store actions to child components', () => {
const noop = (): { type: string } => ({ type: '__INERT__' });
const onClick = jest.fn().mockImplementation(noop);
const StoreWrapper = storeProvider({
'store/name': {
actions: {
onClick,
},
},
});
const Test: React.FC = () => {
// eslint-disable-next-line no-shadow
const { onClick } = useDispatch('store/name');
return (
<button type="button" onClick={onClick}>Click Me</button>
);
};
const { getByText } = render((
<StoreWrapper>
<Test />
</StoreWrapper>
));
const button = getByText('Click Me');
expect(onClick).not.toHaveBeenCalled();
expect(button).toBeInTheDocument();
fireEvent.click(button, {});
expect(onClick).toHaveBeenCalledTimes(1);
});
});
import React from 'react';
import { createRegistry, RegistryProvider } from '@wordpress/data';
/**
* Accept a dictionary of mock store selectors & actions and return a
* React wrapper component which uses WP's RegistryProvider to expose
* that store data to wrapped child components.
*
* @param {Object} stores Dictionary of mock store actions or selectors keyed by store.
* @returns {React.FC} Store provider wrapper component.
*/
export const storeProvider = (
stores: {
// Keyed by name of store, e.g. `core/block-editor`.
[storeKey: string]: {
actions?: KeyedObject;
selectors?: KeyedObject;
};
} = {},
): React.FC => ({ children }): JSX.Element => {
const registry = createRegistry();
// Register all provided stores.
Object.keys(stores).forEach((storeKey) => {
const store = stores[storeKey];
registry.registerStore(storeKey, {
reducer: () => ({}),
actions: store.actions || {},
selectors: store.selectors || {},
});
});
return (
<RegistryProvider value={registry}>
{ children }
</RegistryProvider>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment