Ahora con creación de páginas por IA vía el servidor MCP

Probar una app de cmssy

El editor es el camino que tu build no puede comprobar. Una sola prueba de humo lo cubre.

Un sitio con el editor muerto sigue compilando, sigue sirviéndose y sigue pasando tus pruebas unitarias. Nada en un build normal toca la ruta de edición, así que nada en un build normal te avisa cuando se rompe.

checkCmssyEditMode es la comprobación que sí lo hace.

La prueba de humo

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

const result = await checkCmssyEditMode({
  baseUrl: "http://localhost:3000",
  secret: process.env.CMSSY_DRAFT_SECRET!,
  path: "/",
  // Solo si tus URL llevan el idioma. La comprobación lee <html lang> - un
  // contrato - en vez de buscar una palabra de tu copia, que un editor puede
  // reescribir en cualquier momento.
  localizedPath: "/es",
});

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

Ejecútala contra un build de producción ya arrancado (next build && next start), no contra el servidor de desarrollo. Precisamente el renderizado estático fue lo que hizo necesaria la ruta de edición, así que el servidor de desarrollo prueba la app equivocada.

Existe una opción más para sitios cuyo prefijo de URL no es el código de locale. localizedLocale nombra el idioma que debe renderizar localizedPath; por defecto toma el primer segmento de la ruta, que en un sitio con prefijos es el idioma. Fíjalo explícitamente cuando prefijo y locale difieran -por ejemplo /en-gb sirviendo el locale en-, o la comprobación contrastará con un idioma que no existe y fallará por el motivo equivocado.

Qué asegura

  1. La página pública devuelve 200 sin el editor, con cabecera y pie renderizados en servidor.
  2. Un ?cmssyEdit=1 pelado sin secreto no entra en modo edición. Una petición no verificada nunca debe abrir la puerta.
  3. Un cmssyEdit=1 verificado más cmssySecret renderiza el editor y mueve cabecera y pie al puente de edición.
  4. Opcionalmente: la vista previa localizada declara el idioma que pide su URL, vía <html lang>.

Por qué "sin cabecera en el SSR" significa éxito

Esta afirmación se lee al revés hasta que ves el motivo.

En modo edición, cabecera y pie se montan a través del puente de edición, que renderiza en el cliente. Así que una cabecera todavía presente en el HTML de servidor es una cabecera que el editor puede seleccionar pero no editar: la diferencia entre un bloque editable y simple marcado.

Cuando falla, el mensaje nombra la causa en lugar del síntoma:

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?)

En CI

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

Sáltate el job cuando falten los secretos del workspace. Un check verde que no verifica nada es peor que no tener check: convierte una incógnita en una falsa seguridad.

Conectarlo como script

La app de referencia lo mantiene como script independiente en vez de como caso de test runner, para que corra en CI sin framework:

{
  "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: "/es",
});

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

Qué más probar

Los bloques son componentes de React corrientes, así que pruébalos de forma corriente. Merece la pena mantener dos hábitos propios de cmssy:

  • Renderiza cada bloque con data: undefined: es lo que pasa el editor, y un bloque que lanza sin el resultado de su loader es un bloque que rompe el editor.
  • Renderiza con un locale ausente: puede que el contenido no esté traducido aún, y la ruta de fallback es la primera con la que se toparán tus visitantes en un idioma nuevo.

Siguientes pasos