syntaxai/tdd.md · main · e2e / sama-skill-editable.spec.ts
// E2E: prove /sama/skill is end-to-end editable.
//
// Walks the full user journey:
// 1. Land on https://tdd.md/sama/skill (the SKILL.md viewer)
// 2. Spot the "propose an edit →" link in the docs chrome
// 3. Click it → navigate to /edit/sama/skill
// 4. Confirm the editor login wall renders (server side returns 401
// with the GitHub sign-in button + ?to= preserving where to come
// back to after auth)
// 5. Confirm the raw source is reachable at /content/sama/skill.md
// 6. Screenshot each step into test-results/ for visual evidence
//
// Authenticated submission isn't scripted here because admin write
// requires a real GitHub OAuth round-trip — see the bottom of this
// file for the storage-state-based test that runs when you've saved
// a logged-in session via `bunx playwright codegen` or similar.
import { test, expect } from "@playwright/test";
import * as fs from "fs";
import * as path from "path";
const SCREENSHOT_DIR = "test-results/sama-skill-editable";
test.beforeAll(() => {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
});
test.describe("/sama/skill is editable end-to-end", () => {
test("step 1: docs page renders with propose-an-edit link", async ({ page }) => {
const res = await page.goto("/sama/skill");
expect(res?.status()).toBe(200);
// Page identity — confirms we're on the SKILL.md viewer. The h1
// is the SAMA mnemonic "SAMA — Sorted, Architecture, Modeled,
// Atomic" emitted from the markdown body.
await expect(page.getByRole("heading", { name: /SAMA.*Sorted.*Architecture/i }).first()).toBeVisible();
// Edit link present and points at our self-hosted editor route
// (NOT git.tdd.md).
const editLink = page.locator('a[href="/edit/sama/skill"]', { hasText: /propose an edit/i });
await expect(editLink).toBeVisible();
// View-source goes to /content/sama/skill.md on the main domain.
const sourceLink = page.locator('a[href="/content/sama/skill.md"]', { hasText: /view source/i });
await expect(sourceLink).toBeVisible();
// Hard guarantee: zero links on this page point at the git.
// subdomain anymore.
expect(await page.locator('a[href*="git.tdd.md"]').count()).toBe(0);
await page.screenshot({
path: path.join(SCREENSHOT_DIR, "1-sama-skill-page-with-edit-link.png"),
fullPage: true,
});
});
test("step 2: /content/sama/skill.md serves raw markdown from tdd.md", async ({ request }) => {
const res = await request.get("/content/sama/skill.md");
expect(res.status()).toBe(200);
expect(res.headers()["content-type"]).toMatch(/text\/plain/);
const body = await res.text();
// SKILL.md frontmatter — confirms we got the actual file, not a
// 200-with-html-error-page.
expect(body).toMatch(/^---/m);
expect(body).toMatch(/name:\s*sama/i);
expect(body.length).toBeGreaterThan(500);
});
test("step 3: clicking 'propose an edit' lands on the editor login wall", async ({ page }) => {
await page.goto("/sama/skill");
const [navResponse] = await Promise.all([
page.waitForResponse((r) => r.url().endsWith("/edit/sama/skill")),
page.locator('a[href="/edit/sama/skill"]').first().click(),
]);
// 401 — login required. The page still renders content (login
// wall HTML), it's the status that signals the gate.
expect(navResponse.status()).toBe(401);
await expect(page).toHaveURL(/\/edit\/sama\/skill$/);
await expect(page.getByRole("heading", { name: /edit · SKILL/i })).toBeVisible();
// Sign-in button preserves return path so the user lands back on
// the editor after GitHub OAuth.
const signIn = page.getByRole("link", { name: /sign in with github/i });
await expect(signIn).toBeVisible();
const href = await signIn.getAttribute("href");
expect(href).toContain("/auth/github/start");
expect(href).toContain("to=%2Fedit%2Fsama%2Fskill");
await page.screenshot({
path: path.join(SCREENSHOT_DIR, "2-edit-sama-skill-login-wall.png"),
fullPage: true,
});
});
test("step 4: /edit/sama/skill is the same form regardless of entry path", async ({ page }) => {
// Direct hit on /edit/sama/skill — should render the same login
// wall (proves the route resolves; nav-only pages are now
// editable via the SITE_NAV fallback in c32_edit_resolve).
const res = await page.goto("/edit/sama/skill");
expect(res?.status(), "before this fix it 404'd because 'skill' isn't in ALL_SAMA").toBe(401);
await expect(page.getByRole("heading", { name: /edit · SKILL/i })).toBeVisible();
});
});
// Note: the admin-write happy-path test that used to live here was
// retired — it asserted on a git.tdd.md commit link that no longer
// exists (the applied-live page links to /GIT/... now), and the
// admin-edit-lands-in-bare-repo flow is fully covered by
// e2e/git-native-proof.spec.ts. Keeping a duplicate here would just
// double-edit the same path and fight optimistic concurrency.