POST /sync starts the full synchronization in the background (202, or 409 when one is already running). Entities are synced in dependency order: brands, categories, suppliers, products (with versions and stocks), customers. Each row is synced independently so that a failure is logged without stopping the rest. Replaces the default AppService.
69 lines
2.7 KiB
TypeScript
69 lines
2.7 KiB
TypeScript
import { Logger } from '@nestjs/common';
|
|
import { HiboutikService } from './hiboutik.service';
|
|
|
|
describe('HiboutikService', () => {
|
|
const brandService = { syncBrands: jest.fn() };
|
|
const categoryService = { syncCategories: jest.fn() };
|
|
const supplierService = { syncSuppliers: jest.fn() };
|
|
const productService = { syncProducts: jest.fn() };
|
|
const customerService = { syncCustomers: jest.fn() };
|
|
let service: HiboutikService;
|
|
|
|
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();
|
|
brandService.syncBrands.mockResolvedValue(undefined);
|
|
categoryService.syncCategories.mockResolvedValue(undefined);
|
|
supplierService.syncSuppliers.mockResolvedValue(undefined);
|
|
productService.syncProducts.mockResolvedValue(undefined);
|
|
customerService.syncCustomers.mockResolvedValue(undefined);
|
|
service = new HiboutikService(
|
|
brandService as never,
|
|
categoryService as never,
|
|
customerService as never,
|
|
productService as never,
|
|
supplierService as never,
|
|
);
|
|
});
|
|
|
|
it('runs the steps in dependency order', async () => {
|
|
const order: string[] = [];
|
|
brandService.syncBrands.mockImplementation(() => Promise.resolve(order.push('brands')));
|
|
categoryService.syncCategories.mockImplementation(() => Promise.resolve(order.push('categories')));
|
|
supplierService.syncSuppliers.mockImplementation(() => Promise.resolve(order.push('suppliers')));
|
|
productService.syncProducts.mockImplementation(() => Promise.resolve(order.push('products')));
|
|
customerService.syncCustomers.mockImplementation(() => Promise.resolve(order.push('customers')));
|
|
|
|
await service.syncAll();
|
|
|
|
expect(order).toEqual(['brands', 'categories', 'suppliers', 'products', 'customers']);
|
|
});
|
|
|
|
it('continues with the next steps when one fails', async () => {
|
|
brandService.syncBrands.mockRejectedValue(new Error('boom'));
|
|
|
|
await service.syncAll();
|
|
|
|
expect(productService.syncProducts).toHaveBeenCalled();
|
|
expect(customerService.syncCustomers).toHaveBeenCalled();
|
|
});
|
|
|
|
it('refuses a second synchronization while one is running, and unlocks at the end', async () => {
|
|
let finishBrands: () => void = () => undefined;
|
|
brandService.syncBrands.mockReturnValue(new Promise<void>((resolve) => (finishBrands = resolve)));
|
|
|
|
expect(service.startSync()).toBe(true);
|
|
expect(service.isSyncInProgress).toBe(true);
|
|
expect(service.startSync()).toBe(false);
|
|
|
|
finishBrands();
|
|
await new Promise((resolve) => setImmediate(resolve));
|
|
expect(service.isSyncInProgress).toBe(false);
|
|
});
|
|
});
|