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

Commit 49f2b0d

Browse files
authored
fix(getBy*): throw an error if more than one element is found
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 49f2b0d

23 files changed

+629
-320
lines changed

.all-contributorsrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"projectName": "native-testing-library",
3-
"projectOwner": "bcarroll22",
3+
"projectOwner": "testing-library",
44
"repoType": "github",
55
"files": [
66
"README.md"

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,30 @@
66
height="80"
77
width="80"
88
alt="goat"
9-
src="https://github.com/raw/bcarroll22/native-testing-library/master/other/whale.png"
9+
src="https://github.com/raw/testing-library/native-testing-library/master/other/whale.png"
1010
/>
1111
</a>
1212

1313
<p>Simple and complete React Native testing utilities that encourage good testing practices.</p>
1414

1515
[**Read The Docs**](https://native-testing-library.com/docs/intro) |
16-
[Edit the docs](https://github.com/bcarroll22/native-testing-library-docs)
16+
[Edit the docs](https://github.com/testing-library/native-testing-library-docs)
1717
</div>
1818

1919
<hr />
2020

21-
[![Build Status](https://travis-ci.org/bcarroll22/native-testing-library.svg?branch=master)](https://travis-ci.org/bcarroll22/native-testing-library)
22-
[![Code Coverage](https://img.shields.io/codecov/c/github/bcarroll22/native-testing-library.svg?style=flat-square)](https://codecov.io/github/bcarroll22/native-testing-library)
21+
[![Build Status](https://travis-ci.org/testing-library/native-testing-library.svg?branch=master)](https://travis-ci.org/testing-library/native-testing-library)
22+
[![Code Coverage](https://img.shields.io/codecov/c/github/testing-library/native-testing-library.svg?style=flat-square)](https://codecov.io/github/testing-library/native-testing-library)
2323
[![version](https://img.shields.io/npm/v/native-testing-library.svg?style=flat-square)](https://www.npmjs.com/package/native-testing-library)
2424
[![downloads](https://img.shields.io/npm/dm/native-testing-library.svg?style=flat-square)](http://www.npmtrends.com/native-testing-library)
25-
[![MIT License](https://img.shields.io/npm/l/native-testing-library.svg?style=flat-square)](https://github.com/bcarroll22/native-testing-library/blob/master/LICENSE)
25+
[![MIT License](https://img.shields.io/npm/l/native-testing-library.svg?style=flat-square)](https://github.com/testing-library/native-testing-library/blob/master/LICENSE)
2626

2727
[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors)
2828
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
29-
[![Code of Conduct](https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square)](https://github.com/bcarroll22/native-testing-library/blob/master/CODE_OF_CONDUCT.md)
29+
[![Code of Conduct](https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square)](https://github.com/testing-library/native-testing-library/blob/master/CODE_OF_CONDUCT.md)
3030

31-
[![Watch on GitHub](https://img.shields.io/github/watchers/bcarroll22/native-testing-library.svg?style=social)](https://github.com/bcarroll22/native-testing-library/watchers)
32-
[![Star on GitHub](https://img.shields.io/github/stars/bcarroll22/native-testing-library.svg?style=social)](https://github.com/bcarroll22/native-testing-library/stargazers)
31+
[![Watch on GitHub](https://img.shields.io/github/watchers/testing-library/native-testing-library.svg?style=social)](https://github.com/testing-library/native-testing-library/watchers)
32+
[![Star on GitHub](https://img.shields.io/github/stars/testing-library/native-testing-library.svg?style=social)](https://github.com/testing-library/native-testing-library/stargazers)
3333

3434
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
3535
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
@@ -196,7 +196,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
196196

197197
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
198198
<!-- prettier-ignore -->
199-
<table><tr><td align="center"><a href="https://github.com/bcarroll22"><img src="https://avatars2.githubusercontent.com/u/11020406?v=4" width="100px;" alt="Brandon Carroll"/><br /><sub><b>Brandon Carroll</b></sub></a><br /><a href="https://github.com/bcarroll22/native-testing-library/commits?author=bcarroll22" title="Code">💻</a> <a href="https://github.com/bcarroll22/native-testing-library/commits?author=bcarroll22" title="Documentation">📖</a> <a href="#infra-bcarroll22" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/bcarroll22/native-testing-library/commits?author=bcarroll22" title="Tests">⚠️</a></td><td align="center"><a href="http://tagraves.com"><img src="https://avatars1.githubusercontent.com/u/2263711?v=4" width="100px;" alt="Tommy Graves"/><br /><sub><b>Tommy Graves</b></sub></a><br /><a href="#ideas-TAGraves" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-TAGraves" title="Maintenance">🚧</a> <a href="#review-TAGraves" title="Reviewed Pull Requests">👀</a></td><td align="center"><a href="https://kentcdodds.com"><img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;" alt="Kent C. Dodds"/><br /><sub><b>Kent C. Dodds</b></sub></a><br /><a href="#ideas-kentcdodds" title="Ideas, Planning, & Feedback">🤔</a></td><td align="center"><a href="https://github.com/sz-piotr"><img src="https://avatars2.githubusercontent.com/u/17070569?v=4" width="100px;" alt="Piotr Szlachciak"/><br /><sub><b>Piotr Szlachciak</b></sub></a><br /><a href="https://github.com/bcarroll22/native-testing-library/commits?author=sz-piotr" title="Code">💻</a></td><td align="center"><a href="https://github.com/mcgloneleviROOT"><img src="https://avatars3.githubusercontent.com/u/48258981?v=4" width="100px;" alt="mcgloneleviROOT"/><br /><sub><b>mcgloneleviROOT</b></sub></a><br /><a href="https://github.com/bcarroll22/native-testing-library/issues?q=author%3AmcgloneleviROOT" title="Bug reports">🐛</a> <a href="https://github.com/bcarroll22/native-testing-library/commits?author=mcgloneleviROOT" title="Code">💻</a></td><td align="center"><a href="http://exercism.io/profiles/wolverineks/619ce225090a43cb891d2edcbbf50401"><img src="https://avatars2.githubusercontent.com/u/8462274?v=4" width="100px;" alt="Kevin Sullivan"/><br /><sub><b>Kevin Sullivan</b></sub></a><br /><a href="https://github.com/bcarroll22/native-testing-library/commits?author=wolverineks" title="Documentation">📖</a></td></tr></table>
199+
<table><tr><td align="center"><a href="https://github.com/bcarroll22"><img src="https://avatars2.githubusercontent.com/u/11020406?v=4" width="100px;" alt="Brandon Carroll"/><br /><sub><b>Brandon Carroll</b></sub></a><br /><a href="https://github.com/testing-library/native-testing-library/commits?author=bcarroll22" title="Code">💻</a> <a href="https://github.com/testing-library/native-testing-library/commits?author=bcarroll22" title="Documentation">📖</a> <a href="#infra-bcarroll22" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/testing-library/native-testing-library/commits?author=bcarroll22" title="Tests">⚠️</a></td><td align="center"><a href="http://tagraves.com"><img src="https://avatars1.githubusercontent.com/u/2263711?v=4" width="100px;" alt="Tommy Graves"/><br /><sub><b>Tommy Graves</b></sub></a><br /><a href="#ideas-TAGraves" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-TAGraves" title="Maintenance">🚧</a> <a href="#review-TAGraves" title="Reviewed Pull Requests">👀</a></td><td align="center"><a href="https://kentcdodds.com"><img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;" alt="Kent C. Dodds"/><br /><sub><b>Kent C. Dodds</b></sub></a><br /><a href="#ideas-kentcdodds" title="Ideas, Planning, & Feedback">🤔</a></td><td align="center"><a href="https://github.com/sz-piotr"><img src="https://avatars2.githubusercontent.com/u/17070569?v=4" width="100px;" alt="Piotr Szlachciak"/><br /><sub><b>Piotr Szlachciak</b></sub></a><br /><a href="https://github.com/testing-library/native-testing-library/commits?author=sz-piotr" title="Code">💻</a></td><td align="center"><a href="https://github.com/mcgloneleviROOT"><img src="https://avatars3.githubusercontent.com/u/48258981?v=4" width="100px;" alt="mcgloneleviROOT"/><br /><sub><b>mcgloneleviROOT</b></sub></a><br /><a href="https://github.com/testing-library/native-testing-library/issues?q=author%3AmcgloneleviROOT" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/native-testing-library/commits?author=mcgloneleviROOT" title="Code">💻</a></td><td align="center"><a href="http://exercism.io/profiles/wolverineks/619ce225090a43cb891d2edcbbf50401"><img src="https://avatars2.githubusercontent.com/u/8462274?v=4" width="100px;" alt="Kevin Sullivan"/><br /><sub><b>Kevin Sullivan</b></sub></a><br /><a href="https://github.com/testing-library/native-testing-library/commits?author=wolverineks" title="Documentation">📖</a></td></tr></table>
200200

201201
<!-- ALL-CONTRIBUTORS-LIST:END -->
202202

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,10 @@
9797
},
9898
"repository": {
9999
"type": "git",
100-
"url": "https://github.com/bcarroll22/native-testing-library.git"
100+
"url": "https://github.com/testing-library/native-testing-library.git"
101101
},
102102
"bugs": {
103-
"url": "https://github.com/bcarroll22/native-testing-library/issues"
103+
"url": "https://github.com/testing-library/native-testing-library/issues"
104104
},
105-
"homepage": "https://github.com/bcarroll22/native-testing-library#readme"
105+
"homepage": "https://github.com/testing-library/native-testing-library#readme"
106106
}

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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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" />
14+
<View importantForAccessibility="no-hide-descendants" />
15+
</View>,
16+
);
17+
18+
expect(queryByTestId(container, 'foo')).not.toBeNull();
19+
expect(queryByProp('importantForAccessibility', container, 'auto')).toBeNull();
20+
expect(() => queryByProp('importantForAccessibility', container, /no/)).toThrow(
21+
/multiple elements/,
22+
);
23+
});

src/__tests__/pretty-print.js

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,57 @@
11
import React from 'react';
2-
import { Text } from 'react-native';
2+
import { Text, View } from 'react-native';
33

44
import { render } from '../';
55
import { prettyPrint } from '../pretty-print';
66

7-
test('it prints out the given element tree', () => {
8-
const { container } = render(<Text>Hello World!</Text>);
9-
expect(prettyPrint(container)).toMatchInlineSnapshot(`
10-
"<Text>
11-
Hello World!
12-
</Text>"
7+
test('it prints correctly with no children', () => {
8+
const { baseElement } = render(<View />);
9+
10+
expect(prettyPrint(baseElement)).toMatchInlineSnapshot(`"<View />"`);
11+
});
12+
13+
test('it prints correctly with one child', () => {
14+
const { baseElement } = render(
15+
<View>
16+
<Text>Hello World!</Text>
17+
</View>,
18+
);
19+
20+
expect(prettyPrint(baseElement)).toMatchInlineSnapshot(`
21+
"<View>
22+
<Text>
23+
Hello World!
24+
</Text>
25+
</View>"
26+
`);
27+
});
28+
29+
test('it prints correctly with multiple children', () => {
30+
const { baseElement } = render(
31+
<View>
32+
<Text>Hello</Text>
33+
<Text>World!</Text>
34+
</View>,
35+
);
36+
37+
expect(prettyPrint(baseElement)).toMatchInlineSnapshot(`
38+
"<View>
39+
<Text>
40+
Hello
41+
</Text>
42+
<Text>
43+
World!
44+
</Text>
45+
</View>"
1346
`);
1447
});
1548

1649
test('it supports truncating the output length', () => {
17-
const { container } = render(<Text>Hello World!</Text>);
18-
expect(prettyPrint(container, 5)).toMatch(/\.\.\./);
50+
const { baseElement } = render(
51+
<View>
52+
<Text>Hello World!</Text>
53+
</View>,
54+
);
55+
56+
expect(prettyPrint(baseElement, 5)).toMatch(/\.\.\./);
1957
});

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: 1 addition & 2 deletions
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,
@@ -295,7 +294,7 @@ export declare function render<T>(ui: ReactElement, options: RenderOptionsWithQu
295294
export interface RenderResult {
296295
container: ReactTestRenderer
297296
baseElement: NativeTestInstance
298-
debug: () => void
297+
debug: (el?: NativeTestInstance) => void
299298
rerender: (ui: ReactElement) => void
300299
unmount: () => void
301300
}

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ function render(ui, { options = {}, wrapper: WrapperComponent } = {}) {
2424
return {
2525
container,
2626
baseElement,
27-
debug: (el = container) => console.log(prettyPrint(el)),
27+
debug: (el = baseElement) => console.log(prettyPrint(el)),
2828
unmount: () => container.unmount(),
2929
rerender: rerenderUi => {
3030
act(() => {

0 commit comments

Comments
 (0)