11// @flow
22import * as React from 'react' ;
3- import { View , Text , TouchableOpacity , Image } from 'react-native' ;
4- import { render } from '..' ;
3+ import {
4+ View ,
5+ Text ,
6+ TouchableOpacity ,
7+ Image ,
8+ Button ,
9+ TextInput ,
10+ } from 'react-native' ;
11+ import { render , getDefaultNormalizer } from '..' ;
512
613const MyButton = ( { children, onPress } ) => (
714 < TouchableOpacity onPress = { onPress } >
@@ -88,8 +95,8 @@ test('getAllByText, queryAllByText', () => {
8895test ( 'findByText queries work asynchronously' , async ( ) => {
8996 const options = { timeout : 10 } ; // Short timeout so that this test runs quickly
9097 const { rerender, findByText, findAllByText } = render ( < View /> ) ;
91- await expect ( findByText ( 'Some Text' , options ) ) . rejects . toBeTruthy ( ) ;
92- await expect ( findAllByText ( 'Some Text' , options ) ) . rejects . toBeTruthy ( ) ;
98+ await expect ( findByText ( 'Some Text' , { } , options ) ) . rejects . toBeTruthy ( ) ;
99+ await expect ( findAllByText ( 'Some Text' , { } , options ) ) . rejects . toBeTruthy ( ) ;
93100
94101 setTimeout (
95102 ( ) =>
@@ -105,6 +112,39 @@ test('findByText queries work asynchronously', async () => {
105112 await expect ( findAllByText ( 'Some Text' ) ) . resolves . toHaveLength ( 1 ) ;
106113} , 20000 ) ;
107114
115+ describe ( 'findBy options deprecations' , ( ) => {
116+ let warnSpy ;
117+ beforeEach ( ( ) => {
118+ warnSpy = jest . spyOn ( console , 'warn' ) . mockImplementation ( ( ) => { } ) ;
119+ } ) ;
120+ afterEach ( ( ) => {
121+ warnSpy . mockRestore ( ) ;
122+ } ) ;
123+
124+ test ( 'findByText queries warn on deprecated use of WaitForOptions' , async ( ) => {
125+ const options = { timeout : 10 } ;
126+ // mock implementation to avoid warning in the test suite
127+ const { rerender, findByText } = render ( < View /> ) ;
128+ await expect ( findByText ( 'Some Text' , options ) ) . rejects . toBeTruthy ( ) ;
129+
130+ setTimeout (
131+ ( ) =>
132+ rerender (
133+ < View >
134+ < Text > Some Text</ Text >
135+ </ View >
136+ ) ,
137+ 20
138+ ) ;
139+
140+ await expect ( findByText ( 'Some Text' ) ) . resolves . toBeTruthy ( ) ;
141+
142+ expect ( warnSpy ) . toHaveBeenCalledWith (
143+ expect . stringContaining ( 'Use of option "timeout"' )
144+ ) ;
145+ } , 20000 ) ;
146+ } ) ;
147+
108148test . skip ( 'getByText works properly with custom text component' , ( ) => {
109149 function BoldText ( { children } ) {
110150 return < Text > { children } </ Text > ;
@@ -181,7 +221,7 @@ test('queryByText not found', () => {
181221 ) . toBeFalsy ( ) ;
182222} ) ;
183223
184- test ( 'queryByText nested text across multiple <Text> in <Text>' , ( ) => {
224+ test ( 'queryByText does not match nested text across multiple <Text> in <Text>' , ( ) => {
185225 const { queryByText } = render (
186226 < Text nativeID = "1" >
187227 Hello{ ' ' }
@@ -192,7 +232,7 @@ test('queryByText nested text across multiple <Text> in <Text>', () => {
192232 </ Text >
193233 ) ;
194234
195- expect ( queryByText ( 'Hello World!' ) ?. props . nativeID ) . toBe ( '1' ) ;
235+ expect ( queryByText ( 'Hello World!' ) ) . toBe ( null ) ;
196236} ) ;
197237
198238test ( 'queryByText with nested Text components return the closest Text' , ( ) => {
@@ -204,7 +244,7 @@ test('queryByText with nested Text components return the closest Text', () => {
204244
205245 const { queryByText } = render ( < NestedTexts /> ) ;
206246
207- expect ( queryByText ( 'My text' ) ?. props . nativeID ) . toBe ( '2' ) ;
247+ expect ( queryByText ( 'My text' , { exact : false } ) ?. props . nativeID ) . toBe ( '2' ) ;
208248} ) ;
209249
210250test ( 'queryByText with nested Text components each with text return the lowest one' , ( ) => {
@@ -217,33 +257,182 @@ test('queryByText with nested Text components each with text return the lowest o
217257
218258 const { queryByText } = render ( < NestedTexts /> ) ;
219259
220- expect ( queryByText ( 'My text' ) ?. props . nativeID ) . toBe ( '2' ) ;
260+ expect ( queryByText ( 'My text' , { exact : false } ) ?. props . nativeID ) . toBe ( '2' ) ;
221261} ) ;
222262
223- test ( 'queryByText nested <CustomText> in <Text>' , ( ) => {
263+ test ( 'queryByText nested deep <CustomText> in <Text>' , ( ) => {
224264 const CustomText = ( { children } ) => {
225265 return < Text > { children } </ Text > ;
226266 } ;
227267
228268 expect (
229269 render (
230270 < Text >
231- Hello < CustomText > World!</ CustomText >
271+ < CustomText > Hello</ CustomText > < CustomText > World!</ CustomText >
232272 </ Text >
233273 ) . queryByText ( 'Hello World!' )
234- ) . toBeTruthy ( ) ;
274+ ) . toBe ( null ) ;
235275} ) ;
236276
237- test ( 'queryByText nested deep <CustomText> in <Text>' , ( ) => {
238- const CustomText = ( { children } ) => {
239- return < Text > { children } </ Text > ;
240- } ;
277+ test ( 'queryByText with nested Text components: not-exact text match returns the most deeply nested common component' , ( ) => {
278+ const { queryByText : queryByTextFirstCase } = render (
279+ < Text nativeID = "1" >
280+ bob
281+ < Text nativeID = "2" > My </ Text >
282+ < Text nativeID = "3" > text</ Text >
283+ </ Text >
284+ ) ;
285+
286+ const { queryByText : queryByTextSecondCase } = render (
287+ < Text nativeID = "1" >
288+ bob
289+ < Text nativeID = "2" > My text for test</ Text >
290+ </ Text >
291+ ) ;
241292
293+ expect ( queryByTextFirstCase ( 'My text' ) ) . toBe ( null ) ;
242294 expect (
243- render (
244- < Text >
245- < CustomText > Hello</ CustomText > < CustomText > World!</ CustomText >
246- </ Text >
247- ) . queryByText ( 'Hello World!' )
248- ) . toBeTruthy ( ) ;
295+ queryByTextSecondCase ( 'My text' , { exact : false } ) ?. props . nativeID
296+ ) . toBe ( '2' ) ;
297+ } ) ;
298+
299+ test ( 'queryAllByText does not match several times the same text' , ( ) => {
300+ const allMatched = render (
301+ < Text nativeID = "1" >
302+ Start
303+ < Text nativeID = "2" > This is a long text</ Text >
304+ </ Text >
305+ ) . queryAllByText ( 'long text' , { exact : false } ) ;
306+ expect ( allMatched . length ) . toBe ( 1 ) ;
307+ expect ( allMatched [ 0 ] . props . nativeID ) . toBe ( '2' ) ;
308+ } ) ;
309+
310+ test ( 'queryAllByText matches all the matching nodes' , ( ) => {
311+ const allMatched = render (
312+ < Text nativeID = "1" >
313+ Start
314+ < Text nativeID = "2" > This is a long text</ Text >
315+ < Text nativeID = "3" > This is another long text</ Text >
316+ </ Text >
317+ ) . queryAllByText ( 'long text' , { exact : false } ) ;
318+ expect ( allMatched . length ) . toBe ( 2 ) ;
319+ expect ( allMatched . map ( ( node ) => node . props . nativeID ) ) . toEqual ( [ '2' , '3' ] ) ;
320+ } ) ;
321+
322+ describe ( 'supports TextMatch options' , ( ) => {
323+ test ( 'getByText, getAllByText' , ( ) => {
324+ const { getByText, getAllByText } = render (
325+ < View >
326+ < Text testID = "text" > Text and details</ Text >
327+ < Button
328+ testID = "button"
329+ title = "Button and a detail"
330+ onPress = { jest . fn ( ) }
331+ />
332+ </ View >
333+ ) ;
334+
335+ expect ( getByText ( 'details' , { exact : false } ) ) . toBeTruthy ( ) ;
336+ expect ( getAllByText ( 'detail' , { exact : false } ) ) . toHaveLength ( 2 ) ;
337+ } ) ;
338+
339+ test ( 'getByPlaceholderText, getAllByPlaceholderText' , ( ) => {
340+ const { getByPlaceholderText, getAllByPlaceholderText } = render (
341+ < View >
342+ < TextInput placeholder = { 'Placeholder with details' } />
343+ < TextInput placeholder = { 'Placeholder with a DETAIL' } />
344+ </ View >
345+ ) ;
346+
347+ expect ( getByPlaceholderText ( 'details' , { exact : false } ) ) . toBeTruthy ( ) ;
348+ expect ( getAllByPlaceholderText ( 'detail' , { exact : false } ) ) . toHaveLength ( 2 ) ;
349+ } ) ;
350+
351+ test ( 'getByDisplayValue, getAllByDisplayValue' , ( ) => {
352+ const { getByDisplayValue, getAllByDisplayValue } = render (
353+ < View >
354+ < TextInput value = { 'Value with details' } />
355+ < TextInput value = { 'Value with a detail' } />
356+ </ View >
357+ ) ;
358+
359+ expect ( getByDisplayValue ( 'details' , { exact : false } ) ) . toBeTruthy ( ) ;
360+ expect ( getAllByDisplayValue ( 'detail' , { exact : false } ) ) . toHaveLength ( 2 ) ;
361+ } ) ;
362+
363+ test ( 'getByTestId, getAllByTestId' , ( ) => {
364+ const { getByTestId, getAllByTestId } = render (
365+ < View >
366+ < View testID = "test" />
367+ < View testID = "tests id" />
368+ </ View >
369+ ) ;
370+ expect ( getByTestId ( 'id' , { exact : false } ) ) . toBeTruthy ( ) ;
371+ expect ( getAllByTestId ( 'test' , { exact : false } ) ) . toHaveLength ( 2 ) ;
372+ } ) ;
373+
374+ test ( 'with TextMatch option exact === false text search is NOT case sensitive' , ( ) => {
375+ const { getByText, getAllByText } = render (
376+ < View >
377+ < Text testID = "text" > Text and details</ Text >
378+ < Button
379+ testID = "button"
380+ title = "Button and a DeTAil"
381+ onPress = { jest . fn ( ) }
382+ />
383+ </ View >
384+ ) ;
385+
386+ expect ( getByText ( 'DeTaIlS' , { exact : false } ) ) . toBeTruthy ( ) ;
387+ expect ( getAllByText ( 'detail' , { exact : false } ) ) . toHaveLength ( 2 ) ;
388+ } ) ;
389+ } ) ;
390+
391+ describe ( 'Supports normalization' , ( ) => {
392+ test ( 'trims and collapses whitespace by default' , ( ) => {
393+ const { getByText } = render (
394+ < View >
395+ < Text > { ` Text and
396+
397+
398+ whitespace` } </ Text >
399+ </ View >
400+ ) ;
401+
402+ expect ( getByText ( 'Text and whitespace' ) ) . toBeTruthy ( ) ;
403+ } ) ;
404+
405+ test ( 'trim and collapseWhitespace is customizable by getDefaultNormalizer param' , ( ) => {
406+ const testTextWithWhitespace = ` Text and
407+
408+
409+ whitespace` ;
410+ const { getByText } = render (
411+ < View >
412+ < Text > { testTextWithWhitespace } </ Text >
413+ </ View >
414+ ) ;
415+
416+ expect (
417+ getByText ( testTextWithWhitespace , {
418+ normalizer : getDefaultNormalizer ( {
419+ trim : false ,
420+ collapseWhitespace : false ,
421+ } ) ,
422+ } )
423+ ) . toBeTruthy ( ) ;
424+ } ) ;
425+
426+ test ( 'normalizer function is customisable' , ( ) => {
427+ const testText = 'A TO REMOVE text' ;
428+ const normalizerFn = ( textToNormalize ) =>
429+ textToNormalize . replace ( 'TO REMOVE ' , '' ) ;
430+ const { getByText } = render (
431+ < View >
432+ < Text > { testText } </ Text >
433+ </ View >
434+ ) ;
435+
436+ expect ( getByText ( 'A text' , { normalizer : normalizerFn } ) ) . toBeTruthy ( ) ;
437+ } ) ;
249438} ) ;
0 commit comments