Files
dinggadingga-backend/src/services/hiboutik/category.hiboutik.service.spec.ts

97 lines
3.7 KiB
TypeScript

import { Logger } from '@nestjs/common';
import { CategoryHiboutikService } from './category.hiboutik.service';
import { CategoryConverter } from '../../models/converter/category.converter';
import { CategoryHiboutikDto } from '../../models/hiboutikDTO/category.hiboutik.dto';
const hiboutikCategory = (id: number, parentId: number, overrides: Partial<CategoryHiboutikDto> = {}): CategoryHiboutikDto => ({
category_id: id,
category_name: `Category ${id}`,
category_id_parent: parentId,
category_enabled: 1,
category_enabled_www: 0,
category_position: 3,
...overrides,
});
describe('CategoryHiboutikService', () => {
const categoryHiboutikRepository = { getCategories: jest.fn() };
const categoryDatabaseRepository = { upsert: jest.fn(), setParent: jest.fn(), deleteMissing: jest.fn() };
let service: CategoryHiboutikService;
let calls: string[];
beforeAll(() => {
jest.spyOn(Logger.prototype, 'log').mockImplementation(() => undefined);
jest.spyOn(Logger.prototype, 'warn').mockImplementation(() => undefined);
jest.spyOn(Logger.prototype, 'error').mockImplementation(() => undefined);
});
beforeEach(() => {
jest.clearAllMocks();
calls = [];
categoryDatabaseRepository.upsert.mockImplementation((category: { hiboutikId: number }) => {
calls.push(`upsert ${category.hiboutikId}`);
return Promise.resolve({});
});
categoryDatabaseRepository.setParent.mockImplementation((id: number) => {
calls.push(`parent ${id}`);
return Promise.resolve({});
});
categoryDatabaseRepository.deleteMissing.mockResolvedValue(0);
service = new CategoryHiboutikService(
categoryHiboutikRepository as never,
categoryDatabaseRepository as never,
new CategoryConverter(),
);
});
it('stores position and web visibility', async () => {
categoryHiboutikRepository.getCategories.mockResolvedValue([hiboutikCategory(1, 0)]);
await service.syncCategories();
expect(categoryDatabaseRepository.upsert).toHaveBeenCalledWith({
hiboutikId: 1,
name: 'Category 1',
enabled: true,
position: 3,
webEnabled: false,
});
});
it('links parents once every category is saved, a child being listed before its parent', async () => {
categoryHiboutikRepository.getCategories.mockResolvedValue([hiboutikCategory(2, 3), hiboutikCategory(3, 0)]);
await service.syncCategories();
expect(calls).toEqual(['upsert 2', 'upsert 3', 'parent 2', 'parent 3']);
expect(categoryDatabaseRepository.setParent).toHaveBeenCalledWith(2, 3);
expect(categoryDatabaseRepository.setParent).toHaveBeenCalledWith(3, null);
});
it('keeps syncing the other categories when one fails, then deletes the missing ones', async () => {
categoryHiboutikRepository.getCategories.mockResolvedValue([hiboutikCategory(1, 0), hiboutikCategory(2, 0)]);
categoryDatabaseRepository.upsert.mockRejectedValueOnce(new Error('boom'));
await expect(service.syncCategories()).resolves.toBeUndefined();
expect(categoryDatabaseRepository.upsert).toHaveBeenCalledTimes(2);
expect(categoryDatabaseRepository.deleteMissing).toHaveBeenCalledWith([1, 2]);
});
it('deletes every category when Hiboutik answers with an empty list', async () => {
categoryHiboutikRepository.getCategories.mockResolvedValue([]);
await service.syncCategories();
expect(categoryDatabaseRepository.deleteMissing).toHaveBeenCalledWith([]);
});
it('deletes nothing when the Hiboutik call fails', async () => {
categoryHiboutikRepository.getCategories.mockRejectedValue(new Error('Request failed with status code 500'));
await expect(service.syncCategories()).rejects.toThrow('500');
expect(categoryDatabaseRepository.deleteMissing).not.toHaveBeenCalled();
});
});