test(frontend): raise overall statement coverage to 30.42% for Phase 1 MVP

This commit is contained in:
2026-06-13 22:33:11 +07:00
parent 190b9a3af5
commit 9c5df0abdb
37 changed files with 6128 additions and 24 deletions
@@ -0,0 +1,148 @@
// File: frontend/lib/services/__tests__/dashboard.service.test.ts
// Change Log:
// - 2026-06-13: Initial creation - unit tests for dashboardService
import { describe, it, expect, vi, beforeEach } from 'vitest';
import apiClient from '@/lib/api/client';
import { dashboardService } from '../dashboard.service';
// Mock apiClient
vi.mock('@/lib/api/client', () => ({
default: {
get: vi.fn(),
},
}));
describe('dashboardService', () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe('getStats', () => {
it('ควรดึงข้อมูลสถิติของแดชบอร์ดสำเร็จ', async () => {
const mockResponse = { data: { totalDocuments: 100, pendingApprovals: 5 } };
vi.mocked(apiClient.get).mockResolvedValue(mockResponse);
const result = await dashboardService.getStats('uuid-proj-1');
expect(apiClient.get).toHaveBeenCalledWith('/dashboard/stats', { params: { projectId: 'uuid-proj-1' } });
expect(result).toEqual(mockResponse.data);
});
it('ควรดึงข้อมูลสถิติโดยไม่ต้องส่ง projectId', async () => {
const mockResponse = { data: { totalDocuments: 200 } };
vi.mocked(apiClient.get).mockResolvedValue(mockResponse);
const result = await dashboardService.getStats();
expect(apiClient.get).toHaveBeenCalledWith('/dashboard/stats', { params: undefined });
expect(result).toEqual(mockResponse.data);
});
});
describe('getRecentActivity', () => {
it('ควรดึงประวัติการเคลื่อนไหวล่าสุดและจัดรูปแบบให้ถูกต้อง', async () => {
const mockResponse = {
data: [
{
id: 'act-1',
action: 'CREATE',
entityType: 'RFA',
entityId: 'uuid-rfa',
details: { description: 'สร้างเอกสาร RFA ใหม่' },
createdAt: '2026-01-01T00:00:00Z',
user: { firstName: 'สมชาย', lastName: 'รักดี', username: 'somchai' },
},
{
id: 'act-2',
action: 'UPDATE',
entityType: 'Transmittal',
entityId: 'uuid-trans',
createdAt: '2026-01-01T00:00:00Z',
user: { username: 'testuser' },
},
{
id: 'act-3',
action: 'DELETE',
createdAt: '2026-01-01T00:00:00Z',
},
],
};
vi.mocked(apiClient.get).mockResolvedValue(mockResponse);
const result = await dashboardService.getRecentActivity('uuid-proj-1');
expect(result).toHaveLength(3);
expect(result[0].user.name).toBe('สมชาย รักดี');
expect(result[0].user.initials).toBe('สร');
expect(result[0].description).toBe('สร้างเอกสาร RFA ใหม่');
expect(result[0].targetUrl).toBe('/rfas/uuid-rfa');
expect(result[1].user.name).toBe('testuser');
expect(result[1].user.initials).toBe('T');
expect(result[1].description).toBe('UPDATE Transmittal uuid-trans');
expect(result[1].targetUrl).toBe('/transmittals/uuid-trans');
expect(result[2].user.name).toBe('System');
expect(result[2].user.initials).toBe('S');
expect(result[2].targetUrl).toBe('/correspondences/');
});
it('ควรคืนค่าเป็นอาเรย์ว่างเมื่อเกิดข้อผิดพลาดจาก API', async () => {
vi.mocked(apiClient.get).mockRejectedValue(new Error('API Failure'));
const result = await dashboardService.getRecentActivity();
expect(result).toEqual([]);
});
it('ควรคืนค่าเป็นอาเรย์ว่างเมื่อข้อมูลไม่ใช้รูปแบบอาเรย์', async () => {
vi.mocked(apiClient.get).mockResolvedValue({ data: { message: 'Not an array' } });
const result = await dashboardService.getRecentActivity();
expect(result).toEqual([]);
});
});
describe('getPendingTasks', () => {
it('ควรดึงข้อมูลงานที่ค้างและคำนวณจำนวนวันล่วงเลยกับความสำคัญ', async () => {
const now = new Date();
const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
const fourDaysAgo = new Date(now.getTime() - 4 * 24 * 60 * 60 * 1000);
const mockResponse = {
data: {
data: [
{
instanceId: 'inst-1',
workflowCode: 'WF-RFA',
currentState: 'REVIEWING',
entityType: 'RFA',
entityId: 'uuid-rfa-1',
documentNumber: 'RFA-001',
subject: 'งานด่วนพิเศษ',
assignedAt: oneDayAgo.toISOString(),
},
{
instanceId: 'inst-2',
workflowCode: 'WF-TR',
currentState: 'APPROVED',
entityType: 'Transmittal',
entityId: 'uuid-tr-1',
documentNumber: 'TR-001',
subject: '',
assignedAt: fourDaysAgo.toISOString(),
},
],
},
};
vi.mocked(apiClient.get).mockResolvedValue(mockResponse);
const result = await dashboardService.getPendingTasks('uuid-proj-1');
expect(result).toHaveLength(2);
expect(result[0].publicId).toBe('inst-1');
expect(result[0].title).toBe('งานด่วนพิเศษ');
expect(result[0].daysOverdue).toBe(1);
expect(result[0].priority).toBe('MEDIUM');
expect(result[0].url).toBe('/rfas/uuid-rfa-1');
expect(result[1].publicId).toBe('inst-2');
expect(result[1].title).toBe('TR-001');
expect(result[1].daysOverdue).toBe(4);
expect(result[1].priority).toBe('HIGH');
expect(result[1].url).toBe('/transmittals/uuid-tr-1');
});
it('ควรคืนค่าเป็นอาเรย์ว่างเมื่อเกิดข้อผิดพลาดจาก API', async () => {
vi.mocked(apiClient.get).mockRejectedValue(new Error('API Failure'));
const result = await dashboardService.getPendingTasks();
expect(result).toEqual([]);
});
});
});