189 lines
6.0 KiB
TypeScript
189 lines
6.0 KiB
TypeScript
import { describe, test, expect } from "bun:test";
|
|
import {
|
|
computeProductsCacheTTL,
|
|
PRODUCTS_TTL_HOT,
|
|
PRODUCTS_TTL_LAZY,
|
|
WON_LOST_STATUS_IDS,
|
|
} from "../../src/modules/algorithms/computeProductsCacheTTL";
|
|
|
|
const NOW = new Date("2026-03-02T12:00:00Z");
|
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
|
|
describe("computeProductsCacheTTL", () => {
|
|
// -- Constants ----------------------------------------------------------
|
|
test("PRODUCTS_TTL_HOT is 45 seconds", () => {
|
|
expect(PRODUCTS_TTL_HOT).toBe(45_000);
|
|
});
|
|
|
|
test("PRODUCTS_TTL_LAZY is 20 minutes", () => {
|
|
expect(PRODUCTS_TTL_LAZY).toBe(1_200_000);
|
|
});
|
|
|
|
// -- Won/Lost status set ------------------------------------------------
|
|
test("WON_LOST_STATUS_IDS contains Won canonical ID (29) and Pending Won (49)", () => {
|
|
expect(WON_LOST_STATUS_IDS.has(29)).toBe(true);
|
|
expect(WON_LOST_STATUS_IDS.has(49)).toBe(true);
|
|
});
|
|
|
|
test("WON_LOST_STATUS_IDS contains Lost canonical ID (53) and Pending Lost (50)", () => {
|
|
expect(WON_LOST_STATUS_IDS.has(53)).toBe(true);
|
|
expect(WON_LOST_STATUS_IDS.has(50)).toBe(true);
|
|
});
|
|
|
|
test("WON_LOST_STATUS_IDS does not contain Active (58) or New (24)", () => {
|
|
expect(WON_LOST_STATUS_IDS.has(58)).toBe(false);
|
|
expect(WON_LOST_STATUS_IDS.has(24)).toBe(false);
|
|
});
|
|
|
|
// -- Rule 1: Won/Lost/Pending Won/Lost → null --------------------------
|
|
test("returns null for Won status (CW ID 29)", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 29,
|
|
closedFlag: true,
|
|
closedDate: new Date(NOW.getTime() - 2 * DAY_MS),
|
|
expectedCloseDate: null,
|
|
lastUpdated: new Date(NOW.getTime() - 1 * DAY_MS),
|
|
now: NOW,
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
test("returns null for Pending Won status (CW ID 49)", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 49,
|
|
closedFlag: false,
|
|
closedDate: null,
|
|
expectedCloseDate: null,
|
|
lastUpdated: new Date(NOW.getTime() - 1 * DAY_MS),
|
|
now: NOW,
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
test("returns null for Lost status (CW ID 53)", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 53,
|
|
closedFlag: true,
|
|
closedDate: new Date(NOW.getTime() - 5 * DAY_MS),
|
|
expectedCloseDate: null,
|
|
lastUpdated: null,
|
|
now: NOW,
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
test("returns null for Pending Lost status (CW ID 50)", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 50,
|
|
closedFlag: false,
|
|
closedDate: null,
|
|
expectedCloseDate: null,
|
|
lastUpdated: new Date(NOW.getTime() - 1 * DAY_MS),
|
|
now: NOW,
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
// -- Rule 2: Opp not cacheable → null ----------------------------------
|
|
test("returns null when opp is closed > 30 days (main cache null)", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 58, // Active — but closed flag overrides
|
|
closedFlag: true,
|
|
closedDate: new Date(NOW.getTime() - 60 * DAY_MS),
|
|
expectedCloseDate: null,
|
|
lastUpdated: null,
|
|
now: NOW,
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
// -- Rule 3: Updated within 3 days → 15s -------------------------------
|
|
test("returns PRODUCTS_TTL_HOT when lastUpdated is within 3 days", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 58,
|
|
closedFlag: false,
|
|
closedDate: null,
|
|
expectedCloseDate: null,
|
|
lastUpdated: new Date(NOW.getTime() - 1 * DAY_MS),
|
|
now: NOW,
|
|
});
|
|
expect(result).toBe(PRODUCTS_TTL_HOT);
|
|
});
|
|
|
|
test("returns PRODUCTS_TTL_HOT when lastUpdated is exactly 3 days ago", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 58,
|
|
closedFlag: false,
|
|
closedDate: null,
|
|
expectedCloseDate: null,
|
|
lastUpdated: new Date(NOW.getTime() - 3 * DAY_MS),
|
|
now: NOW,
|
|
});
|
|
expect(result).toBe(PRODUCTS_TTL_HOT);
|
|
});
|
|
|
|
// -- Rule 4: Everything else → 30 min ----------------------------------
|
|
test("returns PRODUCTS_TTL_LAZY when lastUpdated is > 3 days ago", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 58,
|
|
closedFlag: false,
|
|
closedDate: null,
|
|
expectedCloseDate: null,
|
|
lastUpdated: new Date(NOW.getTime() - 10 * DAY_MS),
|
|
now: NOW,
|
|
});
|
|
expect(result).toBe(PRODUCTS_TTL_LAZY);
|
|
});
|
|
|
|
test("returns PRODUCTS_TTL_LAZY when no lastUpdated is set", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 58,
|
|
closedFlag: false,
|
|
closedDate: null,
|
|
expectedCloseDate: null,
|
|
lastUpdated: null,
|
|
now: NOW,
|
|
});
|
|
expect(result).toBe(PRODUCTS_TTL_LAZY);
|
|
});
|
|
|
|
test("returns PRODUCTS_TTL_LAZY for recently-closed (within 30 days) non-won/lost", () => {
|
|
// Edge case: closedFlag true, but status is not Won/Lost (unusual but possible)
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 56, // Internal Review (not won/lost)
|
|
closedFlag: true,
|
|
closedDate: new Date(NOW.getTime() - 10 * DAY_MS),
|
|
expectedCloseDate: null,
|
|
lastUpdated: new Date(NOW.getTime() - 20 * DAY_MS),
|
|
now: NOW,
|
|
});
|
|
expect(result).toBe(PRODUCTS_TTL_LAZY);
|
|
});
|
|
|
|
// -- Rule priority: Won/Lost takes priority over recent activity --------
|
|
test("Won status takes priority even with very recent lastUpdated", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: 29,
|
|
closedFlag: true,
|
|
closedDate: new Date(NOW.getTime() - 1 * DAY_MS),
|
|
expectedCloseDate: null,
|
|
lastUpdated: new Date(NOW.getTime() - 1000), // 1 second ago
|
|
now: NOW,
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
// -- Null statusCwId (should not skip rule 1) ---------------------------
|
|
test("null statusCwId falls through to other rules", () => {
|
|
const result = computeProductsCacheTTL({
|
|
statusCwId: null,
|
|
closedFlag: false,
|
|
closedDate: null,
|
|
expectedCloseDate: null,
|
|
lastUpdated: new Date(NOW.getTime() - 1 * DAY_MS),
|
|
now: NOW,
|
|
});
|
|
expect(result).toBe(PRODUCTS_TTL_HOT);
|
|
});
|
|
});
|