@gpx/render-composer
v3.2.0
Published
Create complex renders for react-testing-library
Downloads
26
Readme
The problem
When working with Testing Library within a large project often you need to wrap your component in several providers:
const history = createMemoryHistory();
const locale = 'en';
const user = {name: 'Giorgio'};
render(
<Router history={history}>
<IntlProvider locale={locale}>
<UserContext.Provider value={user}>
<MyComponent />
</UserContext.Provider>
</IntlProvider>
</Router>,
);
This can lead to a lot of overhead and is not very flexible.
The solution
Render Composer allows you to declare reusable and configurable wraps that define a single provider. These wraps can then be combined to generate more complex hierarchies.
const RouterWrap = wrap((children, {history}) => (
<Router history={history}>{children}</Router>
)).defaultData(() => ({
history: createMemoryHistory(),
}));
const IntlWrap = wrap((children, {locale}) => (
<IntlProvider locale={locale}>{children}</IntlProvider>
)).defaultData({locale: 'en'});
const UserWrap = wrap((children, {user}) => (
<UserContext.Provider value={user}>{children}</UserContext.Provider>
)).defaultData({user: {name: 'Giorgio'}});
const appRender = RouterWrap.wraps(IntlWrap)
.wraps(UserWrap)
.withRenderMethod(render);
appRender(<MyComponent />);
Installation
With NPM:
npm install @gpx/render-composer --save-dev
With Yarn:
yarn add @gpx/render-composer --dev
Now simply import it in your tests:
import wrap from '@gpx/render-composer';
// or
var wrap = require('@gpx/render-composer');
Usage
You can create a wrap with the wrap
method:
const Wrap = wrap((children, data) => <div>{children}</div>);
data
is an empty object by default. You can set some default values with defaultData
:
Wrap.defaultData({foo: 'bar'});
If you need the data to be generated every time rather than be static you can also
pass a function to defaultData
:
Wrap.defaultData(() => ({foo: Math.random()}));
You can compose the wraps with the wraps
method. You can chain as many wraps you want:
WrapA.wraps(WrapB)
.wraps(WrapC)
.wraps(WrapD);
Once you are satisfied with your wrap you can get a render method with withRenderMethod
:
import {render} from '@testing-library/react';
const renderWrap = Wrap.withRenderMethod(render);
renderWrap(<MyComponent />);
The generated render method will also accept data to overwrite the default values you defined in your wraps. The data will be returned too:
Wrap.defaultData(() => ({foo: 'bar'}));
// This `foo` will have value `'bar'`
const {foo} = renderWrap(<MyComponent />);
// This `foo` will have value `'baz'`
const {foo} = renderWrap(<MyComponent />, {foo: 'baz'});
Note that wraps are immutable so that they can be defined in one file and exported and combined.