176 lines
5.7 KiB
TypeScript
176 lines
5.7 KiB
TypeScript
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 – Lemon Squeezy flow', () => {
|
||
test('opens Lemon Squeezy checkout and shows success notice', async ({ page }) => {
|
||
await page.route('**/lemonsqueezy/create-checkout', async (route) => {
|
||
await route.fulfill({
|
||
status: 200,
|
||
contentType: 'application/json',
|
||
body: JSON.stringify({
|
||
checkout_url: 'https://fotospiel.lemonsqueezy.com/checkout/success',
|
||
}),
|
||
});
|
||
});
|
||
|
||
await page.route('https://app.lemonsqueezy.com/js/lemon.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;
|
||
}
|
||
}
|
||
};
|
||
`,
|
||
});
|
||
});
|
||
|
||
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 Lemon Squeezy|Weiter mit Lemon Squeezy/ }).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.__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');
|
||
}
|
||
});
|
||
|
||
test('shows error state when Lemon Squeezy checkout creation fails', async ({ page }) => {
|
||
await page.route('**/lemonsqueezy/create-checkout', async (route) => {
|
||
await route.fulfill({
|
||
status: 500,
|
||
contentType: 'application/json',
|
||
body: JSON.stringify({ message: 'test-error' }),
|
||
});
|
||
});
|
||
|
||
await page.route('https://app.lemonsqueezy.com/js/lemon.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');
|
||
}
|
||
}
|
||
};
|
||
`,
|
||
});
|
||
});
|
||
|
||
await openCheckoutPaymentStep(page, demoTenantCredentials);
|
||
await acceptCheckoutTerms(page);
|
||
|
||
await page.getByRole('button', { name: /Continue with Lemon Squeezy|Weiter mit Lemon Squeezy/ }).first().click();
|
||
|
||
await expect(
|
||
page.locator('text=/Lemon Squeezy-Checkout konnte nicht gestartet werden|Lemon Squeezy 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 }>;
|
||
__lemonOpenedUrl?: string | null;
|
||
__lemonEventHandler?: ((event: { event: string; data?: unknown }) => void) | null;
|
||
}
|
||
}
|