feat: add debug.deep and debug.shallow (#37)

<!-- Please provide enough information so that others can review your pull request. -->
<!-- Keep pull requests small and focused on a single change. -->

### Summary

Adds API proposed by https://github.com/callstack/react-native-testing-library/pull/33#issuecomment-430302079.
Also component output is now highlighted:

<img width="259" alt="screenshot 2018-10-16 at 19 33 25" src="https://user-images.githubusercontent.com/5106466/47035614-c10efb80-d17a-11e8-99ac-00f648880008.png">


### Test plan

Added tests for `debug`.
This commit is contained in:
Michał Pierzchała
2018-10-16 21:45:56 +02:00
committed by GitHub
parent 03e2c4b0f2
commit 05db7bcaac
8 changed files with 190 additions and 9 deletions
+44 -4
View File
@@ -273,12 +273,52 @@ Log prettified shallowly rendered component or test instance (just like snapshot
import { debug } from 'react-native-testing-library';
debug(<Component />);
// console.log:
// <View>
// <Text>Component</Text>
// </View>
debug.shallow(<Component />); // an alias for `debug`
```
logs:
```jsx
<TouchableOpacity
activeOpacity={0.2}
onPress={[Function bound fn]}
>
<TextComponent
text="Press me"
/>
</TouchableOpacity>
```
There's also `debug.deep` that renders deeply to stdout.
```jsx
import { debug } from 'react-native-testing-library';
debug.deep(<Component />);
```
logs:
```jsx
<View
accessible={true}
isTVSelectable={true}
onResponderGrant={[Function bound touchableHandleResponderGrant]}
// ... more props
style={
Object {
\\"opacity\\": 1,
}
}
>
<Text>
Press me
</Text>
</View>
```
Optionally you can provide a string message as a second argument to `debug`, which will be displayed right after the component.
## `flushMicrotasksQueue`
Wait for microtasks queue to flush. Useful if you want to wait for some promises with `async/await`.
+1
View File
@@ -24,6 +24,7 @@
"react": "16.6.0-alpha.8af6728",
"react-native": "^0.57.3",
"react-test-renderer": "16.6.0-alpha.8af6728",
"strip-ansi": "^5.0.0",
"typescript": "^3.1.1"
},
"peerDependencies": {
@@ -0,0 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`debug 1`] = `
"<TouchableOpacity
activeOpacity={0.2}
onPress={[Function bound fn]}
>
<TextComponent
text=\\"Press me\\"
/>
</TouchableOpacity>"
`;
exports[`debug.deep 1`] = `
"<View
accessible={true}
isTVSelectable={true}
onResponderGrant={[Function bound touchableHandleResponderGrant]}
onResponderMove={[Function bound touchableHandleResponderMove]}
onResponderRelease={[Function bound touchableHandleResponderRelease]}
onResponderTerminate={[Function bound touchableHandleResponderTerminate]}
onResponderTerminationRequest={[Function bound touchableHandleResponderTerminationRequest]}
onStartShouldSetResponder={[Function bound touchableHandleStartShouldSetResponder]}
style={
Object {
\\"opacity\\": 1,
}
}
>
<Text>
Press me
</Text>
</View>"
`;
+60
View File
@@ -0,0 +1,60 @@
// @flow
/* eslint-disable no-console */
import React from 'react';
import { TouchableOpacity, Text } from 'react-native';
import stripAnsi from 'strip-ansi';
import { debug } from '..';
function TextComponent({ text }) {
return <Text>{text}</Text>;
}
class Button extends React.Component<*> {
render() {
return (
<TouchableOpacity onPress={this.props.onPress}>
<TextComponent text={this.props.text} />
</TouchableOpacity>
);
}
}
test('debug', () => {
// $FlowFixMe
console.log = jest.fn();
const component = <Button onPress={jest.fn} text="Press me" />;
debug(component);
const output = console.log.mock.calls[0][0];
expect(stripAnsi(output)).not.toEqual(output);
expect(stripAnsi(output)).toMatchSnapshot();
console.log.mockReset();
debug(component, 'test message');
expect(console.log).toBeCalledWith(output, 'test message');
});
test('debug.shallow', () => {
expect(debug.shallow).toBe(debug);
});
test('debug.deep', () => {
// $FlowFixMe
console.log = jest.fn();
const component = <Button onPress={jest.fn} text="Press me" />;
debug.deep(component);
const output = console.log.mock.calls[0][0];
expect(stripAnsi(output)).not.toEqual(output);
expect(stripAnsi(output)).toMatchSnapshot();
console.log.mockReset();
debug.deep(component, 'test message');
expect(console.log).toBeCalledWith(output, 'test message');
});
+21 -2
View File
@@ -1,21 +1,40 @@
// @flow
/* eslint-disable no-console */
import * as React from 'react';
import prettyFormat, { plugins } from 'pretty-format'; // eslint-disable-line import/no-extraneous-dependencies
import shallow from './shallow';
import render from './render';
/**
* Log pretty-printed shallow test component instance
*/
export default function debug(
function debugShallow(
instance: ReactTestInstance | React.Element<*>,
message?: any
) {
const { output } = shallow(instance);
// eslint-disable-next-line no-console
console.log(format(output), message || '');
}
/**
* Log pretty-printed deep test component instance
*/
function debugDeep(instance: React.Element<*>, message?: any) {
const { toJSON } = render(instance);
console.log(format(toJSON()), message || '');
}
const format = input =>
prettyFormat(input, {
plugins: [plugins.ReactTestComponent, plugins.ReactElement],
highlight: true,
});
const debug = debugShallow;
debug.shallow = debugShallow;
debug.deep = debugDeep;
export default debug;
+7
View File
@@ -81,8 +81,15 @@ const shallowTree: { output: React.ReactElement<any> } = shallow(
const waitForFlush: Promise<any> = flushMicrotasksQueue();
// debug API
debug(<TestComponent />);
debug(<TestComponent />, 'message');
debug(getByNameString);
debug(getByNameString, 'message');
debug.shallow(<TestComponent />);
debug.shallow(<TestComponent />, 'message');
debug.deep(<TestComponent />);
debug.deep(<TestComponent />, 'message');
const waitBy: Promise<ReactTestInstance> = waitForElement<ReactTestInstance>(
() => tree.getByName('View')
+11 -3
View File
@@ -51,6 +51,16 @@ export type WaitForElementFunction = <T = any>(
interval?: number
) => Promise<T>;
export type DebugFunction = (
instance: ReactTestInstance | React.ReactElement<any>,
message?: string
) => void;
export type DebugAPI = DebugFunction & {
shallow: DebugFunction;
deep: (instance: React.ReactElement<any>, message?: string) => void;
};
export declare const render: (
component: React.ReactElement<any>,
options?: RenderOptions
@@ -59,8 +69,6 @@ export declare const shallow: <P = {}>(
instance: ReactTestInstance | React.ReactElement<P>
) => { output: React.ReactElement<P> };
export declare const flushMicrotasksQueue: () => Promise<any>;
export declare const debug: (
instance: ReactTestInstance | React.ReactElement<any>
) => void;
export declare const debug: DebugAPI;
export declare const fireEvent: FireEventAPI;
export declare const waitForElement: WaitForElementFunction;
+12
View File
@@ -842,6 +842,11 @@ ansi-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
ansi-regex@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9"
integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
@@ -6275,6 +6280,13 @@ strip-ansi@^4.0.0:
dependencies:
ansi-regex "^3.0.0"
strip-ansi@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f"
integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==
dependencies:
ansi-regex "^4.0.0"
strip-bom@3.0.0, strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"