diff --git a/docs/Queries.md b/docs/Queries.md index 9753dcc83..db7549bce 100644 --- a/docs/Queries.md +++ b/docs/Queries.md @@ -70,6 +70,19 @@ const { getByPlaceholder } = render(); const element = getByPlaceholder('username'); ``` +### `ByDisplayValue` + +> getByDisplayValue, getAllByDisplayValue, queryByDisplayValue, queryAllByDisplayValue + +Returns a `ReactTestInstance` for a `TextInput` with a matching display value – may be a string or regular expression. + +```jsx +import { render } from 'react-native-testing-library'; + +const { getByDisplayValue } = render(); +const element = getByDisplayValue('username'); +``` + ### `ByTestId` > getByTestId, getAllByTestId, queryByTestId, queryAllByTestId diff --git a/src/__tests__/__snapshots__/render.test.js.snap b/src/__tests__/__snapshots__/render.test.js.snap index 58f470c13..29c1bfa1f 100644 --- a/src/__tests__/__snapshots__/render.test.js.snap +++ b/src/__tests__/__snapshots__/render.test.js.snap @@ -16,6 +16,7 @@ exports[`debug 1`] = ` rejectResponderTermination={true} testID=\\"bananaCustomFreshness\\" underlineColorAndroid=\\"transparent\\" + value=\\"Custom Freshie\\" /> @@ -208,6 +215,33 @@ test('getAllByPlaceholder, queryAllByPlaceholder', () => { expect(queryAllByPlaceholder('no placeholder')).toHaveLength(0); }); +test('getByDisplayValue, queryByDisplayValue', () => { + const { getByDisplayValue, queryByDisplayValue } = render(); + const input = getByDisplayValue(/custom/i); + + expect(input.props.value).toBe(INPUT_FRESHNESS); + + const sameInput = getByDisplayValue(INPUT_FRESHNESS); + + expect(sameInput.props.value).toBe(INPUT_FRESHNESS); + expect(() => getByDisplayValue('no value')).toThrow('No instances found'); + + expect(queryByDisplayValue(/custom/i)).toBe(input); + expect(queryByDisplayValue('no value')).toBeNull(); + expect(() => queryByDisplayValue(/fresh/i)).toThrow('Expected 1 but found 2'); +}); + +test('getAllByDisplayValue, queryAllByDisplayValue', () => { + const { getAllByDisplayValue, queryAllByDisplayValue } = render(); + const inputs = getAllByDisplayValue(/fresh/i); + + expect(inputs).toHaveLength(2); + expect(() => getAllByDisplayValue('no value')).toThrow('No instances found'); + + expect(queryAllByDisplayValue(/fresh/i)).toEqual(inputs); + expect(queryAllByDisplayValue('no value')).toHaveLength(0); +}); + test('getByProps, queryByProps', () => { const { getByProps, queryByProps } = render(); const primaryType = getByProps({ type: 'primary' }); diff --git a/src/helpers/getByAPI.js b/src/helpers/getByAPI.js index c8fe5c429..c0a219c85 100644 --- a/src/helpers/getByAPI.js +++ b/src/helpers/getByAPI.js @@ -18,8 +18,7 @@ const getNodeByText = (node, text) => { try { // eslint-disable-next-line const { Text, TextInput } = require('react-native'); - const isTextComponent = - filterNodeByType(node, Text) || filterNodeByType(node, TextInput); + const isTextComponent = filterNodeByType(node, Text); if (isTextComponent) { const textChildren = React.Children.map( node.props.children, @@ -54,6 +53,21 @@ const getTextInputNodeByPlaceholder = (node, placeholder) => { } }; +const getTextInputNodeByDisplayValue = (node, value) => { + try { + // eslint-disable-next-line + const { TextInput } = require('react-native'); + return ( + filterNodeByType(node, TextInput) && + (typeof value === 'string' + ? value === node.props.value + : value.test(node.props.value)) + ); + } catch (error) { + throw createLibraryNotSupportedError(error); + } +}; + export const getByName = (instance: ReactTestInstance) => function getByNameFn(name: string | React.ComponentType<*>) { logDeprecationWarning('getByName', 'getByType'); @@ -95,6 +109,17 @@ export const getByPlaceholder = (instance: ReactTestInstance) => } }; +export const getByDisplayValue = (instance: ReactTestInstance) => + function getByDisplayValueFn(placeholder: string | RegExp) { + try { + return instance.find(node => + getTextInputNodeByDisplayValue(node, placeholder) + ); + } catch (error) { + throw new ErrorWithStack(prepareErrorMessage(error), getByDisplayValueFn); + } + }; + export const getByProps = (instance: ReactTestInstance) => function getByPropsFn(props: { [propName: string]: any }) { try { @@ -161,6 +186,20 @@ export const getAllByPlaceholder = (instance: ReactTestInstance) => return results; }; +export const getAllByDisplayValue = (instance: ReactTestInstance) => + function getAllByDisplayValueFn(value: string | RegExp) { + const results = instance.findAll(node => + getTextInputNodeByDisplayValue(node, value) + ); + if (results.length === 0) { + throw new ErrorWithStack( + `No instances found with display value: ${String(value)}`, + getAllByDisplayValueFn + ); + } + return results; + }; + export const getAllByProps = (instance: ReactTestInstance) => function getAllByPropsFn(props: { [propName: string]: any }) { const results = instance.findAllByProps(props); @@ -179,10 +218,12 @@ export const getByAPI = (instance: ReactTestInstance) => ({ getByType: getByType(instance), getByText: getByText(instance), getByPlaceholder: getByPlaceholder(instance), + getByDisplayValue: getByDisplayValue(instance), getByProps: getByProps(instance), getAllByName: getAllByName(instance), getAllByType: getAllByType(instance), getAllByText: getAllByText(instance), getAllByPlaceholder: getAllByPlaceholder(instance), + getAllByDisplayValue: getAllByDisplayValue(instance), getAllByProps: getAllByProps(instance), }); diff --git a/src/helpers/queryByAPI.js b/src/helpers/queryByAPI.js index 8ca7dbff5..95c6c5c06 100644 --- a/src/helpers/queryByAPI.js +++ b/src/helpers/queryByAPI.js @@ -6,11 +6,13 @@ import { getByType, getByText, getByPlaceholder, + getByDisplayValue, getByProps, getAllByName, getAllByType, getAllByText, getAllByPlaceholder, + getAllByDisplayValue, getAllByProps, } from './getByAPI'; import { logDeprecationWarning, createQueryByError } from './errors'; @@ -48,7 +50,16 @@ export const queryByPlaceholder = (instance: ReactTestInstance) => try { return getByPlaceholder(instance)(placeholder); } catch (error) { - return createQueryByError(error, queryByPlaceholder); + return createQueryByError(error, queryByPlaceholderFn); + } + }; + +export const queryByDisplayValue = (instance: ReactTestInstance) => + function queryByDisplayValueFn(value: string | RegExp) { + try { + return getByDisplayValue(instance)(value); + } catch (error) { + return createQueryByError(error, queryByDisplayValueFn); } }; @@ -111,6 +122,16 @@ export const queryAllByPlaceholder = (instance: ReactTestInstance) => ( } }; +export const queryAllByDisplayValue = (instance: ReactTestInstance) => ( + value: string | RegExp +) => { + try { + return getAllByDisplayValue(instance)(value); + } catch (error) { + return []; + } +}; + export const queryAllByProps = (instance: ReactTestInstance) => (props: { [propName: string]: any, }) => { @@ -127,10 +148,12 @@ export const queryByAPI = (instance: ReactTestInstance) => ({ queryByType: queryByType(instance), queryByText: queryByText(instance), queryByPlaceholder: queryByPlaceholder(instance), + queryByDisplayValue: queryByDisplayValue(instance), queryByProps: queryByProps(instance), queryAllByName: queryAllByName(instance), queryAllByType: queryAllByType(instance), queryAllByText: queryAllByText(instance), queryAllByPlaceholder: queryAllByPlaceholder(instance), + queryAllByDisplayValue: queryAllByDisplayValue(instance), queryAllByProps: queryAllByProps(instance), }); diff --git a/typings/__tests__/index.test.tsx b/typings/__tests__/index.test.tsx index cd14058c1..c06112a86 100644 --- a/typings/__tests__/index.test.tsx +++ b/typings/__tests__/index.test.tsx @@ -46,6 +46,12 @@ const getByPlaceholderString: ReactTestInstance = tree.getByPlaceholder( const getByPlaceholderRegExp: ReactTestInstance = tree.getByPlaceholder( /placeholder/g ); +const getByDisplayValueString: ReactTestInstance = tree.getByDisplayValue( + 'my value' +); +const getByDisplayValueRegExp: ReactTestInstance = tree.getByDisplayValue( + /value/g +); const getByProps: ReactTestInstance = tree.getByProps({ value: 2 }); const getByTestId: ReactTestInstance = tree.getByTestId('test-id'); const getAllByNameString: Array = tree.getAllByName('View'); @@ -71,16 +77,20 @@ const queryByType: ReactTestInstance | null = tree.queryByType(View); const queryByTypeWithRequiredProps: ReactTestInstance | null = tree.queryByType( ElementWithRequiredProps ); -const queryByTextString: ReactTestInstance | null = tree.queryByText( - '' -); +const queryByTextString: ReactTestInstance | null = tree.queryByText('View'); const queryByTextRegExp: ReactTestInstance | null = tree.queryByText(/View/g); -const queryByPlaceholderString: ReactTestInstance | null = tree.queryByText( +const queryByPlaceholderString: ReactTestInstance | null = tree.queryByPlaceholder( 'my placeholder' ); -const queryByPlaceholderRegExp: ReactTestInstance | null = tree.queryByText( +const queryByPlaceholderRegExp: ReactTestInstance | null = tree.queryByPlaceholder( /placeholder/g ); +const queryByDisplayValueString: ReactTestInstance | null = tree.queryByDisplayValue( + 'my value' +); +const queryByDisplayValueRegExp: ReactTestInstance | null = tree.queryByDisplayValue( + /value/g +); const queryByProps: ReactTestInstance | null = tree.queryByProps({ value: 2 }); const queryByTestId: ReactTestInstance | null = tree.queryByTestId('test-id'); const queryAllByNameString: Array = tree.queryAllByName( @@ -99,6 +109,12 @@ const queryAllByTextString: Array = tree.queryAllByText( const queryAllByTextRegExp: Array = tree.queryAllByText( /View/g ); +const queryAllByDisplayValueString: Array< + ReactTestInstance +> = tree.queryAllByDisplayValue('View'); +const queryAllByDisplayValueRegExp: Array< + ReactTestInstance +> = tree.queryAllByDisplayValue(/View/g); // Accessibility queries const getByA11yLabel: ReactTestInstance = tree.getByA11yLabel('label'); diff --git a/typings/index.d.ts b/typings/index.d.ts index c2f805337..838460332 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -6,6 +6,7 @@ export interface GetByAPI { getByType:

(type: React.ComponentType

) => ReactTestInstance; getByText: (text: string | RegExp) => ReactTestInstance; getByPlaceholder: (placeholder: string | RegExp) => ReactTestInstance; + getByDisplayValue: (value: string | RegExp) => ReactTestInstance; getByProps: (props: Record) => ReactTestInstance; getByTestId: (testID: string) => ReactTestInstance; getAllByName: (name: React.ReactType | string) => Array; @@ -14,6 +15,7 @@ export interface GetByAPI { getAllByPlaceholder: ( placeholder: string | RegExp ) => Array; + getAllByDisplayValue: (value: string | RegExp) => Array; getAllByProps: (props: Record) => Array; } @@ -24,6 +26,7 @@ export interface QueryByAPI { queryByPlaceholder: ( placeholder: string | RegExp ) => ReactTestInstance | null; + queryByDisplayValue: (value: string | RegExp) => ReactTestInstance | null; queryByProps: (props: Record) => ReactTestInstance | null; queryByTestId: (testID: string) => ReactTestInstance | null; queryAllByName: ( @@ -36,6 +39,9 @@ export interface QueryByAPI { queryAllByPlaceholder: ( placeholder: string | RegExp ) => Array | []; + queryAllByDisplayValue: ( + value: string | RegExp + ) => Array | []; queryAllByProps: ( props: Record ) => Array | [];