Radix UI Chaos Engineering
Radix UI Primitives Chaos Engineering React Error Boundary Resilience Retry Circuit Breaker Timeout Graceful Degradation Production
| Chaos Type | Scenario | Expected Behavior | Tool |
|---|---|---|---|
| Network | API Timeout 500 Offline | Error Message Retry Cached Data | MSW DevTools Throttle |
| Data | Empty Null Large Malformed | Empty State Fallback Pagination | MSW Faker.js |
| State | Rapid Click Race Condition | Debounce Lock Consistent State | Playwright Cypress |
| Resource | Memory CPU Large DOM | Virtualization Lazy Load Cleanup | Chrome DevTools Lighthouse |
Error Boundary Setup
# === React Error Boundary with Radix UI ===
# // ErrorBoundary.tsx
# import { ErrorBoundary } from 'react-error-boundary';
# import * as Toast from '@radix-ui/react-toast';
#
# function ErrorFallback({ error, resetErrorBoundary }) {
# return (
# <div className="p-4 border border-red-500 rounded-lg">
# <h3 className="text-red-500 font-bold">Something went wrong</h3>
# <p className="text-sm text-gray-400">{error.message}</p>
# <button onClick={resetErrorBoundary}
# className="mt-2 px-4 py-2 bg-red-500 text-white rounded">
# Try Again
# </button>
# </div>
# );
# }
#
# // Granular Error Boundaries
# function Dashboard() {
# return (
# <div className="grid grid-cols-3 gap-4">
# <ErrorBoundary FallbackComponent={ErrorFallback}>
# <StatsWidget />
# </ErrorBoundary>
# <ErrorBoundary FallbackComponent={ErrorFallback}>
# <ChartWidget />
# </ErrorBoundary>
# <ErrorBoundary FallbackComponent={ErrorFallback}>
# <TableWidget />
# </ErrorBoundary>
# </div>
# );
# }
from dataclasses import dataclass
@dataclass
class ErrorBoundaryConfig:
scope: str
fallback: str
recovery: str
logging: str
boundaries = [
ErrorBoundaryConfig("App Level (Root)",
"Full Page Error + Reload Button",
"Window Reload หรือ Navigate Home",
"Sentry captureException + User Context"),
ErrorBoundaryConfig("Page Level",
"Page Error Message + Back Button",
"Navigate Back หรือ Retry Page Load",
"Sentry + Page Route + User Action"),
ErrorBoundaryConfig("Widget Level",
"Small Error Card + Retry Button",
"Reset Widget State + Refetch Data",
"Sentry + Widget Name + Props"),
ErrorBoundaryConfig("Dialog/Modal",
"Close Modal + Toast Error Message",
"Close Modal + Reset Form State",
"Sentry + Modal Name + Form Data"),
ErrorBoundaryConfig("Async Component (Suspense)",
"Loading Skeleton → Error Fallback",
"Retry Fetch + Show Stale Data",
"Sentry + API Endpoint + Response"),
]
print("=== Error Boundary Strategy ===")
for b in boundaries:
print(f" [{b.scope}]")
print(f" Fallback: {b.fallback}")
print(f" Recovery: {b.recovery}")
print(f" Logging: {b.logging}")
Chaos Testing
# === Chaos Test Scenarios ===
# // MSW (Mock Service Worker) for Network Chaos
# import { http, HttpResponse, delay } from 'msw';
#
# export const chaosHandlers = [
# // Timeout (10s delay)
# http.get('/api/stats', async () => {
# await delay(10000);
# return HttpResponse.json({ error: 'timeout' });
# }),
# // 500 Error
# http.get('/api/users', () => {
# return new HttpResponse(null, { status: 500 });
# }),
# // Empty Response
# http.get('/api/orders', () => {
# return HttpResponse.json({ data: [], total: 0 });
# }),
# // Malformed JSON
# http.get('/api/products', () => {
# return new HttpResponse('not json', {
# headers: { 'Content-Type': 'application/json' }
# });
# }),
# ];
@dataclass
class ChaosTest:
scenario: str
chaos_action: str
expected_ui: str
test_tool: str
tests = [
ChaosTest("API Timeout (10s)",
"MSW delay(10000) หรือ DevTools throttle",
"Loading Skeleton → Timeout Error → Retry Button",
"MSW + Playwright waitForTimeout"),
ChaosTest("API 500 Error",
"MSW return HttpResponse(null, {status: 500})",
"Error Boundary Fallback → Retry Button",
"MSW + Playwright expect(errorMsg).toBeVisible()"),
ChaosTest("Empty Data",
"MSW return {data: [], total: 0}",
"Empty State UI (No data found)",
"MSW + Playwright expect(emptyState).toBeVisible()"),
ChaosTest("Rapid Click (Double Submit)",
"Playwright click 10 times fast",
"Button disabled after first click ป้องกัน Double Submit",
"Playwright click({clickCount: 10})"),
ChaosTest("Network Offline",
"Playwright context.setOffline(true)",
"Offline Banner + Cached Data + Auto Retry เมื่อ Online",
"Playwright setOffline + waitForSelector"),
ChaosTest("Large Dataset (10K rows)",
"MSW return Array(10000).fill(row)",
"Virtual List/Pagination ไม่ Freeze ไม่ Memory Leak",
"Playwright + Chrome Performance Monitor"),
]
print("=== Chaos Test Scenarios ===")
for t in tests:
print(f" [{t.scenario}]")
print(f" Chaos: {t.chaos_action}")
print(f" Expected: {t.expected_ui}")
print(f" Tool: {t.test_tool}")
Resilience Patterns
# === UI Resilience Patterns ===
@dataclass
class ResiliencePattern:
pattern: str
implementation: str
radix_component: str
benefit: str
patterns = [
ResiliencePattern("Retry with Backoff",
"TanStack Query retry: 3 retryDelay: exponential",
"Toast แสดง Retrying... + Progress",
"Auto-recover จาก Transient Failure"),
ResiliencePattern("Circuit Breaker",
"Custom Hook ถ้า fail 5 ครั้ง หยุด 30s",
"Alert Dialog แจ้ง Service Unavailable",
"ป้องกัน Server Overload"),
ResiliencePattern("Timeout + AbortController",
"AbortController signal timeout 10s",
"Toast แจ้ง Request Timeout + Retry",
"ไม่ค้าง Loading ตลอดกาล"),
ResiliencePattern("Optimistic Update",
"TanStack Query mutate onMutate optimistic",
"Checkbox/Toggle Update ทันที Rollback ถ้า Fail",
"UX เร็ว ลด Perceived Latency"),
ResiliencePattern("Graceful Degradation",
"Feature Flag + Error Boundary per Widget",
"Widget Error แสดง Fallback ส่วนอื่นทำงานต่อ",
"App ไม่ Crash ทั้งหมดจาก Widget เดียว"),
ResiliencePattern("Stale-while-revalidate",
"TanStack Query staleTime + Cache",
"แสดง Cached Data ทันที Background Refetch",
"User เห็นข้อมูลทันที ไม่ต้องรอ"),
]
print("=== Resilience Patterns ===")
for p in patterns:
print(f" [{p.pattern}]")
print(f" Impl: {p.implementation}")
print(f" Radix: {p.radix_component}")
print(f" Benefit: {p.benefit}")
เคล็ดลับ
- Error Boundary: วาง Granular Error Boundary รอบทุก Widget
- MSW: ใช้ MSW Mock Network Chaos ใน Development
- TanStack Query: ใช้ retry + staleTime + errorBoundary option
- Toast: ใช้ Radix Toast แสดง Error/Retry Notification
- Playwright: เขียน Chaos Test ใน E2E ทดสอบ Resilience
Radix UI คืออะไร
Open Source Unstyled Accessible React Primitives WAI-ARIA Keyboard Focus Composable Dialog Dropdown Popover Tooltip shadcn/ui Base
Chaos Engineering สำหรับ UI คืออะไร
จงใจทำให้ Error Network Timeout 500 Empty Data Rapid Click Offline Large Dataset Memory CPU Resource Test Resilience
Error Boundary ตั้งอย่างไร
react-error-boundary Granular App Page Widget Dialog Fallback Recovery Retry Reset Sentry Logging componentDidCatch Suspense
Resilience Pattern มีอะไร
Retry Backoff Circuit Breaker Timeout AbortController Optimistic Graceful Degradation Stale-while-revalidate TanStack Query Cache
สรุป
Radix UI Primitives Chaos Engineering Error Boundary MSW Resilience Retry Circuit Breaker Timeout Optimistic Graceful TanStack Production
