@@ -84,33 +84,50 @@ const CONSENT_SUBMIT_SELECTORS = ["Allow", "Authorize", "Approve", "Accept", "Co
8484 `input[type="button"][value="${ label } "]`
8585] ) ;
8686
87- async function firstVisible ( page : Page , selectors : string [ ] ) : Promise < string > {
87+ async function waitForPasswordInputAfterUsernameSubmit ( page : Page , usernameSelector : string , userEmail : string , targetHost : string ) : Promise < string > {
8888 const deadline = Date . now ( ) + BROWSER_WAIT_TIMEOUT_MS ;
89- let reloadedBlankLoginPage = false ;
89+ let lastResubmit = 0 ;
90+ let lastBody = "" ;
9091
9192 while ( Date . now ( ) < deadline ) {
92- for ( const selector of selectors ) {
93+ for ( const selector of PASSWORD_INPUT_SELECTORS ) {
9394 const locator = page . locator ( selector ) . first ( ) ;
9495 if ( await locatorVisible ( locator ) ) {
9596 return selector ;
9697 }
9798 }
9899
99- if ( ! reloadedBlankLoginPage && await reloadBlankLoginDocumentIfNeeded ( page ) ) {
100- reloadedBlankLoginPage = true ;
101- await page . waitForTimeout ( 1000 ) ;
102- continue ;
100+ const currentUrl = page . url ( ) ;
101+ lastBody = ( await maybeWithTimeout ( page . locator ( "body" ) . innerText ( { timeout : 1000 } ) . catch ( ( ) => "" ) , 2000 ) ) ?? "" ;
102+ const normalizedBody = lastBody . toLowerCase ( ) ;
103+ if (
104+ normalizedBody . includes ( "user not found" ) ||
105+ normalizedBody . includes ( "invalid login" ) ||
106+ normalizedBody . includes ( "login failed" )
107+ ) {
108+ throw new Error ( `ZITADEL username step failed before password input\nbody:\n${ bodySnippetForError ( lastBody ) } ` ) ;
109+ }
110+
111+ if ( isIdentityLoginInputPage ( currentUrl , targetHost ) ) {
112+ const usernameInputVisible = await inputVisible ( page , USERNAME_INPUT_SELECTORS ) ;
113+ const now = Date . now ( ) ;
114+ if ( usernameInputVisible && now - lastResubmit > 5000 ) {
115+ lastResubmit = now ;
116+ await typeInto ( page , usernameSelector , userEmail ) ;
117+ await submitIdentityForm ( page , usernameSelector , USERNAME_SUBMIT_SELECTORS ) ;
118+ await page . waitForTimeout ( 1000 ) ;
119+ continue ;
120+ }
103121 }
104122
105123 await page . waitForTimeout ( 500 ) ;
106124 }
107125
108- const body = await page . locator ( "body" ) . innerText ( { timeout : 1000 } ) . catch ( ( ) => "" ) ;
109126 throw new Error (
110127 [
111- `none of the selectors were visible: ${ selectors . join ( ", " ) } ` ,
128+ `none of the password selectors were visible after username submit : ${ PASSWORD_INPUT_SELECTORS . join ( ", " ) } ` ,
112129 `current URL: ${ page . url ( ) } ` ,
113- `body:\n${ bodySnippetForError ( body ) || "<empty>" } `
130+ `body:\n${ bodySnippetForError ( lastBody ) || "<empty>" } `
114131 ] . join ( "\n" )
115132 ) ;
116133}
@@ -900,8 +917,8 @@ async function loginThroughZitadelWithBrowser(
900917 stage = "submitting username" ;
901918 await submitIdentityForm ( page , emailSelector , USERNAME_SUBMIT_SELECTORS ) ;
902919
903- stage = "waiting for password input" ;
904- const passwordSelector = await firstVisible ( page , [ ... PASSWORD_INPUT_SELECTORS ] ) ;
920+ stage = "waiting for password input after username submit " ;
921+ const passwordSelector = await waitForPasswordInputAfterUsernameSubmit ( page , emailSelector , user . email , targetHost ) ;
905922 stage = "entering password" ;
906923 await typeInto ( page , passwordSelector , user . password ) ;
907924 stage = "submitting password" ;
0 commit comments