import test from 'node:test'; import assert from 'node:assert/strict'; import { prepareCommand, canonical, mayHaveCommitted } from '../src/utils/command-core.mjs'; test('a timeout retry preserves the original payload and key', () => { const first = prepareCommand(null, { sku_id: 12, quantity: 8 }, () => 'request-1'); const stored = JSON.parse(JSON.stringify(first)); const retry = prepareCommand(stored, { quantity: 8, sku_id: 12 }, () => { throw new Error('must not generate another key'); }); assert.deepEqual(retry, first); }); test('changing an unresolved command cannot silently create a second booking', () => { const first = prepareCommand(null, { quantity: 8 }, () => 'request-1'); assert.throws( () => prepareCommand(first, { quantity: 9 }, () => 'request-2'), /上次提交结果尚未确认/, ); }); test('a completed command permits a new operation with a new key', () => { const first = prepareCommand(null, { quantity: 8 }, () => 'request-1'); const second = prepareCommand(null, { quantity: 8 }, () => 'request-2'); assert.notEqual(first.request_key, second.request_key); }); test('checkout retries repair invalid stored keys before sending', () => { const payload = { items: [{ package_id: 1, quantity: 2 }], invoice: null }; for (const key of [undefined, null, '', 123, 'short', 'x'.repeat(81), 'invalid key']) { const stored = { ...payload, request_key: key }; const repaired = prepareCommand(stored, payload, () => 'checkout-repaired-1'); assert.deepEqual(repaired, { ...payload, request_key: 'checkout-repaired-1' }); assert.deepEqual( prepareCommand(repaired, payload, () => { throw new Error('must preserve repaired key'); }), repaired, ); } }); test('invalid newly generated keys never reach the transport', () => { assert.throws(() => prepareCommand(null, {}, () => ''), /请求标识/); }); test('nested checkout data compares by content, while photo selection order is preserved', () => { assert.equal( canonical({ items: [{ package_id: 1, quantity: 2 }], invoice: null }), canonical({ invoice: null, items: [{ quantity: 2, package_id: 1 }] }), ); assert.notEqual(canonical({ photo_ids: [1, 2] }), canonical({ photo_ids: [2, 1] })); }); test('network and server failures retain the key; explicit business rejections do not', () => { for (const status of [0, 500, 502, 503, 504]) assert.equal(mayHaveCommitted(status), true); for (const status of [400, 401, 403, 409, 422, 429]) assert.equal(mayHaveCommitted(status), false); });