Skip to content

Commit f6f0a70

Browse files
OzzieOrcathymikee
authored andcommitted
feat: Add wrapper option to render (#173)
* Add wrapper option to render * Update TS types and call updateWithAct only once * wrapUiIfNeeded -> wrap * reindent snapshots * adjustments * change name
1 parent f635c85 commit f6f0a70

File tree

4 files changed

+80
-11
lines changed

4 files changed

+80
-11
lines changed

docs/API.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Defined as:
1515
function render(
1616
component: React.Element<any>,
1717
options?: {
18+
/* A React Component that renders `component` as children */
19+
wrapper?: React.ComponentType<any>,
1820
/* You won't often use this, but it's helpful when testing refs */
1921
createNodeMock: (element: React.Element<any>) => any,
2022
}

src/__tests__/render.test.js

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
// @flow
22
/* eslint-disable react/no-multi-comp */
33
import React from 'react';
4-
import { View, Text, TextInput, TouchableOpacity } from 'react-native';
4+
import {
5+
View,
6+
Text,
7+
TextInput,
8+
TouchableOpacity,
9+
SafeAreaView,
10+
} from 'react-native';
511
import stripAnsi from 'strip-ansi';
612
import { render, fireEvent } from '..';
713

@@ -291,3 +297,50 @@ test('debug changing component', () => {
291297
'bananaFresh button message should now be "fresh"'
292298
);
293299
});
300+
301+
test('renders options.wrapper around node', () => {
302+
const WrapperComponent = ({ children }) => (
303+
<SafeAreaView testID="wrapper">{children}</SafeAreaView>
304+
);
305+
306+
const { toJSON, getByTestId } = render(<View testID="inner" />, {
307+
wrapper: WrapperComponent,
308+
});
309+
310+
expect(getByTestId('wrapper')).toBeTruthy();
311+
expect(toJSON()).toMatchInlineSnapshot(`
312+
<RCTSafeAreaView
313+
emulateUnlessSupported={true}
314+
testID="wrapper"
315+
>
316+
<View
317+
testID="inner"
318+
/>
319+
</RCTSafeAreaView>
320+
`);
321+
});
322+
323+
test('renders options.wrapper around updated node', () => {
324+
const WrapperComponent = ({ children }) => (
325+
<SafeAreaView testID="wrapper">{children}</SafeAreaView>
326+
);
327+
328+
const { toJSON, getByTestId, rerender } = render(<View testID="inner" />, {
329+
wrapper: WrapperComponent,
330+
});
331+
332+
rerender(<View testID="inner" accessibilityLabel="test" />);
333+
334+
expect(getByTestId('wrapper')).toBeTruthy();
335+
expect(toJSON()).toMatchInlineSnapshot(`
336+
<RCTSafeAreaView
337+
emulateUnlessSupported={true}
338+
testID="wrapper"
339+
>
340+
<View
341+
accessibilityLabel="test"
342+
testID="inner"
343+
/>
344+
</RCTSafeAreaView>
345+
`);
346+
});

src/render.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,37 @@ import debugShallow from './helpers/debugShallow';
99
import debugDeep from './helpers/debugDeep';
1010

1111
type Options = {
12+
wrapper?: React.ComponentType<any>,
13+
createNodeMock?: (element: React.Element<any>) => any,
14+
};
15+
type TestRendererOptions = {
1216
createNodeMock: (element: React.Element<any>) => any,
1317
};
1418

1519
/**
1620
* Renders test component deeply using react-test-renderer and exposes helpers
1721
* to assert on the output.
1822
*/
19-
export default function render(
20-
component: React.Element<any>,
21-
options?: Options
23+
export default function render<T>(
24+
component: React.Element<T>,
25+
{ wrapper: Wrapper, createNodeMock }: Options = {}
2226
) {
23-
const renderer = renderWithAct(component, options);
27+
const wrap = (innerElement: React.Element<any>) =>
28+
Wrapper ? <Wrapper>{innerElement}</Wrapper> : innerElement;
2429

30+
const renderer = renderWithAct(
31+
wrap(component),
32+
createNodeMock ? { createNodeMock } : undefined
33+
);
34+
const update = updateWithAct(renderer, wrap);
2535
const instance = renderer.root;
2636

2737
return {
2838
...getByAPI(instance),
2939
...queryByAPI(instance),
3040
...a11yAPI(instance),
31-
update: updateWithAct(renderer),
32-
rerender: updateWithAct(renderer), // alias for `update`
41+
update,
42+
rerender: update, // alias for `update`
3343
unmount: renderer.unmount,
3444
toJSON: renderer.toJSON,
3545
debug: debug(instance, renderer),
@@ -38,7 +48,7 @@ export default function render(
3848

3949
function renderWithAct(
4050
component: React.Element<any>,
41-
options?: Options
51+
options?: TestRendererOptions
4252
): ReactTestRenderer {
4353
let renderer: ReactTestRenderer;
4454

@@ -49,10 +59,13 @@ function renderWithAct(
4959
return ((renderer: any): ReactTestRenderer);
5060
}
5161

52-
function updateWithAct(renderer: ReactTestRenderer) {
62+
function updateWithAct(
63+
renderer: ReactTestRenderer,
64+
wrap: (innerElement: React.Element<any>) => React.Element<any>
65+
) {
5366
return function(component: React.Element<any>) {
5467
act(() => {
55-
renderer.update(component);
68+
renderer.update(wrap(component));
5669
});
5770
};
5871
}

typings/index.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ export interface Thenable {
7474
}
7575

7676
export interface RenderOptions {
77-
createNodeMock: (element: React.ReactElement<any>) => any;
77+
wrapper?: React.ComponentType<any>;
78+
createNodeMock?: (element: React.ReactElement<any>) => any;
7879
}
7980

8081
export interface RenderAPI extends GetByAPI, QueryByAPI, A11yAPI {

0 commit comments

Comments
 (0)