import test from "node:test"; import assert from "node:assert/strict"; import { registerHooks } from "node:module"; const monthlyCardUrl = new URL("../functions/monthlyCard.ts", import.meta.url); const MONTH_CARD_DURATION = 30 * 24 * 60 * 60 * 1000; const NOW = 1_800_000_000_000; const state = { user: null, orders: [] }; globalThis.__monthlyCardCloudMock = { database() { return { collection(name) { return { where(query) { return { async getOne() { if (name === "order") { return { data: state.orders.find((order) => matches(order, query)) || null }; } return { data: state.user && matches(state.user, query) ? state.user : null }; }, async update(payload) { if (name === "order") { const orders = state.orders.filter((order) => matches(order, query)); orders.forEach((order) => Object.assign(order, payload)); return { updated: orders.length }; } if (state.user && matches(state.user, query)) { Object.assign(state.user, payload); return { updated: 1 }; } return { updated: 0 }; }, }; }, }; }, }; }, }; globalThis.__monthlyCardUtilsMock = { checkToken(received, expected) { return received === expected; }, }; registerHooks({ resolve(specifier, context, nextResolve) { if (specifier === "@lafjs/cloud") { return { url: "data:text/javascript,export default globalThis.__monthlyCardCloudMock", shortCircuit: true }; } if (specifier === "@/Utils") { return { url: "data:text/javascript,export default globalThis.__monthlyCardUtilsMock", shortCircuit: true }; } return nextResolve(specifier, context); }, }); const { default: monthlyCard } = await import(monthlyCardUrl); const realDateNow = Date.now; Date.now = () => NOW; test.after(() => { Date.now = realDateNow; }); function matches(target, query) { return Object.entries(query || {}).every(([key, value]) => target?.[key] === value); } function reset({ monthCardTime = 0, monthCardReward = 0, granted = false } = {}) { state.user = { _id: "user-1", openid: "openid-1", monthCardTime, monthCardReward }; state.orders = [{ outTradeNo: "order-1", openid: "openid-1", itemid: "month_Card", state: 1, monthCardGranted: granted, }]; } function save(outTradeNo = "order-1") { return monthlyCard({ body: { action: "save", uid: "user-1", outTradeNo } }); } test("first purchase starts a 30-day month card", async () => { reset(); const result = await save(); assert.equal(result.code, 1); assert.equal(state.user.monthCardTime, NOW + MONTH_CARD_DURATION); assert.equal(state.user.monthCardReward, 0); assert.equal(state.orders[0].state, 2); assert.equal(state.orders[0].monthCardGranted, true); }); test("renewal extends from the existing expiry and preserves today's claim state", async () => { const currentExpiry = NOW + 12 * 24 * 60 * 60 * 1000; const rewardTime = NOW - 60_000; reset({ monthCardTime: currentExpiry, monthCardReward: rewardTime }); await save(); assert.equal(state.user.monthCardTime, currentExpiry + MONTH_CARD_DURATION); assert.equal(state.user.monthCardReward, rewardTime); }); test("three different paid orders accumulate 30, 60, then 90 days", async () => { reset(); await save("order-1"); assert.equal(state.user.monthCardTime, NOW + MONTH_CARD_DURATION); for (const [outTradeNo, days] of [["order-2", 60], ["order-3", 90]]) { state.orders.push({ outTradeNo, openid: "openid-1", itemid: "month_Card", state: 1, monthCardGranted: false, }); await save(outTradeNo); assert.equal(state.user.monthCardTime, NOW + days * 24 * 60 * 60 * 1000); } }); test("expired card restarts from now and resets the claim state", async () => { reset({ monthCardTime: NOW - 1, monthCardReward: NOW - 60_000 }); await save(); assert.equal(state.user.monthCardTime, NOW + MONTH_CARD_DURATION); assert.equal(state.user.monthCardReward, 0); }); test("the same paid order cannot extend the card twice", async () => { reset(); await save(); const firstExpiry = state.user.monthCardTime; const result = await save(); assert.equal(result.code, 1); assert.equal(result.data.alreadyGranted, true); assert.equal(state.user.monthCardTime, firstExpiry); }); test("a legacy completed order without a grant marker cannot be replayed", async () => { reset({ monthCardTime: NOW + MONTH_CARD_DURATION }); state.orders[0].state = 2; delete state.orders[0].monthCardGranted; const expiry = state.user.monthCardTime; const result = await save(); assert.equal(result.code, 1); assert.equal(result.data.alreadyGranted, true); assert.equal(state.user.monthCardTime, expiry); }); test("saving without a paid order number is rejected", async () => { reset(); const result = await save(""); assert.equal(result.code, 0); assert.match(result.msg, /订单号/); assert.equal(state.user.monthCardTime, 0); });