'use strict'; const assert = require('node:assert/strict'); const { queryBilling } = require('../mcp/src/core/billing-client'); const { requestPaymentQr } = require('../mcp/src/core/recharge-client'); async function main() { const originalFetch = global.fetch; let billingCalls = 0; global.fetch = async (url, options) => { if (/\/api\/fmode\/billing\/query$/.test(String(url))) { billingCalls += 1; assert.equal(options.method, 'POST'); assert.match(options.headers.Authorization, /^Bearer sk-test$/); return new Response(JSON.stringify({ code: 200, data: { balance: { availableQuota: 1000 }, balanceUrl: billingCalls > 1 ? 'https://app.fmode.cn/dev/studio/balance/?token=r%3Asession-test' : null, estimate: { quota: 2000, amountCny: 1, shortfallQuota: 1000, suggestedRechargeCny: 1.1, sufficient: false, operations: [] }, catalog: [] } }), { status: 200, headers: { 'content-type': 'application/json' } }); } assert.match(String(url), /\/parse\/functions\/pay_code2$/); assert.equal(options.method, 'POST'); assert.match(options.headers['X-Parse-Session-Token'], /^r:/); return new Response(JSON.stringify({ code_url: ['weixin://pay/query-test'], nonce_str: 'nonce-query' }), { status: 200 }); }; const result = await queryBilling({ newapiToken: 'sk-test', baseUrl: 'https://billing.example.test', operations: [{ model: 'voc-social', count: 1 }] }); assert.equal(result.status, 'ok'); if (result.recharge) { assert.equal(result.recharge.paymentMode, 'balance_url_and_payment_request'); assert.equal(Object.prototype.hasOwnProperty.call(result.recharge.paymentRequest, 'headers'), false); assert.doesNotMatch(JSON.stringify(result), /r:[A-Za-z0-9_-]{8,}/); } const qrResult = await queryBilling({ newapiToken: 'sk-test', sessionToken: 'r:session-test', baseUrl: 'https://billing.example.test', createPaymentQr: true, operations: [{ model: 'voc-social', count: 1 }] }); assert.equal(qrResult.status, 'ok'); assert.equal(qrResult.recharge.paymentMode, 'qr_and_balance_url'); assert.equal(qrResult.recharge.qrCodeUrl, 'weixin://pay/query-test'); assert.equal(qrResult.recharge.paymentRequest.nonceStr, 'nonce-query'); assert.doesNotMatch(JSON.stringify(qrResult.recharge.paymentRequest), /r:[A-Za-z0-9_-]{8,}/); const qr = await requestPaymentQr({ amount: 2, sessionToken: 'r:session-test', fetchImpl: async (_url, options) => { assert.match(options.headers['X-Parse-Session-Token'], /^r:/); return new Response(JSON.stringify({ code_url: ['weixin://pay/test'], nonce_str: 'nonce' }), { status: 200 }); } }); assert.equal(qr.qrCodeUrl, 'weixin://pay/test'); assert.equal(qr.amountCny, 2); global.fetch = originalFetch; console.log('billing-client smoke passed'); } main().catch(error => { console.error(error); process.exitCode = 1; });