Files
pitchfast/tests/audit-skills-ui.test.ts

163 lines
4.8 KiB
TypeScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import test from "node:test";
const source = async (relativePath: string) => {
return await readFile(
join(process.cwd(), ...relativePath.split("/")),
"utf8",
);
};
test("audits dashboard page uses a dedicated board component", async () => {
const dashboardPageSource = await source("app/dashboard/audits/page.tsx");
assert.doesNotMatch(
dashboardPageSource,
/DashboardPlaceholderPage/i,
"Dashboard audits route should not render the placeholder page.",
);
assert.match(
dashboardPageSource,
/<AuditsBoard \/>/,
"Audits board should be mounted from route page.",
);
assert.match(
dashboardPageSource,
/"@\/components\/audits\/audits-board"/,
"Audits board should be imported from components.",
);
});
test("audits board renders compact list with convex list query and core columns", async () => {
const boardSource = await source("components/audits/audits-board.tsx");
assert.match(
boardSource,
/\"use client\"/,
"AuditsBoard must be a Client Component for useQuery.",
);
assert.match(
boardSource,
/useQuery\s*\(\s*api\.audits\.list,\s*\{\s*limit:\s*100\s*\}\s*\)/,
"AuditsBoard should call api.audits.list with { limit: 100 }.",
);
assert.match(
boardSource,
/sort\(\(\s*a,\s*b\s*\)\s*=>\s*b\.createdAt\s*-\s*a\.createdAt\)/,
"Audits should be sorted newest first.",
);
assert.match(boardSource, /Loading|lädt|Lade/i);
assert.match(boardSource, /Keine Audits|keine Audits/i);
assert.match(boardSource, /Slug/);
assert.match(boardSource, /Domain/);
assert.match(boardSource, /Status/);
assert.match(boardSource, /Seiten/);
assert.match(
boardSource,
/href=\{`\/dashboard\/audits\/\$\{audit\._id\}`\}/,
"Each audit row should link to /dashboard/audits/{id}.",
);
});
test("audit detail component uses getDetail query and renders skills overview section", async () => {
const detailSource = await source("components/audits/audit-detail.tsx");
assert.match(
detailSource,
/\"use client\"/,
"AuditDetail must be client-side for Convex query calls.",
);
assert.match(
detailSource,
/api\.audits[\s\S]{0,80}getDetail/,
"AuditDetail should use api.audits.getDetail query.",
);
assert.match(
detailSource,
/useQuery\(\s*api\.audits\.getDetail,\s*\{/,
"AuditDetail should call useQuery with api.audits.getDetail directly.",
);
assert.doesNotMatch(
detailSource,
/const\s+auditDetailQueryRef/,
"AuditDetail should not use a cast-based query fallback variable.",
);
assert.match(
detailSource,
/const\s+audit\s*=\s*result\?\.audit;/,
"AuditDetail should destructure audit from result.audit.",
);
assert.match(
detailSource,
/const\s+lead\s*=\s*result\?\.lead;/,
"AuditDetail should destructure lead from result.lead.",
);
assert.match(
detailSource,
/leadSummary\(\s*lead\s*\)/,
"AuditDetail should pass lead into leadSummary from result.lead.",
);
assert.match(
detailSource,
/usedSkills/,
"AuditDetail should inspect usedSkills for overview rendering.",
);
assert.match(
detailSource,
/Keine Skills gespeichert/,
"AuditDetail should show fallback text when no skills are saved.",
);
assert.match(
detailSource,
/Verwendete Skills/,
"AuditDetail should render Verwendete Skills heading.",
);
assert.match(
detailSource,
/Lead|lead/,
"AuditDetail should surface lead context when available.",
);
assert.doesNotMatch(
detailSource,
/<p[^>]*>\s*\{leadSummary\(\s*lead\|[\s\S]*?\)\s*\}\s*<\/p>/,
"Lead summary should not wrap leadSummary output in a nested <p>.",
);
assert.doesNotMatch(
detailSource,
/<p[^>]*>\s*\{leadSummary\(\s*audit\.lead\)\s*\}\s*<\/p>/,
"Lead summary should not wrap leadSummary output in a nested <p>.",
);
});
test("audits detail route passes id to AuditDetail via Promise params", async () => {
const pageSource = await source("app/dashboard/audits/[id]/page.tsx");
assert.match(
pageSource,
/params:\s*Promise<\{\s*id:\s*string\s*\}>/,
"Audit detail route should accept params as Promise in Next.js 16 style.",
);
assert.match(
pageSource,
/const \{\s*id\s*\}\s*=\s*await params/,
"Audit detail route should unwrap Promise params.",
);
assert.match(
pageSource,
/<AuditDetail\s+id=/,
"Audit detail route should pass id prop into AuditDetail.",
);
});
test("public audit page does not expose used skills", async () => {
const publicAuditSource = await source("app/audit/[slug]/page.tsx");
assert.doesNotMatch(
publicAuditSource,
/Verwendete Skills|usedSkills/i,
"Public audit page must not show used skills.",
);
});