fix: 恢复抖音过期支付并完善原生状态确认
This commit is contained in:
@@ -40,7 +40,7 @@ const payment = { orderNum: 'order-1', douyin: { appId: 'app', mchId: 'mch', pre
|
||||
async function payContext(overrides = {}, app = true) {
|
||||
const adapter = await import('../utils/douyin-pay-adapter.mjs');
|
||||
const context = { uni: uniMock(), BASE_URL: 'test-api', TOKEN_NAME: 'token', USER_DATA: 'user',
|
||||
...adapter, canOpenDypay: () => true, initDypay: () => true,
|
||||
...adapter, canOpenDypay: () => true, initDypay: () => true, resetDypay: () => {},
|
||||
openDypay: (_, cb) => cb({ resultCode: '0' }),
|
||||
request: async options => options.url === '/payment/douyin/resume'
|
||||
? ({ bizcode: 100, data: { state: 'paid', orderNum: options.data.orderNum } })
|
||||
@@ -214,12 +214,65 @@ test('terminal server result clears saved order without payment and allows the n
|
||||
? ({bizcode:100,data:{state,orderNum:payment.orderNum}})
|
||||
: ({bizcode:100,data:{state:2}})});
|
||||
ctx.uni.storage.set('tb-douyin:test-api:7', payment.orderNum);
|
||||
assert.equal(await ctx.prepareDouyinPay('douyin'), false);
|
||||
assert.equal(await ctx.prepareDouyinPay('douyin'), state === 'closed');
|
||||
assert.equal(ctx.uni.storage.has('tb-douyin:test-api:7'), false);
|
||||
assert.equal(await ctx.prepareDouyinPay('douyin'), true);
|
||||
}
|
||||
});
|
||||
|
||||
test('closed old transaction unlocks a fresh server order, never reopens old parameters', async () => {
|
||||
let resets=0, opened;
|
||||
const ctx=await payContext({resetDypay:()=>resets++, request:async options => options.url === '/payment/douyin/resume'
|
||||
? {bizcode:100,data:{state:'closed',orderNum:'expired-order'}} : {bizcode:100,data:{state:2}},
|
||||
openDypay:(options,cb)=>{opened=options.payInfo.prepayid; cb({resultCode:'0'});}});
|
||||
ctx.uni.storage.set('tb-douyin:test-api:7','expired-order');
|
||||
assert.equal(await ctx.prepareDouyinPay('douyin'),true);
|
||||
assert.equal(resets,1);
|
||||
const fresh={...payment,orderNum:'fresh-order',douyin:{...payment.douyin,prepayId:'fresh-prepay'}};
|
||||
await ctx.appDypayFun(fresh);
|
||||
assert.equal(opened,'fresh-prepay');
|
||||
assert.equal(ctx.uni.storage.has('tb-douyin:test-api:7'),false);
|
||||
});
|
||||
|
||||
test('declining new payment or switching accounts after closure never creates a payment', async () => {
|
||||
for(const mode of ['cancel','account']) {
|
||||
const ctx=await payContext({request:async()=>({bizcode:100,data:{state:'closed',orderNum:'expired-order'}})});
|
||||
ctx.uni.storage.set('tb-douyin:test-api:7','expired-order');
|
||||
ctx.uni.showModal=options=>{
|
||||
if(mode==='account') ctx.uni.storage.set('user',{userId:8});
|
||||
options.success({confirm:mode!=='cancel'});
|
||||
};
|
||||
assert.equal(await ctx.prepareDouyinPay('douyin'),false);
|
||||
}
|
||||
});
|
||||
|
||||
test('unconfirmed server state never resets the native lock and explains why', async () => {
|
||||
const ctx=await payContext({resetDypay:()=>assert.fail('Unconfirmed native reset'),
|
||||
request:async()=>({bizcode:100,data:{state:'pending',reason:'QUERY_FAILED',orderNum:payment.orderNum}})});
|
||||
ctx.uni.storage.set('tb-douyin:test-api:7',payment.orderNum);
|
||||
assert.equal(await ctx.prepareDouyinPay('douyin'),false);
|
||||
assert.match(ctx.uni.messages.at(-1),/查单失败/);
|
||||
assert.equal(ctx.uni.storage.get('tb-douyin:test-api:7'),payment.orderNum);
|
||||
});
|
||||
|
||||
test('unpaid server confirmation resets a missing native callback before reinitializing SDK', async () => {
|
||||
const sequence=[];
|
||||
const ctx=await payContext({resetDypay:()=>sequence.push('reset'),initDypay:()=>{sequence.push('init');return true;},
|
||||
request:async()=>({bizcode:100,data:{state:'unpaid',orderNum:payment.orderNum,payment}}),
|
||||
queryUntilSettled:async()=>({state:'pending'})});
|
||||
ctx.uni.storage.set('tb-douyin:test-api:7',payment.orderNum);
|
||||
assert.equal(await ctx.prepareDouyinPay('douyin'),false);
|
||||
assert.deepEqual(sequence,['reset','init']);
|
||||
});
|
||||
|
||||
test('SDK rejection stays recoverable but no longer hides the native failure', async () => {
|
||||
const ctx=await payContext({openDypay:(_,cb)=>cb({resultCode:'103'}),queryUntilSettled:async()=>({state:'pending'})});
|
||||
await ctx.appDypayFun(payment);
|
||||
assert.match(ctx.uni.messages.at(-1),/原生支付仍在处理中/);
|
||||
assert.equal(ctx.uni.storage.get('tb-douyin:test-api:7'),payment.orderNum);
|
||||
assert.equal(ctx.uni.messages.includes('支付成功'),false);
|
||||
});
|
||||
|
||||
test('account switch during resume response or confirmation cannot invoke SDK', async () => {
|
||||
for (const phase of ['response','confirmation']) {
|
||||
const ctx = await payContext({openDypay:()=>assert.fail('Old account reached SDK')});
|
||||
|
||||
Reference in New Issue
Block a user