137 lines
7.0 KiB
JavaScript
137 lines
7.0 KiB
JavaScript
// 段位多语言集成回归:请求使用本地桩,缓存通过真实 Pinia 持久化插件恢复。
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { createPinia, defineStore } = require('pinia');
|
|
const { createSSRApp } = require('vue');
|
|
const persist = require('pinia-plugin-persistedstate').default;
|
|
const root = path.resolve(__dirname, '..');
|
|
const read = file => fs.readFileSync(path.join(root, file), 'utf8');
|
|
const requests = [];
|
|
let hasToken = true;
|
|
let nextFailure;
|
|
const rank = {rankLvl: 1, rankName: 'Bronze I', rankIcon: 'https://example.test/青铜1.png'};
|
|
const apiUni = {
|
|
getAccountInfoSync: () => ({miniProgram: {envVersion: 'trial'}}),
|
|
getStorageSync: key => hasToken && key === 'trial_token' ? 'existing-token' : '',
|
|
request(options) {
|
|
requests.push(options);
|
|
if (options.url.endsWith('/user/device/aimRenew')) return {};
|
|
if (nextFailure) {
|
|
const error = nextFailure;
|
|
nextFailure = undefined;
|
|
options.success({statusCode: 200, data: error});
|
|
return;
|
|
}
|
|
const data = options.url.includes('/myHome')
|
|
? {...rank, user: {id: 42, scores: 150, rankLvl: 1, nickName: '原昵称'}}
|
|
: {list: [{...rank}], randInfos: [{rank_id: 1, upgrade_scores: 100, name: 'Bronze I', icoin: rank.rankIcon}]};
|
|
options.success({statusCode: 200, data: {code: 0, data}});
|
|
},
|
|
};
|
|
const apiCode = read('src/apis.js').replace(/^import .*;\r?\n/gm, '').replace(/^export /gm, '');
|
|
const api = new Function('uni', 't', 'normalizeBattleApiResult', apiCode + `
|
|
return {request, getAppConfig, getHomeData, getScoreRankList, getTenRingRankList, getMvpRankList,
|
|
getMyScoreRank, getMyTenRingRank, getMyMvpRank, getSeasonStats, getProvinceData, getDailyCountAPI, aimRenewAPI};
|
|
`)(apiUni, key => key, data => data);
|
|
|
|
const storeCode = read('src/store.js').replace(/^import .*;\r?\n/gm, '').replace('export default defineStore', 'return defineStore');
|
|
function restore(cached) {
|
|
const storage = new Map([
|
|
['store', JSON.stringify(cached)],
|
|
['trial_token', 'existing-token'],
|
|
['point-book', JSON.stringify({draft: true})],
|
|
]);
|
|
const uni = {getStorageSync: key => storage.get(key), setStorageSync: (key, value) => storage.set(key, value)};
|
|
const useStore = new Function('defineStore', 'uni', storeCode)(defineStore, uni);
|
|
const pinia = createPinia();
|
|
pinia.use(persist);
|
|
createSSRApp({}).use(pinia);
|
|
return {store: useStore(pinia), storage};
|
|
}
|
|
|
|
async function main() {
|
|
const config = await api.getAppConfig();
|
|
const home = await api.getHomeData(42);
|
|
await api.getScoreRankList(42, 2, 20);
|
|
await api.getTenRingRankList(42, 2, 20);
|
|
await api.getMvpRankList(42, 2, 20);
|
|
await api.getMyScoreRank(42);
|
|
await api.getMyTenRingRank(42);
|
|
await api.getMyMvpRank(42);
|
|
await api.getSeasonStats(0);
|
|
await api.request('GET', '/index/myHome?seasonId=42');
|
|
for (const request of requests) {
|
|
assert.equal(request.header['Accept-Language'], 'en-US');
|
|
assert.equal(request.header.Authorization, 'Bearer existing-token');
|
|
assert.equal(request.method, 'GET');
|
|
assert(request.url.startsWith('https://apitest.shelingxingqiu.com/api/shoot/'));
|
|
}
|
|
assert(requests[1].url.endsWith('/user/myHome?seasonId=42'), 'Existing home route must remain unchanged');
|
|
assert.deepEqual(requests[2].data, {seasonId: 42, page: 2, perPage: 20});
|
|
assert.deepEqual(requests[8].data, {seasonId: 0});
|
|
assert.equal(home.user.rankName, rank.rankName);
|
|
assert.equal(home.user.rankIcon, rank.rankIcon);
|
|
assert.equal(home.user.nickName, '原昵称');
|
|
await api.getProvinceData();
|
|
await api.getDailyCountAPI();
|
|
await api.request('GET', '/index/appConfig/other');
|
|
await api.request('POST', '/index/appConfig');
|
|
await api.request('PUT', '/test/update', {value: 0});
|
|
await api.request('DELETE', '/test/delete', {id: 42});
|
|
for (const request of requests.slice(10)) {
|
|
assert.equal(request.header['Accept-Language'], 'en-US', 'All HTTP requests must declare English');
|
|
assert.equal(request.header.Authorization, 'Bearer existing-token');
|
|
}
|
|
assert.deepEqual(requests.at(-2).data, {value: 0});
|
|
assert.deepEqual(requests.at(-1).data, {id: 42});
|
|
// 续期请求即使未收到响应,也必须保持同步返回且不弹失败提示。
|
|
assert.equal(api.aimRenewAPI(), undefined);
|
|
assert.equal(requests.at(-1).header['Accept-Language'], 'en-US');
|
|
assert.equal(requests.at(-1).header.Authorization, 'Bearer existing-token');
|
|
assert.equal(requests.at(-1).method, 'POST');
|
|
assert.deepEqual(requests.at(-1).data, {});
|
|
assert.equal(requests.at(-1).timeout, 10000);
|
|
assert.equal(requests.at(-1).fail({errMsg: 'timeout'}), undefined);
|
|
hasToken = false;
|
|
await api.getAppConfig();
|
|
assert.deepEqual(requests.at(-1).header, {'Accept-Language': 'en-US'});
|
|
assert.equal(api.aimRenewAPI(), undefined);
|
|
assert.deepEqual(requests.at(-1).header, {'Accept-Language': 'en-US'});
|
|
hasToken = true;
|
|
nextFailure = {code: 400, message: '设备未连接', data: {reason: 'offline'}};
|
|
await assert.rejects(api.request('POST', '/test/error', {}, undefined, undefined, {showErrorToast: false}),
|
|
error => error.code === 400 && error.message === '设备未连接' && error.data.reason === 'offline');
|
|
assert.equal(requests.at(-1).header['Accept-Language'], 'en-US');
|
|
|
|
const legacy = {
|
|
user: {id: 42, nickName: '原昵称', avatar: 'avatar.png', trio: 1, scores: 150, rankLvl: 1,
|
|
lvlName: '倔强青铜I', rankName: '倔强青铜I', nextRankName: '倔强青铜II',
|
|
rankIcon: rank.rankIcon, nextRankIcon: 'next.png', lvlImage: 'level.png', vip: true},
|
|
device: {deviceId: 'unchanged-device', deviceName: '我的弓'},
|
|
};
|
|
const {store, storage} = restore(legacy);
|
|
for (const [field, value] of Object.entries(legacy.user)) {
|
|
assert.deepEqual(store.user[field], ['lvlName','rankName','nextRankName'].includes(field) ? '' : value);
|
|
}
|
|
assert.deepEqual({...store.device}, legacy.device);
|
|
assert.equal(storage.get('trial_token'), 'existing-token');
|
|
assert.equal(storage.get('point-book'), JSON.stringify({draft: true}));
|
|
assert.deepEqual([...storage.keys()].sort(), ['store', 'trial_token', 'point-book'].sort());
|
|
await store.updateConfig(config);
|
|
await store.updateUser(home.user);
|
|
assert.equal(store.user.rankName, 'Bronze I');
|
|
assert.equal(store.user.lvlName, 'Bronze I');
|
|
assert.equal(store.user.scores, 150);
|
|
assert.equal(store.user.rankLvl, 1);
|
|
store.$persist();
|
|
const next = restore(JSON.parse(storage.get('store'))).store;
|
|
assert.equal(next.user.rankName, 'Bronze I', 'English cached labels must survive cold start');
|
|
assert.equal(next.user.lvlName, 'Bronze I');
|
|
assert.equal(next.user.nickName, '原昵称');
|
|
assert.deepEqual({...next.device}, legacy.device);
|
|
assert.equal(restore({user: {id: 7, rankName: '', lvlName: null}, device: {}}).store.user.lvlName, null);
|
|
console.log('Rank i18n checks passed: global HTTP English headers (GET/POST/PUT/DELETE + aim renewal), auth/query/pagination and original errors preserved; non-blocking renewal and real Pinia cache hydration verified.');
|
|
}
|
|
main().catch(error => {console.error(error); process.exitCode = 1;});
|