Register the popup listener before clicking the trigger: const popupPromise = page.waitForEvent('popup') must be set up before the action that opens the window
Trigger the login button or link that opens the OAuth provider's window: await page.getByRole('button', { name: 'Sign in with GitHub' }).click()
Await the popup page: const popup = await popupPromise; then interact with it using normal Playwright locators — fill in credentials, click confirm, etc.
After the OAuth flow completes, the popup closes and the parent page may reload or update via a postMessage or redirect — await the parent page's expected state change to confirm the auth succeeded
Store the resulting authentication state with context.storageState({ path: 'auth.json' }) so future tests can skip the popup flow entirely
Known gotchas
Always await the popup promise before the click, not after — if the popup opens synchronously before the await, the event is missed and the promise never resolves
OAuth providers frequently change their login page layout; use ARIA-based locators (getByRole, getByLabel) rather than CSS selectors on the popup to be more resilient to UI changes
Some providers check for automated browsers via timing or environment signals — in CI, use stored auth state from a one-time setup script rather than re-running the popup flow in every test
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp