dorfteich/apps/api/prisma/fixtures/regenerate.ts
Claude Sonnet 5 12035e2231
Some checks failed
CD / Build and push images (push) Successful in 2m2s
CI / Lint, typecheck, test (push) Successful in 1m44s
CI / Auth e2e pack (push) Failing after 1m50s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 8s
CD / Smoke tests against Test (push) Successful in 1m8s
CD / Promote to Int (push) Successful in 10s
Add M2 fixtures and content regression pack (#32)
Seed script extends the fixture matrix with a shared "Content Fixtures"
pond (owned by fixture-user): an "Every Element" page covering every
editor schema node and mark (#24), and a "Fixture Image" page with one
real, servable uploaded image. "Every Element" loads a checked-in Yjs
snapshot (prisma/fixtures/content-page.yjs) generated from a
human-readable Markdown source (content-page.md) via a deterministic
regeneration script (pinned Y.Doc clientID; refuses to write a
snapshot that isn't a fixed point of the Markdown round-trip).

New apps/web/e2e/content.spec.ts consolidates the M2 content
regression pack: page lifecycle, editor basics, image paste, trash,
and — the pack's actual regression pin — a byte-for-byte comparison of
the fixture page's exported Markdown against the checked-in fixture.
Verified this catches regressions: temporarily mutated
docToMarkdown's heading serializer, rebuilt, re-seeded, confirmed the
comparison failed, then reverted.

This pack now runs in CI (a second step in the existing auth-e2e job,
reusing its already-built-and-seeded stack) alongside the existing
local-only feature packs.

Closes #32
2026-07-08 13:14:48 +02:00

61 lines
2.5 KiB
TypeScript

/**
* Regenerates `content-page.yjs` from `content-page.md` (issue #32).
*
* `content-page.md` is the source of truth — a Markdown document
* deliberately covering every node type and mark in the editor schema
* (packages/shared/src/editor-schema/schema.ts, issue #24) and already a
* fixed point of the Markdown round-trip (`docToMarkdown(markdownToDoc(x))
* === x`); the seed script (`../seed.ts`) loads the checked-in `.yjs`
* binary directly rather than re-parsing Markdown on every run.
*
* Deterministic: `Y.Doc`'s `clientID` is normally randomized per instance,
* which would make the encoded update differ on every regeneration even
* for identical content. Pinning it to a fixed value makes the output a
* pure function of `content-page.md`, so re-running this without editing
* the Markdown produces a byte-identical `.yjs` (verified — re-run and
* `git diff` should show no changes).
*
* Run after editing `content-page.md`:
* pnpm --filter @dorfteich/api fixtures:regenerate
*/
import { readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { docToMarkdown, editorSchema, markdownToDoc } from '@dorfteich/shared';
import { prosemirrorJSONToYXmlFragment } from 'y-prosemirror';
import * as Y from 'yjs';
const FIXTURE_DIR = join(__dirname);
const FIXED_CLIENT_ID = 1;
function main(): void {
const markdown = readFileSync(join(FIXTURE_DIR, 'content-page.md'), 'utf8');
const doc = markdownToDoc(markdown);
// Round-trip sanity check: if this ever fails, the schema or serializer
// changed in a way that makes content-page.md no longer a fixed point —
// fix the schema/serializer or update content-page.md, don't silently
// check in a snapshot that doesn't match its own source.
const roundTripped = docToMarkdown(doc);
if (roundTripped !== markdown) {
console.error('content-page.md is not a fixed point of the Markdown round-trip.');
console.error('--- expected (content-page.md) ---');
console.error(markdown);
console.error('--- got (docToMarkdown(markdownToDoc(content-page.md))) ---');
console.error(roundTripped);
process.exit(1);
}
const ydoc = new Y.Doc();
ydoc.clientID = FIXED_CLIENT_ID;
const fragment = ydoc.getXmlFragment('default');
prosemirrorJSONToYXmlFragment(editorSchema, doc.toJSON(), fragment);
const state = Y.encodeStateAsUpdate(ydoc);
ydoc.destroy();
writeFileSync(join(FIXTURE_DIR, 'content-page.yjs'), state);
console.log(`fixtures: wrote content-page.yjs (${state.length} bytes)`);
}
main();