Skip to content
This repository was archived by the owner on Jul 30, 2020. It is now read-only.

Commit ebd4410

Browse files
authored
fix(getBy*): throw an error if more than one element is found (#7)
BREAKING CHANGE: `queryBy` and `getBy` now throw when multiple elements are returned and prompt users to use other queries if multiple results were intentional. This was done to remain in feature parity with dom-testing-library.
1 parent 64d8a20 commit ebd4410

17 files changed

+530
-286
lines changed

src/__tests__/get-by-errors.js

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import React from 'react';
2+
import { Text, TextInput, View } from 'react-native';
3+
import cases from 'jest-in-case';
4+
5+
import { render } from '../';
6+
7+
cases(
8+
'getBy* queries throw an error when there are multiple elements returned',
9+
({ name, query, tree }) => {
10+
const utils = render(tree);
11+
expect(() => utils[name](query)).toThrow(/multiple elements/i);
12+
},
13+
{
14+
getByA11yHint: {
15+
query: /his/,
16+
tree: (
17+
<View>
18+
<View accessibilityHint="his" />
19+
<View accessibilityHint="history" />
20+
</View>
21+
),
22+
},
23+
getByA11yLabel: {
24+
query: /his/,
25+
tree: (
26+
<View>
27+
<View accessibilityLabel="his" />
28+
<View accessibilityLabel="history" />
29+
</View>
30+
),
31+
},
32+
getByA11yRole: {
33+
query: 'button',
34+
tree: (
35+
<View>
36+
<View accessibilityRole="button" />
37+
<View accessibilityRole="button" />
38+
</View>
39+
),
40+
},
41+
getByA11yStates: {
42+
query: ['selected'],
43+
tree: (
44+
<View>
45+
<View accessibilityStates={['selected']} />
46+
<View accessibilityStates={['selected']} />
47+
</View>
48+
),
49+
},
50+
getByA11yTraits: {
51+
query: ['button'],
52+
tree: (
53+
<View>
54+
<View accessibilityTraits={['button']} />
55+
<View accessibilityTraits={['button']} />
56+
</View>
57+
),
58+
},
59+
getByPlaceholder: {
60+
query: /his/,
61+
tree: (
62+
<View>
63+
<TextInput placeholder="his" />
64+
<TextInput placeholder="history" />
65+
</View>
66+
),
67+
},
68+
getByTestId: {
69+
query: /his/,
70+
tree: (
71+
<View>
72+
<Text testID="his">text</Text>
73+
<Text testID="history">other</Text>
74+
</View>
75+
),
76+
},
77+
getByText: {
78+
query: /his/,
79+
tree: (
80+
<View>
81+
<Text>his</Text>
82+
<Text>history</Text>
83+
</View>
84+
),
85+
},
86+
getByValue: {
87+
query: /his/,
88+
tree: (
89+
<View>
90+
<TextInput value="his" />
91+
<TextInput value="history" />
92+
</View>
93+
),
94+
},
95+
},
96+
);
97+
98+
cases(
99+
'queryBy* queries throw an error when there are multiple elements returned',
100+
({ name, query, tree }) => {
101+
const utils = render(tree);
102+
expect(() => utils[name](query)).toThrow(/multiple elements/i);
103+
},
104+
{
105+
queryByA11yHint: {
106+
query: /his/,
107+
tree: (
108+
<View>
109+
<View accessibilityHint="his" />
110+
<View accessibilityHint="history" />
111+
</View>
112+
),
113+
},
114+
queryByA11yLabel: {
115+
query: /his/,
116+
tree: (
117+
<View>
118+
<View accessibilityLabel="his" />
119+
<View accessibilityLabel="history" />
120+
</View>
121+
),
122+
},
123+
queryByA11yRole: {
124+
query: 'button',
125+
tree: (
126+
<View>
127+
<View accessibilityRole="button" />
128+
<View accessibilityRole="button" />
129+
</View>
130+
),
131+
},
132+
queryByA11yStates: {
133+
query: ['selected'],
134+
tree: (
135+
<View>
136+
<View accessibilityStates={['selected']} />
137+
<View accessibilityStates={['selected']} />
138+
</View>
139+
),
140+
},
141+
queryByA11yTraits: {
142+
query: ['button'],
143+
tree: (
144+
<View>
145+
<View accessibilityTraits={['button']} />
146+
<View accessibilityTraits={['button']} />
147+
</View>
148+
),
149+
},
150+
queryByPlaceholder: {
151+
query: /his/,
152+
tree: (
153+
<View>
154+
<TextInput placeholder="his" />
155+
<TextInput placeholder="history" />
156+
</View>
157+
),
158+
},
159+
queryByTestId: {
160+
query: /his/,
161+
tree: (
162+
<View>
163+
<Text testID="his">text</Text>
164+
<Text testID="history">other</Text>
165+
</View>
166+
),
167+
},
168+
queryByText: {
169+
query: /his/,
170+
tree: (
171+
<View>
172+
<Text>his</Text>
173+
<Text>history</Text>
174+
</View>
175+
),
176+
},
177+
queryByValue: {
178+
query: /his/,
179+
tree: (
180+
<View>
181+
<TextInput value="his" />
182+
<TextInput value="history" />
183+
</View>
184+
),
185+
},
186+
},
187+
);

src/__tests__/misc.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import { View } from 'react-native';
3+
4+
import { render } from '../';
5+
import { queryByProp, queryByTestId } from '../';
6+
7+
// we used to use queryByProp internally, but we don't anymore. Some people
8+
// use it as an undocumented part of the API, so we'll keep it around.
9+
test('queryByProp', () => {
10+
const { container } = render(
11+
<View>
12+
<View testID="foo" importantForAccessibility="no" />
13+
<View importantForAccessibility="no-hide-descendants" />
14+
</View>,
15+
);
16+
17+
expect(queryByTestId(container, 'foo')).not.toBeNull();
18+
expect(queryByProp('importantForAccessibility', container, 'auto')).toBeNull();
19+
expect(() => queryByProp('importantForAccessibility', container, /no/)).toThrow(
20+
/multiple elements/,
21+
);
22+
});

src/__tests__/text-matchers.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ cases(
141141
query: `Dwayne 'The Rock' Johnson`,
142142
queryFn: `queryAllByPlaceholder`,
143143
},
144+
queryAllByValue: {
145+
tree: <TextInput value="Dwayne 'The Rock' Johnson" />,
146+
query: `Dwayne 'The Rock' Johnson`,
147+
queryFn: `queryAllByValue`,
148+
},
144149
queryAllByAccessibilityLabel: {
145150
tree: <Image accessibilityLabel="Finding Nemo poster " src="/finding-nemo.png" />,
146151
query: `Finding Nemo poster`,

src/index.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ export interface Queries {
227227
export declare function defaultFilter(node: NativeTestInstance): boolean
228228
export declare function getBaseElement(container: ReactTestRenderer | ReactTestInstance): ReactTestInstance
229229
export declare function getElementError(message: string, container: ReactTestRenderer): Error
230-
export declare function firstResultOrNull<T extends any[], U>(query: (...args: T) => U[], ...args: T): U | null
231230
export declare function filterNodeByType(node: NativeTestInstance, type: string): boolean
232231
export declare function queryAllByProp(
233232
attribute: string,

0 commit comments

Comments
 (0)