ai

Radix UI Primitives Chaos Engineering — ทดสอบ UI

Radix UI Primitives Chaos Engineering — ทดสอบ UI

Radix UI Chaos Engineering

Radix UI Primitives Chaos Engineering — ทดสอบ UI

Radix UI Primitives Chaos Engineering React Error Boundary Resilience Retry Circuit Breaker Timeout Graceful Degradation Production

เนื้อหาเกี่ยวข้อง — ทำความเข้าใจ Prometheus Federation Database Migration

Chaos TypeScenarioExpected BehaviorTool
NetworkAPI Timeout 500 OfflineError Message Retry Cached DataMSW DevTools Throttle
DataEmpty Null Large MalformedEmpty State Fallback PaginationMSW Faker.js
StateRapid Click Race ConditionDebounce Lock Consistent StatePlaywright Cypress
ResourceMemory CPU Large DOMVirtualization Lazy Load CleanupChrome 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

Radix UI Primitives Chaos Engineering — ทดสอบ UI
# === 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

แนะนำเพิ่มเติม — iCafeForex

เนื้อหาเกี่ยวข้อง — บทความที่เกี่ยวข้อง: Elixir Phoenix LiveView Load Testing Strategy

เนื้อหาเกี่ยวข้อง — ทำความเข้าใจ LangChain Agent Site Reliability SRE —

XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง