Files
tehran_taj/apps/api/src/modules/cart/cart-expiry.worker.spec.ts
T
mahmoodandCursor 7dd74ff4f7 feat: product design surveys, cart expiry/buy-later, and catalog polish
Add like/dislike surveys with majority alerts for manufacturing decisions, clearer accounting mapping copy, and related cart/catalog admin-app improvements.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-12 17:55:52 +03:30

125 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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');
});
});