diff --git a/miniprogram/host-bridge/payment.js b/miniprogram/host-bridge/payment.js index 0426a8bc4..f0fd71630 100644 --- a/miniprogram/host-bridge/payment.js +++ b/miniprogram/host-bridge/payment.js @@ -64,21 +64,8 @@ function resolvePayStatus(error) { return errCode === -2 || /cancel/i.test(errMsg) ? 'cancel' : 'fail'; } -function normalizePayError(error) { - if (!error) { - return ''; - } - if (typeof error === 'string') { - return error; - } - try { - return JSON.stringify({ - errCode: error.errCode, - errMsg: error.errMsg, - }); - } catch (_error) { - return String(error.errMsg || error); - } +function normalizePayError() { + return 'wechat payment unavailable'; } function requestOrdinaryPayment(payParams) { diff --git a/miniprogram/host-bridge/payment.test.js b/miniprogram/host-bridge/payment.test.js index 3cb7f2a2f..5894ee779 100644 --- a/miniprogram/host-bridge/payment.test.js +++ b/miniprogram/host-bridge/payment.test.js @@ -125,10 +125,7 @@ describe('wechat-pay mini program payment bridge', () => { }), ).resolves.toEqual({ status: 'cancel', - errorMessage: JSON.stringify({ - errCode: -2, - errMsg: 'requestVirtualPayment:fail cancel', - }), + errorMessage: 'wechat payment unavailable', }); expect(console.error).toHaveBeenCalledWith( '[wechat-pay] requestVirtualPayment failed', @@ -136,6 +133,29 @@ describe('wechat-pay mini program payment bridge', () => { ); }); + 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 = { diff --git a/scripts/check-native-shells.mjs b/scripts/check-native-shells.mjs index bcc3eaee5..494e8125d 100644 --- a/scripts/check-native-shells.mjs +++ b/scripts/check-native-shells.mjs @@ -1874,6 +1874,41 @@ function assertWechatMiniProgramCapabilityFlows() { } } +function assertWechatPaymentResultBoundaries() { + const paymentSource = fs.readFileSync( + 'miniprogram/host-bridge/payment.js', + 'utf8', + ); + const paymentTestSource = fs.readFileSync( + 'miniprogram/host-bridge/payment.test.js', + 'utf8', + ); + + for (const snippet of [ + "function normalizePayError()", + "return 'wechat payment unavailable'", + ]) { + if (!paymentSource.includes(snippet)) { + throw new Error(`wechat payment bridge must include ${snippet}`); + } + } + if ( + paymentSource.includes('JSON.stringify({\n errCode') || + paymentSource.includes('String(error.errMsg || error)') + ) { + throw new Error('wechat payment bridge must not expose native payment errors to H5'); + } + for (const snippet of [ + 'maps virtual payment cancel errCode to cancel result', + 'hides ordinary payment native failure details from H5 result', + "errorMessage: 'wechat payment unavailable'", + ]) { + if (!paymentTestSource.includes(snippet)) { + throw new Error(`wechat payment bridge test must include ${snippet}`); + } + } +} + function assertHostBridgeLayerLayout() { assertSameList( readDirectoryFileList( @@ -2101,6 +2136,9 @@ assertWechatMiniProgramRouteParity(); console.log('[check:native-shells] wechat-mini-program-capability-flows'); assertWechatMiniProgramCapabilityFlows(); +console.log('[check:native-shells] wechat-payment-result-boundaries'); +assertWechatPaymentResultBoundaries(); + console.log('[check:native-shells] h5-host-bridge-event-subscription-gates'); assertH5HostBridgeEventSubscriptionGates();