Files
lcbp3/frontend/components/common/__tests__/error-display.test.tsx
T
admin 7e8f4859cd
CI / CD Pipeline / build (push) Failing after 6m24s
CI / CD Pipeline / deploy (push) Has been skipped
feat(ai): add ADR-036 unified OCR architecture and frontend test coverage
- Add ADR-036 unified OCR architecture (typhoon-ocr via Ollama)
- Extend AI execution profiles for OCR sandbox configuration
- Add comprehensive frontend test coverage (components, hooks, services)
- Add backend test coverage for document-numbering services
- Update OCR sidecar with typhoon-ocr integration
- Add AI policy service and execution profile management
- Update AGENTS.md and architecture documentation
2026-06-14 06:34:07 +07:00

140 lines
5.6 KiB
TypeScript

// File: frontend/components/common/__tests__/error-display.test.tsx
// Change Log:
// - 2026-06-13: Initial creation - test coverage for ErrorDisplay component and parseApiError helper
// - 2026-06-13: Refactor to remove blank lines inside functions to satisfy project guidelines
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { ErrorDisplay, parseApiError } from '../error-display';
describe('ErrorDisplay Component', () => {
beforeEach(() => {
vi.stubGlobal('window', {
open: vi.fn(),
});
});
it('ควรส่งกลับ null เมื่อไม่มี error หรือ payload', () => {
const { container } = render(<ErrorDisplay error={null} />);
expect(container.firstChild).toBeNull();
});
it('ควรเรนเดอร์ในโหมด compact สำเร็จ', () => {
const errorPayload = {
type: 'VALIDATION_ERROR',
code: 'ERR_VAL',
message: 'Validation failed',
severity: 'LOW' as const,
timestamp: new Date().toISOString(),
};
render(<ErrorDisplay error={errorPayload} compact={true} />);
expect(screen.getByText('Validation failed')).toBeInTheDocument();
});
it('ควรเรนเดอร์ในโหมดปกติพร้อม Recovery Actions สำเร็จ', () => {
const errorResponse = {
error: {
type: 'SYSTEM_ERROR',
code: 'ERR_SYS',
message: 'System crashed',
severity: 'CRITICAL' as const,
timestamp: new Date().toISOString(),
recoveryActions: ['Restart app', 'Clear cache'],
},
};
render(<ErrorDisplay error={errorResponse} compact={false} />);
expect(screen.getByText('System crashed')).toBeInTheDocument();
expect(screen.getByText('วิธีแก้ไข:')).toBeInTheDocument();
expect(screen.getByText('Restart app')).toBeInTheDocument();
expect(screen.getByText('Clear cache')).toBeInTheDocument();
});
it('ควรเรนเดอร์รายละเอียดทางเทคนิคเมื่อรันในสภาพแวดล้อม development', () => {
const originalEnv = process.env.NODE_ENV;
process.env.NODE_ENV = 'development';
const errorPayload = {
type: 'DATABASE_ERROR',
code: 'ERR_DB',
message: 'DB connection lost',
severity: 'HIGH' as const,
timestamp: new Date().toISOString(),
technicalMessage: 'Failed to connect to host postgres://localhost:5432',
};
render(<ErrorDisplay error={errorPayload} />);
expect(screen.getByText('รายละเอียดทางเทคนิค (Development)')).toBeInTheDocument();
expect(screen.getByText('Failed to connect to host postgres://localhost:5432')).toBeInTheDocument();
process.env.NODE_ENV = originalEnv;
});
it('ควรเรียก onRetry เมื่อคลิกปุ่มลองใหม่', () => {
const mockOnRetry = vi.fn();
const errorPayload = {
type: 'API_ERROR',
code: 'ERR_API',
message: 'API failed',
severity: 'MEDIUM' as const,
timestamp: new Date().toISOString(),
};
render(<ErrorDisplay error={errorPayload} onRetry={mockOnRetry} />);
const retryBtn = screen.getByText('ลองใหม่');
fireEvent.click(retryBtn);
expect(mockOnRetry).toHaveBeenCalled();
});
it('ควรเปิดเมลเมื่อคลิกปุ่มติดต่อผู้ดูแลระบบ', () => {
const errorPayload = {
type: 'API_ERROR',
code: 'ERR_API',
message: 'API failed',
severity: 'MEDIUM' as const,
timestamp: new Date().toISOString(),
};
render(<ErrorDisplay error={errorPayload} />);
const supportBtn = screen.getByText('ติดต่อผู้ดูแลระบบ');
fireEvent.click(supportBtn);
expect(window.open).toHaveBeenCalledWith('mailto:support@np-dms.work', '_blank');
});
});
describe('parseApiError helper', () => {
it('ควรจัดการข้อผิดพลาดจากโครงสร้าง Axios Error ได้อย่างถูกต้อง', () => {
const mockAxiosError = {
response: {
data: {
error: {
type: 'API_ERROR',
code: 'ERR_CODE',
message: 'Mock Axios Error',
severity: 'MEDIUM' as const,
timestamp: '2026-06-13T00:00:00.000Z',
},
},
},
};
const parsed = parseApiError(mockAxiosError);
expect(parsed.error.message).toBe('Mock Axios Error');
expect(parsed.error.code).toBe('ERR_CODE');
});
it('ควรคืนค่าเดิมถ้าเป็นโครงสร้าง ApiErrorResponse อยู่แล้ว', () => {
const mockResponse = {
error: {
type: 'CUSTOM_ERROR',
code: 'ERR_CUSTOM',
message: 'Mock Custom Error',
severity: 'LOW' as const,
timestamp: '2026-06-13T00:00:00.000Z',
},
};
const parsed = parseApiError(mockResponse);
expect(parsed).toEqual(mockResponse);
});
it('ควรส่งกลับ Internal/Network error เมื่อมีข้อผิดพลาดที่ไม่รู้จัก', () => {
const parsed = parseApiError('Random Error String');
expect(parsed.error.type).toBe('INTERNAL_ERROR');
expect(parsed.error.code).toBe('NETWORK_ERROR');
expect(parsed.error.message).toBe('ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้');
});
});