@bigtest/react
React DOM helpers for testing big
What is this?
This package aims to provide a set of helpers to make it easier to
acceptance test your React applications.
The mount
helper will resolve after mounting a component in a
freshly inserted DOM node. Subsequent uses will clean up any previously
mounted component.
import { mount } from '@bigtest/react';
import Button from '../src/components/button';
describe('My Button', () => {
beforeEach(() => mount(() => <Button/>));
it('renders', () => {
expect(document.querySelector('.button')).to.exist;
});
});
The setupAppForTesting
helper not only mounts the application
component, but will resolve with an instance of the component, and
provide an in-memory history object for React
Router to use during
testing.
import { setupAppForTesting } from '@bigtest/react';
import App from '../src/app';
describe('My Application', () => {
let app;
beforeEach(async () => {
app = await setupAppForTesting(App);
});
it('renders', () => {
expect(document.querySelector('#app')).to.exist;
});
it('has a history prop', () => {
expect(app.props).to.have.property('history');
});
});
The visit
helpers (visit
, goBack
, goForward
, and location
)
only work after using setupAppForTesting
and interface with the
application's history
prop to navigate between routes.
import { setupAppForTesting, visit, location } from '@bigtest/react';
import App from '../src/app';
describe('My Application', () => {
beforeEach(() => setupAppForTesting(App));
describe('navigating', () => {
beforeEach(() => visit('/some-route'));
it('is at the new route', () => {
expect(location()).to.have.property('pathname', '/some-route');
});
});
});
The cleanup
helper is called at the start of every mount
and
setupAppForTesting
call to clean up any previously mounted component
or application. It can be also used on it's own if you need to clean
up previously mounted components yourself.
import { mount, cleanup } from '@bigtest/react';
import Button from '../src/components/button';
describe('My Button', () => {
beforeEach(() => mount(() => <Button/>));
afterEach(() => cleanup());
});
Options
Both mount
and setupAppForTesting
accept a hash of options
as
the second argument.
mount(Component, {
mountId: 'testing-root',
rootElement: document.body,
setup: () => {},
teardown: () => {}
})
Additionally, setupAppForTesting
accepts a props
option which will
pass along any user-defined props to the application component.
setupAppForTesting(App, {
props: {
store: createStore(),
history: createHistory(historyOptions)
}
})
Reusability
For the most optimal experience when testing your application, any
required application logic that does not live in a component's
life-cycle hooks should be made reusable. Either by providing the
necessary setup
and teardown
options, or by moving the logic into
component life-cycle hooks.
In addition to this, it will probably make sense to make use of
setupAppForTesting
inside of your own test helper where any other
necessary setup is taken care of. This also allows us to not have to
import our app and duplicate setup logic in every test file.
import { setupAppForTesting } from '@bigtest/react';
export { visit, goBack, goForward, location } from '@bigtest/react';
import App from '../src/app';
import createServer from './mocks/server';
export function setupApplicationForTesting() {
beforeEach(async function () => {
this.app = await setupAppForTesting(App, {
setup: () => this.server = createServer(),
teardown () => this.server.shutdown()
});
});
}
Even Better Testing
While these helpers allow you to repeatedly mount your application for
testing, interacting with your application can also be troublesome.
@bigtest/interactor
provides an easy way to interact with the various parts of your app
via any browser, just like a user would interact with your app. In
fact, composable interactors are the perfect companion for testing
an app made with composable components.
import { setupAppForTesting } from '@bigtest/react';
import App from '../src/app';
import HomePageInteractor from './interactors/home';
describe('My Application', () => {
const home = new HomePageInteractor();
beforeEach(() => setupAppForTesting(App))
it('has a fancy button', () => {
expect(home.button.isPresent).to.be.true;
expect(home.button.isFancy).to.be.true;
});
});
Check out the
@bigtest/interactor
repo
for more information about interactors and how they work.