import assert from 'node:assert/strict'; import { after, beforeEach, test } from 'node:test'; import { createServer } from 'vite'; // Load the real TypeScript store with Vite's existing transformer; no test // dependency or production authentication bypass is required. const vite = await createServer({ configFile: false, root: new URL('..', import.meta.url).pathname, server: { middlewareMode: true, hmr: false, watch: null, ws: false }, appType: 'custom', optimizeDeps: { noDiscovery: true, include: [] } }); const { useDeliveryStore: store } = await vite.ssrLoadModule('/src/stores/deliveryStore.ts'); const { deliveriesApi: api } = await vite.ssrLoadModule('/src/api/deliveries.ts'); const original = { ...api }; const day = '08-10-2026'; const nextDay = '09-10-2026'; const delivery = { id: 'one', date: day, productName: 'Диван', pickupLocation: 'symbat', customerName: 'Тестовый клиент', street: 'Тестовая', house: '1', address: 'Тестовый адрес', phone: '+77761234567', hasElevator: true, paymentStatus: 'paid', comment: '', status: 'new', createdAt: 1, updatedAt: 1 }; const deferred = () => { let resolve; const promise = new Promise(done => { resolve = done; }); return { promise, resolve }; }; const settle = () => new Promise(resolve => setImmediate(resolve)); beforeEach(() => { Object.assign(api, original, { getCounts: async () => ({ [day]: 1 }) }); store.setState({ deliveries: [{ ...delivery }], currentDate: day, isLoading: false, isLoadingCounts: false, error: null, countsError: null, pendingIds: [] }); }); after(async () => { Object.assign(api, original); await vite.close(); }); test('moving a delivery keeps the open day and removes only the moved delivery', async () => { api.update = async () => {}; let fetchedList = false; api.getByDate = async () => { fetchedList = true; return []; }; await store.getState().updateDelivery('one', { ...delivery, date: nextDay }); assert.equal(store.getState().currentDate, day); assert.deepEqual(store.getState().deliveries, []); assert.equal(fetchedList, false); assert.equal(store.getState().isLoading, false); }); test('failed save rejects its callback and leaves existing data intact', async () => { api.create = async () => { throw new Error('network down'); }; await assert.rejects(store.getState().addDelivery(delivery)); assert.deepEqual(store.getState().deliveries, [delivery]); assert.equal(store.getState().isLoading, false); }); test('count refresh failure cannot turn successful creation into a failed save', async () => { api.create = async () => 'two'; api.getCounts = async () => { throw new Error('count failure'); }; await store.getState().addDelivery({ ...delivery, productName: 'Кресло' }); await settle(); assert.equal(store.getState().deliveries.length, 2); assert.equal(store.getState().error, null); assert.match(store.getState().countsError, /календарь/); }); test('status mutation has local pending state and suppresses repeated requests', async () => { const wait = deferred(); let requests = 0; api.updateStatus = async () => { requests++; await wait.promise; }; const first = store.getState().toggleStatus('one', 'new'); assert.deepEqual(store.getState().pendingIds, ['one']); assert.equal(store.getState().isLoading, false); assert.equal(store.getState().deliveries.length, 1); await store.getState().toggleStatus('one', 'new'); assert.equal(requests, 1); wait.resolve(); await first; assert.equal(store.getState().deliveries[0].status, 'delivered'); assert.deepEqual(store.getState().pendingIds, []); }); test('late response from an old day cannot overwrite the selected day', async () => { const old = deferred(); const recent = deferred(); api.getByDate = date => date === day ? old.promise : recent.promise; const first = store.getState().fetchDeliveriesByDate(day); const second = store.getState().fetchDeliveriesByDate(nextDay); recent.resolve([{ ...delivery, id: 'two', date: nextDay }]); await second; old.resolve([delivery]); await first; assert.equal(store.getState().currentDate, nextDay); assert.equal(store.getState().deliveries[0].id, 'two'); assert.equal(store.getState().isLoading, false); });