Release 0.2.0
This commit is contained in:
1 parent
7a49e66c37
commit
08e8875cb5
38 files changed
+2645
-93
No files matched your search
+138
@@ -1,4 +1,11 @@
|
||||
import { expect, test, type Page } from '@playwright/test';
|
||||
import { readFileSync, readdirSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const adminEmail = 'barkeeper@example.test';
|
||||
const adminPassword = 'Nur-fuer-E2E-Admin-1234';
|
||||
const crewEmail = 'crew@example.test';
|
||||
const crewPassword = 'Nur-fuer-E2E-Crew-1234';
|
||||
|
||||
const routes = ['/fundus', '/sendungen', '/eingang', '/archiv', '/verwaltung', '/live'];
|
||||
const viewports = [
|
||||
@@ -22,6 +29,137 @@ async function setTheme(page: Page, theme: 'light' | 'dark') {
|
||||
await page.evaluate((value) => localStorage.setItem('sendewerk-theme', value), theme);
|
||||
}
|
||||
|
||||
async function login(page: Page, email = adminEmail, password = adminPassword) {
|
||||
await page.goto('/login');
|
||||
await page.getByLabel('E-Mail').fill(email);
|
||||
await page.getByLabel('Passwort', { exact: true }).fill(password);
|
||||
await page.getByRole('button', { name: 'Anmelden' }).click();
|
||||
await expect(page).toHaveURL(/\/fundus$/);
|
||||
}
|
||||
|
||||
function latestMailLink(subject: string): string {
|
||||
const outbox = process.env.SENDEWERK_E2E_OUTBOX_DIR;
|
||||
if (!outbox) throw new Error('E2E-Outbox ist nicht konfiguriert.');
|
||||
const messages = readdirSync(outbox)
|
||||
.sort()
|
||||
.map(
|
||||
(file) =>
|
||||
JSON.parse(readFileSync(path.join(outbox, file), 'utf8')) as {
|
||||
subject: string;
|
||||
text: string;
|
||||
}
|
||||
)
|
||||
.filter((message) => message.subject === subject);
|
||||
const match = messages.at(-1)?.text.match(/https?:\/\/[^\s]+/);
|
||||
if (!match) throw new Error(`Keine Testmail mit Betreff ${subject} gefunden.`);
|
||||
return match[0];
|
||||
}
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
const page = await browser.newPage();
|
||||
await page.goto('/');
|
||||
if (await page.getByRole('heading', { name: 'Ersten Barkeeper anlegen' }).isVisible()) {
|
||||
await page.getByLabel('Betreiber-Setup-Token').fill('e2e-only-setup-token-32-characters');
|
||||
await page.getByLabel('Name').fill('E2E Barkeeper');
|
||||
await page.getByLabel('E-Mail').fill(adminEmail);
|
||||
await page.getByLabel('Passwort').fill(adminPassword);
|
||||
await page.getByRole('button', { name: 'Barkeeper anlegen' }).click();
|
||||
} else {
|
||||
await page.getByLabel('E-Mail').fill(adminEmail);
|
||||
await page.getByLabel('Passwort').fill(adminPassword);
|
||||
await page.getByRole('button', { name: 'Anmelden' }).click();
|
||||
}
|
||||
await expect(page).toHaveURL(/\/fundus$/);
|
||||
const sessionCookie = (await page.context().cookies()).find(
|
||||
(cookie) => cookie.name === 'sendewerk_session'
|
||||
);
|
||||
expect(sessionCookie?.httpOnly).toBe(true);
|
||||
expect(sessionCookie?.secure).toBe(false);
|
||||
expect(sessionCookie?.sameSite).toBe('Lax');
|
||||
await page.goto('/setup');
|
||||
await expect(page).toHaveURL(/\/fundus$/);
|
||||
await page.getByRole('button', { name: 'Abmelden', exact: true }).click();
|
||||
await expect(page).toHaveURL(/\/login$/);
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await login(page);
|
||||
});
|
||||
|
||||
test('invitations, direct authorization, locking and password reset work end to end', async ({
|
||||
page,
|
||||
browser
|
||||
}, testInfo) => {
|
||||
await page.goto('/verwaltung');
|
||||
await page.screenshot({
|
||||
path: testInfo.outputPath('verwaltung-konten-desktop.png'),
|
||||
fullPage: true
|
||||
});
|
||||
const crossSite = await page.request.post('/verwaltung?/invite', {
|
||||
form: { email: 'cross-site@example.test', role: 'barkeeper' },
|
||||
headers: { origin: 'https://example.invalid' }
|
||||
});
|
||||
expect(crossSite.status()).toBe(403);
|
||||
const inviteForm = page.locator('.invite-panel').filter({ hasText: 'Neues Konto einladen' });
|
||||
await inviteForm.getByLabel('E-Mail').fill(crewEmail);
|
||||
await inviteForm.getByRole('button', { name: 'Einladung erstellen' }).click();
|
||||
await expect(
|
||||
page.getByText('Einladung wurde in der lokalen Mail-Outbox abgelegt.')
|
||||
).toBeVisible();
|
||||
|
||||
const crewContext = await browser.newContext();
|
||||
const crewPage = await crewContext.newPage();
|
||||
await crewPage.goto(latestMailLink('Einladung zu Sendewerk'));
|
||||
await expect(crewPage).toHaveURL(/\/einladung$/);
|
||||
await crewPage.getByLabel('Name').fill('E2E Crew');
|
||||
await crewPage.getByLabel('Passwort').fill(crewPassword);
|
||||
await crewPage.getByRole('button', { name: 'Konto aktivieren' }).click();
|
||||
await expect(crewPage).toHaveURL(/\/fundus$/);
|
||||
await expect(crewPage.getByText('Verwaltung', { exact: true })).toHaveCount(0);
|
||||
|
||||
const forbidden = await crewPage.request.post('/verwaltung?/invite', {
|
||||
form: { email: 'verboten@example.test', role: 'barkeeper' },
|
||||
headers: { origin: 'http://127.0.0.1:4173' }
|
||||
});
|
||||
expect(forbidden.status()).toBe(403);
|
||||
|
||||
await page.reload();
|
||||
const crewRow = page.locator('.account-row').filter({ hasText: crewEmail });
|
||||
await crewRow.getByRole('button', { name: 'Sperren' }).click();
|
||||
await crewPage.goto('/fundus');
|
||||
await expect(crewPage).toHaveURL(/\/login$/);
|
||||
|
||||
await page.reload();
|
||||
await page
|
||||
.locator('.account-row')
|
||||
.filter({ hasText: crewEmail })
|
||||
.getByRole('button', { name: 'Entsperren' })
|
||||
.click();
|
||||
await crewPage.goto('/passwort-vergessen');
|
||||
await crewPage.getByLabel('E-Mail').fill(crewEmail);
|
||||
await crewPage.getByRole('button', { name: 'Reset-Link anfordern' }).click();
|
||||
await expect(crewPage.getByText('Anfrage verarbeitet.')).toBeVisible();
|
||||
await crewPage.goto(latestMailLink('Sendewerk-Passwort zurücksetzen'));
|
||||
await expect(crewPage).toHaveURL(/\/passwort-zuruecksetzen$/);
|
||||
await crewPage.getByLabel('Neues Passwort').fill('Neues-E2E-Crew-Passwort-1234');
|
||||
await crewPage.getByRole('button', { name: 'Passwort speichern' }).click();
|
||||
await login(crewPage, crewEmail, 'Neues-E2E-Crew-Passwort-1234');
|
||||
await crewContext.close();
|
||||
|
||||
const anonymousContext = await browser.newContext({ viewport: { width: 390, height: 844 } });
|
||||
const loginPage = await anonymousContext.newPage();
|
||||
await loginPage.goto('/login');
|
||||
await setTheme(loginPage, 'dark');
|
||||
await loginPage.reload();
|
||||
await expectNoHorizontalOverflow(loginPage);
|
||||
await loginPage.screenshot({
|
||||
path: testInfo.outputPath('login-mobile-dark.png'),
|
||||
fullPage: true
|
||||
});
|
||||
await anonymousContext.close();
|
||||
});
|
||||
|
||||
test('desktop fundus is a compact, filterable list with persistent themes', async ({
|
||||
page
|
||||
}, testInfo) => {
|
||||
|
||||
Reference in new issue
Block a user