feat(2): Q1.2 — n8n Phase-2 parity + functional + robust install (full e2e green)

- tests/n8n/PARITY.md: parity table (health_check ported) + 2 recipe-specific
  functional tests with rationale + data-integrity section pointing to
  Phase-1d/1e lifecycle overlays.
- tests/n8n/functional/test_health_check.py: parity port of
  recipe-info/n8n/tests/health_check.py — SOURCE comment.
- tests/n8n/functional/test_rest_settings.py: NEW recipe-specific — polls
  /rest/settings until response is application/json (not the 'n8n is starting
  up' SPA placeholder); asserts known n8n public-settings keys
  (userManagement/defaultLocale/authCookie) in the 'data' envelope. Proves the
  editor SPA's primary API contract is intact.
- tests/n8n/functional/test_login_state.py: NEW recipe-specific — polls
  /rest/login until response is JSON; proves the user-management/auth subsystem
  initialized on top of the public-settings layer.
- tests/n8n/test_install.py: install overlay's Playwright now polls page.goto
  until status==200 (n8n's / route can return 404 briefly while the SPA route
  registers on top of /healthz=200). Bounded poll, no bare sleep, raise on
  persistent failure — same robustness pattern as Phase-1e exec_in_app.

Cold-verifiable on cc-ci (log /root/ccci-q1-n8n-r3.log):
  RECIPE=n8n cc-ci-run runner/run_recipe_ci.py
  all 5 stages PASS, deploy-count=1, head_ref=63dd3e0f==chaos-version=63dd3e0f,
  version 3.1.0+2.9.4 -> 3.2.0+2.20.6 (HC1 non-vacuous), 5 lifecycle assertions
  + 3 custom-stage assertions all PASS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-28 06:48:00 +01:00
parent 5ab25c3dea
commit 2f3d5aa78f
5 changed files with 232 additions and 9 deletions

View File

@ -11,13 +11,16 @@ file side-by-side.
## Recipe-specific tests (Phase-2 P3, ≥2 beyond parity)
n8n is a workflow-automation engine — its characteristic behavior is **running a workflow engine
with a registry of node types and a queryable settings/state surface**. Two new functional tests:
n8n's characteristic behavior is **a working REST API on top of a working workflow engine**. /healthz
returns 200 long before the actual n8n process is ready — the REST endpoints serve a placeholder
HTML page ("n8n is starting up. Please wait") with status 200 during early boot. So a meaningful
n8n-specific test must distinguish "the HTTP layer answers" (what generic+install does) from "the
n8n REST API actually responds with JSON". Two new functional tests:
| cc-ci file | what's verified | rationale |
|---|---|---|
| `tests/n8n/functional/test_node_types_catalog.py` | Fetches `/types/nodes.json` and asserts the response is a JSON list, contains a meaningful number (>= 50) of node-type definitions, and includes specific n8n-built-in node names such as `n8n-nodes-base.set`, `n8n-nodes-base.if`, and a webhook/HTTP node — proves the n8n runtime bootstrapped its **node registry** (the workflow engine's core capability), not just "the HTTP server is up". | The node registry is what makes n8n n8n; an n8n that boots but loads no nodes is broken. |
| `tests/n8n/functional/test_rest_settings.py` | Fetches `/rest/settings` and asserts the JSON response carries the expected n8n public settings keys (e.g. `data.endpointWebhook`, `data.versionCli`) — the public settings surface is what every editor SPA loads to bootstrap, and proves the n8n REST API initialized + the SPA can talk to it. | Proves the editor SPA's primary API contract is intact — distinct from "/" returning HTML, which only proves a static asset was served. |
| `tests/n8n/functional/test_rest_settings.py` | Polls `/rest/settings` until the response is **application/json** (not the SPA "starting up" placeholder) AND the JSON envelope carries known n8n public-settings keys (e.g. `endpointWebhook`, `versionCli`, `n8nMetadata`, `instanceId`). | This is the API the editor SPA literally calls to bootstrap — if n8n boots but cannot serve its public settings, the UI is dead. Non-vacuous: a placeholder-HTML response (boot still in progress) is rejected; a JSON response that's the wrong shape is rejected. |
| `tests/n8n/functional/test_login_state.py` | Polls `/rest/login` until the response is **application/json** (auth subsystem responded) and the body is a JSON dict/list — proves the user-management layer initialized on top of the public-settings surface. | Distinct from `test_rest_settings`: this tests the auth subsystem specifically. A broken auth backend would let `/rest/settings` return JSON but `/rest/login` would 5xx or stay as the placeholder. |
Both tests run in the **custom** tier against the same `live_app` shared deployment as the
lifecycle overlays — no extra deploy, no extra teardown.