From a79225daead44e922e6a1834f1c6ff75dd472c70 Mon Sep 17 00:00:00 2001 From: Dana Hartweg Date: Sat, 22 Dec 2018 15:07:31 -0500 Subject: [PATCH 1/5] feat: Add getByPlaceholder support --- src/helpers/getByAPI.js | 42 +++++++++++++++++++++++++++++++++++++++ src/helpers/queryByAPI.js | 23 +++++++++++++++++++++ typings/index.d.ts | 4 ++++ 3 files changed, 69 insertions(+) diff --git a/src/helpers/getByAPI.js b/src/helpers/getByAPI.js index 5d5ca0dc7..a2fd7fd02 100644 --- a/src/helpers/getByAPI.js +++ b/src/helpers/getByAPI.js @@ -28,6 +28,21 @@ const getNodeByText = (node, text) => { } }; +const getTextInputNodeByPlaceholder = (node, placeholder) => { + try { + // eslint-disable-next-line + const { TextInput } = require('react-native'); + return ( + filterNodeByType(node, TextInput) && + (typeof placeholder === 'string' + ? placeholder === node.props.placeholder + : placeholder.test(node.props.placeholder)) + ); + } catch (error) { + throw createLibraryNotSupportedError(error); + } +}; + const prepareErrorMessage = error => // Strip info about custom predicate error.message.replace(/ matching custom predicate[^]*/gm, ''); @@ -62,6 +77,17 @@ export const getByText = (instance: ReactTestInstance) => } }; +export const getByPlaceholder = (instance: ReactTestInstance) => + function getByPlaceholderFn(placeholder: string | RegExp) { + try { + return instance.find(node => + getTextInputNodeByPlaceholder(node, placeholder) + ); + } catch (error) { + throw new ErrorWithStack(prepareErrorMessage(error), getByPlaceholderFn); + } + }; + export const getByProps = (instance: ReactTestInstance) => function getByPropsFn(props: { [propName: string]: any }) { try { @@ -114,6 +140,20 @@ export const getAllByText = (instance: ReactTestInstance) => return results; }; +export const getAllByPlaceholder = (instance: ReactTestInstance) => + function getAllByPlaceholderFn(placeholder: string | RegExp) { + const results = instance.findAll(node => + getTextInputNodeByPlaceholder(node, placeholder) + ); + if (results.length === 0) { + throw new ErrorWithStack( + `No instances found with placeholder: ${String(placeholder)}`, + getAllByPlaceholderFn + ); + } + return results; + }; + export const getAllByProps = (instance: ReactTestInstance) => function getAllByPropsFn(props: { [propName: string]: any }) { const results = instance.findAllByProps(props); @@ -131,9 +171,11 @@ export const getByAPI = (instance: ReactTestInstance) => ({ getByName: getByName(instance), getByType: getByType(instance), getByText: getByText(instance), + getByPlaceholder: getByPlaceholder(instance), getByProps: getByProps(instance), getAllByName: getAllByName(instance), getAllByType: getAllByType(instance), getAllByText: getAllByText(instance), + getAllByPlaceholder: getAllByPlaceholder(instance), getAllByProps: getAllByProps(instance), }); diff --git a/src/helpers/queryByAPI.js b/src/helpers/queryByAPI.js index 15458af86..a5ef80622 100644 --- a/src/helpers/queryByAPI.js +++ b/src/helpers/queryByAPI.js @@ -5,10 +5,12 @@ import { getByName, getByType, getByText, + getByPlaceholder, getByProps, getAllByName, getAllByType, getAllByText, + getAllByPlaceholder, getAllByProps, } from './getByAPI'; import { ErrorWithStack, logDeprecationWarning } from './errors'; @@ -48,6 +50,15 @@ export const queryByText = (instance: ReactTestInstance) => } }; +export const queryByPlaceholder = (instance: ReactTestInstance) => + function queryByPlaceholderFn(placeholder: string | RegExp) { + try { + return getByPlaceholder(instance)(placeholder); + } catch (error) { + return createQueryByError(error, queryByPlaceholder); + } + }; + export const queryByProps = (instance: ReactTestInstance) => function queryByPropsFn(props: { [propName: string]: any }) { try { @@ -97,6 +108,16 @@ export const queryAllByText = (instance: ReactTestInstance) => ( } }; +export const queryAllByPlaceholder = (instance: ReactTestInstance) => ( + placeholder: string | RegExp +) => { + try { + return getAllByPlaceholder(instance)(placeholder); + } catch (error) { + return []; + } +}; + export const queryAllByProps = (instance: ReactTestInstance) => (props: { [propName: string]: any, }) => { @@ -112,9 +133,11 @@ export const queryByAPI = (instance: ReactTestInstance) => ({ queryByName: queryByName(instance), queryByType: queryByType(instance), queryByText: queryByText(instance), + queryByPlaceholder: queryByPlaceholder(instance), queryByProps: queryByProps(instance), queryAllByName: queryAllByName(instance), queryAllByType: queryAllByType(instance), queryAllByText: queryAllByText(instance), + queryAllByPlaceholder: queryAllByPlaceholder(instance), queryAllByProps: queryAllByProps(instance), }); diff --git a/typings/index.d.ts b/typings/index.d.ts index 8232c5371..0b974e597 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -5,11 +5,13 @@ export interface GetByAPI { getByName: (name: React.ReactType | string) => ReactTestInstance; getByType:

(type: React.ComponentType

) => ReactTestInstance; getByText: (text: string | RegExp) => ReactTestInstance; + getByPlaceholder: (placeholder: string | RegExp) => ReactTestInstance; getByProps: (props: Record) => ReactTestInstance; getByTestId: (testID: string) => ReactTestInstance; getAllByName: (name: React.ReactType | string) => Array; getAllByType:

(type: React.ComponentType

) => Array; getAllByText: (text: string | RegExp) => Array; + getAllByPlaceholder: (placeholder: string | RegExp) => Array; getAllByProps: (props: Record) => Array; } @@ -17,6 +19,7 @@ export interface QueryByAPI { queryByName: (name: React.ReactType | string) => ReactTestInstance | null; queryByType:

(type: React.ComponentType

) => ReactTestInstance | null; queryByText: (name: string | RegExp) => ReactTestInstance | null; + queryByPlaceholder: (placeholder: string | RegExp) => ReactTestInstance | null; queryByProps: (props: Record) => ReactTestInstance | null; queryByTestId: (testID: string) => ReactTestInstance | null; queryAllByName: (name: React.ReactType | string) => Array | []; @@ -24,6 +27,7 @@ export interface QueryByAPI { type: React.ComponentType

) => Array | []; queryAllByText: (text: string | RegExp) => Array | []; + queryAllByPlaceholder: (placeholder: string | RegExp) => Array | []; queryAllByProps: ( props: Record ) => Array | []; From f79e05d1bac34ab958118dcd87397deb62e3ee45 Mon Sep 17 00:00:00 2001 From: Dana Hartweg Date: Sat, 22 Dec 2018 15:08:19 -0500 Subject: [PATCH 2/5] test: Add tests for getByPlaceholder functionality --- .../__snapshots__/render.test.js.snap | 60 +++++++++++++++++++ src/__tests__/render.test.js | 41 ++++++++++++- 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/src/__tests__/__snapshots__/render.test.js.snap b/src/__tests__/__snapshots__/render.test.js.snap index 63b4a8c3c..dd0cc8466 100644 --- a/src/__tests__/__snapshots__/render.test.js.snap +++ b/src/__tests__/__snapshots__/render.test.js.snap @@ -10,6 +10,18 @@ exports[`debug 1`] = ` > not fresh + + fresh + + not fresh + + @@ -138,6 +146,37 @@ test('getAllByText, queryAllByText', () => { expect(queryAllByText('InExistent')).toHaveLength(0); }); +test('getByPlaceholder, queryByPlaceholder', () => { + const { getByPlaceholder, queryByPlaceholder } = render(); + const input = getByPlaceholder(/custom/i); + + expect(input.props.placeholder).toBe(PLACEHOLDER_FRESHNESS); + + const sameInput = getByPlaceholder(PLACEHOLDER_FRESHNESS); + + expect(sameInput.props.placeholder).toBe(PLACEHOLDER_FRESHNESS); + expect(() => getByPlaceholder('no placeholder')).toThrow( + 'No instances found' + ); + + expect(queryByPlaceholder(/add/i)).toBe(input); + expect(queryByPlaceholder('no placeholder')).toBeNull(); + expect(() => queryByPlaceholder(/fresh/)).toThrow('Expected 1 but found 2'); +}); + +test('getAllByPlaceholder, queryAllByPlaceholder', () => { + const { getAllByPlaceholder, queryAllByPlaceholder } = render(); + const inputs = getAllByPlaceholder(/fresh/i); + + expect(inputs).toHaveLength(2); + expect(() => getAllByPlaceholder('no placeholder')).toThrow( + 'No instances found' + ); + + expect(queryAllByPlaceholder(/fresh/i)).toEqual(inputs); + expect(queryAllByPlaceholder('no placeholder')).toHaveLength(0); +}); + test('getByProps, queryByProps', () => { const { getByProps, queryByProps } = render(); const primaryType = getByProps({ type: 'primary' }); From fddba9bb5f22f818e486368c41b50dff41e63834 Mon Sep 17 00:00:00 2001 From: Dana Hartweg Date: Sat, 22 Dec 2018 15:11:17 -0500 Subject: [PATCH 3/5] docs: Add documentation for getByPlaceholder --- docs/API.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/API.md b/docs/API.md index 4dd529748..65889a23a 100644 --- a/docs/API.md +++ b/docs/API.md @@ -52,6 +52,14 @@ A method returning a `ReactTestInstance` with matching text – may be a string A method returning an array of `ReactTestInstance`s with matching text – may be a string or regular expression. +### `getByPlaceholder: (placeholder: string | RegExp)` + +A method returning a `ReactTestInstance` for a `TextInput` with a matching placeholder – may be a string or regular expression. Throws when no matches. + +### `getAllByPlaceholder: (text: string | RegExp)` + +A method returning an array of `ReactTestInstance`s for `TextInput`'s with a matching placeholder – may be a string or regular expression. + ### `getByProps: (props: { [propName: string]: any })` A method returning a `ReactTestInstance` with matching props object. Throws when no matches. From 83229fc321d8aba4aa7880a02b08d467eae29cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Sat, 22 Dec 2018 15:39:37 -0500 Subject: [PATCH 4/5] docs: Update missed text argument to placeholder Co-Authored-By: danahartweg --- docs/API.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/API.md b/docs/API.md index 65889a23a..15a89e0ca 100644 --- a/docs/API.md +++ b/docs/API.md @@ -56,7 +56,7 @@ A method returning an array of `ReactTestInstance`s with matching text – may b A method returning a `ReactTestInstance` for a `TextInput` with a matching placeholder – may be a string or regular expression. Throws when no matches. -### `getAllByPlaceholder: (text: string | RegExp)` +### `getAllByPlaceholder: (placeholder: string | RegExp)` A method returning an array of `ReactTestInstance`s for `TextInput`'s with a matching placeholder – may be a string or regular expression. From 5fc60aed511bb1d5f3a49348d16445db4268d6e8 Mon Sep 17 00:00:00 2001 From: Dana Hartweg Date: Sat, 22 Dec 2018 16:45:43 -0500 Subject: [PATCH 5/5] test: Add typescript tests for placeholder queries --- typings/__tests__/index.test.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/typings/__tests__/index.test.tsx b/typings/__tests__/index.test.tsx index 9249ee13f..b9312587f 100644 --- a/typings/__tests__/index.test.tsx +++ b/typings/__tests__/index.test.tsx @@ -15,6 +15,7 @@ interface HasRequiredProp { const View = props => props.children; const Text = props => props.children; +const TextInput = props => props.children; const ElementWithRequiredProps = (props: HasRequiredProp) => ( {props.requiredProp} ); @@ -22,6 +23,7 @@ const ElementWithRequiredProps = (props: HasRequiredProp) => ( const TestComponent = () => ( Test component + ); @@ -36,6 +38,8 @@ const getByTypeWithRequiredProps: ReactTestInstance = tree.getByType( ); const getByTextString: ReactTestInstance = tree.getByText(''); const getByTextRegExp: ReactTestInstance = tree.getByText(/View/g); +const getByPlaceholderString: ReactTestInstance = tree.getByPlaceholder('my placeholder'); +const getByPlaceholderRegExp: ReactTestInstance = tree.getByPlaceholder(/placeholder/g); const getByProps: ReactTestInstance = tree.getByProps({ value: 2 }); const getByTestId: ReactTestInstance = tree.getByTestId('test-id'); const getAllByNameString: Array = tree.getAllByName('View'); @@ -65,6 +69,10 @@ const queryByTextString: ReactTestInstance | null = tree.queryByText( '' ); const queryByTextRegExp: ReactTestInstance | null = tree.queryByText(/View/g); +const queryByPlaceholderString: ReactTestInstance | null = tree.queryByText( + 'my placeholder' +); +const queryByPlaceholderRegExp: ReactTestInstance | null = tree.queryByText(/placeholder/g); const queryByProps: ReactTestInstance | null = tree.queryByProps({ value: 2 }); const queryByTestId: ReactTestInstance | null = tree.queryByTestId('test-id'); const queryAllByNameString: Array = tree.getAllByName(