test(plan): integration test for the new Gantt view

Two tests against the live database and the seeded project:

- loadPlan returns a section containing the seeded project.
- GanttPlanView renders the project name and at least one
  card title to HTML.

vitest integration config now picks up .test.tsx too.
This commit is contained in:
Dave 2026-09-21 16:19:52 +02:00
parent 5ff12a4ef0
commit 14f6c067c2
2 changed files with 74 additions and 1 deletions

View file

@ -0,0 +1,73 @@
import { describe, it, expect, beforeAll } from "vitest";
import PocketBase from "pocketbase";
import { renderToStaticMarkup } from "react-dom/server";
import { GanttPlanView } from "@/components/roadmap/gantt-plan-view";
import { buildPlanSections } from "@/lib/roadmap/load";
import type {
CardRecord,
ClientRecord,
ColumnRecord,
ProjectRecord,
SubtaskRecord,
} from "@/lib/pb/types";
import { DEMO, adminPb, requireServices } from "./helpers";
let admin: PocketBase;
beforeAll(async () => {
await requireServices();
admin = await adminPb();
});
async function loadForProject(slug: string) {
const project = await admin
.collection("projects")
.getFirstListItem<ProjectRecord>(`slug = "${slug}"`);
const [clients, columns, cards, subtasks] = await Promise.all([
admin.collection("clients").getFullList<ClientRecord>(),
admin.collection("columns").getFullList<ColumnRecord>({ sort: "position" }),
admin
.collection("cards")
.getFullList<CardRecord>({ filter: `project = "${project.id}" && archived = false` }),
admin
.collection("subtasks")
.getFullList<SubtaskRecord>({
filter: `card.project = "${project.id}"`,
}),
]);
return buildPlanSections({
clients,
projects: [project],
columns,
cards,
subtasks,
});
}
describe("/plan Gantt — seeded project loads", () => {
it("returns at least one section containing the seeded project", async () => {
const sections = await loadForProject(DEMO.projectSlug);
expect(sections.length).toBe(1);
expect(sections[0].project.slug).toBe(DEMO.projectSlug);
expect(sections[0].cards.length).toBeGreaterThan(0);
});
});
describe("/plan Gantt — render", () => {
it("renders the project name and at least one card title", async () => {
const sections = await loadForProject(DEMO.projectSlug);
const html = renderToStaticMarkup(<GanttPlanView sections={sections} />);
expect(html).toContain(sections[0].project.name);
// Pick a card title that contains no characters React will escape
// (the seeded titles use ASCII letters and spaces only).
const safeTitle =
sections[0].cards.find((c) => /^[A-Z0-9 \-]+$/.test(c.title))?.title ??
sections[0].cards[0].title.slice(0, 10);
expect(html).toContain(safeTitle);
});
});

View file

@ -42,7 +42,7 @@ export default defineConfig({
test: {
name: "integration",
environment: "node",
include: ["tests/integration/**/*.test.ts"],
include: ["tests/integration/**/*.test.ts", "tests/integration/**/*.test.tsx"],
hookTimeout: 30_000,
testTimeout: 30_000,
poolOptions: { forks: { singleFork: true } },