Update PayPal references and tests

This commit is contained in:
Codex Agent
2026-02-04 12:43:40 +01:00
parent fc5dfb272c
commit 239f55f9c5
18 changed files with 655 additions and 729 deletions

View File

@@ -5,31 +5,46 @@ const demoTenantCredentials = {
password: process.env.E2E_DEMO_TENANT_PASSWORD ?? 'Demo1234!',
};
test.describe('Checkout Payment Step Lemon Squeezy flow', () => {
test('opens Lemon Squeezy checkout and shows success notice', async ({ page }) => {
await page.route('**/lemonsqueezy/create-checkout', async (route) => {
test.describe('Checkout Payment Step - PayPal flow', () => {
test('creates PayPal order and completes capture', async ({ page }) => {
let createPayload: Record<string, unknown> | null = null;
let capturePayload: Record<string, unknown> | null = null;
await page.route('**/paypal/create-order', async (route) => {
createPayload = route.request().postDataJSON() as Record<string, unknown>;
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
checkout_url: 'https://fotospiel.lemonsqueezy.com/checkout/success',
order_id: 'order_test_123',
checkout_session_id: 'session_test_123',
}),
});
});
await page.route('https://app.lemonsqueezy.com/js/lemon.js', async (route) => {
await page.route('**/paypal/capture-order', async (route) => {
capturePayload = route.request().postDataJSON() as Record<string, unknown>;
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
status: 'completed',
}),
});
});
await page.route('https://www.paypal.com/sdk/js**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/javascript',
body: `
window.createLemonSqueezy = function() {};
window.LemonSqueezy = {
Setup: function(options) { window.__lemonEventHandler = options?.eventHandler || null; },
Url: {
Open: function(url) {
window.__lemonOpenedUrl = url;
}
}
window.paypal = {
Buttons: function(options) {
window.__paypalOptions = options;
return {
render: function() { return Promise.resolve(); },
};
},
};
`,
});
@@ -38,58 +53,27 @@ test.describe('Checkout Payment Step Lemon Squeezy flow', () => {
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 expect.poll(async () => {
return page.evaluate(() => Boolean(window.__paypalOptions));
}).toBe(true);
const orderId = await page.evaluate(async () => {
return window.__paypalOptions?.createOrder?.();
});
await page.getByRole('button', { name: /Continue with Lemon Squeezy|Weiter mit Lemon Squeezy/ }).first().click();
expect(orderId).toBe('order_test_123');
await expect(page.getByText(/PayPal-Checkout ist bereit|PayPal checkout is ready/i)).toBeVisible();
await expect(
page.locator(
'text=/secure overlay|Overlay|neuen Tab|new tab/i'
)
).toBeVisible();
await page.evaluate(async () => {
await window.__paypalOptions?.onApprove?.({ orderID: 'order_test_123' });
});
let mode: 'inline' | 'hosted' | null = null;
for (let i = 0; i < 8; i++) {
const state = await page.evaluate(() => ({
inline: Boolean(window.__lemonOpenedUrl),
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 inlineUrl = await page.evaluate(() => window.__lemonOpenedUrl ?? null);
expect(inlineUrl).not.toBeNull();
}
if (mode === 'hosted') {
await expect.poll(async () => {
return page.evaluate(() => window.__openedUrls?.[0]?.url ?? null);
}).toContain('lemonsqueezy');
}
expect(createPayload?.package_id).toBeDefined();
expect(capturePayload?.order_id).toBe('order_test_123');
});
test('shows error state when Lemon Squeezy checkout creation fails', async ({ page }) => {
await page.route('**/lemonsqueezy/create-checkout', async (route) => {
test('shows error state when PayPal checkout creation fails', async ({ page }) => {
await page.route('**/paypal/create-order', async (route) => {
await route.fulfill({
status: 500,
contentType: 'application/json',
@@ -97,19 +81,18 @@ test.describe('Checkout Payment Step Lemon Squeezy flow', () => {
});
});
await page.route('https://app.lemonsqueezy.com/js/lemon.js', async (route) => {
await page.route('https://www.paypal.com/sdk/js**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/javascript',
body: `
window.createLemonSqueezy = function() {};
window.LemonSqueezy = {
Setup: function(options) { window.__lemonEventHandler = options?.eventHandler || null; },
Url: {
Open: function() {
throw new Error('forced Lemon Squeezy failure');
}
}
window.paypal = {
Buttons: function(options) {
window.__paypalOptions = options;
return {
render: function() { return Promise.resolve(); },
};
},
};
`,
});
@@ -118,10 +101,20 @@ test.describe('Checkout Payment Step Lemon Squeezy flow', () => {
await openCheckoutPaymentStep(page, demoTenantCredentials);
await acceptCheckoutTerms(page);
await page.getByRole('button', { name: /Continue with Lemon Squeezy|Weiter mit Lemon Squeezy/ }).first().click();
await expect.poll(async () => {
return page.evaluate(() => Boolean(window.__paypalOptions));
}).toBe(true);
await page.evaluate(async () => {
try {
await window.__paypalOptions?.createOrder?.();
} catch {
// swallow error for assertion below
}
});
await expect(
page.locator('text=/Lemon Squeezy-Checkout konnte nicht gestartet werden|Lemon Squeezy checkout could not be started/i')
page.locator('text=/PayPal-Checkout konnte nicht gestartet werden|PayPal checkout could not be started/i')
).toBeVisible();
});
});
@@ -168,8 +161,9 @@ async function acceptCheckoutTerms(page: import('@playwright/test').Page) {
declare global {
interface Window {
__openedUrls?: Array<{ url: string; target?: string | null; features?: string | null }>;
__lemonOpenedUrl?: string | null;
__lemonEventHandler?: ((event: { event: string; data?: unknown }) => void) | null;
__paypalOptions?: {
createOrder?: () => Promise<string>;
onApprove?: (data: { orderID: string }) => Promise<void>;
};
}
}