@@ -8,26 +8,47 @@ type LoginOptions = {
88} ;
99
1010async function firstVisible ( page : Page , selectors : string [ ] ) : Promise < string > {
11- for ( const selector of selectors ) {
12- const locator = page . locator ( selector ) . first ( ) ;
13- if ( await locator . isVisible ( ) . catch ( ( ) => false ) ) {
14- return selector ;
11+ const deadline = Date . now ( ) + 30000 ;
12+
13+ while ( Date . now ( ) < deadline ) {
14+ for ( const selector of selectors ) {
15+ const locator = page . locator ( selector ) . first ( ) ;
16+ if ( await locator . isVisible ( ) . catch ( ( ) => false ) ) {
17+ return selector ;
18+ }
1519 }
20+
21+ await page . waitForTimeout ( 500 ) ;
1622 }
23+
1724 throw new Error ( `none of the selectors were visible: ${ selectors . join ( ", " ) } ` ) ;
1825}
1926
2027async function clickFirst ( page : Page , selectors : string [ ] ) : Promise < void > {
21- for ( const selector of selectors ) {
22- const locator = page . locator ( selector ) . first ( ) ;
23- if ( await locator . isVisible ( ) . catch ( ( ) => false ) ) {
24- await locator . click ( ) ;
25- return ;
28+ const deadline = Date . now ( ) + 30000 ;
29+
30+ while ( Date . now ( ) < deadline ) {
31+ for ( const selector of selectors ) {
32+ const locator = page . locator ( selector ) . first ( ) ;
33+ if ( await locator . isVisible ( ) . catch ( ( ) => false ) ) {
34+ await locator . click ( ) ;
35+ return ;
36+ }
2637 }
38+
39+ await page . waitForTimeout ( 500 ) ;
2740 }
41+
2842 throw new Error ( `none of the click selectors were visible: ${ selectors . join ( ", " ) } ` ) ;
2943}
3044
45+ async function typeInto ( page : Page , selector : string , value : string ) : Promise < void > {
46+ const locator = page . locator ( selector ) . first ( ) ;
47+ await locator . click ( ) ;
48+ await locator . clear ( ) ;
49+ await locator . pressSequentially ( value , { delay : 30 } ) ;
50+ }
51+
3152/** Runs a browser flow and preserves screenshots for post-failure inspection. */
3253export async function withBrowser < T > ( outputDir : string , runFlow : ( browser : Browser ) => Promise < T > ) : Promise < T > {
3354 mkdirSync ( outputDir , { recursive : true } ) ;
@@ -50,17 +71,19 @@ export async function loginThroughZitadel(url: string, user: OidcTestUser, optio
5071 'input[type="email"]' ,
5172 'input[name="loginName"]' ,
5273 'input[name="username"]' ,
53- 'input[autocomplete="username"]'
74+ 'input[autocomplete="username"]' ,
75+ '[data-testid="username-text-input"]'
5476 ] ) ;
55- await page . fill ( emailSelector , user . email ) ;
77+ await typeInto ( page , emailSelector , user . email ) ;
5678 await clickFirst ( page , [ 'button:has-text("Next")' , 'button:has-text("Continue")' , 'button:has-text("Sign in")' ] ) ;
5779
5880 const passwordSelector = await firstVisible ( page , [
5981 'input[type="password"]' ,
6082 'input[name="password"]' ,
61- 'input[autocomplete="current-password"]'
83+ 'input[autocomplete="current-password"]' ,
84+ '[data-testid="password-text-input"]'
6285 ] ) ;
63- await page . fill ( passwordSelector , user . password ) ;
86+ await typeInto ( page , passwordSelector , user . password ) ;
6487 await clickFirst ( page , [ 'button:has-text("Sign in")' , 'button:has-text("Login")' , 'button:has-text("Continue")' ] ) ;
6588
6689 await page . waitForLoadState ( "networkidle" , { timeout : 120000 } ) ;
0 commit comments