diff --git a/.vscode/settings.json b/.vscode/settings.json
index 09b7f95be..2be7fa331 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,11 @@
{
- "cSpell.words": ["labelledby", "Pressable", "RNTL", "Uncapitalize", "valuenow", "valuetext"]
+ "cSpell.words": [
+ "labelledby",
+ "Pressable",
+ "redent",
+ "RNTL",
+ "Uncapitalize",
+ "valuenow",
+ "valuetext"
+ ]
}
diff --git a/src/__tests__/__snapshots__/render-debug.test.tsx.snap b/src/__tests__/__snapshots__/render-debug.test.tsx.snap
index 9d9fdab06..6618efcba 100644
--- a/src/__tests__/__snapshots__/render-debug.test.tsx.snap
+++ b/src/__tests__/__snapshots__/render-debug.test.tsx.snap
@@ -29,35 +29,7 @@ exports[`debug 1`] = `
value=""
/>
@@ -242,54 +214,8 @@ exports[`debug with only prop whose value is bananaChef 1`] = `
"
`;
-exports[`debug with only props from TextInput components 1`] = `
+exports[`debug: All Props 1`] = `
"
-
- Is the banana fresh?
-
-
- not fresh
-
-
-
-
-
-
-
- Change freshness!
-
-
-
- First Text
-
-
- Second Text
-
-
- 0
-
-"
-`;
-
-exports[`debug: another custom message 1`] = `
-"another custom message
-
-
-
Is the banana fresh?
@@ -365,11 +291,12 @@ exports[`debug: another custom message 1`] = `
0
-"
+
+undefined"
`;
-exports[`debug: with message 1`] = `
-"my custom message
+exports[`debug: Option message 1`] = `
+"another custom message
@@ -400,35 +327,7 @@ exports[`debug: with message 1`] = `
value=""
/>
diff --git a/src/__tests__/render-debug.test.tsx b/src/__tests__/render-debug.test.tsx
index eb65c9ad4..aaa4ee8da 100644
--- a/src/__tests__/render-debug.test.tsx
+++ b/src/__tests__/render-debug.test.tsx
@@ -93,27 +93,20 @@ test('debug', () => {
render();
screen.debug();
- screen.debug('my custom message');
screen.debug({ message: 'another custom message' });
+ screen.debug({ mapProps: null });
const mockCalls = jest.mocked(logger.info).mock.calls;
expect(mockCalls[0][0]).toMatchSnapshot();
- expect(`${mockCalls[1][0]}\n${mockCalls[1][1]}`).toMatchSnapshot('with message');
- expect(`${mockCalls[2][0]}\n${mockCalls[2][1]}`).toMatchSnapshot('another custom message');
-
- const mockWarnCalls = jest.mocked(logger.warn).mock.calls;
- expect(mockWarnCalls[0]).toMatchInlineSnapshot(`
- [
- "Using debug("message") is deprecated and will be removed in future release, please use debug({ message: "message" }) instead.",
- ]
- `);
+ expect(`${mockCalls[1][0]}\n${mockCalls[1][1]}`).toMatchSnapshot('Option message');
+ expect(`${mockCalls[2][0]}\n${mockCalls[2][1]}`).toMatchSnapshot('All Props');
});
test('debug changing component', () => {
render();
fireEvent.press(screen.getByRole('button', { name: 'Change freshness!' }));
- screen.debug();
+ screen.debug({ mapProps: null });
const mockCalls = jest.mocked(logger.info).mock.calls;
expect(mockCalls[0][0]).toMatchSnapshot('bananaFresh button message should now be "fresh"');
@@ -145,16 +138,6 @@ test('debug with only prop whose value is bananaChef', () => {
expect(mockCalls[0][0]).toMatchSnapshot();
});
-test('debug with only props from TextInput components', () => {
- render();
- screen.debug({
- mapProps: (props, node) => (node.type === 'TextInput' ? props : {}),
- });
-
- const mockCalls = jest.mocked(logger.info).mock.calls;
- expect(mockCalls[0][0]).toMatchSnapshot();
-});
-
test('debug should use debugOptions from config when no option is specified', () => {
configure({ defaultDebugOptions: { mapProps: () => ({}) } });
diff --git a/src/helpers/__tests__/format-element.test.tsx b/src/helpers/__tests__/format-element.test.tsx
new file mode 100644
index 000000000..ec03fca75
--- /dev/null
+++ b/src/helpers/__tests__/format-element.test.tsx
@@ -0,0 +1,25 @@
+import * as React from 'react';
+import { Text, View } from 'react-native';
+import { render, screen } from '../..';
+import { formatElement } from '../format-element';
+
+test('formatElement', () => {
+ render(
+
+
+ Hello
+ ,
+ );
+
+ expect(formatElement(screen.getByTestId('view'), { mapProps: null })).toMatchInlineSnapshot(`
+ ""
+ `);
+ expect(formatElement(screen.getByText('Hello'))).toMatchInlineSnapshot(`
+ "
+ Hello
+ "
+ `);
+ expect(formatElement(null)).toMatchInlineSnapshot(`"(null)"`);
+});
diff --git a/src/helpers/__tests__/format-default.test.tsx b/src/helpers/__tests__/map-props.test.tsx
similarity index 98%
rename from src/helpers/__tests__/format-default.test.tsx
rename to src/helpers/__tests__/map-props.test.tsx
index 917d9a12e..0c521010f 100644
--- a/src/helpers/__tests__/format-default.test.tsx
+++ b/src/helpers/__tests__/map-props.test.tsx
@@ -1,4 +1,4 @@
-import { defaultMapProps } from '../format-default';
+import { defaultMapProps } from '../map-props';
describe('mapPropsForQueryError', () => {
test('preserves props that are helpful for debugging', () => {
diff --git a/src/helpers/debug.ts b/src/helpers/debug.ts
index 7d92c0ece..af77a5f97 100644
--- a/src/helpers/debug.ts
+++ b/src/helpers/debug.ts
@@ -1,26 +1,22 @@
import type { ReactTestRendererJSON } from 'react-test-renderer';
-import type { FormatOptions } from './format';
-import format from './format';
+import type { FormatElementOptions } from './format-element';
+import { formatJson } from './format-element';
import { logger } from './logger';
export type DebugOptions = {
message?: string;
-} & FormatOptions;
+} & FormatElementOptions;
/**
* Log pretty-printed deep test component instance
*/
export function debug(
instance: ReactTestRendererJSON | ReactTestRendererJSON[],
- options?: DebugOptions | string,
+ { message, ...formatOptions }: DebugOptions = {},
) {
- const message = typeof options === 'string' ? options : options?.message;
-
- const formatOptions = typeof options === 'object' ? { mapProps: options?.mapProps } : undefined;
-
if (message) {
- logger.info(`${message}\n\n`, format(instance, formatOptions));
+ logger.info(`${message}\n\n`, formatJson(instance, formatOptions));
} else {
- logger.info(format(instance, formatOptions));
+ logger.info(formatJson(instance, formatOptions));
}
}
diff --git a/src/helpers/format-element.ts b/src/helpers/format-element.ts
new file mode 100644
index 000000000..2170f83b2
--- /dev/null
+++ b/src/helpers/format-element.ts
@@ -0,0 +1,92 @@
+import type { ReactTestInstance, ReactTestRendererJSON } from 'react-test-renderer';
+import type { NewPlugin } from 'pretty-format';
+import prettyFormat, { plugins } from 'pretty-format';
+import type { MapPropsFunction } from './map-props';
+import { defaultMapProps } from './map-props';
+
+export type FormatElementOptions = {
+ /** Minimize used space. */
+ compact?: boolean;
+
+ /** Highlight the output. */
+ highlight?: boolean;
+
+ /** Filter or map props to display. */
+ mapProps?: MapPropsFunction | null;
+};
+
+/***
+ * Format given element as a pretty-printed string.
+ *
+ * @param element Element to format.
+ */
+export function formatElement(
+ element: ReactTestInstance | null,
+ { compact, highlight = true, mapProps = defaultMapProps }: FormatElementOptions = {},
+) {
+ if (element == null) {
+ return '(null)';
+ }
+
+ const { children, ...props } = element.props;
+ const childrenToDisplay = typeof children === 'string' ? [children] : undefined;
+
+ return prettyFormat(
+ {
+ // This prop is needed persuade the prettyFormat that the element is
+ // a ReactTestRendererJSON instance, so it is formatted as JSX.
+ $$typeof: Symbol.for('react.test.json'),
+ type: `${element.type}`,
+ props: mapProps ? mapProps(props) : props,
+ children: childrenToDisplay,
+ },
+ // See: https://www.npmjs.com/package/pretty-format#usage-with-options
+ {
+ plugins: [plugins.ReactTestComponent, plugins.ReactElement],
+ printFunctionName: false,
+ printBasicPrototype: false,
+ highlight: highlight,
+ min: compact,
+ },
+ );
+}
+
+export function formatElementList(elements: ReactTestInstance[], options?: FormatElementOptions) {
+ if (elements.length === 0) {
+ return '(no elements)';
+ }
+
+ return elements.map((element) => formatElement(element, options)).join('\n');
+}
+
+export function formatJson(
+ json: ReactTestRendererJSON | ReactTestRendererJSON[],
+ { compact, highlight = true, mapProps = defaultMapProps }: FormatElementOptions = {},
+) {
+ return prettyFormat(json, {
+ plugins: [getElementJsonPlugin(mapProps), plugins.ReactElement],
+ highlight: highlight,
+ printBasicPrototype: false,
+ min: compact,
+ });
+}
+
+function getElementJsonPlugin(mapProps?: MapPropsFunction | null): NewPlugin {
+ return {
+ test: (val) => plugins.ReactTestComponent.test(val),
+ serialize: (val, config, indentation, depth, refs, printer) => {
+ let newVal = val;
+ if (mapProps && val.props) {
+ newVal = { ...val, props: mapProps(val.props) };
+ }
+ return plugins.ReactTestComponent.serialize(
+ newVal,
+ config,
+ indentation,
+ depth,
+ refs,
+ printer,
+ );
+ },
+ };
+}
diff --git a/src/helpers/format.ts b/src/helpers/format.ts
deleted file mode 100644
index f70eb8866..000000000
--- a/src/helpers/format.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import type { ReactTestRendererJSON } from 'react-test-renderer';
-import type { NewPlugin } from 'pretty-format';
-import prettyFormat, { plugins } from 'pretty-format';
-
-export type MapPropsFunction = (
- props: Record,
- node: ReactTestRendererJSON,
-) => Record;
-
-export type FormatOptions = {
- mapProps?: MapPropsFunction;
-};
-
-const format = (
- input: ReactTestRendererJSON | ReactTestRendererJSON[],
- options: FormatOptions = {},
-) =>
- prettyFormat(input, {
- plugins: [getCustomPlugin(options.mapProps), plugins.ReactElement],
- highlight: true,
- printBasicPrototype: false,
- });
-
-const getCustomPlugin = (mapProps?: MapPropsFunction): NewPlugin => {
- return {
- test: (val) => plugins.ReactTestComponent.test(val),
- serialize: (val, config, indentation, depth, refs, printer) => {
- let newVal = val;
- if (mapProps && val.props) {
- newVal = { ...val, props: mapProps(val.props, val) };
- }
- return plugins.ReactTestComponent.serialize(
- newVal,
- config,
- indentation,
- depth,
- refs,
- printer,
- );
- },
- };
-};
-
-export default format;
diff --git a/src/helpers/format-default.ts b/src/helpers/map-props.ts
similarity index 94%
rename from src/helpers/format-default.ts
rename to src/helpers/map-props.ts
index cd8947004..2ecefe848 100644
--- a/src/helpers/format-default.ts
+++ b/src/helpers/map-props.ts
@@ -2,6 +2,8 @@ import type { ViewStyle } from 'react-native';
import { StyleSheet } from 'react-native';
import { removeUndefinedKeys } from './object';
+export type MapPropsFunction = (props: Record) => Record;
+
const propsToDisplay = [
'accessible',
'accessibilityElementsHidden',
@@ -25,9 +27,11 @@ const propsToDisplay = [
'aria-valuenow',
'aria-valuetext',
'defaultValue',
+ 'editable',
'importantForAccessibility',
'nativeID',
'placeholder',
+ 'pointerEvents',
'role',
'testID',
'title',
diff --git a/src/matchers/__tests__/to-contain-element.test.tsx b/src/matchers/__tests__/to-contain-element.test.tsx
index 615991db5..c65e8260e 100644
--- a/src/matchers/__tests__/to-contain-element.test.tsx
+++ b/src/matchers/__tests__/to-contain-element.test.tsx
@@ -89,7 +89,7 @@ test('toContainElement() handles null element', () => {
does not contain:
- null
+ (null)
"
`);
});
diff --git a/src/matchers/__tests__/utils.test.tsx b/src/matchers/__tests__/utils.test.tsx
index 104b14a49..3881fc650 100644
--- a/src/matchers/__tests__/utils.test.tsx
+++ b/src/matchers/__tests__/utils.test.tsx
@@ -1,16 +1,12 @@
import React from 'react';
import { View } from 'react-native';
import { render, screen } from '../..';
-import { checkHostElement, formatElement } from '../utils';
+import { checkHostElement } from '../utils';
function fakeMatcher() {
return { pass: true, message: () => 'fake' };
}
-test('formatElement', () => {
- expect(formatElement(null)).toMatchInlineSnapshot(`" null"`);
-});
-
test('checkHostElement allows host element', () => {
render();
diff --git a/src/matchers/to-be-busy.ts b/src/matchers/to-be-busy.ts
index df155c141..f54aa7ddb 100644
--- a/src/matchers/to-be-busy.ts
+++ b/src/matchers/to-be-busy.ts
@@ -1,7 +1,9 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { matcherHint } from 'jest-matcher-utils';
+import redent from 'redent';
import { computeAriaBusy } from '../helpers/accessibility';
-import { checkHostElement, formatElement } from './utils';
+import { formatElement } from '../helpers/format-element';
+import { checkHostElement } from './utils';
export function toBeBusy(this: jest.MatcherContext, element: ReactTestInstance) {
checkHostElement(element, toBeBusy, this);
@@ -14,7 +16,7 @@ export function toBeBusy(this: jest.MatcherContext, element: ReactTestInstance)
matcher,
'',
`Received element is ${this.isNot ? '' : 'not '}busy:`,
- formatElement(element),
+ redent(formatElement(element), 2),
].join('\n');
},
};
diff --git a/src/matchers/to-be-checked.ts b/src/matchers/to-be-checked.ts
index fb9be3927..785fb34bf 100644
--- a/src/matchers/to-be-checked.ts
+++ b/src/matchers/to-be-checked.ts
@@ -1,5 +1,6 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { matcherHint } from 'jest-matcher-utils';
+import redent from 'redent';
import {
computeAriaChecked,
getRole,
@@ -7,8 +8,9 @@ import {
rolesSupportingCheckedState,
} from '../helpers/accessibility';
import { ErrorWithStack } from '../helpers/errors';
+import { formatElement } from '../helpers/format-element';
import { isHostSwitch } from '../helpers/host-component-names';
-import { checkHostElement, formatElement } from './utils';
+import { checkHostElement } from './utils';
export function toBeChecked(this: jest.MatcherContext, element: ReactTestInstance) {
checkHostElement(element, toBeChecked, this);
@@ -28,7 +30,7 @@ export function toBeChecked(this: jest.MatcherContext, element: ReactTestInstanc
matcherHint(`${this.isNot ? '.not' : ''}.toBeChecked`, 'element', ''),
'',
`Received element ${is} checked:`,
- formatElement(element),
+ redent(formatElement(element), 2),
].join('\n');
},
};
diff --git a/src/matchers/to-be-disabled.ts b/src/matchers/to-be-disabled.ts
index 3c917e078..ff6a00371 100644
--- a/src/matchers/to-be-disabled.ts
+++ b/src/matchers/to-be-disabled.ts
@@ -1,8 +1,10 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { matcherHint } from 'jest-matcher-utils';
+import redent from 'redent';
import { computeAriaDisabled } from '../helpers/accessibility';
import { getHostParent } from '../helpers/component-tree';
-import { checkHostElement, formatElement } from './utils';
+import { formatElement } from '../helpers/format-element';
+import { checkHostElement } from './utils';
export function toBeDisabled(this: jest.MatcherContext, element: ReactTestInstance) {
checkHostElement(element, toBeDisabled, this);
@@ -17,7 +19,7 @@ export function toBeDisabled(this: jest.MatcherContext, element: ReactTestInstan
matcherHint(`${this.isNot ? '.not' : ''}.toBeDisabled`, 'element', ''),
'',
`Received element ${is} disabled:`,
- formatElement(element),
+ redent(formatElement(element), 2),
].join('\n');
},
};
@@ -36,7 +38,7 @@ export function toBeEnabled(this: jest.MatcherContext, element: ReactTestInstanc
matcherHint(`${this.isNot ? '.not' : ''}.toBeEnabled`, 'element', ''),
'',
`Received element ${is} enabled:`,
- formatElement(element),
+ redent(formatElement(element), 2),
].join('\n');
},
};
diff --git a/src/matchers/to-be-empty-element.ts b/src/matchers/to-be-empty-element.ts
index eab2eeb8a..9b2c012ac 100644
--- a/src/matchers/to-be-empty-element.ts
+++ b/src/matchers/to-be-empty-element.ts
@@ -1,7 +1,9 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { matcherHint, RECEIVED_COLOR } from 'jest-matcher-utils';
+import redent from 'redent';
import { getHostChildren } from '../helpers/component-tree';
-import { checkHostElement, formatElementArray } from './utils';
+import { formatElementList } from '../helpers/format-element';
+import { checkHostElement } from './utils';
export function toBeEmptyElement(this: jest.MatcherContext, element: ReactTestInstance) {
checkHostElement(element, toBeEmptyElement, this);
@@ -15,7 +17,7 @@ export function toBeEmptyElement(this: jest.MatcherContext, element: ReactTestIn
matcherHint(`${this.isNot ? '.not' : ''}.toBeEmptyElement`, 'element', ''),
'',
'Received:',
- `${RECEIVED_COLOR(formatElementArray(hostChildren))}`,
+ `${RECEIVED_COLOR(redent(formatElementList(hostChildren), 2))}`,
].join('\n');
},
};
diff --git a/src/matchers/to-be-expanded.ts b/src/matchers/to-be-expanded.ts
index 9ee93afef..91c817fa4 100644
--- a/src/matchers/to-be-expanded.ts
+++ b/src/matchers/to-be-expanded.ts
@@ -1,7 +1,9 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { matcherHint } from 'jest-matcher-utils';
+import redent from 'redent';
import { computeAriaExpanded } from '../helpers/accessibility';
-import { checkHostElement, formatElement } from './utils';
+import { formatElement } from '../helpers/format-element';
+import { checkHostElement } from './utils';
export function toBeExpanded(this: jest.MatcherContext, element: ReactTestInstance) {
checkHostElement(element, toBeExpanded, this);
@@ -14,7 +16,7 @@ export function toBeExpanded(this: jest.MatcherContext, element: ReactTestInstan
matcher,
'',
`Received element is ${this.isNot ? '' : 'not '}expanded:`,
- formatElement(element),
+ redent(formatElement(element), 2),
].join('\n');
},
};
@@ -31,7 +33,7 @@ export function toBeCollapsed(this: jest.MatcherContext, element: ReactTestInsta
matcher,
'',
`Received element is ${this.isNot ? '' : 'not '}collapsed:`,
- formatElement(element),
+ redent(formatElement(element), 2),
].join('\n');
},
};
diff --git a/src/matchers/to-be-on-the-screen.ts b/src/matchers/to-be-on-the-screen.ts
index c00958222..9d956530c 100644
--- a/src/matchers/to-be-on-the-screen.ts
+++ b/src/matchers/to-be-on-the-screen.ts
@@ -1,8 +1,10 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { matcherHint, RECEIVED_COLOR } from 'jest-matcher-utils';
+import redent from 'redent';
import { getUnsafeRootElement } from '../helpers/component-tree';
+import { formatElement } from '../helpers/format-element';
import { screen } from '../screen';
-import { checkHostElement, formatElement } from './utils';
+import { checkHostElement } from './utils';
export function toBeOnTheScreen(this: jest.MatcherContext, element: ReactTestInstance) {
if (element !== null || !this.isNot) {
@@ -12,7 +14,10 @@ export function toBeOnTheScreen(this: jest.MatcherContext, element: ReactTestIns
const pass = element === null ? false : screen.UNSAFE_root === getUnsafeRootElement(element);
const errorFound = () => {
- return `expected element tree not to contain element, but found\n${formatElement(element)}`;
+ return `expected element tree not to contain element, but found\n${redent(
+ formatElement(element),
+ 2,
+ )}`;
};
const errorNotFound = () => {
diff --git a/src/matchers/to-be-partially-checked.ts b/src/matchers/to-be-partially-checked.ts
index 975c48e93..25ea288bf 100644
--- a/src/matchers/to-be-partially-checked.ts
+++ b/src/matchers/to-be-partially-checked.ts
@@ -1,8 +1,10 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { matcherHint } from 'jest-matcher-utils';
+import redent from 'redent';
import { computeAriaChecked, getRole, isAccessibilityElement } from '../helpers/accessibility';
import { ErrorWithStack } from '../helpers/errors';
-import { checkHostElement, formatElement } from './utils';
+import { formatElement } from '../helpers/format-element';
+import { checkHostElement } from './utils';
export function toBePartiallyChecked(this: jest.MatcherContext, element: ReactTestInstance) {
checkHostElement(element, toBePartiallyChecked, this);
@@ -22,7 +24,7 @@ export function toBePartiallyChecked(this: jest.MatcherContext, element: ReactTe
matcherHint(`${this.isNot ? '.not' : ''}.toBePartiallyChecked`, 'element', ''),
'',
`Received element ${is} partially checked:`,
- formatElement(element),
+ redent(formatElement(element), 2),
].join('\n');
},
};
diff --git a/src/matchers/to-be-selected.ts b/src/matchers/to-be-selected.ts
index a86f4d74c..8e78ef8f6 100644
--- a/src/matchers/to-be-selected.ts
+++ b/src/matchers/to-be-selected.ts
@@ -1,7 +1,9 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { matcherHint } from 'jest-matcher-utils';
+import redent from 'redent';
import { computeAriaSelected } from '../helpers/accessibility';
-import { checkHostElement, formatElement } from './utils';
+import { formatElement } from '../helpers/format-element';
+import { checkHostElement } from './utils';
export function toBeSelected(this: jest.MatcherContext, element: ReactTestInstance) {
checkHostElement(element, toBeSelected, this);
@@ -14,7 +16,7 @@ export function toBeSelected(this: jest.MatcherContext, element: ReactTestInstan
matcherHint(`${this.isNot ? '.not' : ''}.toBeSelected`, 'element', ''),
'',
`Received element ${is} selected`,
- formatElement(element),
+ redent(formatElement(element), 2),
].join('\n');
},
};
diff --git a/src/matchers/to-be-visible.ts b/src/matchers/to-be-visible.ts
index 4500bda2c..18d7ba83b 100644
--- a/src/matchers/to-be-visible.ts
+++ b/src/matchers/to-be-visible.ts
@@ -1,10 +1,12 @@
import { StyleSheet } from 'react-native';
import type { ReactTestInstance } from 'react-test-renderer';
import { matcherHint } from 'jest-matcher-utils';
+import redent from 'redent';
import { isHiddenFromAccessibility } from '../helpers/accessibility';
import { getHostParent } from '../helpers/component-tree';
+import { formatElement } from '../helpers/format-element';
import { isHostModal } from '../helpers/host-component-names';
-import { checkHostElement, formatElement } from './utils';
+import { checkHostElement } from './utils';
export function toBeVisible(this: jest.MatcherContext, element: ReactTestInstance) {
if (element !== null || !this.isNot) {
@@ -19,7 +21,7 @@ export function toBeVisible(this: jest.MatcherContext, element: ReactTestInstanc
matcherHint(`${this.isNot ? '.not' : ''}.toBeVisible`, 'element', ''),
'',
`Received element ${is} visible:`,
- formatElement(element),
+ redent(formatElement(element), 2),
].join('\n');
},
};
diff --git a/src/matchers/to-contain-element.ts b/src/matchers/to-contain-element.ts
index 10dabcb03..3dddc6e65 100644
--- a/src/matchers/to-contain-element.ts
+++ b/src/matchers/to-contain-element.ts
@@ -1,6 +1,8 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { matcherHint, RECEIVED_COLOR } from 'jest-matcher-utils';
-import { checkHostElement, formatElement } from './utils';
+import redent from 'redent';
+import { formatElement } from '../helpers/format-element';
+import { checkHostElement } from './utils';
export function toContainElement(
this: jest.MatcherContext,
@@ -24,9 +26,9 @@ export function toContainElement(
return [
matcherHint(`${this.isNot ? '.not' : ''}.toContainElement`, 'container', 'element'),
'',
- RECEIVED_COLOR(`${formatElement(container)} ${
+ RECEIVED_COLOR(`${redent(formatElement(container), 2)} ${
this.isNot ? '\n\ncontains:\n\n' : '\n\ndoes not contain:\n\n'
- } ${formatElement(element)}
+ } ${redent(formatElement(element), 2)}
`),
].join('\n');
},
diff --git a/src/matchers/utils.ts b/src/matchers/utils.ts
index 17e054ed3..4ae889c1f 100644
--- a/src/matchers/utils.ts
+++ b/src/matchers/utils.ts
@@ -7,10 +7,8 @@ import {
RECEIVED_COLOR,
stringify,
} from 'jest-matcher-utils';
-import prettyFormat, { plugins } from 'pretty-format';
import redent from 'redent';
import { isHostElement } from '../helpers/component-tree';
-import { defaultMapProps } from '../helpers/format-default';
class HostElementTypeError extends Error {
constructor(received: unknown, matcherFn: jest.CustomMatcher, context: jest.MatcherContext) {
@@ -55,48 +53,6 @@ export function checkHostElement(
}
}
-/***
- * Format given element as a pretty-printed string.
- *
- * @param element Element to format.
- */
-export function formatElement(element: ReactTestInstance | null) {
- if (element == null) {
- return ' null';
- }
-
- const { children, ...props } = element.props;
- const childrenToDisplay = typeof children === 'string' ? [children] : undefined;
-
- return redent(
- prettyFormat(
- {
- // This prop is needed persuade the prettyFormat that the element is
- // a ReactTestRendererJSON instance, so it is formatted as JSX.
- $$typeof: Symbol.for('react.test.json'),
- type: element.type,
- props: defaultMapProps(props),
- children: childrenToDisplay,
- },
- {
- plugins: [plugins.ReactTestComponent, plugins.ReactElement],
- printFunctionName: false,
- printBasicPrototype: false,
- highlight: true,
- },
- ),
- 2,
- );
-}
-
-export function formatElementArray(elements: ReactTestInstance[]) {
- if (elements.length === 0) {
- return ' (no elements)';
- }
-
- return redent(elements.map(formatElement).join('\n'), 2);
-}
-
export function formatMessage(
matcher: string,
expectedLabel: string,
diff --git a/src/queries/make-queries.ts b/src/queries/make-queries.ts
index b32dd8fbb..89f932166 100644
--- a/src/queries/make-queries.ts
+++ b/src/queries/make-queries.ts
@@ -1,7 +1,6 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { ErrorWithStack } from '../helpers/errors';
-import format from '../helpers/format';
-import { defaultMapProps } from '../helpers/format-default';
+import { formatJson } from '../helpers/format-element';
import { logger } from '../helpers/logger';
import { screen } from '../screen';
import type { WaitForOptions } from '../wait-for';
@@ -96,9 +95,7 @@ function formatErrorMessage(message: string, printElementTree: boolean) {
return message;
}
- return `${message}\n\n${format(json, {
- mapProps: defaultMapProps,
- })}`;
+ return `${message}\n\n${formatJson(json)}`;
}
function appendElementTreeToError(error: Error) {
diff --git a/src/render.tsx b/src/render.tsx
index 6980d4247..b6c5486b1 100644
--- a/src/render.tsx
+++ b/src/render.tsx
@@ -10,7 +10,6 @@ import { getConfig } from './config';
import { getHostSelves } from './helpers/component-tree';
import type { DebugOptions } from './helpers/debug';
import { debug } from './helpers/debug';
-import { logger } from './helpers/logger';
import { validateStringsRenderedWithinText } from './helpers/string-validation';
import { renderWithAct } from './render-act';
import { setRenderResult } from './screen';
@@ -115,7 +114,7 @@ function buildRenderResult(
unmount,
rerender: update, // alias for `update`
toJSON: renderer.toJSON,
- debug: makeDebug(instance, renderer),
+ debug: makeDebug(renderer),
get root(): ReactTestInstance {
return getHostSelves(instance)[0];
},
@@ -150,22 +149,12 @@ function updateWithAct(
};
}
-export type DebugFunction = (options?: DebugOptions | string) => void;
+export type DebugFunction = (options?: DebugOptions) => void;
-function makeDebug(instance: ReactTestInstance, renderer: ReactTestRenderer): DebugFunction {
- function debugImpl(options?: DebugOptions | string) {
+function makeDebug(renderer: ReactTestRenderer): DebugFunction {
+ function debugImpl(options?: DebugOptions) {
const { defaultDebugOptions } = getConfig();
- const debugOptions =
- typeof options === 'string'
- ? { ...defaultDebugOptions, message: options }
- : { ...defaultDebugOptions, ...options };
-
- if (typeof options === 'string') {
- logger.warn(
- 'Using debug("message") is deprecated and will be removed in future release, please use debug({ message: "message" }) instead.',
- );
- }
-
+ const debugOptions = { ...defaultDebugOptions, ...options };
const json = renderer.toJSON();
if (json) {
return debug(json, debugOptions);
diff --git a/typings/index.flow.js b/typings/index.flow.js
index df25313d7..e801e9f23 100644
--- a/typings/index.flow.js
+++ b/typings/index.flow.js
@@ -86,12 +86,12 @@ interface ByTextQueries {
findByText: (
text: TextMatch,
queryOptions?: ByTextOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindReturn;
findAllByText: (
text: TextMatch,
queryOptions?: ByTextOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindAllReturn;
}
@@ -105,12 +105,12 @@ interface ByTestIdQueries {
findByTestId: (
testID: TextMatch,
queryOptions?: ByTestIdOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindReturn;
findAllByTestId: (
testID: TextMatch,
queryOptions?: ByTestIdOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindAllReturn;
}
@@ -120,25 +120,25 @@ interface ByDisplayValueQueries {
getByDisplayValue: (value: TextMatch, options?: ByDisplayValueOptions) => ReactTestInstance;
getAllByDisplayValue: (
value: TextMatch,
- options?: ByDisplayValueOptions
+ options?: ByDisplayValueOptions,
) => Array;
queryByDisplayValue: (
value: TextMatch,
- options?: ByDisplayValueOptions
+ options?: ByDisplayValueOptions,
) => ReactTestInstance | null;
queryAllByDisplayValue: (
value: TextMatch,
- options?: ByDisplayValueOptions
+ options?: ByDisplayValueOptions,
) => Array | [];
findByDisplayValue: (
value: TextMatch,
queryOptions?: ByDisplayValueOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindReturn;
findAllByDisplayValue: (
value: TextMatch,
queryOptions?: ByDisplayValueOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindAllReturn;
}
@@ -147,29 +147,29 @@ type ByPlaceholderTextOptions = CommonQueryOptions & TextMatchOptions;
interface ByPlaceholderTextQueries {
getByPlaceholderText: (
placeholder: TextMatch,
- options?: ByPlaceholderTextOptions
+ options?: ByPlaceholderTextOptions,
) => ReactTestInstance;
getAllByPlaceholderText: (
placeholder: TextMatch,
- options?: ByPlaceholderTextOptions
+ options?: ByPlaceholderTextOptions,
) => Array;
queryByPlaceholderText: (
placeholder: TextMatch,
- options?: ByPlaceholderTextOptions
+ options?: ByPlaceholderTextOptions,
) => ReactTestInstance | null;
queryAllByPlaceholderText: (
placeholder: TextMatch,
- options?: ByPlaceholderTextOptions
+ options?: ByPlaceholderTextOptions,
) => Array | [];
findByPlaceholderText: (
placeholder: TextMatch,
queryOptions?: ByPlaceholderTextOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindReturn;
findAllByPlaceholderText: (
placeholder: TextMatch,
queryOptions?: ByPlaceholderTextOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindAllReturn;
}
@@ -205,12 +205,12 @@ interface A11yAPI {
findByLabelText: (
matcher: TextMatch,
queryOptions?: ByLabelTextOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindReturn;
findAllByLabelText: (
matcher: TextMatch,
queryOptions?: ByLabelTextOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindAllReturn;
// Hint
@@ -225,22 +225,22 @@ interface A11yAPI {
findByA11yHint: (
matcher: TextMatch,
queryOptions?: ByHintTextOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindReturn;
findByHintText: (
matcher: TextMatch,
queryOptions?: ByHintTextOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindReturn;
findAllByA11yHint: (
matcher: TextMatch,
queryOptions?: ByHintTextOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindAllReturn;
findAllByHintText: (
matcher: TextMatch,
queryOptions?: ByHintTextOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindAllReturn;
// Role
@@ -251,12 +251,12 @@ interface A11yAPI {
findByRole: (
matcher: A11yRole | RegExp,
queryOptions?: ByRoleOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindReturn;
findAllByRole: (
matcher: A11yRole | RegExp,
queryOptions?: ByRoleOptions,
- waitForOptions?: WaitForOptions
+ waitForOptions?: WaitForOptions,
) => FindAllReturn;
}
@@ -266,7 +266,7 @@ interface Thenable {
type MapPropsFunction = (
props: { [string]: mixed },
- node: ReactTestRendererJSON
+ node: ReactTestRendererJSON,
) => { [string]: mixed };
type DebugOptions = {
@@ -274,10 +274,6 @@ type DebugOptions = {
mapProps?: MapPropsFunction,
};
-type Debug = {
- (options?: DebugOptions | string): void,
-};
-
type Queries = ByTextQueries &
ByTestIdQueries &
ByDisplayValueQueries &
@@ -304,7 +300,7 @@ declare module '@testing-library/react-native' {
rerender(nextElement: React.Element): void;
unmount(nextElement?: React.Element): void;
toJSON(): ReactTestRendererJSON[] | ReactTestRendererJSON | null;
- debug: Debug;
+ debug(options?: DebugOptions): void;
root: ReactTestInstance;
UNSAFE_root: ReactTestInstance;
}
@@ -322,7 +318,7 @@ declare module '@testing-library/react-native' {
declare export var render: (
component: React.Element,
- options?: RenderOptions
+ options?: RenderOptions,
) => RenderResult;
declare export var screen: RenderResult;
@@ -334,7 +330,7 @@ declare module '@testing-library/react-native' {
declare type WaitForElementToBeRemovedFunction = (
expectation: () => T,
- options?: WaitForOptions
+ options?: WaitForOptions,
) => Promise;
declare export var waitForElementToBeRemoved: WaitForElementToBeRemovedFunction;
@@ -375,7 +371,7 @@ declare module '@testing-library/react-native' {
declare type RenderHookFunction = (
renderCallback: (props: Props) => Result,
- options?: RenderHookOptions
+ options?: RenderHookOptions,
) => RenderHookResult;
declare export var renderHook: RenderHookFunction;
diff --git a/website/docs/12.x/docs/migration/v13.mdx b/website/docs/12.x/docs/migration/v13.mdx
index bcf81c721..ba3fbf227 100644
--- a/website/docs/12.x/docs/migration/v13.mdx
+++ b/website/docs/12.x/docs/migration/v13.mdx
@@ -53,6 +53,10 @@ const view = screen.getBy*(...); // Find the element using any query: *ByRole, *
expect(view).toHaveAccessibilityValue({ now: 50, min: 0, max: 50 }); // Assert its accessibility value
```
+## Removed deprecated `debug(message)` variant
+
+The `debug(message)` variant has been removed. Use `debug({ message })` instead.
+
## Removed `debug.shallow`
For a time being we didn't support shallow rendering. Now we are removing the last remains of it: `debug.shallow()`. If you are interested in shallow rendering see [here](docs/migration/previous/v2#removed-global-shallow-function).