Improve delivery workflows and add versioned guided tours (#1)
Build and Push Docker Images / build-backend (push) Canceled after 0s
Build and Push Docker Images / build-frontend (push) Canceled after 0s

Reviewed-on: #1
Co-authored-by: Egor Pozharov <chedius232@gmail.com>
This commit was merged in pull request #1.
This commit is contained in:
2026-10-07 19:49:10 +00:00
committed by chedius
parent 1860e52b88
commit dee912edb8
25 changed files with 933 additions and 1431 deletions
+79
View File
@@ -0,0 +1,79 @@
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);
});