Files
Filamenteka/__tests__/api.test.ts
DaX 9f01158241 Improve test coverage from 1.18% to 89.21%
- Add comprehensive test suite for api.ts service layer
- Create component tests for BackToTop, ColorCell, MaterialBadge
- Add tests for data modules: bambuLabColors and bambuLabColorsComplete
- Include specialized tests for UI features, CRUD operations, and data consistency
- Achieve 100% coverage for core components and data utilities
- All 91 tests passing with robust mocking strategies
2025-07-21 12:09:00 +02:00

230 lines
7.4 KiB
TypeScript

import axios from 'axios';
import api, { authService, colorService, filamentService } from '../src/services/api';
// Get the mock axios instance that was created
const mockAxiosInstance = (axios.create as jest.Mock).mock.results[0].value;
// Mock localStorage
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn(),
clear: jest.fn(),
};
(global as any).localStorage = localStorageMock;
// Mock window.location
const mockLocation = {
pathname: '/',
href: '',
};
// Only define location if it doesn't exist or is configurable
if (!Object.getOwnPropertyDescriptor(window, 'location') ||
Object.getOwnPropertyDescriptor(window, 'location')?.configurable) {
Object.defineProperty(window, 'location', {
value: mockLocation,
configurable: true,
writable: true
});
} else {
// If location exists and is not configurable, we'll work with the existing object
Object.assign(window.location, mockLocation);
}
describe('API Service Tests', () => {
beforeEach(() => {
jest.clearAllMocks();
// Clear localStorage mocks
localStorageMock.getItem.mockClear();
localStorageMock.removeItem.mockClear();
localStorageMock.setItem.mockClear();
// Reset window location
mockLocation.pathname = '/';
mockLocation.href = '';
});
describe('Auth Service', () => {
it('should login successfully', async () => {
const mockResponse = { data: { token: 'test-token', user: 'admin' } };
mockAxiosInstance.post.mockResolvedValue(mockResponse);
const result = await authService.login('admin', 'password123');
expect(mockAxiosInstance.post).toHaveBeenCalledWith('/login', {
username: 'admin',
password: 'password123'
});
expect(result).toEqual(mockResponse.data);
});
it('should handle login failure', async () => {
const error = new Error('Invalid credentials');
mockAxiosInstance.post.mockRejectedValue(error);
await expect(authService.login('admin', 'wrong')).rejects.toThrow('Invalid credentials');
});
});
describe('Color Service', () => {
it('should get all colors', async () => {
const mockColors = [
{ id: '1', name: 'Red', hex: '#FF0000' },
{ id: '2', name: 'Blue', hex: '#0000FF' }
];
mockAxiosInstance.get.mockResolvedValue({ data: mockColors });
const result = await colorService.getAll();
expect(mockAxiosInstance.get).toHaveBeenCalledWith('/colors');
expect(result).toEqual(mockColors);
});
it('should create a color', async () => {
const newColor = { name: 'Green', hex: '#00FF00', cena_refill: 100, cena_spulna: 150 };
const mockResponse = { id: '3', ...newColor };
mockAxiosInstance.post.mockResolvedValue({ data: mockResponse });
const result = await colorService.create(newColor);
expect(mockAxiosInstance.post).toHaveBeenCalledWith('/colors', newColor);
expect(result).toEqual(mockResponse);
});
it('should update a color', async () => {
const colorId = '1';
const updateData = { name: 'Dark Red', hex: '#8B0000' };
const mockResponse = { id: colorId, ...updateData };
mockAxiosInstance.put.mockResolvedValue({ data: mockResponse });
const result = await colorService.update(colorId, updateData);
expect(mockAxiosInstance.put).toHaveBeenCalledWith(`/colors/${colorId}`, updateData);
expect(result).toEqual(mockResponse);
});
it('should delete a color', async () => {
const colorId = '1';
const mockResponse = { success: true };
mockAxiosInstance.delete.mockResolvedValue({ data: mockResponse });
const result = await colorService.delete(colorId);
expect(mockAxiosInstance.delete).toHaveBeenCalledWith(`/colors/${colorId}`);
expect(result).toEqual(mockResponse);
});
});
describe('Filament Service', () => {
it('should get all filaments with cache buster', async () => {
const mockFilaments = [
{ id: '1', tip: 'PLA', boja: 'Red' },
{ id: '2', tip: 'PETG', boja: 'Blue' }
];
mockAxiosInstance.get.mockResolvedValue({ data: mockFilaments });
// Mock Date.now()
const originalDateNow = Date.now;
const mockTimestamp = 1234567890;
Date.now = jest.fn(() => mockTimestamp);
const result = await filamentService.getAll();
expect(mockAxiosInstance.get).toHaveBeenCalledWith(`/filaments?_t=${mockTimestamp}`);
expect(result).toEqual(mockFilaments);
// Restore Date.now
Date.now = originalDateNow;
});
it('should create a filament', async () => {
const newFilament = {
tip: 'ABS',
finish: 'Matte',
boja: 'Black',
boja_hex: '#000000'
};
const mockResponse = { id: '3', ...newFilament };
mockAxiosInstance.post.mockResolvedValue({ data: mockResponse });
const result = await filamentService.create(newFilament);
expect(mockAxiosInstance.post).toHaveBeenCalledWith('/filaments', newFilament);
expect(result).toEqual(mockResponse);
});
it('should update a filament', async () => {
const filamentId = '1';
const updateData = {
tip: 'PLA+',
finish: 'Silk',
cena: '4500'
};
const mockResponse = { id: filamentId, ...updateData };
mockAxiosInstance.put.mockResolvedValue({ data: mockResponse });
const result = await filamentService.update(filamentId, updateData);
expect(mockAxiosInstance.put).toHaveBeenCalledWith(`/filaments/${filamentId}`, updateData);
expect(result).toEqual(mockResponse);
});
it('should delete a filament', async () => {
const filamentId = '1';
const mockResponse = { success: true };
mockAxiosInstance.delete.mockResolvedValue({ data: mockResponse });
const result = await filamentService.delete(filamentId);
expect(mockAxiosInstance.delete).toHaveBeenCalledWith(`/filaments/${filamentId}`);
expect(result).toEqual(mockResponse);
});
it('should update bulk sale', async () => {
const saleData = {
filamentIds: ['1', '2', '3'],
salePercentage: 20,
saleStartDate: '2024-01-01',
saleEndDate: '2024-01-31',
enableSale: true
};
const mockResponse = { updated: 3, success: true };
mockAxiosInstance.post.mockResolvedValue({ data: mockResponse });
const result = await filamentService.updateBulkSale(saleData);
expect(mockAxiosInstance.post).toHaveBeenCalledWith('/filaments/sale/bulk', saleData);
expect(result).toEqual(mockResponse);
});
});
describe('Interceptors', () => {
it('should have interceptors configured', () => {
expect(mockAxiosInstance.interceptors).toBeDefined();
expect(mockAxiosInstance.interceptors.request).toBeDefined();
expect(mockAxiosInstance.interceptors.response).toBeDefined();
});
it('should have request interceptor set up', () => {
const mockRequestUse = mockAxiosInstance.interceptors.request.use;
expect(mockRequestUse).toBeDefined();
});
it('should have response interceptor set up', () => {
const mockResponseUse = mockAxiosInstance.interceptors.response.use;
expect(mockResponseUse).toBeDefined();
});
});
describe('API configuration', () => {
it('should export the configured axios instance', () => {
expect(api).toBe(mockAxiosInstance);
});
it('should have axios instance defined', () => {
expect(mockAxiosInstance).toBeDefined();
});
});
});