Skip to content

Commit c47693e

Browse files
committed
feat: add debug to render helpers for easier console debugging
1 parent 235942b commit c47693e

File tree

6 files changed

+236
-10
lines changed

6 files changed

+236
-10
lines changed

README.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,32 @@ Unmount the in-memory tree, triggering the appropriate lifecycle events
139139

140140
When using React context providers, like Redux Provider, you'll likely want to wrap rendered component with them. In such cases it's convenient to create your custom `render` method. [Follow this great guide on how to set this up](https://github.com/kentcdodds/react-testing-library#custom-render).
141141

142-
### `toJSON: () => ?ReactTestRendererJSON`
142+
### `debug: (message?: string) => void`
143143

144-
Get the rendered component JSON representation, e.g. for snapshot testing.
144+
Prints deeply rendered component passed to `render` with optional message on top. Uses [debug.deep](#debug) under the hood, but it's easier to use.
145+
146+
```jsx
147+
const { debug } = render(<Component />);
148+
149+
debug('optional message');
150+
```
151+
152+
logs optional message and colored JSX:
153+
154+
```jsx
155+
optional message
156+
157+
<TouchableOpacity
158+
activeOpacity={0.2}
159+
onPress={[Function bound fn]}
160+
>
161+
<Text>Press me</Text>
162+
</TouchableOpacity>
163+
```
164+
165+
### `debug.shallow: (message?: string) => void`
166+
167+
Prints shallowly rendered component passed to `render` with optional message on top. Uses [debug.shallow](#debug) under the hood, but it's easier to use.
145168

146169
## `shallow`
147170

src/__tests__/__snapshots__/render.test.js.snap

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,143 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`debug 1`] = `
4+
"<View>
5+
<Text>
6+
Is the banana fresh?
7+
</Text>
8+
<Text
9+
testID=\\"bananaFresh\\"
10+
>
11+
not fresh
12+
</Text>
13+
<View
14+
accessible={true}
15+
isTVSelectable={true}
16+
onResponderGrant={[Function bound touchableHandleResponderGrant]}
17+
onResponderMove={[Function bound touchableHandleResponderMove]}
18+
onResponderRelease={[Function bound touchableHandleResponderRelease]}
19+
onResponderTerminate={[Function bound touchableHandleResponderTerminate]}
20+
onResponderTerminationRequest={[Function bound touchableHandleResponderTerminationRequest]}
21+
onStartShouldSetResponder={[Function bound touchableHandleStartShouldSetResponder]}
22+
style={
23+
Object {
24+
\\"opacity\\": 1,
25+
}
26+
}
27+
>
28+
<Text>
29+
Change freshness!
30+
</Text>
31+
</View>
32+
</View>"
33+
`;
34+
35+
exports[`debug changing component: bananaFresh button message should now be "fresh" 1`] = `
36+
"<View>
37+
<Text>
38+
Is the banana fresh?
39+
</Text>
40+
<Text
41+
testID=\\"bananaFresh\\"
42+
>
43+
fresh
44+
</Text>
45+
<View
46+
accessible={true}
47+
isTVSelectable={true}
48+
onResponderGrant={[Function bound touchableHandleResponderGrant]}
49+
onResponderMove={[Function bound touchableHandleResponderMove]}
50+
onResponderRelease={[Function bound touchableHandleResponderRelease]}
51+
onResponderTerminate={[Function bound touchableHandleResponderTerminate]}
52+
onResponderTerminationRequest={[Function bound touchableHandleResponderTerminationRequest]}
53+
onStartShouldSetResponder={[Function bound touchableHandleStartShouldSetResponder]}
54+
style={
55+
Object {
56+
\\"opacity\\": 1,
57+
}
58+
}
59+
>
60+
<Text>
61+
Change freshness!
62+
</Text>
63+
</View>
64+
</View>"
65+
`;
66+
67+
exports[`debug: shallow 1`] = `
68+
"<View>
69+
<Text>
70+
Is the banana fresh?
71+
</Text>
72+
<Text
73+
testID=\\"bananaFresh\\"
74+
>
75+
not fresh
76+
</Text>
77+
<Button
78+
onPress={[Function anonymous]}
79+
type=\\"primary\\"
80+
>
81+
Change freshness!
82+
</Button>
83+
</View>"
84+
`;
85+
86+
exports[`debug: shallow with message 1`] = `
87+
"my other custom message
88+
89+
<View>
90+
<Text>
91+
Is the banana fresh?
92+
</Text>
93+
<Text
94+
testID=\\"bananaFresh\\"
95+
>
96+
not fresh
97+
</Text>
98+
<Button
99+
onPress={[Function anonymous]}
100+
type=\\"primary\\"
101+
>
102+
Change freshness!
103+
</Button>
104+
</View>"
105+
`;
106+
107+
exports[`debug: with message 1`] = `
108+
"my custom message
109+
110+
<View>
111+
<Text>
112+
Is the banana fresh?
113+
</Text>
114+
<Text
115+
testID=\\"bananaFresh\\"
116+
>
117+
not fresh
118+
</Text>
119+
<View
120+
accessible={true}
121+
isTVSelectable={true}
122+
onResponderGrant={[Function bound touchableHandleResponderGrant]}
123+
onResponderMove={[Function bound touchableHandleResponderMove]}
124+
onResponderRelease={[Function bound touchableHandleResponderRelease]}
125+
onResponderTerminate={[Function bound touchableHandleResponderTerminate]}
126+
onResponderTerminationRequest={[Function bound touchableHandleResponderTerminationRequest]}
127+
onStartShouldSetResponder={[Function bound touchableHandleStartShouldSetResponder]}
128+
style={
129+
Object {
130+
\\"opacity\\": 1,
131+
}
132+
}
133+
>
134+
<Text>
135+
Change freshness!
136+
</Text>
137+
</View>
138+
</View>"
139+
`;
140+
3141
exports[`toJSON 1`] = `
4142
<View
5143
accessible={true}

src/__tests__/debug.test.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ test('debug', () => {
4343

4444
debug(component, 'test message');
4545

46-
expect(console.log).toBeCalledWith(output, 'test message');
46+
expect(console.log).toBeCalledWith('test message\n\n', output);
4747
});
4848

4949
test('debug.shallow', () => {
@@ -56,7 +56,8 @@ test('debug.deep', () => {
5656
const component = <Button onPress={jest.fn} text="Press me" />;
5757
debug.deep(component);
5858

59-
const output = console.log.mock.calls[0][0];
59+
const mockCalls = console.log.mock.calls;
60+
const output = mockCalls[0][0];
6061

6162
expect(stripAnsi(output)).not.toEqual(output);
6263
expect(stripAnsi(output)).toMatchSnapshot();
@@ -65,7 +66,7 @@ test('debug.deep', () => {
6566

6667
debug.deep(component, 'test message');
6768

68-
expect(console.log).toBeCalledWith(output, 'test message');
69+
expect(console.log).toBeCalledWith('test message\n\n', output);
6970
});
7071

7172
test('debug.deep async test', async () => {
@@ -80,7 +81,8 @@ test('debug.deep async test', async () => {
8081

8182
debug.deep(toJSON());
8283

83-
const output = console.log.mock.calls[0][0];
84+
const mockCalls = console.log.mock.calls;
85+
const output = mockCalls[0][0];
8486

8587
expect(stripAnsi(output)).toMatchSnapshot();
8688
});

src/__tests__/render.test.js

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
/* eslint-disable react/no-multi-comp */
33
import React from 'react';
44
import { View, Text, TouchableOpacity } from 'react-native';
5-
import { render } from '..';
5+
import stripAnsi from 'strip-ansi';
6+
import { render, fireEvent } from '..';
67

78
class Button extends React.Component<*> {
89
render() {
@@ -172,3 +173,43 @@ test('toJSON', () => {
172173

173174
expect(toJSON()).toMatchSnapshot();
174175
});
176+
177+
test('debug', () => {
178+
jest.spyOn(console, 'log').mockImplementation(x => x);
179+
180+
const { debug } = render(<Banana />);
181+
182+
debug();
183+
debug('my custom message');
184+
debug.shallow();
185+
debug.shallow('my other custom message');
186+
187+
// eslint-disable-next-line no-console
188+
const mockCalls = console.log.mock.calls;
189+
190+
expect(stripAnsi(mockCalls[0][0])).toMatchSnapshot();
191+
expect(stripAnsi(mockCalls[1][0] + mockCalls[1][1])).toMatchSnapshot(
192+
'with message'
193+
);
194+
expect(stripAnsi(mockCalls[2][0])).toMatchSnapshot('shallow');
195+
expect(stripAnsi(mockCalls[3][0] + mockCalls[3][1])).toMatchSnapshot(
196+
'shallow with message'
197+
);
198+
});
199+
200+
test('debug changing component', () => {
201+
jest.spyOn(console, 'log').mockImplementation(x => x);
202+
203+
const { getByProps, debug } = render(<Banana />);
204+
205+
fireEvent.press(getByProps({ type: 'primary' }));
206+
207+
debug();
208+
209+
// eslint-disable-next-line no-console
210+
const mockCalls = console.log.mock.calls;
211+
212+
expect(stripAnsi(mockCalls[4][0])).toMatchSnapshot(
213+
'bananaFresh button message should now be "fresh"'
214+
);
215+
});

src/debug.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ function debugShallow(
1414
) {
1515
const { output } = shallow(instance);
1616

17-
console.log(format(output), message || '');
17+
if (message) {
18+
console.log(`${message}\n\n`, format(output));
19+
} else {
20+
console.log(format(output));
21+
}
1822
}
1923

2024
/**
@@ -29,9 +33,17 @@ function debugDeep(
2933
// rendering ?ReactTestRendererJSON
3034
// $FlowFixMe
3135
const { toJSON } = render(instance);
32-
console.log(format(toJSON()), message);
36+
if (message) {
37+
console.log(`${message}\n\n`, format(toJSON()));
38+
} else {
39+
console.log(format(toJSON()));
40+
}
3341
} catch (e) {
34-
console.log(format(instance), message);
42+
if (message) {
43+
console.log(`${message}\n\n`, format(instance));
44+
} else {
45+
console.log(format(instance));
46+
}
3547
}
3648
}
3749

src/render.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as React from 'react';
33
import TestRenderer from 'react-test-renderer'; // eslint-disable-line import/no-extraneous-dependencies
44
import { getByAPI } from './helpers/getByAPI';
55
import { queryByAPI } from './helpers/queryByAPI';
6+
import debug from './debug';
67

78
/**
89
* Renders test component deeply using react-test-renderer and exposes helpers
@@ -21,5 +22,14 @@ export default function render(
2122
update: renderer.update,
2223
unmount: renderer.unmount,
2324
toJSON: renderer.toJSON,
25+
debug: renderDebug(instance, renderer),
2426
};
2527
}
28+
29+
function renderDebug(instance: ReactTestInstance, renderer) {
30+
function renderDebugImpl(message?: string) {
31+
return debug.deep(renderer.toJSON(), message);
32+
}
33+
renderDebugImpl.shallow = message => debug.shallow(instance, message);
34+
return renderDebugImpl;
35+
}

0 commit comments

Comments
 (0)