Files
hope-events/e2e/sessions.spec.ts
joshuaandClaude Opus 5.5 48660732fe Run background jobs on a pg-boss queue; add e2e tests, CI and deploy script
Timed jobs move from in-process timers to a job registry run by pg-boss:
once per schedule across processes, retries, run history, cron schedules
in the church timezone, and an admin Background jobs page with Run now.
Playwright end-to-end tests run against their own seeded database. A
Gitea Actions workflow runs backend tests, frontend checks and the e2e
tests, and deploys v* tags with scripts/deploy.sh once secrets are set.
Also fixes the at-the-door check-in count for multi-day tickets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 15:49:46 +02:00

52 lines
2.5 KiB
TypeScript

import { test, expect, seed, loginAs, api } from "./fixtures";
test.describe("multi-day events", () => {
test("check-in is once per session, and the register and certificates follow", async ({ page }) => {
const { course, events } = seed();
// Scanning today: Week 2.
const scan = await api<{ session: { label: string } }>(page, "staff", "POST", `/api/tickets/scan/${course.qrCode}`, { qty: 1 });
expect(scan.session.label).toBe("Week 2");
await expect(api(page, "staff", "POST", `/api/tickets/scan/${course.qrCode}`, { qty: 1 })).rejects.toThrow(/Already checked in for Week 2/);
// The register shows weeks 1 and 2 ticked.
await loginAs(page, "supervisor");
await page.goto(`/dashboard/supervisor/attendance?eventId=${events.course}`);
const row = page.locator("tr", { hasText: "Thandi Test" });
await expect(row.getByText("2/5")).toBeVisible();
// Tick week 3 by hand (e.g. let in without a scan), then untick it.
const week3 = row.locator("td").nth(3).getByRole("button");
await week3.click();
await expect(row.getByText("3/5")).toBeVisible();
await week3.click();
await expect(row.getByText("2/5")).toBeVisible();
// Two sessions meets the rule (at least 2), so a certificate can be issued now.
await page.getByRole("button", { name: "Issue now" }).click();
await expect(page.getByText("1 certificate issued.")).toBeVisible();
const code = (await row.locator("span.font-mono").innerText()).trim();
expect(code).toMatch(/^[A-Z0-9]{5}-[A-Z0-9]{5}$/);
// Anyone can check it.
await page.goto(`/certificates/verify/${code}`);
await expect(page.getByRole("heading", { name: "Valid certificate" })).toBeVisible();
await expect(page.getByText("Thandi Test")).toBeVisible();
});
test("the attendee sees their certificate on My Events", async ({ page }) => {
await loginAs(page, "user");
await page.goto("/dashboard/user");
await expect(page.getByRole("heading", { name: "My Certificates" })).toBeVisible();
await expect(page.getByText("E2E Alpha Course").first()).toBeVisible();
});
test("the scanner offers today's session for a multi-day event", async ({ page }) => {
await loginAs(page, "staff");
await page.goto("/dashboard/staff/ticket-scanning");
await page.locator("select").first().selectOption({ label: "E2E Alpha Course" });
await expect(page.locator("select", { has: page.locator("option", { hasText: "Today's session" }) })).toBeVisible();
await expect(page.getByText("Today's session (Week 2)")).toBeAttached();
});
});