// 集成测试:用真实计时器走完整流程,所以整个文件要跑十几秒。 import test from 'node:test'; import assert from 'node:assert/strict'; import { createOrder, OrderState } from '../src/order.js'; import { createStore } from '../src/order-store.js'; import { createOrderApi } from '../src/order-api.js'; import { scheduleAutoCancel, onPaymentCallback } from '../src/payment.js'; import { shipWithRetry } from '../src/shipping.js'; import { canRefund } from '../src/consumers/refund.js'; import { buildNotification } from '../src/consumers/notify.js'; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); function setup() { const store = createStore(); const api = createOrderApi(store); const order = store.save(createOrder({ amount: 12900 })); const read = () => api.getOrder(order.id).data; return { order, read }; } test('超时未支付自动关单(等 3 秒)', async () => { const { order, read } = setup(); scheduleAutoCancel(order, 3000); await sleep(3200); assert.equal(order.state, OrderState.CANCELLED); assert.equal(canRefund(read()), false); assert.equal(buildNotification(read()).text, '订单已取消'); }); test('支付发生在关单之前,订单保持已支付(等 3 秒)', async () => { const { order, read } = setup(); scheduleAutoCancel(order, 2500); await sleep(1000); assert.equal(onPaymentCallback(order).handled, true); await sleep(2000); assert.equal(order.state, OrderState.PAID); assert.equal(canRefund(read()), true); }); test('重复的支付回调只处理一次(等 2 秒)', async () => { const { order } = setup(); assert.equal(onPaymentCallback(order).handled, true); await sleep(2000); assert.equal(onPaymentCallback(order).handled, false); }); test('发货失败两次后重试成功(等 4 秒)', async () => { const { order, read } = setup(); onPaymentCallback(order); let calls = 0; const flakyWarehouse = async () => { calls += 1; if (calls < 3) throw new Error('仓库接口超时'); }; const result = await shipWithRetry(order, flakyWarehouse, { retries: 2, backoffMs: 2000 }); assert.equal(result.attempts, 3); assert.equal(buildNotification(read()).text, '订单已发货'); }); test('发货重试用尽后订单保持已支付(等 3 秒)', async () => { const { order, read } = setup(); onPaymentCallback(order); const downWarehouse = async () => { throw new Error('仓库接口不可用'); }; await assert.rejects(shipWithRetry(order, downWarehouse, { retries: 2, backoffMs: 1500 })); assert.equal(order.state, OrderState.PAID); assert.equal(canRefund(read()), true); });