syntaxai/tdd.md · main · e2e / git-native-proof.spec.ts

git-native-proof.spec.ts 123 lines · 5423 bytes raw
// 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);
  });
});