neuer checkout-pfad: /de/bestellen/paketID und /en/checkout/PackageID
This commit is contained in:
@@ -1,56 +1,13 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { execSync } from 'child_process';
|
||||
import { test, expectFixture as expect } from '../helpers/test-fixtures';
|
||||
|
||||
const LOGIN_EMAIL = 'checkout-e2e@example.com';
|
||||
const LOGIN_PASSWORD = 'Password123!';
|
||||
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.beforeAll(async () => {
|
||||
execSync(
|
||||
`php artisan tenant:add-dummy --email=${LOGIN_EMAIL} --password=${LOGIN_PASSWORD} --first_name=Checkout --last_name=Tester --address="Playwrightstr. 1" --phone="+4912345678"`
|
||||
);
|
||||
|
||||
execSync(
|
||||
`php artisan tinker --execute="App\\\\Models\\\\User::where('email', '${LOGIN_EMAIL}')->update(['email_verified_at' => now()]);"`
|
||||
);
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
await page.fill('input[name="email"]', LOGIN_EMAIL);
|
||||
await page.fill('input[name="password"]', LOGIN_PASSWORD);
|
||||
await page.getByRole('button', { name: /Anmelden|Login/ }).click();
|
||||
await expect(page).toHaveURL(/dashboard/);
|
||||
});
|
||||
|
||||
test('opens Paddle checkout and shows success notice', async ({ page }) => {
|
||||
await page.route('**/paddle/create-checkout', async (route) => {
|
||||
const request = route.request();
|
||||
const postData = request.postDataJSON() as { inline?: boolean } | null;
|
||||
const inline = Boolean(postData?.inline);
|
||||
|
||||
if (inline) {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
mode: 'inline',
|
||||
items: [
|
||||
{ priceId: 'pri_123', quantity: 1 },
|
||||
],
|
||||
custom_data: {
|
||||
tenant_id: '1',
|
||||
package_id: '2',
|
||||
checkout_session_id: 'cs_123',
|
||||
},
|
||||
customer: {
|
||||
email: LOGIN_EMAIL,
|
||||
},
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
@@ -78,7 +35,8 @@ test.describe('Checkout Payment Step – Paddle flow', () => {
|
||||
});
|
||||
});
|
||||
|
||||
await openCheckoutPaymentStep(page);
|
||||
await openCheckoutPaymentStep(page, demoTenantCredentials);
|
||||
await acceptCheckoutTerms(page);
|
||||
|
||||
await page.evaluate(() => {
|
||||
window.__openedUrls = [];
|
||||
@@ -88,21 +46,46 @@ test.describe('Checkout Payment Step – Paddle flow', () => {
|
||||
};
|
||||
});
|
||||
|
||||
await page.getByRole('button', { name: /Continue with Paddle|Weiter mit Paddle/ }).click();
|
||||
await page.getByRole('button', { name: /Continue with Paddle|Weiter mit Paddle/ }).first().click();
|
||||
|
||||
await expect(
|
||||
page.locator(
|
||||
'text=/Paddle checkout is running in a secure overlay|Der Paddle-Checkout läuft jetzt in einem Overlay/'
|
||||
'text=/secure overlay|Overlay|neuen Tab|new tab/i'
|
||||
)
|
||||
).toBeVisible();
|
||||
|
||||
await expect.poll(async () => {
|
||||
return page.evaluate(() => window.__paddleOpenConfig?.items?.[0]?.priceId ?? null);
|
||||
}).toBe('pri_123');
|
||||
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,
|
||||
}));
|
||||
|
||||
await expect.poll(async () => {
|
||||
return page.evaluate(() => window.__openedUrls?.length ?? 0);
|
||||
}).toBe(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 }) => {
|
||||
@@ -114,35 +97,78 @@ test.describe('Checkout Payment Step – Paddle flow', () => {
|
||||
});
|
||||
});
|
||||
|
||||
await openCheckoutPaymentStep(page);
|
||||
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 page.getByRole('button', { name: /Continue with Paddle|Weiter mit Paddle/ }).click();
|
||||
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 could not be started|Paddle-Checkout konnte nicht gestartet werden/')
|
||||
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) {
|
||||
await page.goto('/packages');
|
||||
const checkoutLink = page.locator('a[href^="/checkout/"]').first();
|
||||
const href = await checkoutLink.getAttribute('href');
|
||||
async function openCheckoutPaymentStep(
|
||||
page: import('@playwright/test').Page,
|
||||
credentials: { email: string; password: string }
|
||||
) {
|
||||
await page.goto('/packages');
|
||||
|
||||
if (!href) {
|
||||
throw new Error('No checkout link found on packages page.');
|
||||
}
|
||||
const detailsButtons = page.getByRole('button', {
|
||||
name: /Details ansehen|Details anzeigen|View details/i,
|
||||
});
|
||||
await expect(detailsButtons.first()).toBeVisible();
|
||||
await detailsButtons.first().click();
|
||||
|
||||
await page.goto(href);
|
||||
const dialog = page.getByRole('dialog');
|
||||
await expect(dialog).toBeVisible();
|
||||
await dialog.getByRole('link', { name: /Jetzt bestellen|Order now|Jetzt buchen/i }).click();
|
||||
|
||||
const nextButton = page.getByRole('button', {
|
||||
name: /Weiter zum Zahlungsschritt|Continue to Payment/,
|
||||
});
|
||||
if (await nextButton.isVisible()) {
|
||||
await nextButton.click();
|
||||
}
|
||||
await expect(page).toHaveURL(/\/(bestellen|checkout)\/\d+/);
|
||||
|
||||
await page.waitForSelector('text=/Zahlung|Payment/');
|
||||
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();
|
||||
|
||||
const waiverCheckbox = page.locator('#checkout-waiver-hero');
|
||||
if (await waiverCheckbox.isVisible()) {
|
||||
await waiverCheckbox.click();
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
Reference in New Issue
Block a user