leethobbit_obsidian-strong-.../tests/session-zero-content.test.ts
Dan 311ad4eda7 M9: session zero checklist, safety tools, feature toggles
Session zero sub-tab: four collapsible sections (pitch and
expectations, safety tools, characters, logistics) over a lazily
created Session zero note - 7 checklist items with stable ids
persisting to done[], hard lines and veils as chip lists feeding run
mode safety card, party roster with add-character, progress line, and
a quiet dashboard nudge while incomplete. New lossless feature-toggle
registry (features.ts, session-zero and dnd5e ids) with a Features
settings section; disabling session zero hides the sub-tab without
touching stored data. 288 vitest cases.

Verified live: first tick creates the note per SCHEMA.md, lines/veils
round-trip, run mode safety card shows the recorded hard line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 00:36:09 -04:00

51 lines
2 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
SESSION_ZERO_CHECKLIST,
SESSION_ZERO_GROUPS,
checklistItemsInGroup,
SAFETY_SENSITIVE_TOPICS_COPY,
SAFETY_LINES_VEILS_COPY,
SAFETY_PAUSE_COPY,
SAFETY_ANONYMOUS_REMINDER,
} from "../src/content/session-zero";
describe("session zero checklist content", () => {
it("has unique, non-empty ids", () => {
const ids = SESSION_ZERO_CHECKLIST.map((item) => item.id);
expect(new Set(ids).size).toBe(ids.length);
for (const id of ids) expect(id.length).toBeGreaterThan(0);
});
it("every item has a non-empty label and detail", () => {
for (const item of SESSION_ZERO_CHECKLIST) {
expect(item.label.trim().length, item.id).toBeGreaterThan(0);
expect(item.detail.trim().length, item.id).toBeGreaterThan(0);
}
});
it("keeps every card's detail under ~80 words (guidance, not a table)", () => {
for (const item of SESSION_ZERO_CHECKLIST) {
expect(item.detail.split(/\s+/).length, item.id).toBeLessThanOrEqual(80);
}
});
it("every item belongs to a declared group, and every declared group covers at least one item", () => {
const groupIds = new Set(SESSION_ZERO_GROUPS.map((g) => g.id));
for (const item of SESSION_ZERO_CHECKLIST) expect(groupIds.has(item.group)).toBe(true);
for (const group of SESSION_ZERO_GROUPS) expect(checklistItemsInGroup(group.id).length, group.id).toBeGreaterThan(0);
});
it("groups partition the checklist with no overlap and no gaps", () => {
const total = SESSION_ZERO_GROUPS.reduce((sum, group) => sum + checklistItemsInGroup(group.id).length, 0);
expect(total).toBe(SESSION_ZERO_CHECKLIST.length);
});
});
describe("safety tools reference copy", () => {
it("is non-empty and reasonably short (reference cards, not the full doc)", () => {
for (const copy of [SAFETY_SENSITIVE_TOPICS_COPY, SAFETY_LINES_VEILS_COPY, SAFETY_PAUSE_COPY, SAFETY_ANONYMOUS_REMINDER]) {
expect(copy.trim().length).toBeGreaterThan(0);
expect(copy.split(/\s+/).length).toBeLessThanOrEqual(80);
}
});
});