Part 07 · Production Readiness · 7.1.10

Testing, SSR, hydration và delivery

Test hành vi user và system boundary, render HTML sớm nhưng giữ server/client output deterministic, rồi phát hành bằng artifact có thể quan sát và rollback. Production correctness là một chuỗi, không phải riêng bước build.

Confidence model: unit test bảo vệ logic/invariant; component và route test bảo vệ integration; browser E2E bảo vệ critical flow; monitoring chứng minh hành vi trên môi trường và traffic thật.

1. Test behavior thay vì implementation

Query UI theo role, accessible name, label và visible text; tương tác bằng event gần hành vi user; assert output/status mà user quan sát. Tránh test state nội bộ, Hook call count hoặc CSS selector gắn với markup ngẫu nhiên. Mock network ở protocol boundary để component vẫn chạy data/cache/error logic thật.

LayerNên testVí dụ
UnitPure logic và invariantReducer transition, formatter, authorization predicate
Component integrationUser interaction + rendered resultForm validation, dialog focus, optimistic state
Route/dataLoader/action/cache/boundary404, unauthorized, retry, redirect
Browser E2ECritical cross-system flowLogin, checkout, deep link, reload
AccessibilityKeyboard/tree/screen readerName-role-state, focus order, live status

Test async bằng condition observable thay vì sleep cố định. Giữ fixture có ý nghĩa domain, reset server/store giữa tests và chỉ fake timer khi timer là phần contract. Coverage phần trăm không thay mutation/race/error cases.

2. Server rendering và streaming

SSR tạo HTML trên server để browser nhận content sớm; hydration sau đó gắn logic React vào markup. Node.js thường dùng renderToPipeableStream, Web Streams runtime dùng renderToReadableStream. Streaming có thể gửi shell trước rồi reveal Suspense boundary khi data/code sẵn sàng.

const { pipe, abort } = renderToPipeableStream(<App />, {
  bootstrapScripts: ['/assets/client.js'],
  onShellReady() {
    response.setHeader('content-type', 'text/html');
    pipe(response);
  },
  onShellError(error) {
    response.statusCode = 500;
    response.end('Unable to render');
  },
  onError(error) {
    reportError(error);
  }
});

Headers/status có thể đã gửi khi stream error muộn, nên shell error và recoverable boundary error cần policy riêng. Abort stream khi timeout/client disconnect; escape serialized data để không biến bootstrap payload thành XSS sink.

3. Hydration correctness

hydrateRoot yêu cầu client render ban đầu tạo cùng output với HTML server. Date/time zone, random ID, browser-only branch, data snapshot khác, invalid HTML nesting hoặc extension sửa DOM đều có thể gây mismatch. React coi mismatch là bug; patch behavior không được đảm bảo.

hydrateRoot(document.getElementById('root'), <App initialData={data} />, {
  onRecoverableError(error, errorInfo) {
    reportError(error, { componentStack: errorInfo.componentStack });
  }
});
Không lạm dụng suppressHydrationWarning. Nó chỉ dành cho chênh lệch không tránh được, phạm vi một level, và không sửa nondeterminism. Ưu tiên serialize snapshot giống nhau, useId cho ID stable và chuyển browser-only work sang Effect hoặc client boundary có chủ đích.

4. Server/client component boundaries

Framework quyết định semantics của Server Components, cache, routing và Server Functions. Code chạy server có thể đọc database/secret nhưng dữ liệu truyền sang client phải serializable và không nhạy cảm. Client boundary kéo module graph liên quan vào browser bundle, nên đặt tại vùng cần state, event hoặc browser API thay vì đánh dấu cả route.

5. Build, cache và security delivery

Phát hành production build với content-hashed assets, immutable cache cho hashed file và revalidation phù hợp cho HTML/data. Đảm bảo deep link rewrite đúng, route chunk tải được, CSP/header security hoạt động và source map không public ngoài chủ đích. Browser compatibility phải khớp targets/polyfill policy.

Deployment cần migration ordering, canary/feature flag khi rủi ro, health check và rollback artifact đã biết tốt. Service worker/CDN cache có thể giữ client cũ nói chuyện với server mới; API và asset strategy cần chịu được version skew.

6. Observability và release verification

Gắn release/version vào error, log và RUM; capture route, browser và correlation context nhưng redact PII/credential. Theo dõi error rate, Web Vitals và critical business success theo percentile/cohort. Alert cần actionable threshold, không chỉ volume thô.

Trước release, smoke test deep link, refresh, back/forward, slow/offline, expired session, API failure, CSP, source maps, accessibility và rollback. Sau release, so baseline theo version và rollback khi user impact vượt guardrail thay vì chờ mọi nguyên nhân được giải thích.

Review checklist: tests bám behavior; async/race/error có case; server HTML deterministic; hydration mismatch được report; server-only code không lọt bundle; cache/version skew có policy; release observable và rollback được.
Tài liệu: renderToPipeableStream · renderToReadableStream · hydrateRoot · useId API · Testing Library Guiding Principles · Web Vitals