界面迁移更新
This commit is contained in:
+116
@@ -0,0 +1,116 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { resolveBootstrap } from '../../YouleNexus/assets/framework/config/bootstrap.ts';
|
||||
import { BUILD_IDENTITY } from '../../YouleNexus/assets/framework/config/sources/defaults.ts';
|
||||
import type { ConfigFetcher, RemoteConfig } from '../../YouleNexus/assets/framework/config/remote-config.ts';
|
||||
import { PROFILES } from '../../YouleNexus/assets/framework/config/profiles.ts';
|
||||
|
||||
function fetcherReturning(config: RemoteConfig): ConfigFetcher & { calls: string[] } {
|
||||
const calls: string[] = [];
|
||||
return { calls, fetch: async (url: string) => { calls.push(url); return config; } };
|
||||
}
|
||||
const throwingFetcher: ConfigFetcher = {
|
||||
fetch: async () => { throw new Error('net down'); },
|
||||
};
|
||||
|
||||
const REMOTE: RemoteConfig = { data: { player_server_tcp: '5.5.5.5:5000' } };
|
||||
|
||||
test('debug + profile=local:用 profile.server 直连,不抓远程', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE);
|
||||
const r = await resolveBootstrap({ mode: 'debug', win: {}, search: '?profile=local', fetcher, isNative: false });
|
||||
assert.deepEqual(r.servers, ['ws://127.0.0.1:3088']);
|
||||
assert.equal(r.rawConfig, null);
|
||||
assert.equal(fetcher.calls.length, 0);
|
||||
});
|
||||
|
||||
test('debug + prod + H5:抓远程配置产出 servers,identity 来自 defaults', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE);
|
||||
const r = await resolveBootstrap({ mode: 'debug', win: {}, search: '', fetcher, isNative: false });
|
||||
assert.deepEqual(r.servers, ['ws://5.5.5.5:5000']);
|
||||
assert.equal(r.identity.agentid, BUILD_IDENTITY.agentid);
|
||||
assert.equal(r.identity.gameid, BUILD_IDENTITY.gameid);
|
||||
assert.equal(fetcher.calls.length, 1);
|
||||
});
|
||||
|
||||
test('debug + H5 显式 URL query 覆盖身份(最高优先级)', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE);
|
||||
const r = await resolveBootstrap({ mode: 'debug', win: {}, search: '?agentid=999&channelid=C9', fetcher, isNative: false });
|
||||
assert.equal(r.identity.agentid, '999');
|
||||
assert.equal(r.identity.channelid, 'C9');
|
||||
});
|
||||
|
||||
test('debug + 原生模式:identity 来自 window.settings', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE);
|
||||
const win = { settings: { getothername: () => 'NA', getchannelName: () => 'NC', getmarketname: () => 3 } };
|
||||
const r = await resolveBootstrap({ mode: 'debug', win, search: '', fetcher, isNative: true });
|
||||
assert.equal(r.identity.agentid, 'NA');
|
||||
assert.equal(r.identity.channelid, 'NC');
|
||||
assert.equal(r.identity.marketid, 3);
|
||||
});
|
||||
|
||||
test('远程抓取失败 → 抛 ConfigFetchError(不兜底)', async () => {
|
||||
await assert.rejects(
|
||||
resolveBootstrap({ mode: 'debug', win: {}, search: '', fetcher: throwingFetcher, isNative: false }),
|
||||
/远程配置抓取失败/,
|
||||
);
|
||||
});
|
||||
|
||||
test('远程配置未给出可用服务器地址 → 抛错(不兜底)', async () => {
|
||||
const emptyFetcher: ConfigFetcher = { fetch: async () => ({ data: {} }) };
|
||||
await assert.rejects(
|
||||
resolveBootstrap({ mode: 'debug', win: {}, search: '', fetcher: emptyFetcher, isNative: false }),
|
||||
/未给出可用服务器/,
|
||||
);
|
||||
});
|
||||
|
||||
test('debug 结果含 mode/isDebugger', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE);
|
||||
const r = await resolveBootstrap({ mode: 'debug', win: {}, search: '', fetcher, isNative: false });
|
||||
assert.equal(r.mode, 'debug');
|
||||
assert.equal(r.isDebugger, true);
|
||||
});
|
||||
|
||||
test('release:忽略所有 URL 覆盖,强制 prod,identity 不被 URL 改', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE);
|
||||
const r = await resolveBootstrap({ mode: 'release', win: {}, search: '?profile=local&agentid=999', fetcher, isNative: false });
|
||||
assert.equal(r.profile.name, 'prod');
|
||||
assert.deepEqual(r.servers, ['ws://5.5.5.5:5000']); // 走远程,不是 local 直连
|
||||
assert.equal(r.identity.agentid, BUILD_IDENTITY.agentid); // 999 无效
|
||||
assert.equal(r.isDebugger, false);
|
||||
assert.equal(r.mode, 'release');
|
||||
assert.equal(fetcher.calls.length, 1);
|
||||
});
|
||||
|
||||
test('release:原生身份仍生效(URL 的 999 无效)', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE);
|
||||
const win = { settings: { getothername: () => 'NA', getchannelName: () => 'NC', getmarketname: () => 3 } };
|
||||
const r = await resolveBootstrap({ mode: 'release', win, search: '?agentid=999', fetcher, isNative: true });
|
||||
assert.equal(r.identity.agentid, 'NA');
|
||||
assert.equal(r.identity.channelid, 'NC');
|
||||
});
|
||||
|
||||
test('debug + serverOverride:走远程全链路但连接地址覆盖为本地', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE); // REMOTE.player_server_tcp = 5.5.5.5:5000
|
||||
const r = await resolveBootstrap({ mode: 'debug', win: {}, search: '?profile=staging', fetcher, isNative: false });
|
||||
assert.deepEqual(r.servers, [PROFILES.staging.serverOverride]); // 覆盖为 profile.serverOverride
|
||||
assert.ok(r.rawConfig); // 远程配置仍抓取(全链路)
|
||||
assert.equal(fetcher.calls.length, 1);
|
||||
});
|
||||
|
||||
test('release:serverOverride 不生效(强制 prod,用远程解析地址)', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE);
|
||||
const r = await resolveBootstrap({ mode: 'release', win: {}, search: '?profile=staging', fetcher, isNative: true });
|
||||
assert.deepEqual(r.servers, ['ws://5.5.5.5:5000']); // prod 无 override,用远程解析
|
||||
});
|
||||
|
||||
test('debug:account 来自当前 profile', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE);
|
||||
const r = await resolveBootstrap({ mode: 'debug', win: {}, search: '?profile=staging', fetcher, isNative: false });
|
||||
assert.deepEqual(r.account, PROFILES.staging.account);
|
||||
});
|
||||
|
||||
test('release:account 恒为 undefined(不从调试配置泄漏账号)', async () => {
|
||||
const fetcher = fetcherReturning(REMOTE);
|
||||
const r = await resolveBootstrap({ mode: 'release', win: {}, search: '?profile=staging', fetcher, isNative: true });
|
||||
assert.equal(r.account, undefined);
|
||||
});
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { resolveIdentity } from '../../YouleNexus/assets/framework/config/identity.ts';
|
||||
import { BUILD_IDENTITY } from '../../YouleNexus/assets/framework/config/sources/defaults.ts';
|
||||
|
||||
test('BUILD_IDENTITY 含全部字段且 gameid 为固定 token', () => {
|
||||
assert.ok(BUILD_IDENTITY.gameid.length > 0);
|
||||
assert.ok('agentid' in BUILD_IDENTITY);
|
||||
assert.ok('channelid' in BUILD_IDENTITY);
|
||||
assert.ok('marketid' in BUILD_IDENTITY);
|
||||
assert.equal(typeof BUILD_IDENTITY.version, 'number'); // 协议 version = 数字 versionCode
|
||||
});
|
||||
|
||||
test('resolveIdentity:后面的 source 覆盖前面的', () => {
|
||||
const id = resolveIdentity([
|
||||
() => BUILD_IDENTITY,
|
||||
() => ({ agentid: 'A2' }),
|
||||
() => ({ agentid: 'A3', channelid: 'C3' }),
|
||||
]);
|
||||
assert.equal(id.agentid, 'A3');
|
||||
assert.equal(id.channelid, 'C3');
|
||||
assert.equal(id.gameid, BUILD_IDENTITY.gameid); // 未被覆盖
|
||||
});
|
||||
|
||||
test('resolveIdentity:undefined / null / 空串 不覆盖', () => {
|
||||
const id = resolveIdentity([
|
||||
() => BUILD_IDENTITY,
|
||||
() => ({ agentid: undefined as any, channelid: '' , marketid: null as any }),
|
||||
]);
|
||||
assert.equal(id.agentid, BUILD_IDENTITY.agentid);
|
||||
assert.equal(id.channelid, BUILD_IDENTITY.channelid);
|
||||
assert.equal(id.marketid, BUILD_IDENTITY.marketid);
|
||||
});
|
||||
|
||||
test('resolveIdentity:marketid=0 是有效值,应覆盖', () => {
|
||||
const id = resolveIdentity([() => BUILD_IDENTITY, () => ({ marketid: 0 })]);
|
||||
assert.equal(id.marketid, 0);
|
||||
});
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { resolveActiveProfile, PROFILES, ACTIVE_PROFILE } from '../../YouleNexus/assets/framework/config/profiles.ts';
|
||||
|
||||
test('默认返回 ACTIVE_PROFILE', () => {
|
||||
const p = resolveActiveProfile('');
|
||||
assert.equal(p.name, ACTIVE_PROFILE);
|
||||
});
|
||||
|
||||
test('prod profile 无调试覆盖、isDebugger=false', () => {
|
||||
const prod = PROFILES['prod'];
|
||||
assert.equal(prod.isDebugger, false);
|
||||
assert.equal(prod.server, undefined);
|
||||
assert.equal(prod.identity, undefined);
|
||||
assert.ok(prod.gameserver && prod.gameserver.length > 0);
|
||||
});
|
||||
|
||||
test('?profile=local 切到 local,含调试服地址', () => {
|
||||
const p = resolveActiveProfile('?profile=local');
|
||||
assert.equal(p.name, 'local');
|
||||
assert.ok(p.server && p.server.startsWith('ws://'));
|
||||
});
|
||||
|
||||
test('未知 profile 回退到 ACTIVE_PROFILE', () => {
|
||||
const p = resolveActiveProfile('?profile=nope');
|
||||
assert.equal(p.name, ACTIVE_PROFILE);
|
||||
});
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { getParam, resolveServers, type RemoteConfig } from '../../YouleNexus/assets/framework/config/remote-config.ts';
|
||||
import type { ChannelIdentity } from '../../YouleNexus/assets/framework/config/identity.ts';
|
||||
|
||||
const ID: ChannelIdentity = { agentid: 'A', channelid: 'C', gameid: 'G', marketid: 2, version: 1 };
|
||||
|
||||
const CONFIG: RemoteConfig = {
|
||||
data: {
|
||||
player_server_tcp: '1.1.1.1:1000', // 顶层默认
|
||||
agentlist: [{
|
||||
agentid: 'A',
|
||||
player_server_tcp: '2.2.2.2:2000', // agent 级覆盖
|
||||
gamelist: [{
|
||||
gameid: 'G',
|
||||
channellist: [{
|
||||
channelid: 'C',
|
||||
player_server_tcp: '3.3.3.3:3000', // channel 级覆盖(最具体)
|
||||
visitor_server_tcp: '4.4.4.4:4000',
|
||||
marketlist: [{ marketid: 2 }],
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
};
|
||||
|
||||
test('getParam:最具体层级胜出', () => {
|
||||
assert.equal(getParam(CONFIG, 'player_server_tcp', ID), '3.3.3.3:3000');
|
||||
});
|
||||
|
||||
test('getParam:channel 未匹配时回退到 agent 级值', () => {
|
||||
const id2 = { ...ID, channelid: 'OTHER' };
|
||||
assert.equal(getParam(CONFIG, 'player_server_tcp', id2), '2.2.2.2:2000');
|
||||
});
|
||||
|
||||
test('getParam:agent 未匹配时回退到顶层默认', () => {
|
||||
const id3 = { ...ID, agentid: 'NONE' };
|
||||
assert.equal(getParam(CONFIG, 'player_server_tcp', id3), '1.1.1.1:1000');
|
||||
});
|
||||
|
||||
test('getParam:键不存在 → null', () => {
|
||||
assert.equal(getParam(CONFIG, 'not_a_key', ID), null);
|
||||
});
|
||||
|
||||
test('getParam:无 data → null', () => {
|
||||
assert.equal(getParam({}, 'player_server_tcp', ID), null);
|
||||
});
|
||||
|
||||
test('resolveServers:player 优先、visitor 回退,前缀 ws://', () => {
|
||||
assert.deepEqual(resolveServers(CONFIG, ID), ['ws://3.3.3.3:3000', 'ws://4.4.4.4:4000']);
|
||||
});
|
||||
|
||||
test('resolveServers:已带 ws:// 不重复前缀;无地址 → 空数组', () => {
|
||||
const cfg: RemoteConfig = { data: { player_server_tcp: 'ws://9.9.9.9:9' } };
|
||||
assert.deepEqual(resolveServers(cfg, ID), ['ws://9.9.9.9:9']);
|
||||
assert.deepEqual(resolveServers({ data: {} }, ID), []);
|
||||
});
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { resolveRuntimeMode } from '../../YouleNexus/assets/framework/config/runtime-mode.ts';
|
||||
|
||||
test('override 优先于构建类型', () => {
|
||||
assert.equal(resolveRuntimeMode(true, 'release'), 'release');
|
||||
assert.equal(resolveRuntimeMode(false, 'debug'), 'debug');
|
||||
});
|
||||
|
||||
test('无 override:debug 构建 → debug', () => {
|
||||
assert.equal(resolveRuntimeMode(true, null), 'debug');
|
||||
});
|
||||
|
||||
test('无 override:release 构建 → release', () => {
|
||||
assert.equal(resolveRuntimeMode(false, null), 'release');
|
||||
});
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { nativeSettingsSource } from '../../../YouleNexus/assets/framework/config/sources/native-settings.ts';
|
||||
|
||||
test('优先从 window.settings 读取 agentid/channelid/marketid', () => {
|
||||
const win = {
|
||||
settings: {
|
||||
getothername: (name: string) => (name === 'agent' ? 'NA' : ''),
|
||||
getchannelName: () => 'NC',
|
||||
getmarketname: () => 7,
|
||||
},
|
||||
};
|
||||
assert.deepEqual(nativeSettingsSource(win)(), { agentid: 'NA', channelid: 'NC', marketid: 7 });
|
||||
});
|
||||
|
||||
test('settings 抛错时回退到全局 app_agent / app_market', () => {
|
||||
const win: any = {
|
||||
settings: { getothername: () => { throw new Error('no bridge'); },
|
||||
getchannelName: () => { throw new Error('no bridge'); },
|
||||
getmarketname: () => { throw new Error('no bridge'); } },
|
||||
app_agent: 'GA',
|
||||
app_market: 5,
|
||||
};
|
||||
assert.deepEqual(nativeSettingsSource(win)(), { agentid: 'GA', marketid: 5 });
|
||||
});
|
||||
|
||||
test('完全无原生注入 → 空对象', () => {
|
||||
assert.deepEqual(nativeSettingsSource({})(), {});
|
||||
});
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { queryStringSource } from '../../../YouleNexus/assets/framework/config/sources/query-string.ts';
|
||||
|
||||
test('解析 agentid/channelid/marketid/version', () => {
|
||||
const src = queryStringSource('?agentid=A1&channelid=C1&marketid=2&version=10001');
|
||||
assert.deepEqual(src(), { agentid: 'A1', channelid: 'C1', marketid: '2', version: 10001 }); // version 解析为数字
|
||||
});
|
||||
|
||||
test('缺省键不出现在结果里', () => {
|
||||
const src = queryStringSource('?agentid=A1');
|
||||
assert.deepEqual(src(), { agentid: 'A1' });
|
||||
});
|
||||
|
||||
test('空 query → 空对象', () => {
|
||||
assert.deepEqual(queryStringSource('')(), {});
|
||||
});
|
||||
|
||||
test('不含前导 ? 也能解析', () => {
|
||||
assert.deepEqual(queryStringSource('agentid=A1')(), { agentid: 'A1' });
|
||||
});
|
||||
Reference in New Issue
Block a user