Files
fotospiel-app/tests/ui/purchase/checkout-payment.test.ts

177 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<string, unknown>;
}
}