mirror of
https://github.com/callstack/react-native-testing-library.git
synced 2026-09-18 23:09:04 +08:00
feat: add the value expected in getBy error messages (#550)
* add the value expected in getBy error messages (e.g. "No instances found with text 'bla'") * updated a11y test * rename fullNoInstanceError to getNoInstancesFoundMessage Co-authored-by: Maciej Jastrzebski <mdjastrzebski@gmail.com> * addressing PR comments * fixed lint error Co-authored-by: Maciej Jastrzebski <mdjastrzebski@gmail.com>
This commit is contained in:
@@ -9,9 +9,17 @@ const TEXT_LABEL = 'cool text';
|
||||
const TEXT_HINT = 'static text';
|
||||
// Little hack to make all the methods happy with type
|
||||
const NO_MATCHES_TEXT: any = 'not-existent-element';
|
||||
const NO_INSTANCES_FOUND = 'No instances found';
|
||||
const FOUND_TWO_INSTANCES = 'Expected 1 but found 2 instances';
|
||||
|
||||
const getNoInstancesFoundMessage = (
|
||||
name: string,
|
||||
value: string = NO_MATCHES_TEXT,
|
||||
includeQuotes: boolean = true
|
||||
) => {
|
||||
const quote = includeQuotes ? '"' : '';
|
||||
return `No instances found with ${name} ${quote}${value}${quote}`;
|
||||
};
|
||||
|
||||
const Typography = ({ children, ...rest }: any) => {
|
||||
return <Text {...rest}>{children}</Text>;
|
||||
};
|
||||
@@ -73,7 +81,9 @@ test('getByA11yLabel, queryByA11yLabel, findByA11yLabel', async () => {
|
||||
const button = queryByA11yLabel(/button/g);
|
||||
expect(button && button.props.accessibilityLabel).toEqual(BUTTON_LABEL);
|
||||
|
||||
expect(() => getByA11yLabel(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getByA11yLabel(NO_MATCHES_TEXT)).toThrow(
|
||||
getNoInstancesFoundMessage('accessibilityLabel')
|
||||
);
|
||||
expect(queryByA11yLabel(NO_MATCHES_TEXT)).toBeNull();
|
||||
|
||||
expect(() => getByA11yLabel(TEXT_LABEL)).toThrow(FOUND_TWO_INSTANCES);
|
||||
@@ -83,7 +93,7 @@ test('getByA11yLabel, queryByA11yLabel, findByA11yLabel', async () => {
|
||||
expect(asyncButton.props.accessibilityLabel).toEqual(BUTTON_LABEL);
|
||||
await expect(
|
||||
findByA11yLabel(NO_MATCHES_TEXT, waitForOptions)
|
||||
).rejects.toThrow(NO_INSTANCES_FOUND);
|
||||
).rejects.toThrow(getNoInstancesFoundMessage('accessibilityLabel'));
|
||||
|
||||
await expect(findByA11yLabel(TEXT_LABEL, waitForOptions)).rejects.toThrow(
|
||||
FOUND_TWO_INSTANCES
|
||||
@@ -98,12 +108,14 @@ test('getAllByA11yLabel, queryAllByA11yLabel, findAllByA11yLabel', async () => {
|
||||
expect(getAllByA11yLabel(TEXT_LABEL)).toHaveLength(2);
|
||||
expect(queryAllByA11yLabel(/cool/g)).toHaveLength(3);
|
||||
|
||||
expect(() => getAllByA11yLabel(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getAllByA11yLabel(NO_MATCHES_TEXT)).toThrow(
|
||||
getNoInstancesFoundMessage('accessibilityLabel')
|
||||
);
|
||||
expect(queryAllByA11yLabel(NO_MATCHES_TEXT)).toEqual([]);
|
||||
|
||||
await expect(findAllByA11yLabel(TEXT_LABEL)).resolves.toHaveLength(2);
|
||||
await expect(findAllByA11yLabel(NO_MATCHES_TEXT)).rejects.toThrow(
|
||||
NO_INSTANCES_FOUND
|
||||
getNoInstancesFoundMessage('accessibilityLabel')
|
||||
);
|
||||
});
|
||||
|
||||
@@ -118,7 +130,9 @@ test('getByA11yHint, queryByA11yHint, findByA11yHint', async () => {
|
||||
const button = queryByA11yHint(/button/g);
|
||||
expect(button && button.props.accessibilityHint).toEqual(BUTTON_HINT);
|
||||
|
||||
expect(() => getByA11yHint(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getByA11yHint(NO_MATCHES_TEXT)).toThrow(
|
||||
getNoInstancesFoundMessage('accessibilityHint')
|
||||
);
|
||||
expect(queryByA11yHint(NO_MATCHES_TEXT)).toBeNull();
|
||||
|
||||
expect(() => getByA11yHint(TEXT_HINT)).toThrow(FOUND_TWO_INSTANCES);
|
||||
@@ -127,7 +141,7 @@ test('getByA11yHint, queryByA11yHint, findByA11yHint', async () => {
|
||||
const asyncButton = await findByA11yHint(BUTTON_HINT);
|
||||
expect(asyncButton.props.accessibilityHint).toEqual(BUTTON_HINT);
|
||||
await expect(findByA11yHint(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow(
|
||||
NO_INSTANCES_FOUND
|
||||
getNoInstancesFoundMessage('accessibilityHint')
|
||||
);
|
||||
await expect(findByA11yHint(TEXT_HINT, waitForOptions)).rejects.toThrow(
|
||||
FOUND_TWO_INSTANCES
|
||||
@@ -142,12 +156,14 @@ test('getAllByA11yHint, queryAllByA11yHint, findAllByA11yHint', async () => {
|
||||
expect(getAllByA11yHint(TEXT_HINT)).toHaveLength(2);
|
||||
expect(queryAllByA11yHint(/static/g)).toHaveLength(2);
|
||||
|
||||
expect(() => getAllByA11yHint(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getAllByA11yHint(NO_MATCHES_TEXT)).toThrow(
|
||||
getNoInstancesFoundMessage('accessibilityHint')
|
||||
);
|
||||
expect(queryAllByA11yHint(NO_MATCHES_TEXT)).toEqual([]);
|
||||
|
||||
await expect(findAllByA11yHint(TEXT_HINT)).resolves.toHaveLength(2);
|
||||
await expect(findAllByA11yHint(NO_MATCHES_TEXT)).rejects.toThrow(
|
||||
NO_INSTANCES_FOUND
|
||||
getNoInstancesFoundMessage('accessibilityHint')
|
||||
);
|
||||
});
|
||||
|
||||
@@ -160,7 +176,9 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole', async () => {
|
||||
const button = queryByA11yRole(/button/g);
|
||||
expect(button && button.props.accessibilityRole).toEqual('button');
|
||||
|
||||
expect(() => getByA11yRole(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getByA11yRole(NO_MATCHES_TEXT)).toThrow(
|
||||
getNoInstancesFoundMessage('accessibilityRole')
|
||||
);
|
||||
expect(queryByA11yRole(NO_MATCHES_TEXT)).toBeNull();
|
||||
|
||||
expect(() => getByA11yRole('link')).toThrow(FOUND_TWO_INSTANCES);
|
||||
@@ -169,7 +187,7 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole', async () => {
|
||||
const asyncButton = await findByA11yRole('button');
|
||||
expect(asyncButton.props.accessibilityRole).toEqual('button');
|
||||
await expect(findByA11yRole(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow(
|
||||
NO_INSTANCES_FOUND
|
||||
getNoInstancesFoundMessage('accessibilityRole')
|
||||
);
|
||||
await expect(findByA11yRole('link')).rejects.toThrow(FOUND_TWO_INSTANCES);
|
||||
});
|
||||
@@ -182,13 +200,15 @@ test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole', async () => {
|
||||
expect(getAllByA11yRole('link')).toHaveLength(2);
|
||||
expect(queryAllByA11yRole(/ink/g)).toHaveLength(2);
|
||||
|
||||
expect(() => getAllByA11yRole(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getAllByA11yRole(NO_MATCHES_TEXT)).toThrow(
|
||||
getNoInstancesFoundMessage('accessibilityRole')
|
||||
);
|
||||
expect(queryAllByA11yRole(NO_MATCHES_TEXT)).toEqual([]);
|
||||
|
||||
await expect(findAllByA11yRole('link')).resolves.toHaveLength(2);
|
||||
await expect(
|
||||
findAllByA11yRole(NO_MATCHES_TEXT, waitForOptions)
|
||||
).rejects.toThrow(NO_INSTANCES_FOUND);
|
||||
).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole'));
|
||||
});
|
||||
|
||||
// TODO: accessibilityStates was removed from RN 0.62
|
||||
@@ -209,7 +229,9 @@ test.skip('getByA11yStates, queryByA11yStates', () => {
|
||||
disabledSelected && disabledSelected.props.accessibilityStates
|
||||
).toEqual(['selected', 'disabled']);
|
||||
|
||||
expect(() => getByA11yStates(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getByA11yStates(NO_MATCHES_TEXT)).toThrow(
|
||||
getNoInstancesFoundMessage('accessibilityStates')
|
||||
);
|
||||
expect(queryByA11yStates(NO_MATCHES_TEXT)).toBeNull();
|
||||
expect(queryByA11yStates([])).toBeNull();
|
||||
|
||||
@@ -224,7 +246,9 @@ test.skip('getAllByA11yStates, queryAllByA11yStates', () => {
|
||||
expect(getAllByA11yStates('selected')).toHaveLength(3);
|
||||
expect(queryAllByA11yStates(['selected'])).toHaveLength(3);
|
||||
|
||||
expect(() => getAllByA11yStates([])).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getAllByA11yStates([])).toThrow(
|
||||
getNoInstancesFoundMessage('accessibilityStates')
|
||||
);
|
||||
expect(queryAllByA11yStates(NO_MATCHES_TEXT)).toEqual([]);
|
||||
});
|
||||
|
||||
@@ -244,7 +268,13 @@ test('getByA11yState, queryByA11yState, findByA11yState', async () => {
|
||||
expanded: false,
|
||||
});
|
||||
|
||||
expect(() => getByA11yState({ disabled: true })).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getByA11yState({ disabled: true })).toThrow(
|
||||
getNoInstancesFoundMessage(
|
||||
'accessibilityState',
|
||||
'{"disabled": true}',
|
||||
false
|
||||
)
|
||||
);
|
||||
expect(queryByA11yState({ disabled: true })).toEqual(null);
|
||||
|
||||
expect(() => getByA11yState({ expanded: false })).toThrow(
|
||||
@@ -261,7 +291,13 @@ test('getByA11yState, queryByA11yState, findByA11yState', async () => {
|
||||
});
|
||||
await expect(
|
||||
findByA11yState({ disabled: true }, waitForOptions)
|
||||
).rejects.toThrow(NO_INSTANCES_FOUND);
|
||||
).rejects.toThrow(
|
||||
getNoInstancesFoundMessage(
|
||||
'accessibilityState',
|
||||
'{"disabled": true}',
|
||||
false
|
||||
)
|
||||
);
|
||||
await expect(
|
||||
findByA11yState({ expanded: false }, waitForOptions)
|
||||
).rejects.toThrow(FOUND_TWO_INSTANCES);
|
||||
@@ -276,7 +312,11 @@ test('getAllByA11yState, queryAllByA11yState, findAllByA11yState', async () => {
|
||||
expect(queryAllByA11yState({ selected: true })).toHaveLength(1);
|
||||
|
||||
expect(() => getAllByA11yState({ disabled: true })).toThrow(
|
||||
NO_INSTANCES_FOUND
|
||||
getNoInstancesFoundMessage(
|
||||
'accessibilityState',
|
||||
'{"disabled": true}',
|
||||
false
|
||||
)
|
||||
);
|
||||
expect(queryAllByA11yState({ disabled: true })).toEqual([]);
|
||||
|
||||
@@ -286,7 +326,13 @@ test('getAllByA11yState, queryAllByA11yState, findAllByA11yState', async () => {
|
||||
await expect(findAllByA11yState({ selected: true })).resolves.toHaveLength(1);
|
||||
await expect(
|
||||
findAllByA11yState({ disabled: true }, waitForOptions)
|
||||
).rejects.toThrow(NO_INSTANCES_FOUND);
|
||||
).rejects.toThrow(
|
||||
getNoInstancesFoundMessage(
|
||||
'accessibilityState',
|
||||
'{"disabled": true}',
|
||||
false
|
||||
)
|
||||
);
|
||||
await expect(findAllByA11yState({ expanded: false })).resolves.toHaveLength(
|
||||
2
|
||||
);
|
||||
@@ -306,7 +352,9 @@ test('getByA11yValue, queryByA11yValue, findByA11yValue', async () => {
|
||||
max: 60,
|
||||
});
|
||||
|
||||
expect(() => getByA11yValue({ min: 50 })).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getByA11yValue({ min: 50 })).toThrow(
|
||||
getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false)
|
||||
);
|
||||
expect(queryByA11yValue({ min: 50 })).toEqual(null);
|
||||
|
||||
expect(() => getByA11yValue({ max: 60 })).toThrow(FOUND_TWO_INSTANCES);
|
||||
@@ -318,7 +366,7 @@ test('getByA11yValue, queryByA11yValue, findByA11yValue', async () => {
|
||||
max: 60,
|
||||
});
|
||||
await expect(findByA11yValue({ min: 50 }, waitForOptions)).rejects.toThrow(
|
||||
NO_INSTANCES_FOUND
|
||||
getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false)
|
||||
);
|
||||
await expect(findByA11yValue({ max: 60 }, waitForOptions)).rejects.toThrow(
|
||||
FOUND_TWO_INSTANCES
|
||||
@@ -333,7 +381,9 @@ test('getAllByA11yValue, queryAllByA11yValue, findAllByA11yValue', async () => {
|
||||
expect(getAllByA11yValue({ min: 40 })).toHaveLength(1);
|
||||
expect(queryAllByA11yValue({ min: 40 })).toHaveLength(1);
|
||||
|
||||
expect(() => getAllByA11yValue({ min: 50 })).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(() => getAllByA11yValue({ min: 50 })).toThrow(
|
||||
getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false)
|
||||
);
|
||||
expect(queryAllByA11yValue({ min: 50 })).toEqual([]);
|
||||
|
||||
expect(queryAllByA11yValue({ max: 60 })).toHaveLength(2);
|
||||
@@ -341,7 +391,7 @@ test('getAllByA11yValue, queryAllByA11yValue, findAllByA11yValue', async () => {
|
||||
|
||||
await expect(findAllByA11yValue({ min: 40 })).resolves.toHaveLength(1);
|
||||
await expect(findAllByA11yValue({ min: 50 }, waitForOptions)).rejects.toThrow(
|
||||
NO_INSTANCES_FOUND
|
||||
getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false)
|
||||
);
|
||||
await expect(findAllByA11yValue({ max: 60 })).resolves.toHaveLength(2);
|
||||
});
|
||||
|
||||
@@ -132,7 +132,9 @@ test('getByText, queryByText', () => {
|
||||
const sameButton = getByText('not fresh');
|
||||
|
||||
expect(sameButton.props.children).toBe('not fresh');
|
||||
expect(() => getByText('InExistent')).toThrow('No instances found');
|
||||
expect(() => getByText('InExistent')).toThrow(
|
||||
'No instances found with text "InExistent"'
|
||||
);
|
||||
|
||||
const zeroText = getByText('0');
|
||||
|
||||
@@ -186,7 +188,7 @@ test('getByPlaceholderText, queryByPlaceholderText', () => {
|
||||
|
||||
expect(sameInput.props.placeholder).toBe(PLACEHOLDER_FRESHNESS);
|
||||
expect(() => getByPlaceholderText('no placeholder')).toThrow(
|
||||
'No instances found'
|
||||
'No instances found with placeholder "no placeholder"'
|
||||
);
|
||||
|
||||
expect(queryByPlaceholderText(/add/i)).toBe(input);
|
||||
@@ -220,7 +222,9 @@ test('getByDisplayValue, queryByDisplayValue', () => {
|
||||
const sameInput = getByDisplayValue(INPUT_FRESHNESS);
|
||||
|
||||
expect(sameInput.props.value).toBe(INPUT_FRESHNESS);
|
||||
expect(() => getByDisplayValue('no value')).toThrow('No instances found');
|
||||
expect(() => getByDisplayValue('no value')).toThrow(
|
||||
'No instances found with display value "no value"'
|
||||
);
|
||||
|
||||
expect(queryByDisplayValue(/custom/i)).toBe(input);
|
||||
expect(queryByDisplayValue('no value')).toBeNull();
|
||||
|
||||
+17
-2
@@ -1,4 +1,6 @@
|
||||
// @flow
|
||||
import prettyFormat from 'pretty-format';
|
||||
|
||||
export class ErrorWithStack extends Error {
|
||||
constructor(message: ?string, callsite: Function) {
|
||||
super(message);
|
||||
@@ -13,9 +15,22 @@ export const createLibraryNotSupportedError = (error: Error) =>
|
||||
`Currently the only supported library to search by text is "react-native".\n\n${error.message}`
|
||||
);
|
||||
|
||||
export const prepareErrorMessage = (error: Error) =>
|
||||
export const prepareErrorMessage = (
|
||||
error: Error,
|
||||
name: ?string,
|
||||
value: ?mixed
|
||||
) => {
|
||||
// Strip info about custom predicate
|
||||
error.message.replace(/ matching custom predicate[^]*/gm, '');
|
||||
let errorMessage = error.message.replace(
|
||||
/ matching custom predicate[^]*/gm,
|
||||
''
|
||||
);
|
||||
|
||||
if (name && value) {
|
||||
errorMessage += ` with ${name} ${prettyFormat(value, { min: true })}`;
|
||||
}
|
||||
return errorMessage;
|
||||
};
|
||||
|
||||
export const createQueryByError = (error: Error, callsite: Function) => {
|
||||
if (error.message.includes('No instances found')) {
|
||||
|
||||
+11
-5
@@ -100,7 +100,10 @@ export const getByText = (instance: ReactTestInstance) =>
|
||||
try {
|
||||
return instance.find((node) => getNodeByText(node, text));
|
||||
} catch (error) {
|
||||
throw new ErrorWithStack(prepareErrorMessage(error), getByTextFn);
|
||||
throw new ErrorWithStack(
|
||||
prepareErrorMessage(error, 'text', text),
|
||||
getByTextFn
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -112,20 +115,23 @@ export const getByPlaceholderText = (instance: ReactTestInstance) =>
|
||||
);
|
||||
} catch (error) {
|
||||
throw new ErrorWithStack(
|
||||
prepareErrorMessage(error),
|
||||
prepareErrorMessage(error, 'placeholder', placeholder),
|
||||
getByPlaceholderTextFn
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const getByDisplayValue = (instance: ReactTestInstance) =>
|
||||
function getByDisplayValueFn(placeholder: string | RegExp) {
|
||||
function getByDisplayValueFn(displayValue: string | RegExp) {
|
||||
try {
|
||||
return instance.find((node) =>
|
||||
getTextInputNodeByDisplayValue(node, placeholder)
|
||||
getTextInputNodeByDisplayValue(node, displayValue)
|
||||
);
|
||||
} catch (error) {
|
||||
throw new ErrorWithStack(prepareErrorMessage(error), getByDisplayValueFn);
|
||||
throw new ErrorWithStack(
|
||||
prepareErrorMessage(error, 'display value', displayValue),
|
||||
getByDisplayValueFn
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -37,7 +37,10 @@ const makeQuery = <P: mixed, M: mixed>(
|
||||
(node) => isNodeValid(node) && matcherFn(node.props[name], matcher)
|
||||
);
|
||||
} catch (error) {
|
||||
throw new ErrorWithStack(prepareErrorMessage(error), getBy);
|
||||
throw new ErrorWithStack(
|
||||
prepareErrorMessage(error, name, matcher),
|
||||
getBy
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -47,7 +50,10 @@ const makeQuery = <P: mixed, M: mixed>(
|
||||
);
|
||||
|
||||
if (results.length === 0) {
|
||||
throw new ErrorWithStack('No instances found', getAllBy);
|
||||
throw new ErrorWithStack(
|
||||
prepareErrorMessage(new Error('No instances found'), name, matcher),
|
||||
getAllBy
|
||||
);
|
||||
}
|
||||
|
||||
return results;
|
||||
|
||||
Reference in New Issue
Block a user