jest.mock('@nestjs/config', () => ({ ConfigService: jest.fn().mockImplementation(() => ({ get: jest.fn().mockReturnValue('http://localhost:3000'), })), })); jest.mock('@nestjs/common', () => ({ Injectable: () => (target: any) => target, HttpException: class HttpException extends Error { constructor( public response: any, public status: number, ) { super(typeof response === 'string' ? response : JSON.stringify(response)); } }, InternalServerErrorException: class InternalServerErrorException extends Error { constructor(message: string) { super(message); } }, })); jest.mock('axios'); jest.mock('lodash', () => ({ omit: jest.fn((obj, keys) => { const result = { ...obj }; keys.forEach((k: string) => delete result[k]); return result; }), omitBy: jest.fn((obj, fn) => obj), keys: jest.fn((obj) => Object.keys(obj)), pick: jest.fn((obj, keys) => { const result: any = {}; keys.forEach((k: string) => { if (k in obj) result[k] = obj[k]; }); return result; }), })); jest.mock('@paralleldrive/cuid2', () => ({ createId: jest.fn().mockReturnValue('new-cuid'), })); import axios from 'axios'; import { CommonService } from '../common/common.service'; const mockAxios = axios as jest.Mocked; const mockConfigService = { get: jest.fn().mockReturnValue('http://localhost:3000'), } as any; describe('CommonService', () => { let service: CommonService; beforeEach(() => { jest.clearAllMocks(); service = new CommonService(mockConfigService); }); describe('handleAxiosError', () => { it('throws HttpException when error has a response', () => { const err = { response: { data: 'Bad Request', status: 400 } }; expect(() => service.handleAxiosError(err)).toThrow(); }); it('throws HttpException when error has a request but no response', () => { const err = { request: 'timeout' }; expect(() => service.handleAxiosError(err)).toThrow(); }); it('throws InternalServerErrorException for generic errors', () => { const err = { message: 'Something went wrong' }; expect(() => service.handleAxiosError(err)).toThrow(); }); }); describe('addActivityHistory', () => { it('posts activity and returns EntityId', async () => { mockAxios.post = jest .fn() .mockResolvedValue({ data: { EntityId: 'entity-123' } }); const record = { Action: 'Insert', EntityValueBefore: {}, EntityValueAfter: { Title: 'Test', CreatedById: 'u1', CreatedAt: new Date(), }, PerformedById: 'user-001', EntityId: 'entity-001', }; const result = await service.addActivityHistory( record, 'Media', 'create', ); expect(result).toBe('entity-123'); expect(mockAxios.post).toHaveBeenCalledWith( 'http://localhost:3000/activity-histories', expect.objectContaining({ EntityId: 'entity-001' }), ); }); it('uses update activity label for update method', async () => { mockAxios.post = jest .fn() .mockResolvedValue({ data: { EntityId: 'e2' } }); const record = { EntityValueBefore: { Title: 'Old' }, EntityValueAfter: { Title: 'New' }, PerformedById: 'user-001', EntityId: 'entity-002', }; await service.addActivityHistory(record, 'Media', 'update'); expect(mockAxios.post).toHaveBeenCalledWith( expect.any(String), expect.objectContaining({ Action: 'Update' }), ); }); it('calls handleAxiosError when axios throws', async () => { const axiosError = { response: { data: 'Error', status: 500 } }; mockAxios.post = jest.fn().mockRejectedValue(axiosError); const record = { EntityValueBefore: {}, EntityValueAfter: {}, PerformedById: 'u1', EntityId: 'e1', }; await expect( service.addActivityHistory(record, 'Media', 'create'), ).rejects.toThrow(); }); }); describe('getList', () => { it('returns rows from the response', async () => { mockAxios.get = jest .fn() .mockResolvedValue({ data: { rows: ['item1', 'item2'] } }); const result = await service.getList('MediaTypes'); expect(result).toEqual(['item1', 'item2']); expect(mockAxios.get).toHaveBeenCalledWith( 'http://localhost:3000/lists/items', expect.objectContaining({ params: { ListName: 'MediaTypes' } }), ); }); it('calls handleAxiosError when axios throws', async () => { mockAxios.get = jest .fn() .mockRejectedValue({ response: { data: 'err', status: 500 } }); await expect(service.getList('Any')).rejects.toThrow(); }); }); describe('addFieldTranslation', () => { it('posts field translation', async () => { mockAxios.post = jest.fn().mockResolvedValue({}); const payload = { field: 'Title', value: 'Tajuk' } as any; await service.addFieldTranslation(payload); expect(mockAxios.post).toHaveBeenCalledWith( 'http://localhost:3000/field-translations', payload, ); }); it('calls handleAxiosError when axios throws', async () => { mockAxios.post = jest.fn().mockRejectedValue({ message: 'fail' }); await expect(service.addFieldTranslation({} as any)).rejects.toThrow(); }); }); describe('getMedia', () => { it('returns rows from the response', async () => { mockAxios.get = jest .fn() .mockResolvedValue({ data: { rows: [{ MediaId: 'm1' }] } }); const result = await service.getMedia({ ObjectId: 'obj1', ObjectType: 'Rental', } as any); expect(result).toEqual([{ MediaId: 'm1' }]); }); it('calls handleAxiosError when axios throws', async () => { mockAxios.get = jest.fn().mockRejectedValue({ message: 'fail' }); await expect(service.getMedia({} as any)).rejects.toThrow(); }); }); });