@@ -24,6 +24,10 @@ async function fillSensitive(page: Page, selector: string, value: string): Promi
2424 * Completes the Shopify OAuth login flow on a Playwright page.
2525 */
2626export async function completeLogin ( page : Page , loginUrl : string , email : string , password : string ) : Promise < void > {
27+ // Disable WebAuthn so passkey/security key system dialogs never appear when headed
28+ const cdp = await page . context ( ) . newCDPSession ( page )
29+ await cdp . send ( 'WebAuthn.enable' , { enableUI : false } )
30+
2731 await page . goto ( loginUrl )
2832
2933 try {
@@ -32,10 +36,30 @@ export async function completeLogin(page: Page, loginUrl: string, email: string,
3236 await fillSensitive ( page , 'input[name="account[email]"], input[type="email"]' , email )
3337 await page . locator ( 'button[type="submit"]' ) . first ( ) . click ( )
3438
39+ // Handle passkey prompt — navigate to password login if needed
40+ const passwordInput = page . locator ( 'input[name="account[password]"], input[type="password"]' )
41+ const differentMethodBtn = page . locator ( 'text=Log in using a different method' )
42+
43+ // Wait for either password field or passkey page
44+ await Promise . race ( [
45+ passwordInput . waitFor ( { timeout : BROWSER_TIMEOUT . max } ) ,
46+ differentMethodBtn . waitFor ( { timeout : BROWSER_TIMEOUT . max } ) ,
47+ ] ) . catch ( ( ) => { } )
48+
49+ // If passkey page shown, navigate to password login
50+ if ( await differentMethodBtn . isVisible ( { timeout : BROWSER_TIMEOUT . short } ) . catch ( ( ) => false ) ) {
51+ await differentMethodBtn . click ( )
52+ await page . waitForTimeout ( BROWSER_TIMEOUT . short )
53+
54+ const continueWithPassword = page . locator ( 'text=Continue with password' )
55+ if ( await continueWithPassword . isVisible ( { timeout : BROWSER_TIMEOUT . medium } ) . catch ( ( ) => false ) ) {
56+ await continueWithPassword . click ( )
57+ await page . waitForTimeout ( BROWSER_TIMEOUT . short )
58+ }
59+ }
60+
3561 // Fill in password
36- await page . waitForSelector ( 'input[name="account[password]"], input[type="password"]' , {
37- timeout : BROWSER_TIMEOUT . max ,
38- } )
62+ await passwordInput . waitFor ( { timeout : BROWSER_TIMEOUT . max } )
3963 await fillSensitive ( page , 'input[name="account[password]"], input[type="password"]' , password )
4064 await page . locator ( 'button[type="submit"]' ) . first ( ) . click ( )
4165
0 commit comments