Teraz z AI - twórz strony przez serwer MCP

Testowanie aplikacji cmssy

Edytor to ścieżka, której Twój build nie sprawdzi. Jeden smoke test ją pokrywa.

Serwis z martwym edytorem dalej się kompiluje, dalej się serwuje i dalej przechodzi Twoje testy jednostkowe. Nic w zwykłym buildzie nie dotyka ścieżki edycji, więc nic w zwykłym buildzie nie powie Ci, że się zepsuła.

checkCmssyEditMode to test, który to robi.

Smoke test

import { checkCmssyEditMode } from "@cmssy/next/testing";

const result = await checkCmssyEditMode({
  baseUrl: "http://localhost:3000",
  secret: process.env.CMSSY_DRAFT_SECRET!,
  path: "/",
  // Tylko jeśli Twoje URL-e niosą język. Test czyta <html lang> - kontrakt -
  // zamiast szukać słowa z Twojej treści, które redaktor może zmienić
  // w dowolnej chwili.
  localizedPath: "/pl",
});

expect(result.failures).toEqual([]);

Uruchamiaj go przeciwko wystartowanemu buildowi produkcyjnemu (next build && next start), nie przeciwko dev serverowi. To właśnie statyczne renderowanie sprawiło, że route edycyjny w ogóle był potrzebny, więc dev server testuje niewłaściwą aplikację.

Jest jeszcze jedna opcja, dla serwisów, w których prefiks URL to nie kod locale. localizedLocale nazywa język, który ma wyrenderować localizedPath; domyślnie bierze pierwszy segment ścieżki, który na serwisie z prefiksami jest językiem. Ustaw go jawnie, gdy prefiks i locale się różnią - na przykład /en-gb serwujące locale en - bo inaczej test porówna z językiem, który nie istnieje, i padnie z niewłaściwego powodu.

Co sprawdza

  1. Publiczna strona zwraca 200 bez edytora, z headerem i footerem wyrenderowanymi na serwerze.
  2. Samo ?cmssyEdit=1 bez sekretu nie wchodzi w tryb edycji. Niezweryfikowane żądanie nigdy nie może otworzyć drzwi.
  3. Zweryfikowane cmssyEdit=1 plus cmssySecret renderuje edytor i przenosi header oraz footer na most edycyjny.
  4. Opcjonalnie: zlokalizowany podgląd deklaruje język, o który prosi jego URL, przez <html lang>.

Dlaczego "brak headera w SSR" oznacza sukces

To asercja, która czyta się na opak, dopóki nie zobaczysz dlaczego.

W trybie edycji header i footer montują się przez most edycyjny, który renderuje się na kliencie. Więc header wciąż obecny w HTML-u z serwera to header, który edytor może zaznaczyć, ale nie może edytować - różnica między edytowalnym blokiem a zwykłym markupem.

Gdy test pada, komunikat nazywa przyczynę, nie objaw:

edit /shop: the header and footer are still server-rendered - they will be
selectable but have no fields (is CMSSY_EDIT_HEADER set on the rewrite?)

W CI

- run: pnpm build
- run: |
    pnpm start &
    npx wait-on http://localhost:3000 --timeout 60000
- run: pnpm smoke:edit

Pomijaj ten job, gdy nie ma sekretów workspace'u. Zielony check, który niczego nie weryfikuje, jest gorszy niż brak checka - zamienia niewiadomą w fałszywe poczucie bezpieczeństwa.

Podpięcie jako skrypt

Aplikacja referencyjna trzyma go jako samodzielny skrypt, a nie case w test runnerze, żeby działał w CI bez frameworka:

{
  "scripts": {
    "smoke:edit": "node smoke-edit.mjs"
  }
}
// smoke-edit.mjs
import { checkCmssyEditMode } from "@cmssy/next/testing";

const result = await checkCmssyEditMode({
  baseUrl: "http://localhost:3000",
  secret: process.env.CMSSY_DRAFT_SECRET,
  localizedPath: "/pl",
});

console.log(result.ok ? "EDITOR OK" : "EDITOR BROKEN");
for (const f of result.failures) console.log("  -", f);
process.exit(result.ok ? 0 : 1);

Co jeszcze warto testować

Bloki to zwykłe komponenty React, więc testuj je zwyczajnie. Dwa nawyki specyficzne dla cmssy warto zachować:

  • Wyrenderuj każdy blok z data: undefined - dokładnie to przekazuje edytor, a blok, który rzuca wyjątkiem bez wyniku loadera, to blok psujący edytor.
  • Wyrenderuj z brakującym locale - treść może jeszcze nie być przetłumaczona, a ścieżka fallbacku to pierwsza, na którą trafią odwiedzający w nowym języku.

Następne kroki