import { test, expectFixture as expect } from '../helpers/test-fixtures'; const demoTenantCredentials = { email: process.env.E2E_DEMO_TENANT_EMAIL ?? 'tenant-demo@fotospiel.app', password: process.env.E2E_DEMO_TENANT_PASSWORD ?? 'Demo1234!', }; test.describe('Checkout Payment Step – Paddle flow', () => { test('opens Paddle checkout and shows success notice', async ({ page }) => { await page.route('**/paddle/create-checkout', async (route) => { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ checkout_url: 'https://paddle.test/checkout/success', }), }); }); await page.route('https://cdn.paddle.com/paddle/v2/paddle.js', async (route) => { await route.fulfill({ status: 200, contentType: 'application/javascript', body: ` window.Paddle = { Environment: { set: function(env) { window.__paddleEnv = env; } }, Initialize: function(opts) { window.__paddleInit = opts; }, Checkout: { open: function(config) { window.__paddleOpenConfig = config; } } }; `, }); }); await openCheckoutPaymentStep(page, demoTenantCredentials); await acceptCheckoutTerms(page); await page.evaluate(() => { window.__openedUrls = []; window.open = (url: string, target?: string | null, features?: string | null) => { window.__openedUrls.push({ url, target: target ?? null, features: features ?? null }); return null; }; }); await page.getByRole('button', { name: /Continue with Paddle|Weiter mit Paddle/ }).first().click(); await expect( page.locator( 'text=/secure overlay|Overlay|neuen Tab|new tab/i' ) ).toBeVisible(); let mode: 'inline' | 'hosted' | null = null; for (let i = 0; i < 8; i++) { const state = await page.evaluate(() => ({ inline: Boolean(window.__paddleOpenConfig), opened: window.__openedUrls?.length ?? 0, })); if (state.inline) { mode = 'inline'; break; } if (state.opened > 0) { mode = 'hosted'; break; } await page.waitForTimeout(300); } expect(mode).not.toBeNull(); if (mode === 'inline') { const inlineConfig = await page.evaluate(() => window.__paddleOpenConfig ?? null); expect(inlineConfig).not.toBeNull(); } if (mode === 'hosted') { await expect.poll(async () => { return page.evaluate(() => window.__openedUrls?.[0]?.url ?? null); }).toContain('paddle'); } }); test('shows error state when Paddle checkout creation fails', async ({ page }) => { await page.route('**/paddle/create-checkout', async (route) => { await route.fulfill({ status: 500, contentType: 'application/json', body: JSON.stringify({ message: 'test-error' }), }); }); await page.route('https://cdn.paddle.com/paddle/v2/paddle.js', async (route) => { await route.fulfill({ status: 200, contentType: 'application/javascript', body: ` window.Paddle = { Environment: { set: function(env) { window.__paddleEnv = env; } }, Initialize: function(opts) { window.__paddleInit = opts; }, Checkout: { open: function() { throw new Error('forced paddle failure'); } } }; `, }); }); await openCheckoutPaymentStep(page, demoTenantCredentials); await acceptCheckoutTerms(page); await page.getByRole('button', { name: /Continue with Paddle|Weiter mit Paddle/ }).first().click(); await expect( page.locator('text=/Paddle-Checkout konnte nicht gestartet werden|Paddle checkout could not be started/i') ).toBeVisible(); }); }); async function openCheckoutPaymentStep( page: import('@playwright/test').Page, credentials: { email: string; password: string } ) { await page.goto('/packages'); const detailsButtons = page.getByRole('button', { name: /Details ansehen|Details anzeigen|View details/i, }); await expect(detailsButtons.first()).toBeVisible(); await detailsButtons.first().click(); const dialog = page.getByRole('dialog'); await expect(dialog).toBeVisible(); await dialog.getByRole('link', { name: /Jetzt bestellen|Order now|Jetzt buchen/i }).click(); await expect(page).toHaveURL(/\/(bestellen|checkout)\/\d+/); await page.getByRole('button', { name: /^Weiter$/ }).first().click(); const continueButton = page.getByRole('button', { name: /Weiter zur Zahlung|Continue to Payment/i }); if (await continueButton.isVisible()) { await continueButton.click(); } else { await page.getByRole('button', { name: /^Anmelden$/ }).first().click(); await expect(page.locator('input[name="identifier"]')).toBeVisible(); await page.fill('input[name="identifier"]', credentials.email); await page.fill('input[name="password"]', credentials.password); await page.getByRole('button', { name: /^Anmelden$/ }).last().click(); } await expect(page.getByPlaceholder(/Gutscheincode/i)).toBeVisible(); } async function acceptCheckoutTerms(page: import('@playwright/test').Page) { const termsCheckbox = page.locator('#checkout-terms-hero'); await expect(termsCheckbox).toBeVisible(); await termsCheckbox.click(); } declare global { interface Window { __openedUrls?: Array<{ url: string; target?: string | null; features?: string | null }>; __paddleOpenConfig?: { url?: string; items?: Array<{ priceId: string; quantity: number }>; settings?: { displayMode?: string } }; __paddleEnv?: string; __paddleInit?: Record; } }