@@ -90,6 +90,13 @@ async function waitForPasswordInputAfterUsernameSubmit(page: Page, usernameSelec
9090 let lastBody = "" ;
9191
9292 while ( Date . now ( ) < deadline ) {
93+ if ( isPasswordLoginStep ( page . url ( ) ) ) {
94+ const selector = await visiblePasswordInputSelector ( page , 5000 ) ;
95+ if ( selector ) {
96+ return selector ;
97+ }
98+ }
99+
93100 for ( const selector of PASSWORD_INPUT_SELECTORS ) {
94101 const locator = page . locator ( selector ) . first ( ) ;
95102 if ( await locatorVisible ( locator ) ) {
@@ -108,14 +115,17 @@ async function waitForPasswordInputAfterUsernameSubmit(page: Page, usernameSelec
108115 throw new Error ( `ZITADEL username step failed before password input\nbody:\n${ bodySnippetForError ( lastBody ) } ` ) ;
109116 }
110117
111- const parsedUrl = parseBrowserUrl ( currentUrl ) ;
112- const onUsernameStep = parsedUrl ?. pathname . toLowerCase ( ) . startsWith ( "/ui/v2/login/loginname" ) ?? false ;
113- if ( onUsernameStep && isIdentityLoginInputPage ( currentUrl , targetHost ) ) {
114- const usernameInputVisible = await inputVisible ( page , USERNAME_INPUT_SELECTORS ) ;
118+ if ( isUsernameLoginStep ( currentUrl ) && isIdentityLoginInputPage ( currentUrl , targetHost ) ) {
115119 const now = Date . now ( ) ;
116- if ( usernameInputVisible && now - lastResubmit > 5000 ) {
120+ if ( now - lastResubmit > 5000 && await canResubmitUsername ( page , usernameSelector ) ) {
117121 lastResubmit = now ;
122+ if ( isPasswordLoginStep ( page . url ( ) ) ) {
123+ continue ;
124+ }
118125 await typeInto ( page , usernameSelector , userEmail ) ;
126+ if ( isPasswordLoginStep ( page . url ( ) ) ) {
127+ continue ;
128+ }
119129 await submitIdentityForm ( page , usernameSelector , USERNAME_SUBMIT_SELECTORS ) ;
120130 await page . waitForTimeout ( 1000 ) ;
121131 continue ;
@@ -134,6 +144,41 @@ async function waitForPasswordInputAfterUsernameSubmit(page: Page, usernameSelec
134144 ) ;
135145}
136146
147+ async function visiblePasswordInputSelector ( page : Page , timeoutMs : number ) : Promise < string | undefined > {
148+ const deadline = Date . now ( ) + timeoutMs ;
149+ while ( Date . now ( ) < deadline ) {
150+ for ( const selector of PASSWORD_INPUT_SELECTORS ) {
151+ const locator = page . locator ( selector ) . first ( ) ;
152+ if ( await locatorVisible ( locator ) ) {
153+ return selector ;
154+ }
155+ }
156+
157+ await page . waitForTimeout ( 250 ) ;
158+ }
159+
160+ return undefined ;
161+ }
162+
163+ async function canResubmitUsername ( page : Page , usernameSelector : string ) : Promise < boolean > {
164+ if ( ! isUsernameLoginStep ( page . url ( ) ) ) {
165+ return false ;
166+ }
167+
168+ const locator = page . locator ( usernameSelector ) . first ( ) ;
169+ return ( await locatorVisible ( locator ) ) && ( await waitForEditableInput ( locator ) ) && isUsernameLoginStep ( page . url ( ) ) ;
170+ }
171+
172+ function isUsernameLoginStep ( currentUrl : string ) : boolean {
173+ const parsedUrl = parseBrowserUrl ( currentUrl ) ;
174+ return parsedUrl ?. pathname . toLowerCase ( ) . startsWith ( "/ui/v2/login/loginname" ) ?? false ;
175+ }
176+
177+ function isPasswordLoginStep ( currentUrl : string ) : boolean {
178+ const parsedUrl = parseBrowserUrl ( currentUrl ) ;
179+ return parsedUrl ?. pathname . toLowerCase ( ) . startsWith ( "/ui/v2/login/password" ) ?? false ;
180+ }
181+
137182async function reloadBlankLoginDocumentIfNeeded ( page : Page ) : Promise < boolean > {
138183 const parsed = parseBrowserUrl ( page . url ( ) ) ;
139184 if ( ! parsed || ! isLoginOrOauthCallbackPlumbingPath ( parsed . pathname ) ) {
0 commit comments