From 86f5574aca69ca20d71ff858f9da903e725b8f44 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Wed, 28 Sep 2022 10:45:11 +0200 Subject: [PATCH 1/6] chore: tripwire tests to detect broken assumptions about React Native rendering --- src/__tests__/tripwire.test.tsx | 54 +++++++++++++++++++++++++++++++++ src/helpers/component-tree.ts | 26 ++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 src/__tests__/tripwire.test.tsx diff --git a/src/__tests__/tripwire.test.tsx b/src/__tests__/tripwire.test.tsx new file mode 100644 index 000000000..8a1e916cd --- /dev/null +++ b/src/__tests__/tripwire.test.tsx @@ -0,0 +1,54 @@ +import * as React from 'react'; +import { View, Text, TextInput } from 'react-native'; +import { render } from '..'; +import { getHostSelf } from '../helpers/component-tree'; + +test('React Native tripwire: renders single host element', () => { + const view = render(); + const hostView = view.getByTestId('test'); + expect(getHostSelf(hostView)).toBe(hostView); + + expect(view.toJSON()).toMatchInlineSnapshot(` + + `); +}); + +test('React Native tripwire: renders single host element', () => { + const view = render(Hello); + const compositeView = view.getByText('Hello'); + const hostView = view.getByTestId('test'); + expect(getHostSelf(compositeView)).toBe(hostView); + + expect(view.toJSON()).toMatchInlineSnapshot(` + + Hello + + `); +}); + +test('React Native tripwire: renders single host element', () => { + const view = render( + + ); + const compositeView = view.getByPlaceholderText('Placeholder'); + const hostView = view.getByTestId('test'); + expect(getHostSelf(compositeView)).toBe(hostView); + + expect(view.toJSON()).toMatchInlineSnapshot(` + + `); +}); diff --git a/src/helpers/component-tree.ts b/src/helpers/component-tree.ts index 340472d72..cdc6374a3 100644 --- a/src/helpers/component-tree.ts +++ b/src/helpers/component-tree.ts @@ -59,6 +59,32 @@ export function getHostChildren( return hostChildren; } +/** + * Return a single host element that represent the passed host or composite element. + * + * @param element The element start traversing from. + * @throws Error if the passed element is a composite element and has no host children or has more than one host child. + * @returns If the passed element is a host element, it will return itself, if the passed element is a composite + * element, it will return a single host descendant. + */ +export function getHostSelf( + element: ReactTestInstance | null +): ReactTestInstance { + const hostSelves = getHostSelves(element); + + if (hostSelves.length === 0) { + throw new Error(`Expected exactly one host element, but found none.`); + } + + if (hostSelves.length > 1) { + throw new Error( + `Expected exactly one host element, but got ${hostSelves.length}.` + ); + } + + return hostSelves[0]; +} + /** * Return the array of host elements that represent the passed element. * From 10194d3561e5590af52d62db1fe1a63af3038dba Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Wed, 28 Sep 2022 10:53:01 +0200 Subject: [PATCH 2/6] chore: component-tree function tests --- src/helpers/__tests__/component-tree.test.tsx | 82 ++++++++++++++++++- src/helpers/component-tree.ts | 2 +- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/helpers/__tests__/component-tree.test.tsx b/src/helpers/__tests__/component-tree.test.tsx index 2b1b5c619..3671f3d1d 100644 --- a/src/helpers/__tests__/component-tree.test.tsx +++ b/src/helpers/__tests__/component-tree.test.tsx @@ -4,10 +4,15 @@ import { render } from '../..'; import { getHostChildren, getHostParent, + getHostSelf, getHostSelves, getHostSiblings, } from '../component-tree'; +function ZeroHostChildren() { + return <>; +} + function MultipleHostChildren() { return ( <> @@ -89,6 +94,29 @@ test('returns host children for composite component', () => { ]); }); +test('returns host self for host components', () => { + const view = render( + + + + + + + ); + + const hostSubject = view.getByTestId('subject'); + expect(getHostSelf(hostSubject)).toEqual(hostSubject); + + const hostSibling = view.getByTestId('sibling'); + expect(getHostSelf(hostSibling)).toEqual(hostSibling); + + const hostParent = view.getByTestId('parent'); + expect(getHostSelf(hostParent)).toEqual(hostParent); + + const hostGrandparent = view.getByTestId('grandparent'); + expect(getHostSelf(hostGrandparent)).toEqual(hostGrandparent); +}); + test('returns host selves for host components', () => { const view = render( @@ -112,6 +140,51 @@ test('returns host selves for host components', () => { expect(getHostSelves(hostGrandparent)).toEqual([hostGrandparent]); }); +test('returns host self for React Native composite components', () => { + const view = render( + + Text + + + ); + + const compositeText = view.getByText('Text'); + const hostText = view.getByTestId('text'); + expect(getHostSelf(compositeText)).toEqual(hostText); + + const compositeTextInputByValue = view.getByDisplayValue('TextInputValue'); + const compositeTextInputByPlaceholder = view.getByPlaceholderText( + 'TextInputPlaceholder' + ); + const hostTextInput = view.getByTestId('textInput'); + expect(getHostSelf(compositeTextInputByValue)).toEqual(hostTextInput); + expect(getHostSelf(compositeTextInputByPlaceholder)).toEqual(hostTextInput); +}); + +test('throws on non-single host self element for custom composite components', () => { + const view = render( + + + + + ); + + const zeroCompositeComponent = view.UNSAFE_getByType(ZeroHostChildren); + expect(() => getHostSelf(zeroCompositeComponent)).toThrow( + 'Expected exactly one host element, but found none.' + ); + + const multipleCompositeComponent = + view.UNSAFE_getByType(MultipleHostChildren); + expect(() => getHostSelf(multipleCompositeComponent)).toThrow( + 'Expected exactly one host element, but found 3.' + ); +}); + test('returns host selves for React Native composite components', () => { const view = render( @@ -142,16 +215,21 @@ test('returns host selves for React Native composite components', () => { test('returns host selves for custom composite components', () => { const view = render( + ); - const compositeComponent = view.UNSAFE_getByType(MultipleHostChildren); + const zeroCompositeComponent = view.UNSAFE_getByType(ZeroHostChildren); + expect(getHostSelves(zeroCompositeComponent)).toEqual([]); + + const multipleCompositeComponent = + view.UNSAFE_getByType(MultipleHostChildren); const hostChild1 = view.getByTestId('child1'); const hostChild2 = view.getByTestId('child2'); const hostChild3 = view.getByTestId('child3'); - expect(getHostSelves(compositeComponent)).toEqual([ + expect(getHostSelves(multipleCompositeComponent)).toEqual([ hostChild1, hostChild2, hostChild3, diff --git a/src/helpers/component-tree.ts b/src/helpers/component-tree.ts index cdc6374a3..d6be13755 100644 --- a/src/helpers/component-tree.ts +++ b/src/helpers/component-tree.ts @@ -78,7 +78,7 @@ export function getHostSelf( if (hostSelves.length > 1) { throw new Error( - `Expected exactly one host element, but got ${hostSelves.length}.` + `Expected exactly one host element, but found ${hostSelves.length}.` ); } From 233e1c2d8a3a9da5120f9a802453a10bb1a1a9fc Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Wed, 28 Sep 2022 10:54:15 +0200 Subject: [PATCH 3/6] fix: jest native warnings --- src/__tests__/jest-native.test.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/__tests__/jest-native.test.tsx b/src/__tests__/jest-native.test.tsx index f52e74f7e..64601f47e 100644 --- a/src/__tests__/jest-native.test.tsx +++ b/src/__tests__/jest-native.test.tsx @@ -40,10 +40,10 @@ test('jest-native matchers work correctly', () => { expect(getByText('Disabled Button')).toBeDisabled(); expect(getByText('Enabled Button')).not.toBeDisabled(); - expect(getByA11yHint('Empty Text')).toBeEmpty(); - expect(getByA11yHint('Empty View')).toBeEmpty(); - expect(getByA11yHint('Not Empty Text')).not.toBeEmpty(); - expect(getByA11yHint('Not Empty View')).not.toBeEmpty(); + expect(getByA11yHint('Empty Text')).toBeEmptyElement(); + expect(getByA11yHint('Empty View')).toBeEmptyElement(); + expect(getByA11yHint('Not Empty Text')).not.toBeEmptyElement(); + expect(getByA11yHint('Not Empty View')).not.toBeEmptyElement(); expect(getByA11yHint('Container View')).toContainElement( // $FlowFixMe - TODO: fix @testing-library/jest-native flow typings From db00f57a11733d18a3d515ec00b67cda25e5eb3e Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Wed, 28 Sep 2022 11:41:51 +0200 Subject: [PATCH 4/6] chore: deeply nested text --- src/__tests__/tripwire.test.tsx | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/__tests__/tripwire.test.tsx b/src/__tests__/tripwire.test.tsx index 8a1e916cd..c1de236fd 100644 --- a/src/__tests__/tripwire.test.tsx +++ b/src/__tests__/tripwire.test.tsx @@ -30,6 +30,47 @@ test('React Native tripwire: renders single host element', () => { `); }); +test('React Native tripwire: nested renders single host element', () => { + const view = render( + + Before + Hello + + Deeply nested + + + ); + expect(getHostSelf(view.getByText('Hello'))).toBe(view.getByTestId('test')); + expect(getHostSelf(view.getByText('Before'))).toBe( + view.getByTestId('before') + ); + expect(getHostSelf(view.getByText('Deeply nested'))).toBe( + view.getByTestId('deeplyNested') + ); + + expect(view.toJSON()).toMatchInlineSnapshot(` + + + Before + + Hello + + + Deeply nested + + + + `); +}); + test('React Native tripwire: renders single host element', () => { const view = render( Date: Wed, 28 Sep 2022 11:41:51 +0200 Subject: [PATCH 5/6] refactor: rename tripwire to API assuptions --- src/__tests__/react-native-api.test.tsx | 100 ++++++++++++++++++++++++ src/__tests__/tripwire.test.tsx | 54 ------------- 2 files changed, 100 insertions(+), 54 deletions(-) create mode 100644 src/__tests__/react-native-api.test.tsx delete mode 100644 src/__tests__/tripwire.test.tsx diff --git a/src/__tests__/react-native-api.test.tsx b/src/__tests__/react-native-api.test.tsx new file mode 100644 index 000000000..6fa2018aa --- /dev/null +++ b/src/__tests__/react-native-api.test.tsx @@ -0,0 +1,100 @@ +import * as React from 'react'; +import { View, Text, TextInput } from 'react-native'; +import { render } from '..'; +import { getHostSelf } from '../helpers/component-tree'; + +/** + * Tests in this file are intended to give us an proactive warning that React Native behavior has + * changed in a way that may impact our code like queries or event handling. + */ + +test('React Native API assumption: renders single host element', () => { + const view = render(); + const hostView = view.getByTestId('test'); + expect(getHostSelf(hostView)).toBe(hostView); + + expect(view.toJSON()).toMatchInlineSnapshot(` + + `); +}); + +test('React Native API assumption: renders single host element', () => { + const view = render(Hello); + const compositeView = view.getByText('Hello'); + const hostView = view.getByTestId('test'); + expect(getHostSelf(compositeView)).toBe(hostView); + + expect(view.toJSON()).toMatchInlineSnapshot(` + + Hello + + `); +}); + +test('React Native API assumption: nested renders single host element', () => { + const view = render( + + Before + Hello + + Deeply nested + + + ); + expect(getHostSelf(view.getByText('Hello'))).toBe(view.getByTestId('test')); + expect(getHostSelf(view.getByText('Before'))).toBe( + view.getByTestId('before') + ); + expect(getHostSelf(view.getByText('Deeply nested'))).toBe( + view.getByTestId('deeplyNested') + ); + + expect(view.toJSON()).toMatchInlineSnapshot(` + + + Before + + Hello + + + Deeply nested + + + + `); +}); + +test('React Native API assumption: renders single host element', () => { + const view = render( + + ); + const compositeView = view.getByPlaceholderText('Placeholder'); + const hostView = view.getByTestId('test'); + expect(getHostSelf(compositeView)).toBe(hostView); + + expect(view.toJSON()).toMatchInlineSnapshot(` + + `); +}); diff --git a/src/__tests__/tripwire.test.tsx b/src/__tests__/tripwire.test.tsx deleted file mode 100644 index 8a1e916cd..000000000 --- a/src/__tests__/tripwire.test.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import * as React from 'react'; -import { View, Text, TextInput } from 'react-native'; -import { render } from '..'; -import { getHostSelf } from '../helpers/component-tree'; - -test('React Native tripwire: renders single host element', () => { - const view = render(); - const hostView = view.getByTestId('test'); - expect(getHostSelf(hostView)).toBe(hostView); - - expect(view.toJSON()).toMatchInlineSnapshot(` - - `); -}); - -test('React Native tripwire: renders single host element', () => { - const view = render(Hello); - const compositeView = view.getByText('Hello'); - const hostView = view.getByTestId('test'); - expect(getHostSelf(compositeView)).toBe(hostView); - - expect(view.toJSON()).toMatchInlineSnapshot(` - - Hello - - `); -}); - -test('React Native tripwire: renders single host element', () => { - const view = render( - - ); - const compositeView = view.getByPlaceholderText('Placeholder'); - const hostView = view.getByTestId('test'); - expect(getHostSelf(compositeView)).toBe(hostView); - - expect(view.toJSON()).toMatchInlineSnapshot(` - - `); -}); From 03443e92d9f6ec21a32d4cfb43c2a4822cb3eedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Wed, 28 Sep 2022 13:47:23 +0200 Subject: [PATCH 6/6] refactor: group component-tree test by function name --- src/helpers/__tests__/component-tree.test.tsx | 439 +++++++++--------- 1 file changed, 225 insertions(+), 214 deletions(-) diff --git a/src/helpers/__tests__/component-tree.test.tsx b/src/helpers/__tests__/component-tree.test.tsx index 3671f3d1d..29d793c56 100644 --- a/src/helpers/__tests__/component-tree.test.tsx +++ b/src/helpers/__tests__/component-tree.test.tsx @@ -23,258 +23,269 @@ function MultipleHostChildren() { ); } -test('returns host parent for host component', () => { - const view = render( - - - - +describe('getHostParent()', () => { + it('returns host parent for host component', () => { + const view = render( + + + + + - - ); + ); - const hostParent = getHostParent(view.getByTestId('subject')); - expect(hostParent).toBe(view.getByTestId('parent')); + const hostParent = getHostParent(view.getByTestId('subject')); + expect(hostParent).toBe(view.getByTestId('parent')); - const hostGrandparent = getHostParent(hostParent); - expect(hostGrandparent).toBe(view.getByTestId('grandparent')); + const hostGrandparent = getHostParent(hostParent); + expect(hostGrandparent).toBe(view.getByTestId('grandparent')); - expect(getHostParent(hostGrandparent)).toBe(null); -}); - -test('returns host parent for composite component', () => { - const view = render( - - - - - ); + expect(getHostParent(hostGrandparent)).toBe(null); + }); - const compositeComponent = view.UNSAFE_getByType(MultipleHostChildren); - const hostParent = getHostParent(compositeComponent); - expect(hostParent).toBe(view.getByTestId('parent')); -}); - -test('returns host children for host component', () => { - const view = render( - + it('returns host parent for composite component', () => { + const view = render( + - - - ); - - const hostSubject = view.getByTestId('subject'); - expect(getHostChildren(hostSubject)).toEqual([]); - - const hostSibling = view.getByTestId('sibling'); - const hostParent = view.getByTestId('parent'); - expect(getHostChildren(hostParent)).toEqual([hostSubject, hostSibling]); - - const hostGrandparent = view.getByTestId('grandparent'); - expect(getHostChildren(hostGrandparent)).toEqual([hostParent]); -}); - -test('returns host children for composite component', () => { - const view = render( - - - - - - ); + ); - expect(getHostChildren(view.getByTestId('parent'))).toEqual([ - view.getByTestId('child1'), - view.getByTestId('child2'), - view.getByTestId('child3'), - view.getByTestId('subject'), - view.getByTestId('sibling'), - ]); + const compositeComponent = view.UNSAFE_getByType(MultipleHostChildren); + const hostParent = getHostParent(compositeComponent); + expect(hostParent).toBe(view.getByTestId('parent')); + }); }); -test('returns host self for host components', () => { - const view = render( - - - - +describe('getHostChildren()', () => { + it('returns host children for host component', () => { + const view = render( + + + + + - - ); + ); - const hostSubject = view.getByTestId('subject'); - expect(getHostSelf(hostSubject)).toEqual(hostSubject); + const hostSubject = view.getByTestId('subject'); + expect(getHostChildren(hostSubject)).toEqual([]); - const hostSibling = view.getByTestId('sibling'); - expect(getHostSelf(hostSibling)).toEqual(hostSibling); + const hostSibling = view.getByTestId('sibling'); + const hostParent = view.getByTestId('parent'); + expect(getHostChildren(hostParent)).toEqual([hostSubject, hostSibling]); - const hostParent = view.getByTestId('parent'); - expect(getHostSelf(hostParent)).toEqual(hostParent); + const hostGrandparent = view.getByTestId('grandparent'); + expect(getHostChildren(hostGrandparent)).toEqual([hostParent]); + }); - const hostGrandparent = view.getByTestId('grandparent'); - expect(getHostSelf(hostGrandparent)).toEqual(hostGrandparent); -}); - -test('returns host selves for host components', () => { - const view = render( - + it('returns host children for composite component', () => { + const view = render( + - - ); - - const hostSubject = view.getByTestId('subject'); - expect(getHostSelves(hostSubject)).toEqual([hostSubject]); - - const hostSibling = view.getByTestId('sibling'); - expect(getHostSelves(hostSibling)).toEqual([hostSibling]); - - const hostParent = view.getByTestId('parent'); - expect(getHostSelves(hostParent)).toEqual([hostParent]); - - const hostGrandparent = view.getByTestId('grandparent'); - expect(getHostSelves(hostGrandparent)).toEqual([hostGrandparent]); + ); + + expect(getHostChildren(view.getByTestId('parent'))).toEqual([ + view.getByTestId('child1'), + view.getByTestId('child2'), + view.getByTestId('child3'), + view.getByTestId('subject'), + view.getByTestId('sibling'), + ]); + }); }); -test('returns host self for React Native composite components', () => { - const view = render( - - Text - - - ); +describe('getHostSelf()', () => { + it('returns passed element for host components', () => { + const view = render( + + + + + + + ); - const compositeText = view.getByText('Text'); - const hostText = view.getByTestId('text'); - expect(getHostSelf(compositeText)).toEqual(hostText); + const hostSubject = view.getByTestId('subject'); + expect(getHostSelf(hostSubject)).toEqual(hostSubject); - const compositeTextInputByValue = view.getByDisplayValue('TextInputValue'); - const compositeTextInputByPlaceholder = view.getByPlaceholderText( - 'TextInputPlaceholder' - ); - const hostTextInput = view.getByTestId('textInput'); - expect(getHostSelf(compositeTextInputByValue)).toEqual(hostTextInput); - expect(getHostSelf(compositeTextInputByPlaceholder)).toEqual(hostTextInput); -}); + const hostSibling = view.getByTestId('sibling'); + expect(getHostSelf(hostSibling)).toEqual(hostSibling); -test('throws on non-single host self element for custom composite components', () => { - const view = render( - - - - - ); + const hostParent = view.getByTestId('parent'); + expect(getHostSelf(hostParent)).toEqual(hostParent); - const zeroCompositeComponent = view.UNSAFE_getByType(ZeroHostChildren); - expect(() => getHostSelf(zeroCompositeComponent)).toThrow( - 'Expected exactly one host element, but found none.' - ); + const hostGrandparent = view.getByTestId('grandparent'); + expect(getHostSelf(hostGrandparent)).toEqual(hostGrandparent); + }); - const multipleCompositeComponent = - view.UNSAFE_getByType(MultipleHostChildren); - expect(() => getHostSelf(multipleCompositeComponent)).toThrow( - 'Expected exactly one host element, but found 3.' - ); + it('returns single host child for React Native composite components', () => { + const view = render( + + Text + + + ); + + const compositeText = view.getByText('Text'); + const hostText = view.getByTestId('text'); + expect(getHostSelf(compositeText)).toEqual(hostText); + + const compositeTextInputByValue = view.getByDisplayValue('TextInputValue'); + const compositeTextInputByPlaceholder = view.getByPlaceholderText( + 'TextInputPlaceholder' + ); + const hostTextInput = view.getByTestId('textInput'); + expect(getHostSelf(compositeTextInputByValue)).toEqual(hostTextInput); + expect(getHostSelf(compositeTextInputByPlaceholder)).toEqual(hostTextInput); + }); + + it('throws on non-single host children elements for custom composite components', () => { + const view = render( + + + + + ); + + const zeroCompositeComponent = view.UNSAFE_getByType(ZeroHostChildren); + expect(() => getHostSelf(zeroCompositeComponent)).toThrow( + 'Expected exactly one host element, but found none.' + ); + + const multipleCompositeComponent = + view.UNSAFE_getByType(MultipleHostChildren); + expect(() => getHostSelf(multipleCompositeComponent)).toThrow( + 'Expected exactly one host element, but found 3.' + ); + }); }); -test('returns host selves for React Native composite components', () => { - const view = render( - - Text - - - ); +describe('getHostSelves()', () => { + it('returns passed element for host components', () => { + const view = render( + + + + + + + ); - const compositeText = view.getByText('Text'); - const hostText = view.getByTestId('text'); - expect(getHostSelves(compositeText)).toEqual([hostText]); + const hostSubject = view.getByTestId('subject'); + expect(getHostSelves(hostSubject)).toEqual([hostSubject]); - const compositeTextInputByValue = view.getByDisplayValue('TextInputValue'); - const compositeTextInputByPlaceholder = view.getByPlaceholderText( - 'TextInputPlaceholder' - ); - const hostTextInput = view.getByTestId('textInput'); - expect(getHostSelves(compositeTextInputByValue)).toEqual([hostTextInput]); - expect(getHostSelves(compositeTextInputByPlaceholder)).toEqual([ - hostTextInput, - ]); -}); + const hostSibling = view.getByTestId('sibling'); + expect(getHostSelves(hostSibling)).toEqual([hostSibling]); -test('returns host selves for custom composite components', () => { - const view = render( - - - - - - ); + const hostParent = view.getByTestId('parent'); + expect(getHostSelves(hostParent)).toEqual([hostParent]); - const zeroCompositeComponent = view.UNSAFE_getByType(ZeroHostChildren); - expect(getHostSelves(zeroCompositeComponent)).toEqual([]); - - const multipleCompositeComponent = - view.UNSAFE_getByType(MultipleHostChildren); - const hostChild1 = view.getByTestId('child1'); - const hostChild2 = view.getByTestId('child2'); - const hostChild3 = view.getByTestId('child3'); - expect(getHostSelves(multipleCompositeComponent)).toEqual([ - hostChild1, - hostChild2, - hostChild3, - ]); -}); + const hostGrandparent = view.getByTestId('grandparent'); + expect(getHostSelves(hostGrandparent)).toEqual([hostGrandparent]); + }); -test('returns host siblings for host component', () => { - const view = render( - + test('returns single host element for React Native composite components', () => { + const view = render( - - - - + Text + - - ); - - const hostSiblings = getHostSiblings(view.getByTestId('subject')); - expect(hostSiblings).toEqual([ - view.getByTestId('siblingBefore'), - view.getByTestId('siblingAfter'), - view.getByTestId('child1'), - view.getByTestId('child2'), - view.getByTestId('child3'), - ]); -}); - -test('returns host siblings for composite component', () => { - const view = render( - + ); + + const compositeText = view.getByText('Text'); + const hostText = view.getByTestId('text'); + expect(getHostSelves(compositeText)).toEqual([hostText]); + + const compositeTextInputByValue = view.getByDisplayValue('TextInputValue'); + const compositeTextInputByPlaceholder = view.getByPlaceholderText( + 'TextInputPlaceholder' + ); + + const hostTextInput = view.getByTestId('textInput'); + expect(getHostSelves(compositeTextInputByValue)).toEqual([hostTextInput]); + expect(getHostSelves(compositeTextInputByPlaceholder)).toEqual([ + hostTextInput, + ]); + }); + + test('returns host children for custom composite components', () => { + const view = render( - - - + + - - ); + ); + + const zeroCompositeComponent = view.UNSAFE_getByType(ZeroHostChildren); + expect(getHostSelves(zeroCompositeComponent)).toEqual([]); + + const multipleCompositeComponent = + view.UNSAFE_getByType(MultipleHostChildren); + const hostChild1 = view.getByTestId('child1'); + const hostChild2 = view.getByTestId('child2'); + const hostChild3 = view.getByTestId('child3'); + expect(getHostSelves(multipleCompositeComponent)).toEqual([ + hostChild1, + hostChild2, + hostChild3, + ]); + }); +}); - const compositeComponent = view.UNSAFE_getByType(MultipleHostChildren); - const hostSiblings = getHostSiblings(compositeComponent); - expect(hostSiblings).toEqual([ - view.getByTestId('siblingBefore'), - view.getByTestId('subject'), - view.getByTestId('siblingAfter'), - ]); +describe('getHostSiblings()', () => { + it('returns host siblings for host component', () => { + const view = render( + + + + + + + + + ); + + const hostSiblings = getHostSiblings(view.getByTestId('subject')); + expect(hostSiblings).toEqual([ + view.getByTestId('siblingBefore'), + view.getByTestId('siblingAfter'), + view.getByTestId('child1'), + view.getByTestId('child2'), + view.getByTestId('child3'), + ]); + }); + + it('returns host siblings for composite component', () => { + const view = render( + + + + + + + + + ); + + const compositeComponent = view.UNSAFE_getByType(MultipleHostChildren); + const hostSiblings = getHostSiblings(compositeComponent); + expect(hostSiblings).toEqual([ + view.getByTestId('siblingBefore'), + view.getByTestId('subject'), + view.getByTestId('siblingAfter'), + ]); + }); });