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

@@ -87,13 +87,13 @@ function Result({ data, error }: { data?: unknown; error?: unknown }) {
// ─── Hook runner: calls a generated hook and renders result ─────────────────
function useRun<T>(hook: () => (input?: any) => Promise<T>, input?: any) {
const call = hook()
function useRun<T>(hook: () => { mutate: (input?: any) => Promise<T> }, input?: any) {
const { mutate } = hook()
const [data, setData] = useState<T>()
const [error, setError] = useState<unknown>()
useEffect(() => {
call(input).then(setData).catch(setError)
mutate(input).then(setData).catch(setError)
}, []) // eslint-disable-line react-hooks/exhaustive-deps
return { data, error }
@@ -126,9 +126,9 @@ function NotFound() {
function ValidationError() {
// Send wrong types to add (strings instead of numbers)
const call = useAdd()
const { mutate } = useAdd()
const [error, setError] = useState<unknown>()
useEffect(() => { (call as any)({ a: 'not_a_number', b: 'also_not' }).catch(setError) }, [call])
useEffect(() => { (mutate as any)({ a: 'not_a_number', b: 'also_not' }).catch(setError) }, [mutate])
return <Result error={error} />
}