jasonlooked #1
75
e2e/e2e_multi_client.cjs
Normal file
75
e2e/e2e_multi_client.cjs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
const WebSocket = require('ws')
|
||||||
|
|
||||||
|
const room = 'MULTI' + Math.floor(Math.random() * 1000)
|
||||||
|
const base = 'ws://127.0.0.1:3000/ws?room=' + room
|
||||||
|
|
||||||
|
function connect(name) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const ws = new WebSocket(base)
|
||||||
|
const messages = []
|
||||||
|
ws.on('message', (data) => {
|
||||||
|
const msg = JSON.parse(data.toString())
|
||||||
|
messages.push(msg)
|
||||||
|
console.log(`[${name}]`, msg.type)
|
||||||
|
if (msg.type === 'joined') {
|
||||||
|
resolve({ ws, messages })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ws.on('open', () => console.log(`[${name}] open`))
|
||||||
|
ws.on('error', (e) => { console.error(`[${name}] error`, e.message); reject(e) })
|
||||||
|
ws.on('close', (code) => console.log(`[${name}] close`, code))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitFor(client, pred, timeout = 10000) {
|
||||||
|
const start = Date.now()
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const check = () => {
|
||||||
|
if (pred(client.messages)) return resolve(undefined)
|
||||||
|
if (Date.now() - start > timeout) return reject(new Error('timeout'))
|
||||||
|
setTimeout(check, 50)
|
||||||
|
}
|
||||||
|
check()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
// 3 clients join the same room
|
||||||
|
const p1 = await connect('p1')
|
||||||
|
const p2 = await connect('p2')
|
||||||
|
const p3 = await connect('p3')
|
||||||
|
|
||||||
|
// All 3 receive game_state after join
|
||||||
|
await waitFor(p1, msgs => msgs.some(m => m.type === 'game_state'), 5000)
|
||||||
|
await waitFor(p2, msgs => msgs.some(m => m.type === 'game_state'), 5000)
|
||||||
|
await waitFor(p3, msgs => msgs.some(m => m.type === 'game_state'), 5000)
|
||||||
|
console.log('All 3 clients received game_state')
|
||||||
|
|
||||||
|
// p1 throws for the current turn_team
|
||||||
|
const state = p1.messages.find(m => m.type === 'game_state')
|
||||||
|
const turn = state.turn_team
|
||||||
|
console.log(`p1 throwing for team ${turn}`)
|
||||||
|
p1.ws.send(JSON.stringify({ type: 'throw', team: turn, broom_x: 0.5, broom_y: 39, weight: 7, curl: 1, friction: 1.0 }))
|
||||||
|
|
||||||
|
// All 3 clients eventually see trajectory or updated game_state
|
||||||
|
await waitFor(p1, msgs => msgs.some(m => m.type === 'trajectory'), 15000)
|
||||||
|
await waitFor(p2, msgs => msgs.some(m => m.type === 'trajectory'), 15000)
|
||||||
|
await waitFor(p3, msgs => msgs.some(m => m.type === 'trajectory'), 15000)
|
||||||
|
console.log('All 3 clients received trajectory')
|
||||||
|
|
||||||
|
// All 3 see an updated game_state after the throw
|
||||||
|
const lastIdx = p1.messages.length - 1
|
||||||
|
await waitFor(p1, msgs => msgs.slice(-1)[0]?.type === 'game_state', 15000)
|
||||||
|
await waitFor(p2, msgs => msgs.slice(-1)[0]?.type === 'game_state', 15000)
|
||||||
|
await waitFor(p3, msgs => msgs.slice(-1)[0]?.type === 'game_state', 15000)
|
||||||
|
console.log('All 3 clients received updated game_state after throw')
|
||||||
|
|
||||||
|
console.log('Multi-client observer test passed')
|
||||||
|
p1.ws.close()
|
||||||
|
p2.ws.close()
|
||||||
|
p3.ws.close()
|
||||||
|
process.exit(0)
|
||||||
|
})().catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
@ -1,43 +0,0 @@
|
|||||||
const WebSocket = require('ws')
|
|
||||||
|
|
||||||
const base = (room) => `ws://127.0.0.1:3000/ws?room=${room}`
|
|
||||||
|
|
||||||
function connect(name, room) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const ws = new WebSocket(base(room))
|
|
||||||
const messages = []
|
|
||||||
ws.on('open', () => resolve({ ws, messages }))
|
|
||||||
ws.on('message', (data) => messages.push(JSON.parse(data.toString())))
|
|
||||||
ws.on('error', reject)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function waitFor(messages, pred, timeout = 10000) {
|
|
||||||
const start = Date.now()
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const check = () => {
|
|
||||||
if (pred()) return resolve(undefined)
|
|
||||||
if (Date.now() - start > timeout) return reject(new Error('timeout'))
|
|
||||||
setTimeout(check, 50)
|
|
||||||
}
|
|
||||||
check()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
;(async () => {
|
|
||||||
const room = 'ROOMFULL' + Math.floor(Math.random() * 1000)
|
|
||||||
const p1 = await connect('p1', room)
|
|
||||||
const p2 = await connect('p2', room)
|
|
||||||
const p3 = await connect('p3', room)
|
|
||||||
await waitFor(p1.messages, () => p1.messages.some(m => m.type === 'game_state'), 5000)
|
|
||||||
await waitFor(p2.messages, () => p2.messages.some(m => m.type === 'game_state'), 5000)
|
|
||||||
await waitFor(p3.messages, () => p3.messages.some(m => m.type === 'game_state'), 5000)
|
|
||||||
console.log('Multiple observers can watch the same room state')
|
|
||||||
p1.ws.close()
|
|
||||||
p2.ws.close()
|
|
||||||
p3.ws.close()
|
|
||||||
process.exit(0)
|
|
||||||
})().catch((e) => {
|
|
||||||
console.error(e)
|
|
||||||
process.exit(1)
|
|
||||||
})
|
|
||||||
Loading…
x
Reference in New Issue
Block a user