Files
cannamanage/cannamanage-frontend/e2e/screenshot-tour.spec.ts
T
Patrick Plate 599514c0db
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
feat(sprint-6): Phase 6 — Notifications (WebSocket) + PWA
- WebSocket: Spring STOMP + SockJS, NotificationService, persistent notifications table
- NotificationController: GET/PUT endpoints for notification management
- Frontend: notification bell with unread badge, dropdown panel, real-time via STOMP
- PWA: manifest.json, service worker (manual sw.js), offline page, install prompt
- PWA icons (192+512), dark theme colors, standalone display
- Full i18n (de/en) for notifications and PWA
- Flyway V10 migration for notifications table
- spring-boot-starter-websocket dependency added
2026-06-12 23:02:44 +02:00

197 lines
6.0 KiB
TypeScript

/**
* CannaManage Sprint 4 — Visual Screenshot Tour
*
* Takes screenshots of every page in both dark and light mode.
* Requires: pnpm exec playwright install chromium
* Usage: pnpm exec playwright test e2e/screenshot-tour.spec.ts --reporter=list
*
* Prerequisites:
* 1. Start mock backend: node e2e/mock-backend.mjs
* 2. Start dev server: pnpm dev
*/
import path from "path"
import { expect, test } from "@playwright/test"
import type { Page } from "@playwright/test"
const SCREENSHOT_DIR = path.join(__dirname, "..", "docs", "screenshots")
// Pages accessible without auth
const PUBLIC_PAGES = [
{ route: "/login", name: "01-login", title: "Admin Login" },
{
route: "/portal-login",
name: "02-portal-login",
title: "Member Portal Login",
},
]
// Admin pages (require auth session)
const ADMIN_PAGES = [
{ route: "/dashboard", name: "03-dashboard", title: "Club Dashboard" },
{ route: "/members", name: "04-members", title: "Member Management" },
{
route: "/distributions",
name: "05-distributions",
title: "Distribution History",
},
{
route: "/distributions/new",
name: "06-distribution-new",
title: "New Distribution (Multi-Step)",
},
{ route: "/stock", name: "07-stock", title: "Stock & Batch Management" },
{ route: "/stock/new", name: "08-stock-new", title: "Add New Batch" },
{ route: "/reports", name: "09-reports", title: "Compliance Reports" },
]
// Portal pages (no admin auth needed per middleware)
const PORTAL_PAGES = [
{
route: "/portal/dashboard",
name: "10-portal-dashboard",
title: "Member Quota Overview",
},
{
route: "/portal/history",
name: "11-portal-history",
title: "My Distribution History",
},
{
route: "/portal/profile",
name: "12-portal-profile",
title: "Profile & Settings",
},
]
async function setTheme(page: Page, theme: "dark" | "light") {
await page.evaluate((t) => {
localStorage.setItem("theme", t)
document.documentElement.classList.remove("dark", "light")
document.documentElement.classList.add(t)
// Also set the next-themes cookie
document.cookie = `theme=${t}; path=/`
}, theme)
}
async function capturePageScreenshot(
page: Page,
route: string,
name: string,
theme: "dark" | "light"
) {
await page.goto(route, { waitUntil: "domcontentloaded" })
await page.waitForTimeout(2000) // Wait for hydration + animations
await setTheme(page, theme)
await page.waitForTimeout(500) // Let theme apply
const filename = `${name}-${theme}.png`
await page.screenshot({
path: path.join(SCREENSHOT_DIR, filename),
fullPage: true,
})
return filename
}
test.describe("CannaManage Screenshot Tour", () => {
test.setTimeout(120_000)
test("capture all pages in dark and light mode", async ({ page }) => {
const results: {
name: string
title: string
dark: string
light: string
}[] = []
// --- PUBLIC PAGES ---
for (const p of PUBLIC_PAGES) {
const dark = await capturePageScreenshot(page, p.route, p.name, "dark")
const light = await capturePageScreenshot(page, p.route, p.name, "light")
results.push({ name: p.name, title: p.title, dark, light })
}
// --- LOGIN to get admin session ---
await page.goto("/login", { waitUntil: "domcontentloaded" })
await page.waitForTimeout(2000)
const emailField = page.locator('input[id="email"]')
const passwordField = page.locator('input[id="password"]')
const submitButton = page.locator('button[type="submit"]')
if (await emailField.isVisible({ timeout: 5000 })) {
await emailField.fill("admin@cannamanage.de")
await passwordField.fill("admin123")
await submitButton.click()
// Wait for redirect after login
await page.waitForTimeout(5000)
}
// Check if we got authenticated (redirected to dashboard)
const isAuthenticated =
page.url().includes("/dashboard") || page.url().includes("/login")
if (page.url().includes("/dashboard")) {
// --- ADMIN PAGES (authenticated) ---
for (const p of ADMIN_PAGES) {
const dark = await capturePageScreenshot(page, p.route, p.name, "dark")
const light = await capturePageScreenshot(
page,
p.route,
p.name,
"light"
)
results.push({ name: p.name, title: p.title, dark, light })
}
} else {
// Auth failed — still capture what we can see (login page with error)
console.log("⚠️ Auth failed — admin pages will show login redirect")
for (const p of ADMIN_PAGES) {
const dark = await capturePageScreenshot(page, p.route, p.name, "dark")
results.push({
name: p.name,
title: `${p.title} (auth required)`,
dark,
light: dark,
})
}
}
// --- PORTAL PAGES (no auth needed) ---
for (const p of PORTAL_PAGES) {
const dark = await capturePageScreenshot(page, p.route, p.name, "dark")
const light = await capturePageScreenshot(page, p.route, p.name, "light")
results.push({ name: p.name, title: p.title, dark, light })
}
// Generate markdown index
let md = "# CannaManage — Visual Tour (Sprint 4)\n\n"
md += `**Generated:** ${new Date().toISOString().split("T")[0]}\n\n`
md += "---\n\n"
for (const r of results) {
md += `## ${r.title}\n\n`
md += `| Dark Mode | Light Mode |\n`
md += `|-----------|------------|\n`
md += `| ![${r.title} Dark](screenshots/${r.dark}) | ![${r.title} Light](screenshots/${r.light}) |\n\n`
}
// Write the markdown file
const fs = await import("fs")
const docsDir = path.join(__dirname, "..", "docs")
if (!fs.existsSync(path.join(docsDir, "screenshots"))) {
fs.mkdirSync(path.join(docsDir, "screenshots"), { recursive: true })
}
fs.writeFileSync(path.join(docsDir, "visual-tour.md"), md)
console.log(
`\n✅ Screenshot tour complete! ${results.length} pages captured.`
)
console.log(`📄 Markdown: docs/visual-tour.md`)
console.log(`📸 Screenshots: docs/screenshots/`)
})
})