Skip to content

Commit 484c9f7

Browse files
sreggmdjastrzebski
andauthored
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 <[email protected]> * addressing PR comments * fixed lint error Co-authored-by: Maciej Jastrzebski <[email protected]>
1 parent 1b5569b commit 484c9f7

File tree

5 files changed

+116
-35
lines changed

5 files changed

+116
-35
lines changed

src/__tests__/a11yAPI.test.js

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,17 @@ const TEXT_LABEL = 'cool text';
99
const TEXT_HINT = 'static text';
1010
// Little hack to make all the methods happy with type
1111
const NO_MATCHES_TEXT: any = 'not-existent-element';
12-
const NO_INSTANCES_FOUND = 'No instances found';
1312
const FOUND_TWO_INSTANCES = 'Expected 1 but found 2 instances';
1413

14+
const getNoInstancesFoundMessage = (
15+
name: string,
16+
value: string = NO_MATCHES_TEXT,
17+
includeQuotes: boolean = true
18+
) => {
19+
const quote = includeQuotes ? '"' : '';
20+
return `No instances found with ${name} ${quote}${value}${quote}`;
21+
};
22+
1523
const Typography = ({ children, ...rest }: any) => {
1624
return <Text {...rest}>{children}</Text>;
1725
};
@@ -73,7 +81,9 @@ test('getByA11yLabel, queryByA11yLabel, findByA11yLabel', async () => {
7381
const button = queryByA11yLabel(/button/g);
7482
expect(button && button.props.accessibilityLabel).toEqual(BUTTON_LABEL);
7583

76-
expect(() => getByA11yLabel(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
84+
expect(() => getByA11yLabel(NO_MATCHES_TEXT)).toThrow(
85+
getNoInstancesFoundMessage('accessibilityLabel')
86+
);
7787
expect(queryByA11yLabel(NO_MATCHES_TEXT)).toBeNull();
7888

7989
expect(() => getByA11yLabel(TEXT_LABEL)).toThrow(FOUND_TWO_INSTANCES);
@@ -83,7 +93,7 @@ test('getByA11yLabel, queryByA11yLabel, findByA11yLabel', async () => {
8393
expect(asyncButton.props.accessibilityLabel).toEqual(BUTTON_LABEL);
8494
await expect(
8595
findByA11yLabel(NO_MATCHES_TEXT, waitForOptions)
86-
).rejects.toThrow(NO_INSTANCES_FOUND);
96+
).rejects.toThrow(getNoInstancesFoundMessage('accessibilityLabel'));
8797

8898
await expect(findByA11yLabel(TEXT_LABEL, waitForOptions)).rejects.toThrow(
8999
FOUND_TWO_INSTANCES
@@ -98,12 +108,14 @@ test('getAllByA11yLabel, queryAllByA11yLabel, findAllByA11yLabel', async () => {
98108
expect(getAllByA11yLabel(TEXT_LABEL)).toHaveLength(2);
99109
expect(queryAllByA11yLabel(/cool/g)).toHaveLength(3);
100110

101-
expect(() => getAllByA11yLabel(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
111+
expect(() => getAllByA11yLabel(NO_MATCHES_TEXT)).toThrow(
112+
getNoInstancesFoundMessage('accessibilityLabel')
113+
);
102114
expect(queryAllByA11yLabel(NO_MATCHES_TEXT)).toEqual([]);
103115

104116
await expect(findAllByA11yLabel(TEXT_LABEL)).resolves.toHaveLength(2);
105117
await expect(findAllByA11yLabel(NO_MATCHES_TEXT)).rejects.toThrow(
106-
NO_INSTANCES_FOUND
118+
getNoInstancesFoundMessage('accessibilityLabel')
107119
);
108120
});
109121

@@ -118,7 +130,9 @@ test('getByA11yHint, queryByA11yHint, findByA11yHint', async () => {
118130
const button = queryByA11yHint(/button/g);
119131
expect(button && button.props.accessibilityHint).toEqual(BUTTON_HINT);
120132

121-
expect(() => getByA11yHint(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
133+
expect(() => getByA11yHint(NO_MATCHES_TEXT)).toThrow(
134+
getNoInstancesFoundMessage('accessibilityHint')
135+
);
122136
expect(queryByA11yHint(NO_MATCHES_TEXT)).toBeNull();
123137

124138
expect(() => getByA11yHint(TEXT_HINT)).toThrow(FOUND_TWO_INSTANCES);
@@ -127,7 +141,7 @@ test('getByA11yHint, queryByA11yHint, findByA11yHint', async () => {
127141
const asyncButton = await findByA11yHint(BUTTON_HINT);
128142
expect(asyncButton.props.accessibilityHint).toEqual(BUTTON_HINT);
129143
await expect(findByA11yHint(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow(
130-
NO_INSTANCES_FOUND
144+
getNoInstancesFoundMessage('accessibilityHint')
131145
);
132146
await expect(findByA11yHint(TEXT_HINT, waitForOptions)).rejects.toThrow(
133147
FOUND_TWO_INSTANCES
@@ -142,12 +156,14 @@ test('getAllByA11yHint, queryAllByA11yHint, findAllByA11yHint', async () => {
142156
expect(getAllByA11yHint(TEXT_HINT)).toHaveLength(2);
143157
expect(queryAllByA11yHint(/static/g)).toHaveLength(2);
144158

145-
expect(() => getAllByA11yHint(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
159+
expect(() => getAllByA11yHint(NO_MATCHES_TEXT)).toThrow(
160+
getNoInstancesFoundMessage('accessibilityHint')
161+
);
146162
expect(queryAllByA11yHint(NO_MATCHES_TEXT)).toEqual([]);
147163

148164
await expect(findAllByA11yHint(TEXT_HINT)).resolves.toHaveLength(2);
149165
await expect(findAllByA11yHint(NO_MATCHES_TEXT)).rejects.toThrow(
150-
NO_INSTANCES_FOUND
166+
getNoInstancesFoundMessage('accessibilityHint')
151167
);
152168
});
153169

@@ -160,7 +176,9 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole', async () => {
160176
const button = queryByA11yRole(/button/g);
161177
expect(button && button.props.accessibilityRole).toEqual('button');
162178

163-
expect(() => getByA11yRole(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
179+
expect(() => getByA11yRole(NO_MATCHES_TEXT)).toThrow(
180+
getNoInstancesFoundMessage('accessibilityRole')
181+
);
164182
expect(queryByA11yRole(NO_MATCHES_TEXT)).toBeNull();
165183

166184
expect(() => getByA11yRole('link')).toThrow(FOUND_TWO_INSTANCES);
@@ -169,7 +187,7 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole', async () => {
169187
const asyncButton = await findByA11yRole('button');
170188
expect(asyncButton.props.accessibilityRole).toEqual('button');
171189
await expect(findByA11yRole(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow(
172-
NO_INSTANCES_FOUND
190+
getNoInstancesFoundMessage('accessibilityRole')
173191
);
174192
await expect(findByA11yRole('link')).rejects.toThrow(FOUND_TWO_INSTANCES);
175193
});
@@ -182,13 +200,15 @@ test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole', async () => {
182200
expect(getAllByA11yRole('link')).toHaveLength(2);
183201
expect(queryAllByA11yRole(/ink/g)).toHaveLength(2);
184202

185-
expect(() => getAllByA11yRole(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
203+
expect(() => getAllByA11yRole(NO_MATCHES_TEXT)).toThrow(
204+
getNoInstancesFoundMessage('accessibilityRole')
205+
);
186206
expect(queryAllByA11yRole(NO_MATCHES_TEXT)).toEqual([]);
187207

188208
await expect(findAllByA11yRole('link')).resolves.toHaveLength(2);
189209
await expect(
190210
findAllByA11yRole(NO_MATCHES_TEXT, waitForOptions)
191-
).rejects.toThrow(NO_INSTANCES_FOUND);
211+
).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole'));
192212
});
193213

194214
// TODO: accessibilityStates was removed from RN 0.62
@@ -209,7 +229,9 @@ test.skip('getByA11yStates, queryByA11yStates', () => {
209229
disabledSelected && disabledSelected.props.accessibilityStates
210230
).toEqual(['selected', 'disabled']);
211231

212-
expect(() => getByA11yStates(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND);
232+
expect(() => getByA11yStates(NO_MATCHES_TEXT)).toThrow(
233+
getNoInstancesFoundMessage('accessibilityStates')
234+
);
213235
expect(queryByA11yStates(NO_MATCHES_TEXT)).toBeNull();
214236
expect(queryByA11yStates([])).toBeNull();
215237

@@ -224,7 +246,9 @@ test.skip('getAllByA11yStates, queryAllByA11yStates', () => {
224246
expect(getAllByA11yStates('selected')).toHaveLength(3);
225247
expect(queryAllByA11yStates(['selected'])).toHaveLength(3);
226248

227-
expect(() => getAllByA11yStates([])).toThrow(NO_INSTANCES_FOUND);
249+
expect(() => getAllByA11yStates([])).toThrow(
250+
getNoInstancesFoundMessage('accessibilityStates')
251+
);
228252
expect(queryAllByA11yStates(NO_MATCHES_TEXT)).toEqual([]);
229253
});
230254

@@ -244,7 +268,13 @@ test('getByA11yState, queryByA11yState, findByA11yState', async () => {
244268
expanded: false,
245269
});
246270

247-
expect(() => getByA11yState({ disabled: true })).toThrow(NO_INSTANCES_FOUND);
271+
expect(() => getByA11yState({ disabled: true })).toThrow(
272+
getNoInstancesFoundMessage(
273+
'accessibilityState',
274+
'{"disabled": true}',
275+
false
276+
)
277+
);
248278
expect(queryByA11yState({ disabled: true })).toEqual(null);
249279

250280
expect(() => getByA11yState({ expanded: false })).toThrow(
@@ -261,7 +291,13 @@ test('getByA11yState, queryByA11yState, findByA11yState', async () => {
261291
});
262292
await expect(
263293
findByA11yState({ disabled: true }, waitForOptions)
264-
).rejects.toThrow(NO_INSTANCES_FOUND);
294+
).rejects.toThrow(
295+
getNoInstancesFoundMessage(
296+
'accessibilityState',
297+
'{"disabled": true}',
298+
false
299+
)
300+
);
265301
await expect(
266302
findByA11yState({ expanded: false }, waitForOptions)
267303
).rejects.toThrow(FOUND_TWO_INSTANCES);
@@ -276,7 +312,11 @@ test('getAllByA11yState, queryAllByA11yState, findAllByA11yState', async () => {
276312
expect(queryAllByA11yState({ selected: true })).toHaveLength(1);
277313

278314
expect(() => getAllByA11yState({ disabled: true })).toThrow(
279-
NO_INSTANCES_FOUND
315+
getNoInstancesFoundMessage(
316+
'accessibilityState',
317+
'{"disabled": true}',
318+
false
319+
)
280320
);
281321
expect(queryAllByA11yState({ disabled: true })).toEqual([]);
282322

@@ -286,7 +326,13 @@ test('getAllByA11yState, queryAllByA11yState, findAllByA11yState', async () => {
286326
await expect(findAllByA11yState({ selected: true })).resolves.toHaveLength(1);
287327
await expect(
288328
findAllByA11yState({ disabled: true }, waitForOptions)
289-
).rejects.toThrow(NO_INSTANCES_FOUND);
329+
).rejects.toThrow(
330+
getNoInstancesFoundMessage(
331+
'accessibilityState',
332+
'{"disabled": true}',
333+
false
334+
)
335+
);
290336
await expect(findAllByA11yState({ expanded: false })).resolves.toHaveLength(
291337
2
292338
);
@@ -306,7 +352,9 @@ test('getByA11yValue, queryByA11yValue, findByA11yValue', async () => {
306352
max: 60,
307353
});
308354

309-
expect(() => getByA11yValue({ min: 50 })).toThrow(NO_INSTANCES_FOUND);
355+
expect(() => getByA11yValue({ min: 50 })).toThrow(
356+
getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false)
357+
);
310358
expect(queryByA11yValue({ min: 50 })).toEqual(null);
311359

312360
expect(() => getByA11yValue({ max: 60 })).toThrow(FOUND_TWO_INSTANCES);
@@ -318,7 +366,7 @@ test('getByA11yValue, queryByA11yValue, findByA11yValue', async () => {
318366
max: 60,
319367
});
320368
await expect(findByA11yValue({ min: 50 }, waitForOptions)).rejects.toThrow(
321-
NO_INSTANCES_FOUND
369+
getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false)
322370
);
323371
await expect(findByA11yValue({ max: 60 }, waitForOptions)).rejects.toThrow(
324372
FOUND_TWO_INSTANCES
@@ -333,15 +381,17 @@ test('getAllByA11yValue, queryAllByA11yValue, findAllByA11yValue', async () => {
333381
expect(getAllByA11yValue({ min: 40 })).toHaveLength(1);
334382
expect(queryAllByA11yValue({ min: 40 })).toHaveLength(1);
335383

336-
expect(() => getAllByA11yValue({ min: 50 })).toThrow(NO_INSTANCES_FOUND);
384+
expect(() => getAllByA11yValue({ min: 50 })).toThrow(
385+
getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false)
386+
);
337387
expect(queryAllByA11yValue({ min: 50 })).toEqual([]);
338388

339389
expect(queryAllByA11yValue({ max: 60 })).toHaveLength(2);
340390
expect(getAllByA11yValue({ max: 60 })).toHaveLength(2);
341391

342392
await expect(findAllByA11yValue({ min: 40 })).resolves.toHaveLength(1);
343393
await expect(findAllByA11yValue({ min: 50 }, waitForOptions)).rejects.toThrow(
344-
NO_INSTANCES_FOUND
394+
getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false)
345395
);
346396
await expect(findAllByA11yValue({ max: 60 })).resolves.toHaveLength(2);
347397
});

src/__tests__/render.test.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ test('getByText, queryByText', () => {
132132
const sameButton = getByText('not fresh');
133133

134134
expect(sameButton.props.children).toBe('not fresh');
135-
expect(() => getByText('InExistent')).toThrow('No instances found');
135+
expect(() => getByText('InExistent')).toThrow(
136+
'No instances found with text "InExistent"'
137+
);
136138

137139
const zeroText = getByText('0');
138140

@@ -186,7 +188,7 @@ test('getByPlaceholderText, queryByPlaceholderText', () => {
186188

187189
expect(sameInput.props.placeholder).toBe(PLACEHOLDER_FRESHNESS);
188190
expect(() => getByPlaceholderText('no placeholder')).toThrow(
189-
'No instances found'
191+
'No instances found with placeholder "no placeholder"'
190192
);
191193

192194
expect(queryByPlaceholderText(/add/i)).toBe(input);
@@ -220,7 +222,9 @@ test('getByDisplayValue, queryByDisplayValue', () => {
220222
const sameInput = getByDisplayValue(INPUT_FRESHNESS);
221223

222224
expect(sameInput.props.value).toBe(INPUT_FRESHNESS);
223-
expect(() => getByDisplayValue('no value')).toThrow('No instances found');
225+
expect(() => getByDisplayValue('no value')).toThrow(
226+
'No instances found with display value "no value"'
227+
);
224228

225229
expect(queryByDisplayValue(/custom/i)).toBe(input);
226230
expect(queryByDisplayValue('no value')).toBeNull();

src/helpers/errors.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// @flow
2+
import prettyFormat from 'pretty-format';
3+
24
export class ErrorWithStack extends Error {
35
constructor(message: ?string, callsite: Function) {
46
super(message);
@@ -13,9 +15,22 @@ export const createLibraryNotSupportedError = (error: Error) =>
1315
`Currently the only supported library to search by text is "react-native".\n\n${error.message}`
1416
);
1517

16-
export const prepareErrorMessage = (error: Error) =>
18+
export const prepareErrorMessage = (
19+
error: Error,
20+
name: ?string,
21+
value: ?mixed
22+
) => {
1723
// Strip info about custom predicate
18-
error.message.replace(/ matching custom predicate[^]*/gm, '');
24+
let errorMessage = error.message.replace(
25+
/ matching custom predicate[^]*/gm,
26+
''
27+
);
28+
29+
if (name && value) {
30+
errorMessage += ` with ${name} ${prettyFormat(value, { min: true })}`;
31+
}
32+
return errorMessage;
33+
};
1934

2035
export const createQueryByError = (error: Error, callsite: Function) => {
2136
if (error.message.includes('No instances found')) {

src/helpers/getByAPI.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,10 @@ export const getByText = (instance: ReactTestInstance) =>
100100
try {
101101
return instance.find((node) => getNodeByText(node, text));
102102
} catch (error) {
103-
throw new ErrorWithStack(prepareErrorMessage(error), getByTextFn);
103+
throw new ErrorWithStack(
104+
prepareErrorMessage(error, 'text', text),
105+
getByTextFn
106+
);
104107
}
105108
};
106109

@@ -112,20 +115,23 @@ export const getByPlaceholderText = (instance: ReactTestInstance) =>
112115
);
113116
} catch (error) {
114117
throw new ErrorWithStack(
115-
prepareErrorMessage(error),
118+
prepareErrorMessage(error, 'placeholder', placeholder),
116119
getByPlaceholderTextFn
117120
);
118121
}
119122
};
120123

121124
export const getByDisplayValue = (instance: ReactTestInstance) =>
122-
function getByDisplayValueFn(placeholder: string | RegExp) {
125+
function getByDisplayValueFn(displayValue: string | RegExp) {
123126
try {
124127
return instance.find((node) =>
125-
getTextInputNodeByDisplayValue(node, placeholder)
128+
getTextInputNodeByDisplayValue(node, displayValue)
126129
);
127130
} catch (error) {
128-
throw new ErrorWithStack(prepareErrorMessage(error), getByDisplayValueFn);
131+
throw new ErrorWithStack(
132+
prepareErrorMessage(error, 'display value', displayValue),
133+
getByDisplayValueFn
134+
);
129135
}
130136
};
131137

src/helpers/makeQuery.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ const makeQuery = <P: mixed, M: mixed>(
3737
(node) => isNodeValid(node) && matcherFn(node.props[name], matcher)
3838
);
3939
} catch (error) {
40-
throw new ErrorWithStack(prepareErrorMessage(error), getBy);
40+
throw new ErrorWithStack(
41+
prepareErrorMessage(error, name, matcher),
42+
getBy
43+
);
4144
}
4245
};
4346

@@ -47,7 +50,10 @@ const makeQuery = <P: mixed, M: mixed>(
4750
);
4851

4952
if (results.length === 0) {
50-
throw new ErrorWithStack('No instances found', getAllBy);
53+
throw new ErrorWithStack(
54+
prepareErrorMessage(new Error('No instances found'), name, matcher),
55+
getAllBy
56+
);
5157
}
5258

5359
return results;

0 commit comments

Comments
 (0)