163 lines
6.8 KiB
TypeScript
163 lines
6.8 KiB
TypeScript
import { config } from "dotenv";
|
|
import { chromium, request } from "@playwright/test";
|
|
import assert from "node:assert/strict";
|
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
config({ path: ".env.demo.local", quiet: true });
|
|
async function main() {
|
|
if (
|
|
process.env.DEMO_MODE !== "true" ||
|
|
process.env.NEXTAUTH_URL !== "http://localhost:3110"
|
|
)
|
|
throw new Error("Local demo configuration required");
|
|
const baseURL = "http://localhost:3110";
|
|
const api = await request.newContext({
|
|
baseURL,
|
|
extraHTTPHeaders: { Origin: baseURL },
|
|
});
|
|
const browser = await chromium.launch();
|
|
try {
|
|
assert.equal((await api.get("/api/health")).status(), 200);
|
|
const csrf = await (await api.get("/api/auth/csrf")).json();
|
|
await api.post("/api/auth/callback/credentials", {
|
|
form: {
|
|
csrfToken: csrf.csrfToken,
|
|
email: "admin@example.test",
|
|
password: process.env.DEMO_PASSWORD!,
|
|
json: "true",
|
|
},
|
|
});
|
|
assert.equal(
|
|
(await (await api.get("/api/auth/session")).json()).user.id,
|
|
"demo-admin",
|
|
);
|
|
// A valid tiny PDF fixture also exercises the read-only container's upload volume.
|
|
const objects = [
|
|
"<< /Type /Catalog /Pages 2 0 R >>",
|
|
"<< /Type /Pages /Kids [3 0 R] /Count 1 >>",
|
|
"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 400 200] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >>",
|
|
"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>",
|
|
];
|
|
const stream =
|
|
"BT /F1 16 Tf 30 140 Td (Taskmanager - Testprotokoll) Tj 0 -30 Td (Private Datei erfolgreich gespeichert.) Tj ET";
|
|
objects.push(
|
|
`<< /Length ${Buffer.byteLength(stream)} >>\nstream\n${stream}\nendstream`,
|
|
);
|
|
let pdf = "%PDF-1.4\n";
|
|
const offsets: number[] = [0];
|
|
objects.forEach((object, i) => {
|
|
offsets.push(Buffer.byteLength(pdf));
|
|
pdf += `${i + 1} 0 obj\n${object}\nendobj\n`;
|
|
});
|
|
const xref = Buffer.byteLength(pdf);
|
|
pdf += `xref\n0 6\n0000000000 65535 f \n${offsets
|
|
.slice(1)
|
|
.map((n) => `${String(n).padStart(10, "0")} 00000 n \n`)
|
|
.join(
|
|
"",
|
|
)}trailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`;
|
|
const detail = await (await api.get("/api/tasks/demo-task-1")).json();
|
|
if (
|
|
!detail.files?.some(
|
|
(f: { name: string }) => f.name === "Testprotokoll.pdf",
|
|
)
|
|
) {
|
|
const upload = await api.post("/api/tasks/demo-task-1/files", {
|
|
multipart: {
|
|
file: {
|
|
name: "Testprotokoll.pdf",
|
|
mimeType: "application/pdf",
|
|
buffer: Buffer.from(pdf),
|
|
},
|
|
},
|
|
});
|
|
assert.equal(upload.status(), 201, await upload.text());
|
|
const file = await upload.json();
|
|
assert.deepEqual(
|
|
await (await api.get(file.path)).body(),
|
|
Buffer.from(pdf),
|
|
);
|
|
}
|
|
const durations: number[] = [];
|
|
await Promise.all(
|
|
Array.from({ length: 5 }, async () => {
|
|
for (let i = 0; i < 10; i++) {
|
|
const start = performance.now();
|
|
assert.equal((await api.get("/api/tasks?limit=25")).status(), 200);
|
|
durations.push(performance.now() - start);
|
|
}
|
|
}),
|
|
);
|
|
durations.sort((a, b) => a - b);
|
|
const page = await browser.newPage({
|
|
storageState: await api.storageState(),
|
|
viewport: { width: 1440, height: 1000 },
|
|
});
|
|
const errors: string[] = [];
|
|
page.on("pageerror", (error) => errors.push(error.message));
|
|
await page.goto(`${baseURL}/dashboard/tasks`);
|
|
await page
|
|
.getByRole("link", { name: "Heizungsanlage prüfen", exact: true })
|
|
.waitFor();
|
|
await mkdir("test-results", { recursive: true });
|
|
await page.screenshot({
|
|
path: "test-results/demo-desktop.png",
|
|
fullPage: true, animations: "disabled",
|
|
});
|
|
await page.goto(`${baseURL}/dashboard/access`);
|
|
await page.getByRole("heading", { name: "Gruppen & Rechte" }).waitFor();
|
|
await page.getByRole("button", { name: "Haustechnik", exact: true }).waitFor();
|
|
await page.screenshot({ path: "test-results/demo-rbac.png", fullPage: true, animations: "disabled" });
|
|
await page.getByRole("button", { name: "Haustechnik", exact: true }).click();
|
|
await page.getByRole("dialog", { name: "Haustechnik", exact: true }).waitFor();
|
|
await page.screenshot({ path: "test-results/demo-group-detail.png", fullPage: true, animations: "disabled" });
|
|
await page.getByRole("dialog", { name: "Haustechnik", exact: true }).getByRole("button", { name: "Schließen" }).click();
|
|
for (const [route, heading] of [
|
|
["/dashboard", "Übersicht"],
|
|
["/dashboard/tasks/demo-task-1", "Heizungsanlage prüfen"],
|
|
["/dashboard/users", "Benutzer"],
|
|
["/dashboard/settings", "Import & Integrationen"],
|
|
["/dashboard/calendar", "Kalender"],
|
|
]) {
|
|
await page.goto(`${baseURL}${route}`);
|
|
if (route !== "/dashboard") await page.getByRole("heading", { name: heading, exact: true }).waitFor();
|
|
await page.waitForLoadState("networkidle");
|
|
await page.screenshot({ path: `test-results/demo-${route.split("/").pop() || "overview"}.png`, fullPage: true, animations: "disabled" });
|
|
}
|
|
await page.setViewportSize({ width: 390, height: 844 });
|
|
await page.goto(`${baseURL}/dashboard/tasks`);
|
|
await page.getByRole("link", { name: "Heizungsanlage prüfen", exact: true }).waitFor();
|
|
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), true);
|
|
await page.screenshot({ path: "test-results/demo-mobile.png", fullPage: true, animations: "disabled" });
|
|
await page.getByRole("button", { name: "Neue Aufgabe", exact: true }).click();
|
|
await page.getByRole("dialog", { name: "Neue Aufgabe", exact: true }).waitFor();
|
|
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), true);
|
|
await page.screenshot({ path: "test-results/demo-mobile-dialog.png", fullPage: false, animations: "disabled" });
|
|
await page.getByRole("dialog", { name: "Neue Aufgabe", exact: true }).getByRole("button", { name: "Abbrechen" }).click();
|
|
await page.setViewportSize({ width: 1440, height: 1000 });
|
|
await page.emulateMedia({ colorScheme: "dark" });
|
|
await page.reload();
|
|
await page.getByRole("link", { name: "Heizungsanlage prüfen", exact: true }).waitFor();
|
|
await page.screenshot({ path: "test-results/demo-dark.png", fullPage: true, animations: "disabled" });
|
|
assert.deepEqual(errors, []);
|
|
const result = {
|
|
requests: durations.length,
|
|
concurrency: 5,
|
|
medianMs: Math.round(durations[25]),
|
|
p95Ms: Math.round(durations[47]),
|
|
browserErrors: errors,
|
|
};
|
|
await writeFile(
|
|
"test-results/demo-check.json",
|
|
JSON.stringify(result, null, 2),
|
|
);
|
|
console.log(JSON.stringify(result));
|
|
} finally {
|
|
await api.dispose();
|
|
await browser.close();
|
|
}
|
|
}
|
|
main().catch((error) => {
|
|
console.error(error);
|
|
process.exitCode = 1;
|
|
});
|