Using JSX in React component tests
Overview
Starting with version 2.4, Nightwatch supports running React component tests with JSX and which are written in a Component Story Format (CSF) subset.
What is Component Story Format
Component Story Format (CSF) is an open standard based on ES6 modules introduced by the Storybook team as a declarative model for writing component stories.
A story is a named export
which is an instance of the component, together with props, args, and/or test capabilities. A component test file contains one or more stories.
File names must use .jsx
or .tsx
as extension. In its simplest form, the component test looks as follows:
import Form from '../components/Form.jsx';
export default {
title: 'Form',
component: Form,
}
export const FormStory = () => <Form />
Considering the above example, let's add a second story for our component test:
import Form from '../components/Form.jsx';
export default {
title: 'Form Component',
component: Form
}
export const EmptyForm = () => <Form />
export const AnotherForm = Object.assign(() => <Form addTask={function(value) {
console.log('Add Task', value);
}} />, {
// additional parameters
});
Add interaction tests
Each component story (i.e. named export) takes several (async
) function properties which define the tests that need to be executed. The testing functionality can be written using the following functions:
play({canvasElement, args})
– is executed in the DOM context and receives the component story elementtest(browser, {component, result})
– is executed in the Node context and receives the Nightwatch api object (browser
); receives thecomponent
element object as a Nightwatch compatible element instancepreRender()
– runs before the component is renderedpostRender()
– runs after the component is rendered
In addition, component level test hooks can be declared on the top level, in the default export
section.
Example
In the example below, the play()
function uses the DOM utilities from the Testing Library.
import { fireEvent, within } from '@testing-library/dom';
import Form from '../components/Form.jsx';
export default {
title: 'Form Component',
component: Form,
// executed before all the individual component stories; runs in Node context
async setup(browser) {
console.log('global setup hook', browser.capabilities)
},
// executed after all the individual component stories; runs in Node context
async teardown(browser) {
console.log('global teardown hook')
},
// executed before each individual component story; runs in Node context
async preRender(browser, context) {
// context is made of {id, name, title}
console.log('preRender', context.id);
},
// executed after each individual component story; runs in Node context
async postRender(browser, context) {
// context is made of {id, name, title}
console.log('postRender', context.id);
}
}
export const AnotherForm = Object.assign(() => <Form addTask={function(value) {
console.log('Add Task', value);
}} />, {
async preRender() {},
async postRender() {
console.log('after mount', window);
},
async play({canvasElement, args}) {
console.log('play function', args);
const root = within(canvasElement);
const input = root.getByTestId('new-todo-input');
fireEvent.change(input, {
target: {
value: 'another one bites the dust'
}
});
return {
fromPlay: input
}
},
test: async (browser, {component, result}) => {
console.log('Result from play', result)
await expect(component).to.be.visible;
await expect(component.find('input')).to.have.property('value').equal('another one bites the dust');
}
});
Loading static assets
When loading components in isolation, it's often needed to load additional static assets, such as CSS files, which contain styles used by the component.
Beside loading assets in the (JSX) test file directly, Nightwatch provides 2 ways to accomplish this:
- create a
nightwatch/index.jsx
file in the current project - create an entirely new test renderer file and use the
renderPage
option in the Vite plugin
Example project
We've put together a basic To-do app written in React and built on top of Vite which can be used as a boilerplate. It can be found at https://github.com/nightwatchjs-community/todo-react