BREAKING: make getAllBy* methods throwable (#12)

* BREAKING: make getAllBy* methods throwable

* fix wrong fn args
This commit is contained in:
Michał Pierzchała
2018-10-06 23:42:52 +02:00
committed by Kacper Wiszczuk
parent 08c5725984
commit 9d14406832
8 changed files with 189 additions and 131 deletions
+7 -15
View File
@@ -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', () => {
+21
View File
@@ -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],
});
+7
View File
@@ -0,0 +1,7 @@
// @flow
/**
* Wait for microtasks queue to flush
*/
export default function flushMicrotasksQueue(): Promise<any> {
return new Promise(resolve => setImmediate(resolve));
}
+9
View File
@@ -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);
}
}
}
+77
View File
@@ -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
View File
@@ -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 };
+36
View File
@@ -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,
};
}
+24
View File
@@ -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,
};
}