hypothesis / hypothesis/frontend-testing
Test API usability improvements
- Dominant language
- TypeScript
- Stars
- 1
- Forks
- 3
- PR merge metrics
- No merged PRs in 30d
Description
This issue tracks a few ideas for improving the APIs we use for writing tests. This means reducing the amount of code needed for common uses, eliminating pitfalls etc.
This issue is a place to brainstorm. Separate issues can be created to flesh ideas out more fully. Some of these issues are also really about the underlying libraries, so the issues need to be created downstream.
## `waitFor` method on wrappers
A common action is to trigger an async operation in a test, then wait for the UI to change in some way.
This is currently handled via a `waitForElement` function, but it would be useful if it was an operation on the wrapper.
Current:
```js
import { mount, waitForElement } from '@hypothesis/frontend-testing';
...
const wrapper = mount();
const items = waitForElement(wrapper, 'ul[data-testid="item-list"]');
```
Proposed:
```js
import { mount } from '@hypothesis/frontend-testing';
...
const wrapper = mount();
const items = await wrapper.waitFor('ul[data-testid="item-list"]');
```
## Clarify or simplify use of `act` and `wrapper.update()`
It is often not intuitive when `act` and `wrapper.update()` are required. It would make writing tests easier if there was at least good documentation, or perhaps better yet changes that could be made to reduce how often this is needed.
- The `act` function runs a callback and then repeatedly flushes effects and state updates, until a flush triggers no further updates
- `wrapper.update()` synchronizes the Enzyme wrapper's snapshot of the rendered output to match the current output
A common pattern of usage is:
```js
act(() => {
wrapper.find('SomeChild').prop('onClick')();
});
wrapper.update();
```
Here the `act` callback ensures that state updates and effects triggered by `onClick` are flushed, then `wrapper.update` ensures that subsequent queries on `wrapper` reflect the current UI.
Often it is possible to omit the use of `act` if the `onClick` handler triggers state updates but no effects. This is because the `wrapper.update()` call will implicitly flush any pending state updates. Internally `wrapper.update()` calls the Enzyme adapater's `getNode` method and the `MountRenderer.getNode` implementation in `enzyme-adapter-preact-pure` calls `flushRenders` first.
## Inspecting updates to child components
Another common sequence looks like:
```js
// Get child and trigger an update
let child = wrapper.find('SomeWidget');
assert.equal(child.prop('value'), 'Original value');
act(() => {
child.prop('onChange')('Updated value');
}); // nb. The `act` can often be omitted. See above.
// Refresh the parent component and re-find the child.
wrapper.update();
child = wrapper.find('SomeWidget');
assert.equal(child.prop('value'), 'Updated value');
```
Re-finding the child is necessary because the original `child` value was a snapshot from the initial render that doesn't change after refreshing the root `wrapper`. It would be more ergonomic if the above could be written as:
```js
const child = wrapper.find('SomeWidget');
assert.equal(child.prop('value'), 'Original value');
child.prop('onChange')('Updated value');
assert.equal(child.prop('value'), 'Updated value');
```
## Built-in `data-testid` support
We extensively use the pattern of adding a `data-testid` attribute to DOM elements and components, then use an attribute selector to find those in tests. This pattern is taken from Testing Library. eg.
```js
wrapper.find('button[data-testid="foo-button"]')
```
These selectors are a bit awkward to write, especially if `foo-button` is partly dynamic. It would be useful to have some built-in support for them. A complication is that the `data-testid` value is often not enough on its own, because that attribute might be passed down multiple elements. eg. `...` will render both a `Button` and `button` with `data-testid` props.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.