Files
tehran_taj/apps/api/src/modules/cart/cart-expiry.worker.spec.ts
T

125 lines
4.5 KiB
TypeScript
Raw Normal View History

import { CartExpiryWorkerService } from './cart-expiry.worker';
import { tehranWallToUtc } from './cart-schedule';
describe('CartExpiryWorkerService', () => {
function build(opts: {
cfg?: Record<string, unknown>;
carts?: Array<Record<string, unknown>>;
}) {
const carts = opts.carts ?? [];
const updates: Array<{ customerId: string; data: Record<string, unknown> }> = [];
const sms = { send: jest.fn(async () => ({ ok: true })) };
const prisma = {
customerCart: {
findMany: jest.fn(async () => carts),
update: jest.fn(async ({ where, data }: { where: { customerId: string }; data: Record<string, unknown> }) => {
updates.push({ customerId: where.customerId, data });
return {};
}),
},
$executeRaw: jest.fn(async () => 1),
};
const cart = {
getConfig: jest.fn(async () => ({
enabled: true,
clearHour: 13,
clearMinute: 0,
sameDayDeferFromHour: 8,
sameDayDeferFromMinute: 0,
reminderEnabled: true,
reminderHoursBefore: 2,
reminderBody: 'تا %count ساعت',
worker: 'on' as const,
...opts.cfg,
})),
};
const worker = new CartExpiryWorkerService(prisma as never, cart as never, sms as never);
return { worker, sms, updates, prisma, cart };
}
it('no-ops when disabled', async () => {
const { worker, sms, prisma } = build({ cfg: { enabled: false } });
await worker.tick(tehranWallToUtc(2026, 11, 12, 12, 0, 0));
expect(sms.send).not.toHaveBeenCalled();
expect(prisma.customerCart.findMany).not.toHaveBeenCalled();
});
it('reminds carts due today (touched before 08:00), not deferred ones', async () => {
const todayClear = tehranWallToUtc(2026, 11, 12, 13, 0, 0);
const { worker, sms, updates } = build({
carts: [
{
customerId: 'early',
items: [{ pid: 'p1', vid: 'v1', qty: 1 }],
reminderSentForClearAt: null,
updatedAt: tehranWallToUtc(2026, 11, 12, 7, 0, 0),
customer: { mobile: '09120000000', isActive: true },
},
{
customerId: 'deferred',
items: [{ pid: 'p2', vid: 'v2', qty: 1 }],
reminderSentForClearAt: null,
// 10:00 → deadline tomorrow 13 — no reminder yet at 11:30 today
updatedAt: tehranWallToUtc(2026, 11, 12, 10, 0, 0),
customer: { mobile: '09121111111', isActive: true },
},
],
});
await worker.tick(tehranWallToUtc(2026, 11, 12, 11, 30, 0));
expect(sms.send).toHaveBeenCalledTimes(1);
expect(sms.send).toHaveBeenCalledWith('09120000000', expect.any(String));
expect(updates[0]?.customerId).toBe('early');
expect(updates[0]?.data.reminderSentForClearAt).toEqual(todayClear);
});
it('does not clear 08–13 carts at today 13; clears pre-08 carts', async () => {
const { worker, updates, sms } = build({
carts: [
{
customerId: 'early',
items: [{ pid: 'p1', vid: 'v1', qty: 1 }],
reminderSentForClearAt: null,
updatedAt: tehranWallToUtc(2026, 11, 12, 7, 0, 0),
customer: { mobile: '09120000000', isActive: true },
},
{
customerId: 'deferred',
items: [{ pid: 'p2', vid: 'v2', qty: 1 }],
reminderSentForClearAt: null,
updatedAt: tehranWallToUtc(2026, 11, 12, 10, 0, 0),
customer: { mobile: '09121111111', isActive: true },
},
{
customerId: 'afternoon',
items: [{ pid: 'p3', vid: 'v3', qty: 1 }],
reminderSentForClearAt: null,
updatedAt: tehranWallToUtc(2026, 11, 12, 14, 0, 0),
customer: { mobile: '09122222222', isActive: true },
},
],
});
await worker.tick(tehranWallToUtc(2026, 11, 12, 13, 5, 0));
expect(sms.send).not.toHaveBeenCalled();
expect(updates).toHaveLength(1);
expect(updates[0].customerId).toBe('early');
expect(updates[0].data.items).toEqual([]);
});
it('clears deferred (08–13) carts at tomorrow 13', async () => {
const { worker, updates } = build({
carts: [
{
customerId: 'deferred',
items: [{ pid: 'p2', vid: 'v2', qty: 1 }],
reminderSentForClearAt: null,
updatedAt: tehranWallToUtc(2026, 11, 12, 10, 0, 0),
customer: { mobile: '09121111111', isActive: true },
},
],
});
await worker.tick(tehranWallToUtc(2026, 11, 13, 13, 5, 0));
expect(updates).toHaveLength(1);
expect(updates[0].customerId).toBe('deferred');
});
});