End-to-end: harness Playwright suite green (14 pass, 1 skip)

After the React-codegen rework, ran the full e2e harness against the
docker-stack backend. Surfaced and fixed real friction:

mizan-base/src/index.ts (kernel):
- MizanError now parses both error envelopes — the FastAPI shape
  ({"error": {"code", "message", "details"}}) and the Django shape
  ({"error": true, "code", "message", "details"}). Exposes .code and
  .details on the thrown error so consumer code can branch on them.
  This was needed for the harness's `instanceof MizanError && error.code
  === 'NOT_FOUND'` pattern to work; the previous MizanError only carried
  status + raw body, leaving callers to parse the body themselves.

examples/django-react-site/Dockerfile.test:
- Backend image now copies and installs cores/mizan-python before
  installing mizan-django (which imports from mizan_core after the
  Layer 1 extraction).

harness/src/fixtures.tsx:
- useRun helper updated for the new mutation-hook shape: pulls
  { mutate } off the hook result instead of treating the hook return
  as a callable. Same for ValidationError fixture.

mizan.spec.ts:
- DjangoError → MizanError (kernel error class is backend-agnostic).
- Form tests removed (forms codegen deferred per Blazr scope).
- Channel test marked test.skip (channels deferred per Blazr scope).

.gitignore: ignore Playwright test-results/.

Final verification across all surfaces:
- mizan-core unit:       15/15
- mizan-django unit:     348 pass, 21 skip
- mizan-fastapi unit:    11/11
- mizan-ts edge-compat:  34/34 (cross-language HMAC pin)
- harness e2e (Playwright): 14/15 (1 skip = channels deferred)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-06 17:38:52 -04:00
parent 2982741aad
commit aaaf80cdbf
5 changed files with 39 additions and 45 deletions

View File

@@ -9,8 +9,24 @@
// === Error ===
export class MizanError extends Error {
public code: string
public details?: unknown
constructor(public status: number, public body: string) {
super(`Mizan call failed (${status})`)
// Two envelope shapes are tolerated:
// FastAPI: {"error": {"code", "message", "details"}}
// Django: {"error": true, "code", "message", "details"}
try {
const parsed = JSON.parse(body)
const err = parsed?.error
const source = typeof err === 'object' && err !== null ? err : parsed
this.code = source?.code ?? `HTTP_${status}`
this.details = source?.details
if (source?.message) this.message = source.message
} catch {
this.code = `HTTP_${status}`
}
}
}