From c6fd06b3de4769e4fb20e66ad6594461b53a595e Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Mon, 11 May 2026 09:54:55 -0500 Subject: [PATCH] Fix Stripe CDN mock override and free-plan sync guards in E2E tests - Block real Stripe CDN (js.stripe.com) in injectMockStripe() so the addInitScript mock is never overwritten by the async-loaded SDK - Replace waitForFunction(signUpWithEmail) with waitForLoadState in all 8 free-plan auth tests; defer scripts run before DOMContentLoaded so the function is guaranteed present without polling for it --- tests/e2e/checkout-flows.spec.ts | 16 ++++++++-------- tests/e2e/checkout-stripe.spec.ts | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/e2e/checkout-flows.spec.ts b/tests/e2e/checkout-flows.spec.ts index ff4a568..dc02df9 100644 --- a/tests/e2e/checkout-flows.spec.ts +++ b/tests/e2e/checkout-flows.spec.ts @@ -301,7 +301,7 @@ for (const plan of ['professional', 'founding'] as const) { test('[free] submit with empty email shows auth error', async ({ page }) => { await mockSupabaseConfig(page); await page.goto('/checkout?plan=free'); - await page.waitForFunction(() => typeof (window as any).signUpWithEmail === 'function', { timeout: 10000 }); + await page.waitForLoadState('domcontentloaded'); await page.locator('.checkout-email-btn').click(); const msg = page.locator('#auth-message'); await expect(msg).toBeVisible({ timeout: 4000 }); @@ -312,7 +312,7 @@ test('[free] submit with empty email shows auth error', async ({ page }) => { test('[free] submit with password < 8 chars shows length error', async ({ page }) => { await mockSupabaseConfig(page); await page.goto('/checkout?plan=free'); - await page.waitForFunction(() => typeof (window as any).signUpWithEmail === 'function', { timeout: 10000 }); + await page.waitForLoadState('domcontentloaded'); await page.fill('#auth-email', 'test@example.com'); await page.fill('#auth-password', 'short'); await page.locator('.checkout-email-btn').click(); @@ -325,7 +325,7 @@ test('[free] submit with password < 8 chars shows length error', async ({ page } test('[free] submit with email only (no password) shows error', async ({ page }) => { await mockSupabaseConfig(page); await page.goto('/checkout?plan=free'); - await page.waitForFunction(() => typeof (window as any).signUpWithEmail === 'function', { timeout: 10000 }); + await page.waitForLoadState('domcontentloaded'); await page.fill('#auth-email', 'test@example.com'); // leave password empty await page.locator('.checkout-email-btn').click(); @@ -342,7 +342,7 @@ test('[free] initial button says "Create account"', async ({ page }) => { test('[free] clicking "Sign in" link changes button text to "Sign in"', async ({ page }) => { await page.goto('/checkout?plan=free'); - await page.waitForFunction(() => typeof (window as any).signUpWithEmail === 'function', { timeout: 10000 }); + await page.waitForLoadState('domcontentloaded'); await page.click('a[onclick*="showSignIn"]'); await expect(page.locator('.checkout-email-btn')).toContainText('Sign in'); }); @@ -358,7 +358,7 @@ test('[free] successful sign-up → payment-section shown, auth-section hidden', await mockSupabaseConfig(page); await mockSignUpSuccess(page); await page.goto('/checkout?plan=free'); - await page.waitForFunction(() => typeof (window as any).signUpWithEmail === 'function', { timeout: 10000 }); + await page.waitForLoadState('domcontentloaded'); await page.fill('#auth-email', 'newuser@example.com'); await page.fill('#auth-password', 'password123'); @@ -372,7 +372,7 @@ test('[free] sign-up email-confirm-required → shows check-email message', asyn await mockSupabaseConfig(page); await mockSignUpEmailConfirmRequired(page); await page.goto('/checkout?plan=free'); - await page.waitForFunction(() => typeof (window as any).signUpWithEmail === 'function', { timeout: 10000 }); + await page.waitForLoadState('domcontentloaded'); await page.fill('#auth-email', 'confirm@example.com'); await page.fill('#auth-password', 'password123'); @@ -388,7 +388,7 @@ test('[free] sign-in success (via toggle) → payment-section shown', async ({ p await mockSupabaseConfig(page); await mockSignInSuccess(page); await page.goto('/checkout?plan=free'); - await page.waitForFunction(() => typeof (window as any).signUpWithEmail === 'function', { timeout: 10000 }); + await page.waitForLoadState('domcontentloaded'); await page.click('a[onclick*="showSignIn"]'); await page.fill('#auth-email', 'existing@example.com'); @@ -402,7 +402,7 @@ test('[free] sign-in error → shows error message, form stays visible', async ( await mockSupabaseConfig(page); await mockSignInError(page, 'Invalid login credentials'); await page.goto('/checkout?plan=free'); - await page.waitForFunction(() => typeof (window as any).signUpWithEmail === 'function', { timeout: 10000 }); + await page.waitForLoadState('domcontentloaded'); await page.click('a[onclick*="showSignIn"]'); await page.fill('#auth-email', 'wrong@example.com'); diff --git a/tests/e2e/checkout-stripe.spec.ts b/tests/e2e/checkout-stripe.spec.ts index 9725e73..78df731 100644 --- a/tests/e2e/checkout-stripe.spec.ts +++ b/tests/e2e/checkout-stripe.spec.ts @@ -36,6 +36,8 @@ async function injectMockStripe(page: Page, opts: { confirmResult?: { error?: { message: string } }; declineMessage?: string; } = {}) { + // Block the real Stripe CDN so it cannot override the addInitScript mock + await page.route('https://js.stripe.com/**', (route) => route.abort()); await page.addInitScript((o) => { (window as any).Stripe = function (_key: string) { const confirmResult = o.declineMessage -- 2.52.0