mirror of
https://github.com/luanslimadev/Wand-Enhancer.git
synced 2026-08-28 17:01:05 +00:00
a0b3968d33
Reorganize the panel around product capabilities and integrate the remote i18n feature from origin/master into the new structure. - Restructure src into capability features (app, trainer, library, remote-session, appearance, shared); move the bridge to bridge/src. - Add lingui-based UI localization and wrap remaining user-facing strings (Trans / msg macros); fix the 'END В·' mojibake. - Port WeMod cheat-metadata i18n: capture the access token from the snapshot's renderer in the bridge and fetch localized trainer_meta in remote-session.i18n; guarantee snapshot sync on token failure. - Wire vitest to the app's lingui/preact pipeline (mergeConfig).
92 lines
2.8 KiB
TypeScript
92 lines
2.8 KiB
TypeScript
import { createServer } from 'node:net';
|
|
import { describe, expect, it } from 'vitest';
|
|
import { WebSocket as NodeWebSocket } from 'ws';
|
|
|
|
describe('production bridge runtime', () => {
|
|
it('preserves the public API and sends cached snapshots after hello', async () => {
|
|
const bridge = require('../../dist/bridge.cjs');
|
|
expect(Object.keys(bridge).sort()).toEqual(['createBridgeRuntime', 'ensureBridge', 'installWandRuntime']);
|
|
|
|
const port = await getFreePort();
|
|
const runtime = bridge.createBridgeRuntime({ host: '127.0.0.1', port, maxPort: port });
|
|
runtime.sync(rawTrainerSnapshot());
|
|
|
|
try {
|
|
await waitUntil(() => runtime.listening);
|
|
const messages = await connectAndCollect(port, 3);
|
|
expect(messages.map((message) => message.type)).toEqual(['hello_ack', 'trainer_meta', 'trainer_values']);
|
|
expect(messages[2].payload.values.god).toBe(true);
|
|
} finally {
|
|
runtime.close();
|
|
}
|
|
});
|
|
});
|
|
|
|
async function getFreePort(): Promise<number> {
|
|
return await new Promise((resolve, reject) => {
|
|
const server = createServer();
|
|
server.once('error', reject);
|
|
server.listen(0, '127.0.0.1', () => {
|
|
const address = server.address();
|
|
const port = typeof address === 'object' && address ? address.port : 0;
|
|
server.close((error) => error ? reject(error) : resolve(port));
|
|
});
|
|
});
|
|
}
|
|
|
|
async function connectAndCollect(port: number, count: number): Promise<any[]> {
|
|
return await new Promise((resolve, reject) => {
|
|
const messages: any[] = [];
|
|
const socket = new NodeWebSocket(`ws://127.0.0.1:${port}/remote/ws`);
|
|
socket.once('error', reject);
|
|
socket.once('open', () => socket.send(JSON.stringify({
|
|
type: 'hello',
|
|
version: 1,
|
|
requestId: 'hello',
|
|
payload: {
|
|
client: 'mobile-web',
|
|
clientVersion: 'test',
|
|
capabilities: { supportsDeltaValues: true, supportsTrainerSwitch: true },
|
|
},
|
|
})));
|
|
socket.on('message', (raw) => {
|
|
messages.push(JSON.parse(String(raw)));
|
|
if (messages.length === count) {
|
|
socket.close();
|
|
resolve(messages);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
async function waitUntil(predicate: () => boolean): Promise<void> {
|
|
const deadline = Date.now() + 3000;
|
|
while (!predicate()) {
|
|
if (Date.now() > deadline) throw new Error('Bridge did not start listening.');
|
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
}
|
|
}
|
|
|
|
function rawTrainerSnapshot() {
|
|
return {
|
|
instanceId: 'instance',
|
|
trainerId: 'trainer',
|
|
trainerInfo: { gameId: 'game', displayName: 'Game' },
|
|
metadata: {
|
|
info: {
|
|
blueprint: {
|
|
cheats: [{
|
|
uuid: 'god',
|
|
target: 'god',
|
|
type: 'toggle',
|
|
name: 'God mode',
|
|
category: 'player',
|
|
args: {},
|
|
}],
|
|
},
|
|
},
|
|
},
|
|
values: { god: 1 },
|
|
};
|
|
}
|