diff --git a/README.md b/README.md
index f82129b2b..a7e92f7fa 100644
--- a/README.md
+++ b/README.md
@@ -282,6 +282,30 @@ test('fetch data', async () => {
});
```
+## `query` APIs
+
+Each of the get APIs listed in the render section above have a complimentary query API. The get APIs will throw errors if a proper node cannot be found. This is normally the desired effect. However, if you want to make an assertion that an element is not present in the hierarchy, then you can use the query API instead:
+
+```jsx
+import { render } from 'react-native-testing-library';
+
+const { queryByText } = render(
);
+const submitButton = queryByText('submit');
+expect(submitButton).toBeNull(); // it doesn't exist
+```
+
+## `queryAll` APIs
+
+Each of the query APIs have a corresponding queryAll version that always returns an Array of matching nodes. getAll is the same but throws when the array has a length of 0.
+
+```jsx
+import { render } from 'react-native-testing-library';
+
+const { queryAllByText } = render();
+const submitButtons = queryAllByText('submit');
+expect(submitButtons).toHaveLength(3); // expect 3 elements
+```
+
[build-badge]: https://img.shields.io/circleci/project/github/callstack/react-native-testing-library/master.svg?style=flat-square
diff --git a/src/__tests__/render.test.js b/src/__tests__/render.test.js
index a952ebd10..98a6c7cbc 100644
--- a/src/__tests__/render.test.js
+++ b/src/__tests__/render.test.js
@@ -51,16 +51,19 @@ class Banana extends React.Component {
}
}
-test('getByTestId', () => {
- const { getByTestId } = render();
+test('getByTestId, queryByTestId', () => {
+ const { getByTestId, queryByTestId } = render();
const component = getByTestId('bananaFresh');
expect(component.props.children).toBe('not fresh');
expect(() => getByTestId('InExistent')).toThrow();
+
+ expect(getByTestId('bananaFresh')).toBe(component);
+ expect(queryByTestId('InExistent')).toBeNull();
});
-test('getByName', () => {
- const { getByTestId, getByName } = render();
+test('getByName, queryByName', () => {
+ const { getByTestId, getByName, queryByName } = render();
const bananaFresh = getByTestId('bananaFresh');
const button = getByName('Button');
@@ -72,22 +75,27 @@ test('getByName', () => {
sameButton.props.onPress();
expect(bananaFresh.props.children).toBe('not fresh');
-
expect(() => getByName('InExistent')).toThrow();
+
+ expect(queryByName('Button')).toBe(button);
+ expect(queryByName('InExistent')).toBeNull();
});
-test('getAllByName', () => {
- const { getAllByName } = render();
+test('getAllByName, queryAllByName', () => {
+ const { getAllByName, queryAllByName } = render();
const [text, status, button] = getAllByName('Text');
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')).toThrow();
+
+ expect(queryAllByName('Text')[1]).toBe(status);
+ expect(queryAllByName('InExistent')).toHaveLength(0);
});
-test('getByText', () => {
- const { getByText } = render();
+test('getByText, queryByText', () => {
+ const { getByText, queryByText } = render();
const button = getByText(/change/i);
expect(button.props.children).toBe('Change freshness!');
@@ -96,30 +104,42 @@ test('getByText', () => {
expect(sameButton.props.children).toBe('not fresh');
expect(() => getByText('InExistent')).toThrow();
+
+ expect(queryByText(/change/i)).toBe(button);
+ expect(queryByText('InExistent')).toBeNull();
});
-test('getAllByText', () => {
- const { getAllByText } = render();
- const button = getAllByText(/fresh/i);
+test('getAllByText, queryAllByText', () => {
+ const { getAllByText, queryAllByText } = render();
+ const buttons = getAllByText(/fresh/i);
- expect(button).toHaveLength(3);
+ expect(buttons).toHaveLength(3);
expect(() => getAllByText('InExistent')).toThrow();
+
+ expect(queryAllByText(/fresh/i)).toEqual(buttons);
+ expect(queryAllByText('InExistent')).toHaveLength(0);
});
-test('getByProps', () => {
- const { getByProps } = render();
+test('getByProps, queryByProps', () => {
+ const { getByProps, queryByProps } = render();
const primaryType = getByProps({ type: 'primary' });
expect(primaryType.props.children).toBe('Change freshness!');
expect(() => getByProps({ type: 'inexistent' })).toThrow();
+
+ expect(queryByProps({ type: 'primary' })).toBe(primaryType);
+ expect(queryByProps({ type: 'inexistent' })).toBeNull();
});
-test('getAllByProps', () => {
- const { getAllByProps } = render();
+test('getAllByProp, queryAllByProps', () => {
+ const { getAllByProps, queryAllByProps } = render();
const primaryTypes = getAllByProps({ type: 'primary' });
expect(primaryTypes).toHaveLength(1);
expect(() => getAllByProps({ type: 'inexistent' })).toThrow();
+
+ expect(queryAllByProps({ type: 'primary' })).toEqual(primaryTypes);
+ expect(queryAllByProps({ type: 'inexistent' })).toHaveLength(0);
});
test('update', () => {
diff --git a/src/helpers/getBy.js b/src/helpers/getByAPI.js
similarity index 87%
rename from src/helpers/getBy.js
rename to src/helpers/getByAPI.js
index 783c9e2c6..312625117 100644
--- a/src/helpers/getBy.js
+++ b/src/helpers/getByAPI.js
@@ -75,3 +75,13 @@ export const getAllByProps = (instance: ReactTestInstance) => (props: {
}
return results;
};
+
+export const getByAPI = (instance: ReactTestInstance) => ({
+ getByTestId: getByTestId(instance),
+ getByName: getByName(instance),
+ getByText: getByText(instance),
+ getByProps: getByProps(instance),
+ getAllByName: getAllByName(instance),
+ getAllByText: getAllByText(instance),
+ getAllByProps: getAllByProps(instance),
+});
diff --git a/src/helpers/queryByAPI.js b/src/helpers/queryByAPI.js
new file mode 100644
index 000000000..0005f6dce
--- /dev/null
+++ b/src/helpers/queryByAPI.js
@@ -0,0 +1,91 @@
+// @flow
+import * as React from 'react';
+import {
+ getByTestId,
+ getByName,
+ getByText,
+ getByProps,
+ getAllByName,
+ getAllByText,
+ getAllByProps,
+} from './getByAPI';
+
+export const queryByName = (instance: ReactTestInstance) => (
+ name: string | React.Element<*>
+) => {
+ try {
+ return getByName(instance)(name);
+ } catch (error) {
+ return null;
+ }
+};
+
+export const queryByText = (instance: ReactTestInstance) => (
+ text: string | RegExp
+) => {
+ try {
+ return getByText(instance)(text);
+ } catch (error) {
+ return null;
+ }
+};
+
+export const queryByProps = (instance: ReactTestInstance) => (props: {
+ [propName: string]: any,
+}) => {
+ try {
+ return getByProps(instance)(props);
+ } catch (error) {
+ return null;
+ }
+};
+
+export const queryByTestId = (instance: ReactTestInstance) => (
+ testID: string
+) => {
+ try {
+ return getByTestId(instance)(testID);
+ } catch (error) {
+ return null;
+ }
+};
+
+export const queryAllByName = (instance: ReactTestInstance) => (
+ name: string | React.Element<*>
+) => {
+ try {
+ return getAllByName(instance)(name);
+ } catch (error) {
+ return [];
+ }
+};
+
+export const queryAllByText = (instance: ReactTestInstance) => (
+ text: string | RegExp
+) => {
+ try {
+ return getAllByText(instance)(text);
+ } catch (error) {
+ return [];
+ }
+};
+
+export const queryAllByProps = (instance: ReactTestInstance) => (props: {
+ [propName: string]: any,
+}) => {
+ try {
+ return getAllByProps(instance)(props);
+ } catch (error) {
+ return [];
+ }
+};
+
+export const queryByAPI = (instance: ReactTestInstance) => ({
+ queryByTestId: queryByTestId(instance),
+ queryByName: queryByName(instance),
+ queryByText: queryByText(instance),
+ queryByProps: queryByProps(instance),
+ queryAllByName: queryAllByName(instance),
+ queryAllByText: queryAllByText(instance),
+ queryAllByProps: queryAllByProps(instance),
+});
diff --git a/src/render.js b/src/render.js
index f41583655..0a3184ede 100644
--- a/src/render.js
+++ b/src/render.js
@@ -1,15 +1,8 @@
// @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';
+import { getByAPI } from './helpers/getByAPI';
+import { queryByAPI } from './helpers/queryByAPI';
/**
* Renders test component deeply using react-test-renderer and exposes helpers
@@ -23,13 +16,8 @@ export default function render(
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),
+ ...getByAPI(instance),
+ ...queryByAPI(instance),
update: renderer.update,
unmount: renderer.unmount,
};