diff --git a/README.md b/README.md
index 586658ca5..02853eae3 100644
--- a/README.md
+++ b/README.md
@@ -139,6 +139,33 @@ Unmount the in-memory tree, triggering the appropriate lifecycle events
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).
+### `debug: (message?: string) => void`
+
+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.
+
+```jsx
+const { debug } = render();
+
+debug('optional message');
+```
+
+logs optional message and colored JSX:
+
+```jsx
+optional message
+
+
+ Press me
+
+```
+
+### `debug.shallow: (message?: string) => void`
+
+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.
+
### `toJSON: () => ?ReactTestRendererJSON`
Get the rendered component JSON representation, e.g. for snapshot testing.
diff --git a/src/__tests__/__snapshots__/render.test.js.snap b/src/__tests__/__snapshots__/render.test.js.snap
index 09bae7c49..63b4a8c3c 100644
--- a/src/__tests__/__snapshots__/render.test.js.snap
+++ b/src/__tests__/__snapshots__/render.test.js.snap
@@ -1,5 +1,143 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`debug 1`] = `
+"
+
+ Is the banana fresh?
+
+
+ not fresh
+
+
+
+ Change freshness!
+
+
+"
+`;
+
+exports[`debug changing component: bananaFresh button message should now be "fresh" 1`] = `
+"
+
+ Is the banana fresh?
+
+
+ fresh
+
+
+
+ Change freshness!
+
+
+"
+`;
+
+exports[`debug: shallow 1`] = `
+"
+
+ Is the banana fresh?
+
+
+ not fresh
+
+
+"
+`;
+
+exports[`debug: shallow with message 1`] = `
+"my other custom message
+
+
+
+ Is the banana fresh?
+
+
+ not fresh
+
+
+"
+`;
+
+exports[`debug: with message 1`] = `
+"my custom message
+
+
+
+ Is the banana fresh?
+
+
+ not fresh
+
+
+
+ Change freshness!
+
+
+"
+`;
+
exports[`toJSON 1`] = `
{text};
@@ -43,11 +44,11 @@ test('debug', () => {
debug(component, 'test message');
- expect(console.log).toBeCalledWith(output, 'test message');
+ expect(console.log).toBeCalledWith('test message\n\n', output);
});
test('debug.shallow', () => {
- expect(debug.shallow).toBe(debug);
+ expect(debug.shallow).toBe(debugShallow);
});
test('debug.deep', () => {
@@ -65,7 +66,7 @@ test('debug.deep', () => {
debug.deep(component, 'test message');
- expect(console.log).toBeCalledWith(output, 'test message');
+ expect(console.log).toBeCalledWith('test message\n\n', output);
});
test('debug.deep async test', async () => {
diff --git a/src/__tests__/render.test.js b/src/__tests__/render.test.js
index 91365fffe..73cf86f31 100644
--- a/src/__tests__/render.test.js
+++ b/src/__tests__/render.test.js
@@ -2,7 +2,8 @@
/* eslint-disable react/no-multi-comp */
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
-import { render } from '..';
+import stripAnsi from 'strip-ansi';
+import { render, fireEvent } from '..';
class Button extends React.Component<*> {
render() {
@@ -172,3 +173,43 @@ test('toJSON', () => {
expect(toJSON()).toMatchSnapshot();
});
+
+test('debug', () => {
+ jest.spyOn(console, 'log').mockImplementation(x => x);
+
+ const { debug } = render();
+
+ debug();
+ debug('my custom message');
+ debug.shallow();
+ debug.shallow('my other custom message');
+
+ // eslint-disable-next-line no-console
+ const mockCalls = console.log.mock.calls;
+
+ expect(stripAnsi(mockCalls[0][0])).toMatchSnapshot();
+ expect(stripAnsi(mockCalls[1][0] + mockCalls[1][1])).toMatchSnapshot(
+ 'with message'
+ );
+ expect(stripAnsi(mockCalls[2][0])).toMatchSnapshot('shallow');
+ expect(stripAnsi(mockCalls[3][0] + mockCalls[3][1])).toMatchSnapshot(
+ 'shallow with message'
+ );
+});
+
+test('debug changing component', () => {
+ jest.spyOn(console, 'log').mockImplementation(x => x);
+
+ const { getByProps, debug } = render();
+
+ fireEvent.press(getByProps({ type: 'primary' }));
+
+ debug();
+
+ // eslint-disable-next-line no-console
+ const mockCalls = console.log.mock.calls;
+
+ expect(stripAnsi(mockCalls[4][0])).toMatchSnapshot(
+ 'bananaFresh button message should now be "fresh"'
+ );
+});
diff --git a/src/debug.js b/src/debug.js
index 6aa050d49..0cd63a100 100644
--- a/src/debug.js
+++ b/src/debug.js
@@ -1,26 +1,15 @@
// @flow
/* eslint-disable no-console */
import * as React from 'react';
-import prettyFormat, { plugins } from 'pretty-format';
-import shallow from './shallow';
import render from './render';
-
-/**
- * Log pretty-printed shallow test component instance
- */
-function debugShallow(
- instance: ReactTestInstance | React.Element<*>,
- message?: any
-) {
- const { output } = shallow(instance);
-
- console.log(format(output), message || '');
-}
+import debugShallow from './helpers/debugShallow';
+import debugDeep from './helpers/debugDeep';
+import format from './helpers/format';
/**
* Log pretty-printed deep test component instance
*/
-function debugDeep(
+function debugDeepElementOrInstance(
instance: React.Element<*> | ?ReactTestRendererJSON,
message?: any = ''
) {
@@ -29,21 +18,22 @@ function debugDeep(
// rendering ?ReactTestRendererJSON
// $FlowFixMe
const { toJSON } = render(instance);
- console.log(format(toJSON()), message);
+ if (message) {
+ console.log(`${message}\n\n`, format(toJSON()));
+ } else {
+ console.log(format(toJSON()));
+ }
} catch (e) {
- console.log(format(instance), message);
+ // $FlowFixMe
+ debugDeep(instance);
}
}
-const format = input =>
- prettyFormat(input, {
- plugins: [plugins.ReactTestComponent, plugins.ReactElement],
- highlight: true,
- });
-
-const debug = debugShallow;
+function debug(instance: ReactTestInstance | React.Element<*>, message?: any) {
+ return debugShallow(instance, message);
+}
debug.shallow = debugShallow;
-debug.deep = debugDeep;
+debug.deep = debugDeepElementOrInstance;
export default debug;
diff --git a/src/helpers/debugDeep.js b/src/helpers/debugDeep.js
new file mode 100644
index 000000000..16d2e0eaf
--- /dev/null
+++ b/src/helpers/debugDeep.js
@@ -0,0 +1,16 @@
+// @flow
+import format from './format';
+
+/**
+ * Log pretty-printed deep test component instance
+ */
+export default function debugDeep(
+ instance: ?ReactTestRendererJSON,
+ message?: any = ''
+) {
+ if (message) {
+ console.log(`${message}\n\n`, format(instance));
+ } else {
+ console.log(format(instance));
+ }
+}
diff --git a/src/helpers/debugShallow.js b/src/helpers/debugShallow.js
new file mode 100644
index 000000000..1df224360
--- /dev/null
+++ b/src/helpers/debugShallow.js
@@ -0,0 +1,20 @@
+// @flow
+import * as React from 'react';
+import shallow from '../shallow';
+import format from './format';
+
+/**
+ * Log pretty-printed shallow test component instance
+ */
+export default function debugShallow(
+ instance: ReactTestInstance | React.Element<*>,
+ message?: any
+) {
+ const { output } = shallow(instance);
+
+ if (message) {
+ console.log(`${message}\n\n`, format(output));
+ } else {
+ console.log(format(output));
+ }
+}
diff --git a/src/helpers/format.js b/src/helpers/format.js
new file mode 100644
index 000000000..b295974ce
--- /dev/null
+++ b/src/helpers/format.js
@@ -0,0 +1,10 @@
+// @flow
+import prettyFormat, { plugins } from 'pretty-format';
+
+const format = (input: ?ReactTestRendererJSON) =>
+ prettyFormat(input, {
+ plugins: [plugins.ReactTestComponent, plugins.ReactElement],
+ highlight: true,
+ });
+
+export default format;
diff --git a/src/render.js b/src/render.js
index 10830dcdd..a953e90e0 100644
--- a/src/render.js
+++ b/src/render.js
@@ -3,6 +3,8 @@ import * as React from 'react';
import TestRenderer from 'react-test-renderer'; // eslint-disable-line import/no-extraneous-dependencies
import { getByAPI } from './helpers/getByAPI';
import { queryByAPI } from './helpers/queryByAPI';
+import debugShallow from './helpers/debugShallow';
+import debugDeep from './helpers/debugDeep';
/**
* Renders test component deeply using react-test-renderer and exposes helpers
@@ -21,5 +23,14 @@ export default function render(
update: renderer.update,
unmount: renderer.unmount,
toJSON: renderer.toJSON,
+ debug: debug(instance, renderer),
};
}
+
+function debug(instance: ReactTestInstance, renderer) {
+ function debugImpl(message?: string) {
+ return debugDeep(renderer.toJSON(), message);
+ }
+ debugImpl.shallow = message => debugShallow(instance, message);
+ return debugImpl;
+}
diff --git a/typings/__tests__/index.test.tsx b/typings/__tests__/index.test.tsx
index 7446554d1..5e0b70147 100644
--- a/typings/__tests__/index.test.tsx
+++ b/typings/__tests__/index.test.tsx
@@ -63,6 +63,8 @@ const queryAllByTextRegExp: Array = tree.queryAllByText(
const queryAllByProps: Array = tree.getAllByProps({
value: 2,
});
+const debugFn = tree.debug()
+const debugFnWithMessage = tree.debug('my message')
tree.update();
tree.unmount();
diff --git a/typings/index.d.ts b/typings/index.d.ts
index 15b2d02d4..d4c0f0f9d 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -31,6 +31,7 @@ export interface RenderAPI extends GetByAPI, QueryByAPI {
update(nextElement: React.ReactElement): void;
unmount(nextElement?: React.ReactElement): void;
toJSON(): ReactTestRendererJSON | null;
+ debug(message?: string): void;
}
export type FireEventFunction = (