mirror of
https://github.com/callstack/react-native-testing-library.git
synced 2026-09-18 23:09:04 +08:00
BREAKING: make getAllBy* methods throwable (#12)
* BREAKING: make getAllBy* methods throwable * fix wrong fn args
This commit is contained in:
committed by
Kacper Wiszczuk
parent
08c5725984
commit
9d14406832
@@ -72,9 +72,7 @@ test('getByTestId', () => {
|
||||
const component = getByTestId('bananaFresh');
|
||||
|
||||
expect(component.props.children).toBe('not fresh');
|
||||
expect(() => {
|
||||
getByTestId('InExistent');
|
||||
}).toThrow();
|
||||
expect(() => getByTestId('InExistent')).toThrow();
|
||||
});
|
||||
|
||||
test('getByName', () => {
|
||||
@@ -91,9 +89,7 @@ test('getByName', () => {
|
||||
|
||||
expect(bananaFresh.props.children).toBe('not fresh');
|
||||
|
||||
expect(() => {
|
||||
getByName('InExistent');
|
||||
}).toThrow();
|
||||
expect(() => getByName('InExistent')).toThrow();
|
||||
});
|
||||
|
||||
test('getAllByName', () => {
|
||||
@@ -103,7 +99,7 @@ test('getAllByName', () => {
|
||||
expect(text.props.children).toBe('Is the banana fresh?');
|
||||
expect(status.props.children).toBe('not fresh');
|
||||
expect(button.props.children).toBe('Change freshness!');
|
||||
expect(getAllByName('InExistent')).toHaveLength(0);
|
||||
expect(() => getAllByName('InExistent')).toThrow();
|
||||
});
|
||||
|
||||
test('getByText', () => {
|
||||
@@ -115,9 +111,7 @@ test('getByText', () => {
|
||||
const sameButton = getByText('not fresh');
|
||||
|
||||
expect(sameButton.props.children).toBe('not fresh');
|
||||
expect(() => {
|
||||
getByText('InExistent');
|
||||
}).toThrow();
|
||||
expect(() => getByText('InExistent')).toThrow();
|
||||
});
|
||||
|
||||
test('getAllByText', () => {
|
||||
@@ -125,7 +119,7 @@ test('getAllByText', () => {
|
||||
const button = getAllByText(/fresh/i);
|
||||
|
||||
expect(button).toHaveLength(3);
|
||||
expect(getAllByText('InExistent')).toHaveLength(0);
|
||||
expect(() => getAllByText('InExistent')).toThrow();
|
||||
});
|
||||
|
||||
test('getByProps', () => {
|
||||
@@ -133,9 +127,7 @@ test('getByProps', () => {
|
||||
const primaryType = getByProps({ type: 'primary' });
|
||||
|
||||
expect(primaryType.props.children).toBe('Change freshness!');
|
||||
expect(() => {
|
||||
getByProps({ type: 'inexistent' });
|
||||
}).toThrow();
|
||||
expect(() => getByProps({ type: 'inexistent' })).toThrow();
|
||||
});
|
||||
|
||||
test('getAllByProps', () => {
|
||||
@@ -143,7 +135,7 @@ test('getAllByProps', () => {
|
||||
const primaryTypes = getAllByProps({ type: 'primary' });
|
||||
|
||||
expect(primaryTypes).toHaveLength(1);
|
||||
expect(getAllByProps({ type: 'inexistent' })).toHaveLength(0);
|
||||
expect(() => getAllByProps({ type: 'inexistent' })).toThrow();
|
||||
});
|
||||
|
||||
test('update', () => {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import prettyFormat, { plugins } from 'pretty-format'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import shallow from './shallow';
|
||||
|
||||
/**
|
||||
* Log pretty-printed shallow test component instance
|
||||
*/
|
||||
export default function debug(
|
||||
instance: ReactTestInstance | React.Element<*>,
|
||||
message?: any
|
||||
) {
|
||||
const { output } = shallow(instance);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(format(output), message || '');
|
||||
}
|
||||
|
||||
const format = input =>
|
||||
prettyFormat(input, {
|
||||
plugins: [plugins.ReactTestComponent, plugins.ReactElement],
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
// @flow
|
||||
/**
|
||||
* Wait for microtasks queue to flush
|
||||
*/
|
||||
export default function flushMicrotasksQueue(): Promise<any> {
|
||||
return new Promise(resolve => setImmediate(resolve));
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// @flow
|
||||
export default class ErrorWithStack extends Error {
|
||||
constructor(message: ?string, callsite: Function) {
|
||||
super(message);
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, callsite);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import ErrorWithStack from './errorWithStack';
|
||||
|
||||
const getNodeByName = (node, name) =>
|
||||
node.type.name === name ||
|
||||
node.type.displayName === name ||
|
||||
node.type === name;
|
||||
|
||||
const getNodeByText = (node, text) =>
|
||||
(getNodeByName(node, 'Text') || getNodeByName(node, 'TextInput')) &&
|
||||
(typeof text === 'string'
|
||||
? text === node.props.children
|
||||
: text.test(node.props.children));
|
||||
|
||||
export const getByName = (instance: ReactTestInstance) => (
|
||||
name: string | React.Element<*>
|
||||
) => {
|
||||
try {
|
||||
return instance.find(node => getNodeByName(node, name));
|
||||
} catch (error) {
|
||||
throw new ErrorWithStack(`Error: Component not found.`, getByName);
|
||||
}
|
||||
};
|
||||
|
||||
export const getByText = (instance: ReactTestInstance) => (
|
||||
text: string | RegExp
|
||||
) => {
|
||||
try {
|
||||
return instance.find(node => getNodeByText(node, text));
|
||||
} catch (error) {
|
||||
throw new ErrorWithStack(`Error: Component not found.`, getByText);
|
||||
}
|
||||
};
|
||||
|
||||
export const getByProps = (instance: ReactTestInstance) => (props: {
|
||||
[propName: string]: any,
|
||||
}) => {
|
||||
try {
|
||||
return instance.findByProps(props);
|
||||
} catch (error) {
|
||||
throw new ErrorWithStack(`Error: Component not found.`, getByProps);
|
||||
}
|
||||
};
|
||||
|
||||
export const getByTestId = (instance: ReactTestInstance) => (testID: string) =>
|
||||
getByProps(instance)({ testID });
|
||||
|
||||
export const getAllByName = (instance: ReactTestInstance) => (
|
||||
name: string | React.Element<*>
|
||||
) => {
|
||||
const results = instance.findAll(node => getNodeByName(node, name));
|
||||
if (results.length === 0) {
|
||||
throw new ErrorWithStack(`Error: Components not found.`, getAllByName);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
export const getAllByText = (instance: ReactTestInstance) => (
|
||||
text: string | RegExp
|
||||
) => {
|
||||
const results = instance.findAll(node => getNodeByText(node, text));
|
||||
if (results.length === 0) {
|
||||
throw new ErrorWithStack(`Error: Components not found.`, getAllByText);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
export const getAllByProps = (instance: ReactTestInstance) => (props: {
|
||||
[propName: string]: any,
|
||||
}) => {
|
||||
const results = instance.findAllByProps(props);
|
||||
if (results.length === 0) {
|
||||
throw new ErrorWithStack(`Error: Components not found.`, getAllByProps);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
+8
-116
@@ -1,118 +1,10 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { isValidElementType } from 'react-is';
|
||||
import TestRenderer from 'react-test-renderer'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import ShallowRenderer from 'react-test-renderer/shallow'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import prettyFormat, { plugins } from 'pretty-format'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import render from './render';
|
||||
import shallow from './shallow';
|
||||
import flushMicrotasksQueue from './flushMicrotasksQueue';
|
||||
import debug from './debug';
|
||||
|
||||
const getNodeByName = (node, name) =>
|
||||
node.type.name === name ||
|
||||
node.type.displayName === name ||
|
||||
node.type === name;
|
||||
|
||||
const getNodeByText = (node, text) =>
|
||||
(getNodeByName(node, 'Text') || getNodeByName(node, 'TextInput')) &&
|
||||
(typeof text === 'string'
|
||||
? text === node.props.children
|
||||
: text.test(node.props.children));
|
||||
|
||||
/**
|
||||
* Wait for microtasks queue to flush
|
||||
*/
|
||||
export const flushMicrotasksQueue = (): Promise<any> =>
|
||||
new Promise(resolve => setImmediate(resolve));
|
||||
|
||||
/**
|
||||
* Renders test component deeply using react-test-renderer and exposes helpers
|
||||
* to assert on the output.
|
||||
*/
|
||||
export const render = (
|
||||
component: React.Element<*>,
|
||||
options?: { createNodeMock: (element: React.Element<*>) => any }
|
||||
) => {
|
||||
const renderer = TestRenderer.create(component, options);
|
||||
const instance = renderer.root;
|
||||
|
||||
const getByName = (name: string | React.Element<*>) => {
|
||||
try {
|
||||
return instance.find(node => getNodeByName(node, name));
|
||||
} catch (error) {
|
||||
throw new ErrorWithStack(`Error: Component not found.`, getByName);
|
||||
}
|
||||
};
|
||||
|
||||
const getByText = (text: string | RegExp) => {
|
||||
try {
|
||||
return instance.find(node => getNodeByText(node, text));
|
||||
} catch (error) {
|
||||
throw new ErrorWithStack(`Error: Component not found.`, getByText);
|
||||
}
|
||||
};
|
||||
|
||||
const getByProps = (props: { [propName: string]: any }) => {
|
||||
try {
|
||||
return instance.findByProps(props);
|
||||
} catch (error) {
|
||||
throw new ErrorWithStack(`Error: Component not found.`, getByProps);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
getByTestId: (testID: string) => instance.findByProps({ testID }),
|
||||
getByName,
|
||||
getAllByName: (name: string | React.Element<*>) =>
|
||||
instance.findAll(node => getNodeByName(node, name)),
|
||||
getByText,
|
||||
getAllByText: (text: string | RegExp) =>
|
||||
instance.findAll(node => getNodeByText(node, text)),
|
||||
getByProps,
|
||||
getAllByProps: (props: { [propName: string]: any }) =>
|
||||
instance.findAllByProps(props),
|
||||
update: renderer.update,
|
||||
unmount: renderer.unmount,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders test component shallowly using react-test-renderer/shallow
|
||||
*/
|
||||
export const shallow = (instance: ReactTestInstance | React.Element<*>) => {
|
||||
const renderer = new ShallowRenderer();
|
||||
if (isValidElementType(instance)) {
|
||||
// $FlowFixMe - instance is React.Element<*> in this branch
|
||||
renderer.render(instance);
|
||||
} else {
|
||||
renderer.render(React.createElement(instance.type, instance.props));
|
||||
}
|
||||
const output = renderer.getRenderOutput();
|
||||
|
||||
return {
|
||||
output,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Log pretty-printed shallow test component instance
|
||||
*/
|
||||
export const debug = (
|
||||
instance: ReactTestInstance | React.Element<*>,
|
||||
message?: any
|
||||
) => {
|
||||
const { output } = shallow(instance);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(format(output), message || '');
|
||||
};
|
||||
|
||||
const format = input =>
|
||||
prettyFormat(input, {
|
||||
plugins: [plugins.ReactTestComponent, plugins.ReactElement],
|
||||
});
|
||||
|
||||
class ErrorWithStack extends Error {
|
||||
constructor(message: ?string, callsite: Function) {
|
||||
super(message);
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, callsite);
|
||||
}
|
||||
}
|
||||
}
|
||||
export { render };
|
||||
export { shallow };
|
||||
export { flushMicrotasksQueue };
|
||||
export { debug };
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import TestRenderer from 'react-test-renderer'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
import {
|
||||
getByTestId,
|
||||
getByName,
|
||||
getByText,
|
||||
getByProps,
|
||||
getAllByName,
|
||||
getAllByText,
|
||||
getAllByProps,
|
||||
} from './helpers/getBy';
|
||||
|
||||
/**
|
||||
* Renders test component deeply using react-test-renderer and exposes helpers
|
||||
* to assert on the output.
|
||||
*/
|
||||
export default function render(
|
||||
component: React.Element<*>,
|
||||
options?: { createNodeMock: (element: React.Element<*>) => any }
|
||||
) {
|
||||
const renderer = TestRenderer.create(component, options);
|
||||
const instance = renderer.root;
|
||||
|
||||
return {
|
||||
getByTestId: getByTestId(instance),
|
||||
getByName: getByName(instance),
|
||||
getByText: getByText(instance),
|
||||
getByProps: getByProps(instance),
|
||||
getAllByName: getAllByName(instance),
|
||||
getAllByText: getAllByText(instance),
|
||||
getAllByProps: getAllByProps(instance),
|
||||
update: renderer.update,
|
||||
unmount: renderer.unmount,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { isValidElementType } from 'react-is';
|
||||
import ShallowRenderer from 'react-test-renderer/shallow'; // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
/**
|
||||
* Renders test component shallowly using react-test-renderer/shallow
|
||||
*/
|
||||
export default function shallow(
|
||||
instance: ReactTestInstance | React.Element<*>
|
||||
) {
|
||||
const renderer = new ShallowRenderer();
|
||||
if (isValidElementType(instance)) {
|
||||
// $FlowFixMe - instance is React.Element<*> in this branch
|
||||
renderer.render(instance);
|
||||
} else {
|
||||
renderer.render(React.createElement(instance.type, instance.props));
|
||||
}
|
||||
const output = renderer.getRenderOutput();
|
||||
|
||||
return {
|
||||
output,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user