Skip to content

Commit 22aa072

Browse files
authored
Merge pull request #53 from hypothesis/mount-utils
Add utilities for mounting and un-mounting components
2 parents ba7bdd2 + 0b51eb0 commit 22aa072

File tree

4 files changed

+87
-2
lines changed

4 files changed

+87
-2
lines changed

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
This package contains common utilities for testing UI components across
44
Hypothesis frontend projects. It includes tools for:
55

6+
- Rendering UI components and unmounting them once the test ends
67
- Waiting for conditions to be met
78
- Mocking UI components
89
- Testing accessibility using [axe-core](https://github.com/dequelabs/axe-core)
@@ -14,3 +15,36 @@ standard UI and UI testing stack, built on:
1415
- [Enzyme](https://github.com/enzymejs/enzyme)
1516
- [babel-plugin-mockable-imports](https://github.com/robertknight/babel-plugin-mockable-imports)
1617

18+
## API guide
19+
20+
### Rendering components
21+
22+
This package exports a wrapper around Enzyme's `mount` function to render
23+
a component, query its output and interact with it. The function in this
24+
package adds the wrapper to a global list of active wrappers which can then
25+
be conveniently unmounted using `unmountAll` at the end of a test.
26+
27+
```js
28+
import { mount, unmountAll } from '@hypothesis/frontend-testing';
29+
30+
describe('MyWidget', () => {
31+
afterEach(() => {
32+
// Clean up by unmounting any wrappers mounted in the current test and
33+
// removing associated DOM containers.
34+
unmountAll();
35+
});
36+
37+
it('should render', () => {
38+
const wrapper = mount(<MyWidget/>);
39+
40+
// Query component content etc.
41+
});
42+
43+
it('should do something that requires component to be connected', () => {
44+
const wrapper = mount(<MyWidget/>, { connected: true });
45+
46+
// Test behavior that relies on rendered component being part of the
47+
// DOM tree under `document.body`.
48+
});
49+
});
50+
```

src/enzyme.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
declare module 'enzyme' {
55
export class ReactWrapper {
66
getDOMNode(): HTMLElement;
7+
unmount(): void;
78
}
89

910
export function mount(
1011
elementOrWrapper: VNode | ReactWrapper,
11-
{ attachTo: HTMLElement },
12-
);
12+
options?: { attachTo?: HTMLElement },
13+
): ReactWrapper;
1314
}

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
export type { Scenario } from './accessibility.js';
22
export { checkAccessibility } from './accessibility.js';
33
export { mockImportedComponents } from './mock-imported-components.js';
4+
export { mount, unmountAll } from './mount.js';
5+
export type { MountOptions } from './mount.js';
46
export type { TestTimeout, TimeoutSpec } from './wait.js';
57
export { delay, waitFor, waitForElement } from './wait.js';

src/mount.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import * as enzyme from 'enzyme';
2+
import type { ReactWrapper } from 'enzyme';
3+
import type { VNode } from 'preact';
4+
5+
let containers: HTMLElement[] = [];
6+
let wrappers: ReactWrapper[] = [];
7+
8+
export type MountOptions = {
9+
/**
10+
* If true, the element will be rendered in a container element which is
11+
* attached to `document.body`.
12+
*/
13+
connected?: boolean;
14+
};
15+
16+
/**
17+
* Render a Preact component using Enzyme and return a wrapper.
18+
*
19+
* The component can be unmounted by calling `wrapper.unmount()` or by calling
20+
* {@link unmountAll} at the end of the test.
21+
*/
22+
export function mount(jsx: VNode, { connected = false }: MountOptions = {}) {
23+
let wrapper;
24+
if (connected) {
25+
const container = document.createElement('div');
26+
container.setAttribute('data-enzyme-container', '');
27+
containers.push(container);
28+
wrapper = enzyme.mount(jsx, { attachTo: container });
29+
} else {
30+
wrapper = enzyme.mount(jsx);
31+
}
32+
33+
wrappers.push(wrapper);
34+
35+
return wrapper;
36+
}
37+
38+
/**
39+
* Unmount all Preact components rendered using {@link mount} and remove their
40+
* parent container elements (if any) from the DOM.
41+
*/
42+
export function unmountAll() {
43+
wrappers.forEach(w => w.unmount());
44+
wrappers = [];
45+
46+
containers.forEach(c => c.remove());
47+
containers = [];
48+
}

0 commit comments

Comments
 (0)