import { expect, test } from '@playwright/test'; import { test as base } from '../helpers/test-fixtures'; const shouldRun = process.env.E2E_PADDLE_SANDBOX === '1'; const baseUrl = process.env.E2E_BASE_URL ?? 'https://test-y0k0.fotospiel.app'; const locale = process.env.E2E_LOCALE ?? 'de'; const checkoutSlug = locale === 'en' ? 'checkout' : 'bestellen'; const sandboxEmail = process.env.E2E_PADDLE_EMAIL ?? 'playwright-buyer@example.com'; test.describe('Paddle sandbox full flow (staging)', () => { test.skip(!shouldRun, 'Set E2E_PADDLE_SANDBOX=1 to run live sandbox checkout on staging.'); test('create checkout, simulate webhook completion, and verify session completion', async ({ page, request }) => { // Jump directly into wizard for Standard package (2) await page.goto(`${baseUrl}/${locale}/${checkoutSlug}/2`); const acceptCookies = page.getByRole('button', { name: /akzeptieren|accept/i }); if (await acceptCookies.isVisible()) { await acceptCookies.click(); } // If login/register step is present, choose guest path or continue const continueButtons = page.getByRole('button', { name: /weiter|continue/i }); if (await continueButtons.first().isVisible()) { await continueButtons.first().click(); } // Fill minimal registration form to reach payment step await page.fill('input[name="first_name"]', 'Play'); await page.fill('input[name="last_name"]', 'Wright'); await page.fill('input[name="email"]', sandboxEmail); await page.fill('input[name="address"]', 'Teststrasse 1, 12345 Berlin'); await page.fill('input[name="phone"]', '+49123456789'); await page.fill('input[name="username"]', 'playwright-buyer'); await page.fill('input[name="password"]', 'Password123!'); await page.fill('input[name="password_confirmation"]', 'Password123!'); await page.check('input[name="privacy_consent"]'); await page.getByRole('button', { name: /^Registrieren$/i }).last().click(); await expect(page.getByPlaceholder(/Gutscheincode/i)).toBeVisible({ timeout: 20000 }); const termsCheckbox = page.locator('#checkout-terms-hero'); await expect(termsCheckbox).toBeVisible(); await termsCheckbox.click(); const checkoutCta = page.getByRole('button', { name: /Weiter mit Paddle|Continue with Paddle/i }).first(); await expect(checkoutCta).toBeVisible({ timeout: 20000 }); const [apiResponse] = await Promise.all([ page.waitForResponse((resp) => resp.url().includes('/paddle/create-checkout') && resp.status() < 500), checkoutCta.click(), ]); const checkoutPayload = await apiResponse.json(); const checkoutUrl: string = checkoutPayload.checkout_url ?? checkoutPayload.url ?? ''; expect(checkoutUrl).toContain('paddle'); // Navigate to checkout to ensure it loads (hosted page). Use sandbox card data if needed later. await page.goto(checkoutUrl); await expect(page).toHaveURL(/paddle/); // Fetch latest session for this buyer const latestSession = await request.get('/api/_testing/checkout/sessions/latest', { params: { email: sandboxEmail }, }); expect(latestSession.status()).toBe(200); const sessionJson = await latestSession.json(); const sessionId: string | undefined = sessionJson?.data?.id; expect(sessionId, 'checkout session id').toBeTruthy(); // Simulate Paddle webhook completion const simulate = await request.post(`/api/_testing/checkout/sessions/${sessionId}/simulate-paddle`, { data: { status: 'completed', transaction_id: 'txn_playwright_' + Date.now(), }, }); expect(simulate.status()).toBe(200); // Confirm session is marked completed const latestCompleted = await request.get('/api/_testing/checkout/sessions/latest', { params: { status: 'completed', email: sandboxEmail }, }); expect(latestCompleted.status()).toBe(200); }); });