syntaxai/tdd.md · main · e2e / admin-block-editor.spec.ts

admin-block-editor.spec.ts 63 lines · 2707 bytes raw
// E2E: Fase 2b block-editor surface. This is the SAMA-ported CMS UI at
// /admin/edit/:type/:slug — distinct from the legacy textarea editor at
// /edit/:section/:slug. The legacy editor is covered by
// git-native-proof.spec; this file proves the new block-editor
// infrastructure is alive on live:
//
//   1. /admin is auth-gated (anonymous → 401)
//   2. /admin/assets/blockeditor.js bundles + serves the client TS as
//      JavaScript with an ETag (and 304s on re-request)
//   3. With the admin storage state, /admin renders the list page
//      (no 401, contains the "+ New" button or admin chrome)
//
// We deliberately do NOT exercise create/edit/save here — those
// roundtrip sxdoc → SQLite → commit and need fixtures + cleanup.
// git-native-proof.spec already proves the commit-pipeline shape via
// the legacy editor; what this file proves is that the *new* surface
// also exists, is gated correctly, and ships its bundle.

import { test, expect } from "@playwright/test";
import * as fs from "fs";

const ADMIN_AUTH_FILE = ".auth/admin.json";

test.describe("admin block-editor infrastructure", () => {
  test("anonymous /admin is 401 (auth-gate intact)", async ({ request }) => {
    const res = await request.get("/admin", { failOnStatusCode: false });
    expect(res.status()).toBe(401);
  });

  test("blockeditor bundle serves with ETag + 304 on re-request", async ({ request }) => {
    const first = await request.get("/admin/assets/blockeditor.js");
    expect(first.status()).toBe(200);
    expect(first.headers()["content-type"]).toMatch(/javascript/);
    const body = await first.text();
    // It's an ES-module bundle compiled from src/client/blockeditor.ts +
    // src/client/blocks.ts + src/client/slashmenu.ts — the slash-menu
    // ID is a stable marker that survives minification.
    expect(body.length).toBeGreaterThan(2000);

    const etag = first.headers()["etag"];
    expect(etag).toBeTruthy();

    const second = await request.get("/admin/assets/blockeditor.js", {
      headers: { "If-None-Match": etag! },
    });
    expect(second.status()).toBe(304);
  });
});

test.describe("admin block-editor (authenticated)", () => {
  test.skip(!fs.existsSync(ADMIN_AUTH_FILE), `no ${ADMIN_AUTH_FILE} found`);
  test.use({ storageState: ADMIN_AUTH_FILE });

  test("authenticated /admin renders the list page", async ({ page }) => {
    const res = await page.goto("/admin");
    expect(res?.status()).toBe(200);
    // The list page links to /admin/new — that anchor is the canonical
    // marker that the block-editor surface (not the legacy editor) is
    // serving this request.
    await expect(page.locator('a[href="/admin/new"]')).toBeVisible();
  });
});