MatchMaster/server/laf-cloud/tests/shop-ab.test.cjs

66 lines
4.1 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const crypto = require('node:crypto');
const fs = require('node:fs');
const path = require('node:path');
const vm = require('node:vm');
const ts = require('typescript');
function load(file, deps = {}, globals = {}) {
const exports = {};
const source = fs.readFileSync(path.resolve(__dirname, '../functions', file), 'utf8');
const code = ts.transpileModule(source, { compilerOptions: { target:ts.ScriptTarget.ES2020, module:ts.ModuleKind.CommonJS } }).outputText;
vm.runInNewContext(code, { exports, require:name=>{
if (!(name in deps)) throw new Error('Missing test dependency: '+name);
return deps[name];
}, Date, ...globals });
return exports;
}
const ids = [1,2,3,4,5,6].map(i=>'new_gold_'+i).concat([8,18,36,68,98].map(i=>'new_unlimited_health_bundle_'+i));
const prices = [600,3000,6800,12800,32800,64800,800,1800,3600,6800,9800];
function fixture() {
const state={orders:[],requests:[],user:{_id:'u',openid:'o',session_key:'session'}};
const db={collection:()=>({add:async row=>{state.orders.push(row);return {};},where:()=>({getOne:async()=>({data:state.user}),update:async()=>({})})})};
const cloud={database:()=>db,shared:{get:()=> 'token'},storage:{bucket:()=>({readFile:async()=>({Body:{transformToString:async()=> 'synthetic-key'}})})}};
const deps={
'@lafjs/cloud':{default:cloud},
'@/limitedTimeEvent':{starterPackOrderSnapshot:()=>({})},
'@/passCheckUpgrade':{passOrderFields:()=>({}),PASS_PRICES:{}},
'@/jungleConfig':{getJunglePaidTierByProductId:()=>null},
crypto:{...crypto,default:{...crypto,createSign:()=>({update(){},sign:()=> 'synthetic-signature'})}}
};
const globals={console:{log(){},error(){}},process:{env:{PAYMENT_APP_ENV:'test',WX_MIDAS_PAY_SIGN_KEY:'synthetic-key'}},
fetch:async(url,options)=>{state.requests.push({url,body:JSON.parse(options.body)});return {ok:true,json:async()=>({prepay_id:'synthetic-prepay',errcode:0})};}};
return {state,load:file=>load(file,deps,globals).default};
}
test('both signing endpoints enforce all eleven B prices and quantity one', async()=>{
for(const file of ['wx/orderPaySig.ts','wx/iosorderPaySig.ts']) {
const f=fixture(), create=f.load(file);
for(const [i,id] of ids.entries()) {
const result=await create({body:{uid:'u',itemid:id,itemCount:99,itemPrice:1}});
assert.equal(result.code,1);
const signed=JSON.parse(result.data.signData), row=f.state.orders[i];
assert.equal(row.itemid,id);assert.equal(row.itemCount,1);assert.equal(row.goodsPrice,prices[i]);
assert.equal(signed.productId,id);assert.equal(signed.buyQuantity,1);assert.equal(signed.goodsPrice,prices[i]);
assert.equal(result.data.paySig,crypto.createHmac('sha256','synthetic-key').update('requestMidasPaymentGameItem&'+result.data.signData).digest('hex'));
}
const legacy=await create({body:{uid:'u',itemid:'gold_2',itemCount:1,itemPrice:3600}});
assert.equal(legacy.code,1);assert.equal(f.state.orders.at(-1).goodsPrice,3600);
}
});
test('legacy iOS cashier uses all B prices, display names and order IDs',async()=>{
const f=fixture(), create=f.load('wx/KeFuInfo.ts');
for(const [i,id] of ids.entries()) {
await create({body:{FromUserName:'o',SessionFrom:JSON.stringify({tpye:'ios',propName:id,price:1,count:99,outTradeNo:'ios-'+i})}});
const row=f.state.orders[i];assert.ok(row,'customer-service request must create order');
assert.equal(row.goodsPrice,prices[i]);assert.equal(row.itemCount,1);assert.equal(row.itemid,id);
const payments=f.state.requests.filter(r=>r.url.includes('/v3/pay/transactions/jsapi'));
assert.equal(payments[i].body.amount.total,prices[i]);
const link=f.state.requests.filter(r=>r.body.msgtype==='link')[i].body.link;
const data=JSON.parse(decodeURIComponent(link.url.split('#data=')[1]));
assert.equal(data.name,i < 6 ? '新版金币包'+(i+1) : '新版组合礼包'+[8,18,36,68,98][i-6]+'元');assert.equal(data.price,prices[i]);assert.equal(data.outTradeNo,'ios-'+i);
}
});