Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"shopify:run": "node packages/cli/bin/dev.js",
"shopify": "nx build cli && node packages/cli/bin/dev.js",
"test:e2e": "nx run-many --target=build --projects=cli,create-app --skip-nx-cache && pnpm --filter e2e exec playwright test",
"test:e2e-cleanup": "npx tsx packages/e2e/scripts/cleanup-stores.ts && npx tsx packages/e2e/scripts/cleanup-apps.ts",
"test:regenerate-snapshots": "packages/e2e/scripts/regenerate-snapshots.sh",
"test": "pnpm vitest run",
"type-check:affected": "nx affected --target=type-check",
Expand Down Expand Up @@ -143,9 +144,13 @@
"unresolved": "error"
},
"ignoreBinaries": [
"playwright"
"playwright",
"tsx"
],
"ignoreDependencies": [
"dotenv",
"@playwright/test"
],
"ignoreDependencies": [],
"ignoreWorkspaces": [
"packages/eslint-plugin-cli",
"packages/e2e"
Expand Down
30 changes: 27 additions & 3 deletions packages/e2e/helpers/browser-login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ async function fillSensitive(page: Page, selector: string, value: string): Promi
* Completes the Shopify OAuth login flow on a Playwright page.
*/
export async function completeLogin(page: Page, loginUrl: string, email: string, password: string): Promise<void> {
// Disable WebAuthn so passkey/security key system dialogs never appear when headed
const cdp = await page.context().newCDPSession(page)
await cdp.send('WebAuthn.enable', {enableUI: false})

await page.goto(loginUrl)

try {
Expand All @@ -32,10 +36,30 @@ export async function completeLogin(page: Page, loginUrl: string, email: string,
await fillSensitive(page, 'input[name="account[email]"], input[type="email"]', email)
await page.locator('button[type="submit"]').first().click()

// Handle passkey prompt — navigate to password login if needed
const passwordInput = page.locator('input[name="account[password]"], input[type="password"]')
const differentMethodBtn = page.locator('text=Log in using a different method')

// Wait for either password field or passkey page
await Promise.race([
passwordInput.waitFor({timeout: BROWSER_TIMEOUT.max}),
differentMethodBtn.waitFor({timeout: BROWSER_TIMEOUT.max}),
]).catch(() => {})

// If passkey page shown, navigate to password login
if (await differentMethodBtn.isVisible({timeout: BROWSER_TIMEOUT.short}).catch(() => false)) {
await differentMethodBtn.click()
await page.waitForTimeout(BROWSER_TIMEOUT.short)

const continueWithPassword = page.locator('text=Continue with password')
if (await continueWithPassword.isVisible({timeout: BROWSER_TIMEOUT.medium}).catch(() => false)) {
await continueWithPassword.click()
await page.waitForTimeout(BROWSER_TIMEOUT.short)
}
}

// Fill in password
await page.waitForSelector('input[name="account[password]"], input[type="password"]', {
timeout: BROWSER_TIMEOUT.max,
})
await passwordInput.waitFor({timeout: BROWSER_TIMEOUT.max})
await fillSensitive(page, 'input[name="account[password]"], input[type="password"]', password)
await page.locator('button[type="submit"]').first().click()

Expand Down
5 changes: 3 additions & 2 deletions packages/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ config()
const isCI = Boolean(process.env.CI)

export default defineConfig({
globalSetup: './setup/global-auth.ts',
testDir: './tests',
fullyParallel: false,
fullyParallel: true,
forbidOnly: isCI,
retries: 0,
workers: 1,
workers: 5,
maxFailures: isCI ? 3 : 0, // Stop early in CI after 3 failures
reporter: isCI ? [['html', {open: 'never'}], ['list']] : [['list']],
timeout: TEST_TIMEOUT.default, // Heavy tests override via test.setTimeout()
Expand Down
Loading
Loading