React testing tools for tdd-buffet
This package can be used independently of
tdd-buffet
.
npm install @tdd-buffet/react
This package wraps the excellent @testing-library/react and adds jQuery for its powerful selection engine.
The following table illustrates the methods available in @testing-library/react
and their equivalents in this package:
@testing-library/react |
@tdd-buffet/react |
---|---|
render |
$render |
rerender |
$rerender |
unmount |
$unmount |
fireEvent.* |
$fireEvent.* |
fireEvent.click |
$click |
fireEvent.change |
$change |
fireEvent.submit |
$submit |
fireEvent.keyDown |
$keyDown |
waitFor |
$wait , $waitForElement |
queryBy |
$find |
ByText |
$*ByText |
ByTestId |
$*ByTestId |
prettyDOM |
$prettyDOM |
import React from 'react';
import { expect } from 'tdd-buffet/suite/chai';
import { $render } from '@tdd-buffet/react';
const $container = $render(<span>foobar</span>);
expect($container.text()).to.equal('foobar');
The returned $container
is a JQuery wrapper over the container that holds the component. You can use the familiar JQuery API to query for content ($container.find('p')
), get text content ($container.text()
), assert visibility ($container.find('.class').is(':visible')
) etc.
Since $render
returns a jQuery container you can use the $.find
method to query elements by any CSS selector (ID, class name, data-*
attribute etc.) or by jQuery's special selectors (:contains
, :checked
, :disabled
etc.).
import React from 'react';
import { $render } from '@tdd-buffet/react';
const $container = $render(<div>
<p>first paragraph</p>
<p>second paragraph</p>
</div>);
$container.find('p:second').text() === 'second paragraph';
There are also a few convenience query methods for finding elements by test ID ($getByTestId
, $getAllByTestId
, $queryByTestId
) and by text ($getByText
, $queryByText
).
import React from 'react';
import { $render, $getByText, $getByTestId } from '@tdd-buffet/react';
$render(<div>
<p>first paragraph</p>
<p data-testid="second">second paragraph</p>
</div>);
$getByText('first').text() === 'first paragraph';
$getByTestId('second').text() === 'second paragraph';
By default, all queries search throw the whole component that's currently rendered. You can override this by passing an optional selector to limit the search to e.g. a subtree of the component.
import React from 'react';
import { $render, $getByText, $getByTestId } from '@tdd-buffet/react';
$render(<div>
<div data-testid="foo">
<span>foo text</span>
</div>
<div data-testid="bar">
<span>bar text</span>
</div>
</div>);
console.log(
$getByText('text', $getByTestId('bar'))
); // 'bar text'
The package exposes the fireEvent
object from @testing-library/react wrapped in a helper that can take a DOM element, a CSS selector or a JQuery collection:
import React from 'react';
import { $render, $fireEvent } from '@tdd-buffet/react';
$render(<button onClick={() => console.log('clicked')}>
click me
</button>);
$fireEvent.click('button'); // will log 'clicked'
Some aliases are also exported for the most common events:
Simulate click events on buttons, checkboxes, radio buttons etc.
import React from 'react';
import { $render, $click } from '@tdd-buffet/react';
$render(<button onClick={() => console.log('clicked')}>
click me
</button>);
$click('button'); // will log 'clicked'
Simulate change events on inputs. Receives the text value as the 2nd argument.
import React from 'react';
import { $render, $change } from '@tdd-buffet/react';
$render(<input onChange={e => console.log(e.target.value)} />);
$change('input', 'foobar'); // will log 'foobar'
Simulate form submissions. Can be triggered on a form or on a linked button (either inside the form or linked via the form
attribute).
import React from 'react';
import { $render, $submit } from '@tdd-buffet/react';
$render(<form onSubmit={() => console.log('submit')}>
<button>Submit me</button>
</form>);
$submit('button'); // will log 'submit'
Simulate pressing down a key. Receives the key character as the 2nd argument.
import React from 'react';
import { $render, $keyDown } from '@tdd-buffet/react';
$render(<div onKeyDown={(e) => console.log(e.which)} />);
$keyDown('div', 'A'); // will log 65
If your component contains async logic like waiting for a promise or for a timer you can use the $wait
function to wait for a condition to be satisfied such as an element becoming visible.
import React, { useState } from 'react';
import { $render, $wait, $click } from '@tdd-buffet/react';
const MyComponent = () => {
const [isLoading, setIsLoading] = useState(true);
return <button onClick={() => setIsLoading(false)}>
{isLoading ? 'loading' : 'done'}
</button>;
};
$render(<MyComponent />);
$click('button');
await $wait($container => $container.text() === 'done');
The package exposes a shortcut to wait for the condition that an element is present in the container.
import React, { useState } from 'react';
import { $render, $waitForElement, $click } from '@tdd-buffet/react';
const MyComponent = () => {
const [isLoading, setIsLoading] = useState(true);
return <>
<button onClick={() => setIsLoading(false)}>Click me</button>
{!isLoading && <span className="present">I'm here</span>}
</>;
};
$render(<MyComponent />);
$click('button');
await $waitForElement($container => $container.find('.present'));
If your component has cleanup logic e.g. clearing timers in componentWillUnmount
you can check them in your tests by manually unmounting the component.
import React from 'react';
import { $render, $unmount } from '@tdd-buffet/react';
const $container = $render(<span>foobar</span>);
$unmount();
$container.text() === '';
Rerendering a component with new props can be useful if you want to check that it reacts to the new props e.g. getDerivedStateFromProps
.
import React from 'react';
import { $render, $rerender } from '@tdd-buffet/react';
$render(<span>foobar</span>);
$rerender(<span>potato</span>);
To help with debugging tests, you can use the $.html()
method to get the HTML content of an element. For large DOM trees the output could be hard to read, so you can use the $prettyDOM
helper instead to get a more readable representation. By default, it prints the currently rendered component's container, but you can pass a different element e.g. the result of $find
.
import { $render, $prettyDOM } from '@tdd-buffet/react';
import React from 'react';
$render(<div>foobar</div>);
console.log($prettyDOM());
// <div>
// foobar
// </div>