syntaxai/tdd.md · main · e2e / git-native-proof.spec.ts
// E2E PROOF: tdd.md's CMS commits to a local bare git repo, not Forgejo.
//
// What this test demonstrates, end-to-end against the live deployed
// container:
// 1. The admin (syntaxai, via storage-state) saves an edit through
// the web editor at /edit/sama/skill.
// 2. The "applied live" page shows a fresh full SHA.
// 3. That SHA matches refs/heads/main of the bare repo on p620
// (/home/scri/repos/tdd.md.git) — proving the commit landed in
// our own git storage, not via a Forgejo HTTP round-trip.
// 4. /GIT/syntaxai/tdd.md/commit/<sha> renders the same commit
// (read-side also flows through c14_git, not c14_forgejo).
// 5. The commit's parent matches what HEAD was *before* the edit —
// proving we observed the commit graph genuinely advance, not
// a coincidental SHA match.
//
// The dramatic version of this test is in git-native-forgejo-down.spec.ts
// (separate file because it stops the forgejo service on p620 — only
// run that one when you can tolerate brief downtime).
import { test, expect } from "@playwright/test";
import * as fs from "fs";
import * as path from "path";
import { execSync } from "child_process";
const SCREENSHOT_DIR = "test-results/git-native-proof";
// When run inside a Flatpak sandbox (e.g. the VS Code .flatpak), `ssh` lives
// on the host so we have to hop through flatpak-spawn. When run on the host
// directly, flatpak-spawn isn't on PATH — call ssh straight. Detect by env.
const SSH_HOP = process.env.FLATPAK_ID ? "flatpak-spawn --host ssh" : "ssh";
const sshGit = (args: string): string =>
execSync(`${SSH_HOP} p620 'git --git-dir=/home/scri/repos/tdd.md.git ${args}'`, {
encoding: "utf8",
}).trim();
test.beforeAll(() => {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
});
const ADMIN_AUTH_FILE = ".auth/admin.json";
test.describe("CMS commits to local bare repo, not Forgejo", () => {
test.skip(!fs.existsSync(ADMIN_AUTH_FILE), `no ${ADMIN_AUTH_FILE} found`);
test.use({ storageState: ADMIN_AUTH_FILE });
test("admin web-edit lands as a commit in /home/scri/repos/tdd.md.git on p620", async ({
page,
request,
}) => {
// Snapshot HEAD before the edit. Read directly from the bare repo
// via SSH — no HTTP, no Forgejo, just `git` on disk.
const headBefore = sshGit("rev-parse refs/heads/main");
expect(headBefore).toMatch(/^[a-f0-9]{40}$/);
// Load current source so we can busy-the-no-op-skip with a marker.
const before = await (await request.get("/content/sama/skill.md")).text();
const marker = `<!-- git-native proof @ ${new Date().toISOString()} -->`;
const newBody = before + "\n" + marker + "\n";
// Save through the web editor.
await page.goto("/edit/sama/skill");
const textarea = page.locator("textarea[name='body']");
await expect(textarea).toBeVisible();
await textarea.fill(newBody);
await page.locator("button[type='submit']").click();
// Land on "applied live" with a 40-char commit SHA.
await expect(page.getByRole("heading", { name: /applied live/i })).toBeVisible();
const commitLink = page.locator('a[href^="/GIT/syntaxai/tdd.md/commit/"]');
await expect(commitLink).toBeVisible();
const href = await commitLink.getAttribute("href");
const newSha = href!.replace("/GIT/syntaxai/tdd.md/commit/", "");
expect(newSha).toMatch(/^[a-f0-9]{40}$/);
await page.screenshot({
path: path.join(SCREENSHOT_DIR, "1-applied-live-with-bare-repo-sha.png"),
fullPage: true,
});
// The bare repo on p620 — read-only check via SSH — must now point
// at this exact SHA. If it doesn't, the commit either didn't land
// or landed somewhere else (e.g. Forgejo).
const headAfter = sshGit("rev-parse refs/heads/main");
expect(headAfter).toBe(newSha);
expect(headAfter).not.toBe(headBefore);
// The new commit's parent must be the OLD HEAD — proving the graph
// genuinely advanced and our optimistic-concurrency check held.
const parentOfNew = sshGit(`rev-parse ${newSha}^`);
expect(parentOfNew).toBe(headBefore);
// The commit message subject must match what c31_commit_meta emits.
const msgSubject = sshGit(`log -1 --format=%s ${newSha}`);
expect(msgSubject).toBe("edit content/sama/skill.md via web");
// The author must be syntaxai (set by c21_handlers_edit using viewer).
const authorName = sshGit(`log -1 --format=%an ${newSha}`);
expect(authorName).toBe("syntaxai");
// /GIT/.../commit/<sha> reads from the same bare repo via c14_git
// and renders Bun-native. Walk it and check it matches.
const commitPage = await page.goto(`/GIT/syntaxai/tdd.md/commit/${newSha}`);
expect(commitPage?.status()).toBe(200);
await expect(page.locator(".commit-meta")).toContainText(newSha);
await expect(page.locator(".commit-meta")).toContainText(headBefore.slice(0, 7));
await page.screenshot({
path: path.join(SCREENSHOT_DIR, "2-commit-view-served-from-bare-repo.png"),
fullPage: true,
});
// The raw .diff endpoint also goes through c14_git (git diff-tree
// against the local bare repo, no Forgejo).
const diffRes = await request.get(`/GIT/syntaxai/tdd.md/commit/${newSha}.diff`);
expect(diffRes.status()).toBe(200);
const diffBody = await diffRes.text();
expect(diffBody).toContain("diff --git");
expect(diffBody).toContain(marker);
});
});