feat: add server and frontend initial - wood chopping
This commit is contained in:
+49
-19
@@ -1,38 +1,68 @@
|
||||
/* Дымовой тест M0: сервер должен быть запущен. `pnpm --filter @idle/server smoke` */
|
||||
/* Дымовой тест M1: сервер должен быть запущен с DEV_HTTP=1, SQLITE_PATH=:memory:.
|
||||
`pnpm --filter @idle/server smoke` */
|
||||
import WebSocket from 'ws';
|
||||
|
||||
const seen = [];
|
||||
const BASE = 'http://localhost:3000';
|
||||
const WS = 'ws://localhost:3000/ws';
|
||||
|
||||
function connect(onMsg) {
|
||||
const ws = new WebSocket(WS);
|
||||
ws.on('open', () => ws.send(JSON.stringify({ t: 'hello', v: 2 })));
|
||||
ws.on('message', (d) => onMsg(JSON.parse(String(d))));
|
||||
return ws;
|
||||
}
|
||||
|
||||
// 1. welcome + полный снапшот
|
||||
const first = [];
|
||||
await new Promise((resolve, reject) => {
|
||||
const ws = new WebSocket('ws://localhost:3000/ws');
|
||||
ws.on('open', () => ws.send(JSON.stringify({ t: 'hello', v: 1 })));
|
||||
ws.on('message', (d) => {
|
||||
seen.push(JSON.parse(String(d)));
|
||||
if (seen.length >= 2) {
|
||||
const ws = connect((m) => {
|
||||
first.push(m);
|
||||
if (first.length >= 2) {
|
||||
ws.close();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
ws.on('error', reject);
|
||||
setTimeout(() => reject(new Error('timeout waiting for welcome+snapshot')), 5000);
|
||||
setTimeout(() => reject(new Error('timeout waiting welcome+snapshot')), 5000);
|
||||
});
|
||||
const [welcome, snap] = first;
|
||||
console.log('welcome:', JSON.stringify({ t: welcome.t, v: welcome.v, tickMs: welcome.tickMs }));
|
||||
if (welcome.t !== 'welcome' || welcome.v !== 2) throw new Error(`bad welcome: ${JSON.stringify(welcome)}`);
|
||||
if (snap.t !== 'snapshot' || snap.nodes.length !== 7) throw new Error(`bad snapshot: ${snap.t}, nodes=${snap.nodes?.length}`);
|
||||
console.log(`snapshot: деревьев=${snap.nodes.length}, зрителей=${snap.avatars.length}`);
|
||||
|
||||
const [welcome, snap] = seen;
|
||||
console.log('welcome:', JSON.stringify(welcome));
|
||||
console.log(
|
||||
'avatars:',
|
||||
snap.avatars.map((a) => `${a.name}@${a.x},${a.y} ${a.face}`).join(' | '),
|
||||
);
|
||||
if (welcome.t !== 'welcome' || welcome.v !== 1) throw new Error('bad welcome');
|
||||
if (snap.t !== 'snapshot' || snap.avatars.length !== 3) throw new Error('bad snapshot');
|
||||
// 2. команда через dev-эндпоинт
|
||||
const res = await fetch(`${BASE}/dev/command`, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ name: 'Тестер', text: '!рубить' }),
|
||||
});
|
||||
if (!res.ok) throw new Error(`dev command failed: ${res.status} ${await res.text()}`);
|
||||
console.log('dev command: accepted');
|
||||
|
||||
// неверная версия протокола — сервер обязан закрыть сокет с кодом 4001
|
||||
// 3. ждём дельту: аватар «Тестер» должен заспавниться и пойти к дереву
|
||||
const delta = await new Promise((resolve, reject) => {
|
||||
const ws = connect((m) => {
|
||||
if (m.t === 'delta' && m.avatars?.some((a) => a.name === 'Тестер')) {
|
||||
ws.close();
|
||||
resolve(m);
|
||||
}
|
||||
});
|
||||
ws.on('error', reject);
|
||||
setTimeout(() => reject(new Error('no delta with Тестер')), 8000);
|
||||
});
|
||||
const tester = delta.avatars.find((a) => a.name === 'Тестер');
|
||||
console.log(`delta: ${tester.name} moving=${tester.moving} action=${tester.action} target=(${tester.tx},${tester.ty})`);
|
||||
console.log(`events: ${(delta.events ?? []).map((e) => e.k).join(',') || '—'}`);
|
||||
if (!tester.moving || tester.action !== 'idle') throw new Error('Тестер должен идти к дереву (idle + moving)');
|
||||
|
||||
// 4. неверная версия протокола — close 4001
|
||||
const closeCode = await new Promise((resolve) => {
|
||||
const ws = new WebSocket('ws://localhost:3000/ws');
|
||||
const ws = new WebSocket(WS);
|
||||
ws.on('open', () => ws.send(JSON.stringify({ t: 'hello', v: 999 })));
|
||||
ws.on('close', (code) => resolve(code));
|
||||
setTimeout(() => resolve('no-close'), 3000);
|
||||
});
|
||||
console.log('close code for wrong version:', closeCode);
|
||||
if (closeCode !== 4001) throw new Error(`expected close 4001, got ${closeCode}`);
|
||||
|
||||
console.log('WS smoke: OK');
|
||||
|
||||
Reference in New Issue
Block a user