syntaxai/tdd.md · main · e2e / sama-skill-editable.spec.ts

sama-skill-editable.spec.ts 112 lines · 5000 bytes raw
// 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.