11import path from 'node:path' ;
22
3- const isIndexableNativeElement = (
4- v : Detox . IndexableNativeElement | Detox . NativeMatcher ,
5- ) : v is Detox . IndexableNativeElement => {
3+ import { scheduleAction } from '@trezor/utils' ;
4+
5+ type ElementAttributes = {
6+ text ?: string ;
7+ label ?: string ;
8+ value ?: string ;
9+ } ;
10+
11+ type ElementOrMatcher = Detox . IndexableNativeElement | Detox . NativeMatcher ;
12+
13+ const isIndexableNativeElement = ( v : ElementOrMatcher ) : v is Detox . IndexableNativeElement => {
614 const anyV = v as any ;
715
816 return ! ! anyV && ( typeof anyV . tap === 'function' || typeof anyV . atIndex === 'function' ) ;
@@ -14,6 +22,11 @@ export const platform = device.getPlatform();
1422// On the other hand, if we are trying to scroll to 100% visibility on iOS, it causes scrolling more than height of the screen and it makes Detox crash.
1523const SCROLL_VISIBILITY_THRESHOLD = platform === 'android' ? 100 : undefined ;
1624
25+ export const RETRY_CONF = {
26+ attempts : 5 ,
27+ gap : 500 ,
28+ } ;
29+
1730export const wait = async ( ms : number ) => {
1831 await new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
1932} ;
@@ -40,13 +53,17 @@ function pruneToAppStack(invocationStack: string): string {
4053 return kept . length ? [ 'Error' ] . concat ( kept ) . join ( '\n' ) : invocationStack ;
4154}
4255
56+ function getTarget ( elementOrMatcher : ElementOrMatcher ) {
57+ return isIndexableNativeElement ( elementOrMatcher )
58+ ? elementOrMatcher
59+ : element ( elementOrMatcher ) ;
60+ }
61+
4362export const waitForVisible = async (
44- elementOrMatcher : Detox . IndexableNativeElement | Detox . NativeMatcher ,
63+ elementOrMatcher : ElementOrMatcher ,
4564 { timeout = 30_000 } : { timeout ?: number } = { } ,
4665) => {
47- const target = isIndexableNativeElement ( elementOrMatcher )
48- ? elementOrMatcher
49- : element ( elementOrMatcher ) ;
66+ const target = getTarget ( elementOrMatcher ) ;
5067 const invocationStack = new Error ( ) . stack || '' ;
5168 try {
5269 await waitFor ( target ) . toBeVisible ( ) . withTimeout ( timeout ) ;
@@ -58,6 +75,34 @@ export const waitForVisible = async (
5875 }
5976} ;
6077
78+ export const waitToHaveRegex = async (
79+ elementOrMatcher : ElementOrMatcher ,
80+ expectedRegex : RegExp ,
81+ {
82+ timeout = 30_000 ,
83+ attributeType = 'text' ,
84+ } : { timeout ?: number ; attributeType ?: 'text' | 'label' | 'value' } = { } ,
85+ ) => {
86+ const target = getTarget ( elementOrMatcher ) ;
87+ await waitForVisible ( target , { timeout } ) ;
88+ await scheduleAction ( async ( ) => {
89+ const attributes = await target . getAttributes ( ) ;
90+ const testedAttribute = ( attributes as ElementAttributes ) [ attributeType ] ;
91+
92+ if ( typeof testedAttribute !== 'string' ) {
93+ throw new Error (
94+ `waitForRegex(): could not get "${ attributeType } " property from the element` ,
95+ ) ;
96+ }
97+
98+ if ( ! expectedRegex . test ( testedAttribute ) ) {
99+ throw new Error (
100+ `waitForRegex(): target text "${ testedAttribute } " not matching ${ expectedRegex } after ${ timeout } ms` ,
101+ ) ;
102+ }
103+ } , RETRY_CONF ) ;
104+ } ;
105+
61106export const appIsFullyLoaded = async ( ) => {
62107 await waitForVisible ( by . id ( '@screen/mainScrollView' ) , { timeout : 35_000 } ) ;
63108} ;
@@ -85,9 +130,7 @@ export const inputTextToElement = async (element: Detox.IndexableNativeElement,
85130} ;
86131
87132// Use this method in absolute necessity only! Try-catch in tests is discouraged because it may hide real issues.
88- export const isElementVisible = async (
89- elementOrMatcher : Detox . IndexableNativeElement | Detox . NativeMatcher ,
90- ) : Promise < boolean > => {
133+ export const isElementVisible = async ( elementOrMatcher : ElementOrMatcher ) : Promise < boolean > => {
91134 const target = isIndexableNativeElement ( elementOrMatcher )
92135 ? elementOrMatcher
93136 : element ( elementOrMatcher ) ;
@@ -99,3 +142,20 @@ export const isElementVisible = async (
99142 return false ;
100143 }
101144} ;
145+
146+ export function testWithRepeat (
147+ runs : number ,
148+ name : string ,
149+ testFunction : ( ) => Promise < void > | void ,
150+ timeout ?: number ,
151+ ) {
152+ for ( let i = 1 ; i <= runs ; i ++ ) {
153+ it (
154+ name ,
155+ async ( ) => {
156+ await testFunction ( ) ;
157+ } ,
158+ timeout ,
159+ ) ;
160+ }
161+ }
0 commit comments