16ae7925e2
微信支付失败结果不再向 H5 透出原生错误 微信支付测试覆盖普通支付失败和虚拟支付取消的稳定文案 native shell 总门禁反查微信支付结果边界
191 lines
6.2 KiB
JavaScript
191 lines
6.2 KiB
JavaScript
import path from 'node:path';
|
|
|
|
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
|
|
import { loadCommonJsModule } from '../test-utils/loadCommonJsModule.js';
|
|
|
|
const payBridgePath = path.resolve(
|
|
process.cwd(),
|
|
'miniprogram/host-bridge/payment.js',
|
|
);
|
|
|
|
describe('wechat-pay mini program payment bridge', () => {
|
|
let wechatPayBridge;
|
|
|
|
beforeEach(() => {
|
|
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
globalThis.wx = {
|
|
requestPayment: vi.fn(),
|
|
requestVirtualPayment: vi.fn(),
|
|
getSystemInfoSync: vi.fn(() => ({ SDKVersion: '2.32.0' })),
|
|
setStorageSync: vi.fn(),
|
|
navigateBack: vi.fn(),
|
|
};
|
|
globalThis.getCurrentPages = vi.fn(() => []);
|
|
wechatPayBridge = loadCommonJsModule(payBridgePath);
|
|
});
|
|
|
|
test('routes virtual payloads to wx.requestVirtualPayment', async () => {
|
|
const { requestWechatPayment } = wechatPayBridge;
|
|
globalThis.wx.requestVirtualPayment.mockImplementationOnce((options) => {
|
|
options.success?.({ errMsg: 'requestVirtualPayment:ok' });
|
|
});
|
|
const payParams = {
|
|
mode: 'short_series_coin',
|
|
signData:
|
|
'{"offerId":"offer-1","buyQuantity":1,"env":0,"currencyType":"CNY","outTradeNo":"order-virtual-1","attach":"mud_points_60"}',
|
|
paySig: 'pay-sig',
|
|
signature: 'user-sig',
|
|
};
|
|
|
|
const result = await requestWechatPayment(payParams);
|
|
|
|
expect(result).toEqual({ status: 'success', errorMessage: '' });
|
|
expect(globalThis.wx.requestVirtualPayment).toHaveBeenCalledWith({
|
|
mode: 'short_series_coin',
|
|
signData: payParams.signData,
|
|
paySig: 'pay-sig',
|
|
signature: 'user-sig',
|
|
success: expect.any(Function),
|
|
fail: expect.any(Function),
|
|
});
|
|
expect(globalThis.wx.requestPayment).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('routes goods virtual payloads to wx.requestVirtualPayment', async () => {
|
|
const { requestWechatPayment } = wechatPayBridge;
|
|
globalThis.wx.requestVirtualPayment.mockImplementationOnce((options) => {
|
|
options.success?.({ errMsg: 'requestVirtualPayment:ok' });
|
|
});
|
|
const payParams = {
|
|
mode: 'short_series_goods',
|
|
signData:
|
|
'{"offerId":"offer-1","buyQuantity":1,"env":0,"currencyType":"CNY","productId":"member_month","goodsPrice":2800,"outTradeNo":"order-goods-1","attach":"member_month"}',
|
|
paySig: 'pay-sig',
|
|
signature: 'user-sig',
|
|
};
|
|
|
|
const result = await requestWechatPayment(payParams);
|
|
|
|
expect(result).toEqual({ status: 'success', errorMessage: '' });
|
|
expect(globalThis.wx.requestVirtualPayment).toHaveBeenCalledWith({
|
|
mode: 'short_series_goods',
|
|
signData: payParams.signData,
|
|
paySig: 'pay-sig',
|
|
signature: 'user-sig',
|
|
success: expect.any(Function),
|
|
fail: expect.any(Function),
|
|
});
|
|
expect(globalThis.wx.requestPayment).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('keeps ordinary requestPayment payloads on wx.requestPayment', async () => {
|
|
const { requestWechatPayment } = wechatPayBridge;
|
|
globalThis.wx.requestPayment.mockImplementationOnce((options) => {
|
|
options.success?.();
|
|
});
|
|
|
|
const result = await requestWechatPayment({
|
|
timeStamp: '1777110165',
|
|
nonceStr: 'nonce',
|
|
package: 'prepay_id=wx-prepay',
|
|
signType: 'RSA',
|
|
paySign: 'signature',
|
|
});
|
|
|
|
expect(result).toEqual({ status: 'success', errorMessage: '' });
|
|
expect(globalThis.wx.requestPayment).toHaveBeenCalledWith({
|
|
timeStamp: '1777110165',
|
|
nonceStr: 'nonce',
|
|
package: 'prepay_id=wx-prepay',
|
|
signType: 'RSA',
|
|
paySign: 'signature',
|
|
success: expect.any(Function),
|
|
fail: expect.any(Function),
|
|
});
|
|
expect(globalThis.wx.requestVirtualPayment).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('maps virtual payment cancel errCode to cancel result', async () => {
|
|
const { requestWechatPayment } = wechatPayBridge;
|
|
const payError = {
|
|
errCode: -2,
|
|
errMsg: 'requestVirtualPayment:fail cancel',
|
|
};
|
|
globalThis.wx.requestVirtualPayment.mockImplementationOnce((options) => {
|
|
options.fail?.(payError);
|
|
});
|
|
|
|
await expect(
|
|
requestWechatPayment({
|
|
mode: 'short_series_coin',
|
|
signData: '{}',
|
|
paySig: 'pay-sig',
|
|
signature: 'user-sig',
|
|
}),
|
|
).resolves.toEqual({
|
|
status: 'cancel',
|
|
errorMessage: 'wechat payment unavailable',
|
|
});
|
|
expect(console.error).toHaveBeenCalledWith(
|
|
'[wechat-pay] requestVirtualPayment failed',
|
|
payError,
|
|
);
|
|
});
|
|
|
|
test('hides ordinary payment native failure details from H5 result', async () => {
|
|
const { requestWechatPayment } = wechatPayBridge;
|
|
globalThis.wx.requestPayment.mockImplementationOnce((options) => {
|
|
options.fail?.({
|
|
errCode: 1001,
|
|
errMsg: 'requestPayment:fail private native detail',
|
|
});
|
|
});
|
|
|
|
await expect(
|
|
requestWechatPayment({
|
|
timeStamp: '1777110165',
|
|
nonceStr: 'nonce',
|
|
package: 'prepay_id=wx-prepay',
|
|
signType: 'RSA',
|
|
paySign: 'signature',
|
|
}),
|
|
).resolves.toEqual({
|
|
status: 'fail',
|
|
errorMessage: 'wechat payment unavailable',
|
|
});
|
|
});
|
|
|
|
test('notifies previous web-view after virtual payment', () => {
|
|
const { notifyPreviousWebView } = wechatPayBridge;
|
|
const previousPage = {
|
|
data: { webViewUrl: 'https://web.test/#tab=profile' },
|
|
setData: vi.fn(),
|
|
};
|
|
globalThis.getCurrentPages = vi.fn(() => [previousPage, {}]);
|
|
|
|
notifyPreviousWebView('request-1', 'order-1', {
|
|
status: 'success',
|
|
errorMessage: '',
|
|
});
|
|
|
|
expect(globalThis.wx.setStorageSync).toHaveBeenCalledWith(
|
|
'genarrative:wechat-pay-result',
|
|
'request-1:success:order-1',
|
|
);
|
|
expect(previousPage.setData).toHaveBeenCalledWith({
|
|
webViewUrl: 'https://web.test/#tab=profile&wx_pay_result=request-1%3Asuccess%3Aorder-1',
|
|
});
|
|
});
|
|
|
|
test('parsePayParams and appendPayResult keep existing behavior', () => {
|
|
const { appendPayResult, parsePayParams } = wechatPayBridge;
|
|
expect(parsePayParams(encodeURIComponent('{"paySign":"sig"}'))).toEqual({
|
|
paySign: 'sig',
|
|
});
|
|
expect(appendPayResult('https://web.test/#old=1', 'req:fail:order-1')).toBe(
|
|
'https://web.test/#old=1&wx_pay_result=req%3Afail%3Aorder-1',
|
|
);
|
|
});
|
|
});
|