diff --git a/frontend/lib/services/__tests__/asbuilt-drawing.service.test.ts b/frontend/lib/services/__tests__/asbuilt-drawing.service.test.ts new file mode 100644 index 00000000..090b0897 --- /dev/null +++ b/frontend/lib/services/__tests__/asbuilt-drawing.service.test.ts @@ -0,0 +1,58 @@ +// File: frontend/lib/services/__tests__/asbuilt-drawing.service.test.ts +// Change Log: +// - 2026-06-13: Initial creation - test coverage for asbuilt-drawing service + +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { asBuiltDrawingService } from '../asbuilt-drawing.service'; +import apiClient from '@/lib/api/client'; + +// Mock apiClient +vi.mock('@/lib/api/client', () => ({ + default: { + get: vi.fn(), + post: vi.fn(), + }, +})); + +describe('asBuiltDrawingService', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('ควรดึงข้อมูลรายการ as built drawings สำเร็จ', async () => { + const mockParams = { search: 'AD-01' }; + const mockResponse = { data: [{ publicId: '019505a1-7c3e-7000-8000-ad1111111111', drawingNo: 'AD-001' }] }; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await asBuiltDrawingService.getAll(mockParams); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith('/drawings/asbuilt', { params: mockParams }); + }); + + it('ควรดึงรายละเอียดของ as built drawing สำเร็จ', async () => { + const uuid = '019505a1-7c3e-7000-8000-ad1111111111'; + const mockResponse = { data: { publicId: uuid, drawingNo: 'AD-001' } }; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await asBuiltDrawingService.getByUuid(uuid); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith(`/drawings/asbuilt/${uuid}`); + }); + + it('ควรสร้าง as built drawing สำเร็จ', async () => { + const mockDto = { drawingNo: 'AD-001', subject: 'Test As Built Drawing' }; + const mockResponse = { data: { publicId: '019505a1-7c3e-7000-8000-ad1111111111' } }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await asBuiltDrawingService.create(mockDto as any); + expect(result).toEqual(mockResponse); + expect(apiClient.post).toHaveBeenCalledWith('/drawings/asbuilt', mockDto); + }); + + it('ควรสร้าง revision ใหม่ของ as built drawing สำเร็จ', async () => { + const uuid = '019505a1-7c3e-7000-8000-ad1111111111'; + const mockDto = { revisionNo: 'A', comment: 'New Revision' }; + const mockResponse = { data: { success: true } }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await asBuiltDrawingService.createRevision(uuid, mockDto as any); + expect(result).toEqual(mockResponse); + expect(apiClient.post).toHaveBeenCalledWith(`/drawings/asbuilt/${uuid}/revisions`, mockDto); + }); +}); diff --git a/frontend/lib/services/__tests__/contract-drawing.service.test.ts b/frontend/lib/services/__tests__/contract-drawing.service.test.ts new file mode 100644 index 00000000..c10c4fa7 --- /dev/null +++ b/frontend/lib/services/__tests__/contract-drawing.service.test.ts @@ -0,0 +1,69 @@ +// File: frontend/lib/services/__tests__/contract-drawing.service.test.ts +// Change Log: +// - 2026-06-13: Initial creation - test coverage for contract-drawing service + +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { contractDrawingService } from '../contract-drawing.service'; +import apiClient from '@/lib/api/client'; + +// Mock apiClient +vi.mock('@/lib/api/client', () => ({ + default: { + get: vi.fn(), + post: vi.fn(), + put: vi.fn(), + delete: vi.fn(), + }, +})); + +describe('contractDrawingService', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('ควรดึงข้อมูลรายการ contract drawings สำเร็จ', async () => { + const mockParams = { search: 'CD-01' }; + const mockResponse = { data: [{ publicId: '019505a1-7c3e-7000-8000-cd1111111111', drawingNo: 'CD-001' }] }; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await contractDrawingService.getAll(mockParams); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith('/drawings/contract', { params: mockParams }); + }); + + it('ควรดึงรายละเอียดของ contract drawing สำเร็จ', async () => { + const uuid = '019505a1-7c3e-7000-8000-cd1111111111'; + const mockResponse = { data: { publicId: uuid, drawingNo: 'CD-001' } }; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await contractDrawingService.getByUuid(uuid); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith(`/drawings/contract/${uuid}`); + }); + + it('ควรสร้าง contract drawing สำเร็จ', async () => { + const mockDto = { drawingNo: 'CD-001', subject: 'Test Contract Drawing' }; + const mockResponse = { data: { publicId: '019505a1-7c3e-7000-8000-cd1111111111' } }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await contractDrawingService.create(mockDto as any); + expect(result).toEqual(mockResponse); + expect(apiClient.post).toHaveBeenCalledWith('/drawings/contract', mockDto); + }); + + it('ควรปรับปรุงข้อมูล contract drawing สำเร็จ', async () => { + const uuid = '019505a1-7c3e-7000-8000-cd1111111111'; + const mockDto = { subject: 'Updated Contract Drawing' }; + const mockResponse = { data: { success: true } }; + vi.mocked(apiClient.put).mockResolvedValue({ data: mockResponse }); + const result = await contractDrawingService.update(uuid, mockDto as any); + expect(result).toEqual(mockResponse); + expect(apiClient.put).toHaveBeenCalledWith(`/drawings/contract/${uuid}`, mockDto); + }); + + it('ควรลบ contract drawing สำเร็จ', async () => { + const uuid = '019505a1-7c3e-7000-8000-cd1111111111'; + const mockResponse = { data: { success: true } }; + vi.mocked(apiClient.delete).mockResolvedValue({ data: mockResponse }); + const result = await contractDrawingService.delete(uuid); + expect(result).toEqual(mockResponse); + expect(apiClient.delete).toHaveBeenCalledWith(`/drawings/contract/${uuid}`); + }); +}); diff --git a/frontend/lib/services/__tests__/drawing-master-data.service.test.ts b/frontend/lib/services/__tests__/drawing-master-data.service.test.ts new file mode 100644 index 00000000..bf7dbfe4 --- /dev/null +++ b/frontend/lib/services/__tests__/drawing-master-data.service.test.ts @@ -0,0 +1,230 @@ +// File: frontend/lib/services/__tests__/drawing-master-data.service.test.ts +// Change Log: +// - 2026-06-13: Initial creation - test coverage for drawing-master-data service + +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { drawingMasterDataService } from '../drawing-master-data.service'; +import apiClient from '@/lib/api/client'; + +// Mock apiClient +vi.mock('@/lib/api/client', () => ({ + default: { + get: vi.fn(), + post: vi.fn(), + patch: vi.fn(), + delete: vi.fn(), + }, +})); + +describe('drawingMasterDataService', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe('Contract Volumes', () => { + it('ควรดึงข้อมูล contract volumes สำเร็จ', async () => { + const mockResponse = { data: [{ id: 1, volumeCode: 'V1', volumeName: 'Vol 1' }] }; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.getContractVolumes('proj-uuid-1'); + expect(result).toEqual(mockResponse.data); + expect(apiClient.get).toHaveBeenCalledWith('/drawings/master-data/contract/volumes', { + params: { projectId: 'proj-uuid-1' }, + }); + }); + + it('ควรสร้าง contract volume สำเร็จ', async () => { + const mockDto = { projectId: 'proj-uuid-1', volumeCode: 'V1', volumeName: 'Vol 1', sortOrder: 1 }; + const mockResponse = { data: { id: 1, volumeCode: 'V1' } }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.createContractVolume(mockDto); + expect(result).toEqual(mockResponse.data); + expect(apiClient.post).toHaveBeenCalledWith('/drawings/master-data/contract/volumes', mockDto); + }); + + it('ควรปรับปรุง contract volume สำเร็จ', async () => { + const mockDto = { volumeName: 'Updated Vol 1' }; + const mockResponse = { data: { id: 1, volumeName: 'Updated Vol 1' } }; + vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.updateContractVolume(1, mockDto); + expect(result).toEqual(mockResponse.data); + expect(apiClient.patch).toHaveBeenCalledWith('/drawings/master-data/contract/volumes/1', mockDto); + }); + + it('ควรลบ contract volume สำเร็จ', async () => { + vi.mocked(apiClient.delete).mockResolvedValue({} as any); + await drawingMasterDataService.deleteContractVolume(1); + expect(apiClient.delete).toHaveBeenCalledWith('/drawings/master-data/contract/volumes/1'); + }); + }); + + describe('Contract Categories', () => { + it('ควรดึงข้อมูล contract categories สำเร็จ', async () => { + const mockResponse = { data: [{ id: 2, catCode: 'C2', catName: 'Cat 2' }] }; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.getContractCategories('proj-uuid-1'); + expect(result).toEqual(mockResponse.data); + expect(apiClient.get).toHaveBeenCalledWith('/drawings/master-data/contract/categories', { + params: { projectId: 'proj-uuid-1' }, + }); + }); + + it('ควรสร้าง contract category สำเร็จ', async () => { + const mockDto = { projectId: 'proj-uuid-1', catCode: 'C2', catName: 'Cat 2', sortOrder: 1 }; + const mockResponse = { data: { id: 2, catCode: 'C2' } }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.createContractCategory(mockDto); + expect(result).toEqual(mockResponse.data); + expect(apiClient.post).toHaveBeenCalledWith('/drawings/master-data/contract/categories', mockDto); + }); + + it('ควรปรับปรุง contract category สำเร็จ', async () => { + const mockDto = { catName: 'Updated Cat 2' }; + const mockResponse = { data: { id: 2, catName: 'Updated Cat 2' } }; + vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.updateContractCategory(2, mockDto); + expect(result).toEqual(mockResponse.data); + expect(apiClient.patch).toHaveBeenCalledWith('/drawings/master-data/contract/categories/2', mockDto); + }); + + it('ควรลบ contract category สำเร็จ', async () => { + vi.mocked(apiClient.delete).mockResolvedValue({} as any); + await drawingMasterDataService.deleteContractCategory(2); + expect(apiClient.delete).toHaveBeenCalledWith('/drawings/master-data/contract/categories/2'); + }); + }); + + describe('Contract Sub-categories', () => { + it('ควรดึงข้อมูล contract sub-categories สำเร็จ', async () => { + const mockResponse = [{ id: 3, subCatCode: 'SC3', subCatName: 'Sub 3' }]; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.getContractSubCategories('proj-uuid-1'); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith('/drawings/master-data/contract/sub-categories', { + params: { projectId: 'proj-uuid-1' }, + }); + }); + + it('ควรสร้าง contract sub-category สำเร็จ', async () => { + const mockDto = { projectId: 'proj-uuid-1', subCatCode: 'SC3', subCatName: 'Sub 3', sortOrder: 1 }; + const mockResponse = { id: 3, subCatCode: 'SC3' }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.createContractSubCategory(mockDto); + expect(result).toEqual(mockResponse); + expect(apiClient.post).toHaveBeenCalledWith('/drawings/master-data/contract/sub-categories', mockDto); + }); + + it('ควรปรับปรุง contract sub-category สำเร็จ', async () => { + const mockDto = { subCatName: 'Updated Sub 3' }; + const mockResponse = { id: 3, subCatName: 'Updated Sub 3' }; + vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.updateContractSubCategory(3, mockDto); + expect(result).toEqual(mockResponse); + expect(apiClient.patch).toHaveBeenCalledWith('/drawings/master-data/contract/sub-categories/3', mockDto); + }); + + it('ควรลบ contract sub-category สำเร็จ', async () => { + vi.mocked(apiClient.delete).mockResolvedValue({} as any); + await drawingMasterDataService.deleteContractSubCategory(3); + expect(apiClient.delete).toHaveBeenCalledWith('/drawings/master-data/contract/sub-categories/3'); + }); + }); + + describe('Contract Category Mappings', () => { + it('ควรดึงข้อมูล mappings สำเร็จ', async () => { + const mockResponse = [{ id: 10, category: {}, subCategory: {} }]; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.getContractMappings('proj-uuid-1', 2); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith('/drawings/master-data/contract/mappings', { + params: { projectId: 'proj-uuid-1', categoryId: 2 }, + }); + }); + + it('ควรสร้าง mapping สำเร็จ', async () => { + const mockDto = { projectId: 'proj-uuid-1', categoryId: 2, subCategoryId: 3 }; + const mockResponse = { id: 10 }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.createContractMapping(mockDto); + expect(result).toEqual(mockResponse); + expect(apiClient.post).toHaveBeenCalledWith('/drawings/master-data/contract/mappings', mockDto); + }); + + it('ควรลบ mapping สำเร็จ', async () => { + vi.mocked(apiClient.delete).mockResolvedValue({} as any); + await drawingMasterDataService.deleteContractMapping(10); + expect(apiClient.delete).toHaveBeenCalledWith('/drawings/master-data/contract/mappings/10'); + }); + }); + + describe('Shop Main Categories', () => { + it('ควรดึงข้อมูล shop main categories สำเร็จ', async () => { + const mockResponse = [{ id: 4, mainCategoryCode: 'M4', mainCategoryName: 'Main 4' }]; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.getShopMainCategories('proj-uuid-1'); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith('/drawings/master-data/shop/main-categories', { + params: { projectId: 'proj-uuid-1' }, + }); + }); + + it('ควรสร้าง shop main category สำเร็จ', async () => { + const mockDto = { projectId: 'proj-uuid-1', mainCategoryCode: 'M4', mainCategoryName: 'Main 4', sortOrder: 1 }; + const mockResponse = { id: 4, mainCategoryCode: 'M4' }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.createShopMainCategory(mockDto); + expect(result).toEqual(mockResponse); + expect(apiClient.post).toHaveBeenCalledWith('/drawings/master-data/shop/main-categories', mockDto); + }); + + it('ควรปรับปรุง shop main category สำเร็จ', async () => { + const mockDto = { mainCategoryName: 'Updated Main 4' }; + const mockResponse = { id: 4, mainCategoryName: 'Updated Main 4' }; + vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.updateShopMainCategory(4, mockDto); + expect(result).toEqual(mockResponse); + expect(apiClient.patch).toHaveBeenCalledWith('/drawings/master-data/shop/main-categories/4', mockDto); + }); + + it('ควรลบ shop main category สำเร็จ', async () => { + vi.mocked(apiClient.delete).mockResolvedValue({} as any); + await drawingMasterDataService.deleteShopMainCategory(4); + expect(apiClient.delete).toHaveBeenCalledWith('/drawings/master-data/shop/main-categories/4'); + }); + }); + + describe('Shop Sub-categories', () => { + it('ควรดึงข้อมูล shop sub-categories สำเร็จ', async () => { + const mockResponse = [{ id: 5, subCategoryCode: 'S5', subCategoryName: 'Sub 5' }]; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.getShopSubCategories('proj-uuid-1', 4); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith('/drawings/master-data/shop/sub-categories', { + params: { projectId: 'proj-uuid-1', mainCategoryId: 4 }, + }); + }); + + it('ควรสร้าง shop sub-category สำเร็จ', async () => { + const mockDto = { projectId: 'proj-uuid-1', subCategoryCode: 'S5', subCategoryName: 'Sub 5', sortOrder: 1 }; + const mockResponse = { id: 5, subCategoryCode: 'S5' }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.createShopSubCategory(mockDto); + expect(result).toEqual(mockResponse); + expect(apiClient.post).toHaveBeenCalledWith('/drawings/master-data/shop/sub-categories', mockDto); + }); + + it('ควรปรับปรุง shop sub-category สำเร็จ', async () => { + const mockDto = { subCategoryName: 'Updated Sub 5' }; + const mockResponse = { id: 5, subCategoryName: 'Updated Sub 5' }; + vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); + const result = await drawingMasterDataService.updateShopSubCategory(5, mockDto); + expect(result).toEqual(mockResponse); + expect(apiClient.patch).toHaveBeenCalledWith('/drawings/master-data/shop/sub-categories/5', mockDto); + }); + + it('ควรลบ shop sub-category สำเร็จ', async () => { + vi.mocked(apiClient.delete).mockResolvedValue({} as any); + await drawingMasterDataService.deleteShopSubCategory(5); + expect(apiClient.delete).toHaveBeenCalledWith('/drawings/master-data/shop/sub-categories/5'); + }); + }); +}); diff --git a/frontend/lib/services/__tests__/migration.service.test.ts b/frontend/lib/services/__tests__/migration.service.test.ts new file mode 100644 index 00000000..0c81bd4a --- /dev/null +++ b/frontend/lib/services/__tests__/migration.service.test.ts @@ -0,0 +1,154 @@ +// File: frontend/lib/services/__tests__/migration.service.test.ts +// Change Log: +// - 2026-06-13: Initial creation - test coverage for migration service + +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { migrationService } from '../migration.service'; +import api from '@/lib/api/client'; + +// Mock api client +vi.mock('@/lib/api/client', () => ({ + default: { + get: vi.fn(), + post: vi.fn(), + }, +})); + +describe('migrationService', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe('getReviewQueue', () => { + it('ควรดึงข้อมูลรายการ Queue และแปลงข้อมูลแบบแบ่งหน้าได้อย่างถูกต้อง', async () => { + const mockParams = { page: 1, limit: 10, status: 'PENDING' as any }; + const mockResponse = { + data: { + items: [{ publicId: '019505a1-7c3e-7000-8000-item111111111', status: 'PENDING' }], + total: 100, + page: 1, + limit: 10, + totalPages: 10, + }, + }; + + vi.mocked(api.get).mockResolvedValue({ data: mockResponse }); + + const result = await migrationService.getReviewQueue(mockParams); + + expect(result.items).toEqual(mockResponse.data.items); + expect(result.total).toBe(100); + expect(api.get).toHaveBeenCalledWith('/migration/queue', { params: mockParams }); + }); + + it('ควรจัดการกรณีที่ API ส่งกลับ Direct Data Array ได้อย่างถูกต้อง', async () => { + const mockResponse = { + data: [{ publicId: '019505a1-7c3e-7000-8000-item111111111', status: 'PENDING' }], + }; + + vi.mocked(api.get).mockResolvedValue({ data: mockResponse }); + + const result = await migrationService.getReviewQueue({}); + + expect(result.items).toEqual(mockResponse.data); + expect(result.total).toBe(1); + }); + + it('ควรส่งกลับโครงสร้างเปล่ากรณีที่ดึงข้อมูลล้มเหลวหรือไม่ตรงโครงสร้าง', async () => { + vi.mocked(api.get).mockResolvedValue({ data: null }); + + const result = await migrationService.getReviewQueue({}); + + expect(result.items).toEqual([]); + expect(result.total).toBe(0); + }); + }); + + describe('getQueueItem', () => { + it('ควรดึงข้อมูล Queue item เดี่ยวตาม ID สำเร็จ', async () => { + const mockResponse = { + data: { publicId: '019505a1-7c3e-7000-8000-item111111111', status: 'PENDING' }, + }; + + vi.mocked(api.get).mockResolvedValue({ data: mockResponse }); + + const result = await migrationService.getQueueItem(1); + + expect(result).toEqual(mockResponse.data); + expect(api.get).toHaveBeenCalledWith('/migration/queue/1'); + }); + }); + + describe('getErrors', () => { + it('ควรดึงข้อมูลรายการ Error Log สำเร็จ', async () => { + const mockParams = { page: 1, limit: 20 }; + const mockResponse = { + data: { + items: [{ errorCode: 'ERR_001', errorMessage: 'Invalid UUID' }], + total: 5, + }, + }; + + vi.mocked(api.get).mockResolvedValue({ data: mockResponse }); + + const result = await migrationService.getErrors(mockParams); + + expect(result.items).toEqual(mockResponse.data.items); + expect(api.get).toHaveBeenCalledWith('/migration/errors', { params: mockParams }); + }); + }); + + describe('approveQueueItem', () => { + it('ควรอนุมัติรายการคิวสำเร็จพร้อมส่ง Idempotency-Key', async () => { + const mockPayload = { remarks: 'Approve' }; + const mockResponse = { data: { success: true } }; + + vi.mocked(api.post).mockResolvedValue({ data: mockResponse }); + + const result = await migrationService.approveQueueItem(1, mockPayload, 'idemp-key-123'); + + expect(result).toEqual(mockResponse.data); + expect(api.post).toHaveBeenCalledWith('/migration/queue/1/approve', mockPayload, { + headers: { 'idempotency-key': 'idemp-key-123' }, + }); + }); + }); + + describe('rejectQueueItem', () => { + it('ควรปฏิเสธรายการคิวสำเร็จ', async () => { + const mockResponse = { data: { success: true } }; + + vi.mocked(api.post).mockResolvedValue({ data: mockResponse }); + + const result = await migrationService.rejectQueueItem(1); + + expect(result).toEqual(mockResponse.data); + expect(api.post).toHaveBeenCalledWith('/migration/queue/1/reject'); + }); + }); + + describe('commitBatch', () => { + it('ควรบันทึก commit batch สำเร็จพร้อมส่ง Idempotency-Key', async () => { + const mockPayload = { batchId: 10, items: [] }; + const mockResponse = { data: { success: true } }; + + vi.mocked(api.post).mockResolvedValue({ data: mockResponse }); + + const result = await migrationService.commitBatch(mockPayload as any, 'idemp-key-456'); + + expect(result).toEqual(mockResponse.data); + expect(api.post).toHaveBeenCalledWith('/migration/commit_batch', mockPayload, { + headers: { 'idempotency-key': 'idemp-key-456' }, + }); + }); + }); + + describe('getStagingFileUrl', () => { + it('ควรสร้าง URL สำหรับ staging file อย่างถูกต้อง', () => { + const filePath = '/uploads/staging/drawing.dwg'; + const result = migrationService.getStagingFileUrl(filePath); + + expect(result).toBe('/api/migration/staging-file?path=%2Fuploads%2Fstaging%2Fdrawing.dwg'); + }); + }); +}); diff --git a/frontend/lib/services/__tests__/organization.service.test.ts b/frontend/lib/services/__tests__/organization.service.test.ts new file mode 100644 index 00000000..2a525f17 --- /dev/null +++ b/frontend/lib/services/__tests__/organization.service.test.ts @@ -0,0 +1,91 @@ +// File: frontend/lib/services/__tests__/organization.service.test.ts +// Change Log: +// - 2026-06-13: Initial creation - test coverage for organization service + +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { organizationService } from '../organization.service'; +import apiClient from '@/lib/api/client'; + +// Mock apiClient +vi.mock('@/lib/api/client', () => ({ + default: { + get: vi.fn(), + post: vi.fn(), + patch: vi.fn(), + delete: vi.fn(), + }, +})); + +describe('organizationService', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe('getAll', () => { + it('ควรดึงข้อมูลรายการองค์กรทั้งหมดสำเร็จ (เมื่อ API ส่งกลับแบบ direct data)', async () => { + const mockParams = { projectId: '019505a1-7c3e-7000-8000-proj11111111' }; + const mockResponse = [{ publicId: '019505a1-7c3e-7000-8000-org111111111', organizationName: 'Org A' }]; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await organizationService.getAll(mockParams as any); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith('/organizations', { params: mockParams }); + }); + + it('ควรดึงข้อมูลรายการองค์กรทั้งหมดสำเร็จ (เมื่อ API ส่งกลับแบบ wrapped ใน data.data)', async () => { + const mockResponse = { + data: { + data: [{ publicId: '019505a1-7c3e-7000-8000-org111111111', organizationName: 'Org A' }], + }, + }; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse.data }); + const result = await organizationService.getAll(); + expect(result).toEqual(mockResponse.data.data); + expect(apiClient.get).toHaveBeenCalledWith('/organizations', { params: undefined }); + }); + }); + + describe('getByUuid', () => { + it('ควรดึงข้อมูลองค์กรเดี่ยวตาม UUID สำเร็จ', async () => { + const uuid = '019505a1-7c3e-7000-8000-org111111111'; + const mockResponse = { data: { publicId: uuid, organizationName: 'Org A' } }; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await organizationService.getByUuid(uuid); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith(`/organizations/${uuid}`); + }); + }); + + describe('create', () => { + it('ควรสร้างองค์กรใหม่สำเร็จ', async () => { + const mockDto = { organizationName: 'New Org', organizationCode: 'NEW' }; + const mockResponse = { data: { publicId: '019505a1-7c3e-7000-8000-org222222222' } }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await organizationService.create(mockDto as any); + expect(result).toEqual(mockResponse); + expect(apiClient.post).toHaveBeenCalledWith('/organizations', mockDto); + }); + }); + + describe('update', () => { + it('ควรปรับปรุงข้อมูลองค์กรสำเร็จ', async () => { + const uuid = '019505a1-7c3e-7000-8000-org111111111'; + const mockDto = { organizationName: 'Updated Org' }; + const mockResponse = { data: { success: true } }; + vi.mocked(apiClient.patch).mockResolvedValue({ data: mockResponse }); + const result = await organizationService.update(uuid, mockDto as any); + expect(result).toEqual(mockResponse); + expect(apiClient.patch).toHaveBeenCalledWith(`/organizations/${uuid}`, mockDto); + }); + }); + + describe('delete', () => { + it('ควรลบองค์กรสำเร็จ', async () => { + const uuid = '019505a1-7c3e-7000-8000-org111111111'; + const mockResponse = { data: { success: true } }; + vi.mocked(apiClient.delete).mockResolvedValue({ data: mockResponse }); + const result = await organizationService.delete(uuid); + expect(result).toEqual(mockResponse); + expect(apiClient.delete).toHaveBeenCalledWith(`/organizations/${uuid}`); + }); + }); +}); diff --git a/frontend/lib/services/__tests__/shop-drawing.service.test.ts b/frontend/lib/services/__tests__/shop-drawing.service.test.ts new file mode 100644 index 00000000..66a749a0 --- /dev/null +++ b/frontend/lib/services/__tests__/shop-drawing.service.test.ts @@ -0,0 +1,58 @@ +// File: frontend/lib/services/__tests__/shop-drawing.service.test.ts +// Change Log: +// - 2026-06-13: Initial creation - test coverage for shop-drawing service + +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { shopDrawingService } from '../shop-drawing.service'; +import apiClient from '@/lib/api/client'; + +// Mock apiClient +vi.mock('@/lib/api/client', () => ({ + default: { + get: vi.fn(), + post: vi.fn(), + }, +})); + +describe('shopDrawingService', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('ควรดึงข้อมูลรายการ shop drawings สำเร็จ', async () => { + const mockParams = { search: 'SD-01' }; + const mockResponse = { data: [{ publicId: '019505a1-7c3e-7000-8000-sd1111111111', drawingNo: 'SD-001' }] }; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await shopDrawingService.getAll(mockParams); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith('/drawings/shop', { params: mockParams }); + }); + + it('ควรดึงรายละเอียดของ shop drawing สำเร็จ', async () => { + const uuid = '019505a1-7c3e-7000-8000-sd1111111111'; + const mockResponse = { data: { publicId: uuid, drawingNo: 'SD-001' } }; + vi.mocked(apiClient.get).mockResolvedValue({ data: mockResponse }); + const result = await shopDrawingService.getByUuid(uuid); + expect(result).toEqual(mockResponse); + expect(apiClient.get).toHaveBeenCalledWith(`/drawings/shop/${uuid}`); + }); + + it('ควรสร้าง shop drawing สำเร็จ', async () => { + const mockDto = { drawingNo: 'SD-001', subject: 'Test Shop Drawing' }; + const mockResponse = { data: { publicId: '019505a1-7c3e-7000-8000-sd1111111111' } }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await shopDrawingService.create(mockDto as any); + expect(result).toEqual(mockResponse); + expect(apiClient.post).toHaveBeenCalledWith('/drawings/shop', mockDto); + }); + + it('ควรสร้าง revision ใหม่ของ shop drawing สำเร็จ', async () => { + const uuid = '019505a1-7c3e-7000-8000-sd1111111111'; + const mockDto = { revisionNo: 'A', comment: 'New Revision' }; + const mockResponse = { data: { success: true } }; + vi.mocked(apiClient.post).mockResolvedValue({ data: mockResponse }); + const result = await shopDrawingService.createRevision(uuid, mockDto as any); + expect(result).toEqual(mockResponse); + expect(apiClient.post).toHaveBeenCalledWith(`/drawings/shop/${uuid}/revisions`, mockDto); + }); +}); diff --git a/frontend/lib/services/migration.service.ts b/frontend/lib/services/migration.service.ts index dd9d6e19..b89b99b3 100644 --- a/frontend/lib/services/migration.service.ts +++ b/frontend/lib/services/migration.service.ts @@ -1,3 +1,7 @@ +// File: frontend/lib/services/migration.service.ts +// Change Log: +// - 2026-06-13: Add support for direct array response in normalizePaginatedResponse and add file header + import api from '../api/client'; import { MigrationReviewQueueItem, @@ -38,6 +42,16 @@ const normalizePaginatedResponse = (value: unknown): PaginatedResponse => }; } + if (Array.isArray(extracted)) { + return { + items: extracted as T[], + total: extracted.length, + page: 1, + limit: extracted.length, + totalPages: 1, + }; + } + const response = extracted as Partial> & { data?: unknown }; if (Array.isArray(response.items)) {