curltastic/e2e/e2e_score.cjs
Jason Dekarske 56ab1fb2e3 test(e2e): align suite with PR-B protocol and physics
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-10 23:47:17 -07:00

76 lines
2.5 KiB
JavaScript

const WebSocket = require('ws')
const DRAW_VEL = 2.38
const base = 'ws://127.0.0.1:3000/ws?room=SCOREQA' + Math.floor(Math.random() * 10000)
function throwFor(ws, team, broom_x, broom_y, velocity = DRAW_VEL, curl = 0, friction = 1.0) {
ws.send(JSON.stringify({ type: 'throw', team, broom_x, broom_y, velocity, curl, friction }))
}
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)
if (msg.type === 'joined') resolve({ ws, messages })
})
ws.on('error', reject)
})
}
function waitFor(condFn, timeout = 5000) {
const start = Date.now()
return new Promise((resolve, reject) => {
const check = () => {
if (condFn()) return resolve(undefined)
if (Date.now() - start > timeout) return reject(new Error('timeout'))
setTimeout(check, 50)
}
check()
})
}
function latestState(messages) {
for (let i = messages.length - 1; i >= 0; i--) {
if (messages[i].type === 'game_state') return messages[i]
}
return null
}
;(async () => {
const p1 = await connect('p1')
await waitFor(() => p1.messages.some(m => m.type === 'game_state'))
let state = latestState(p1.messages)
console.log('start turn', state.turn_team, 'hammer', state.hammer, 'stones_remaining', state.stones_remaining)
const thrower1 = state.turn_team
throwFor(p1.ws, thrower1, 0.2, 38.5, DRAW_VEL, 0, 1.0)
await waitFor(() => p1.messages.some(m => m.type === 'trajectories'), 15000)
await waitFor(() => {
const s = latestState(p1.messages)
return s && s.stones && s.stones.length >= 1 && s.phase === 'playing'
}, 15000)
await new Promise(r => setTimeout(r, 200))
state = latestState(p1.messages)
console.log('After first throw stones:', state.stones.length, 'remaining', state.stones_remaining)
const thrower2 = state.turn_team
throwFor(p1.ws, thrower2, -0.2, 38.5, DRAW_VEL, 0, 1.0)
await waitFor(() => p1.messages.filter(m => m.type === 'trajectories').length >= 2, 15000)
await waitFor(() => {
const s = latestState(p1.messages)
return s && s.stones && s.stones.length >= 2 && s.phase === 'playing'
}, 15000)
await new Promise(r => setTimeout(r, 200))
state = latestState(p1.messages)
console.log('Final stones', state.stones)
console.log('scoreboard', state.scoreboard, 'stones_remaining', state.stones_remaining)
p1.ws.close()
process.exit(0)
})().catch(e => {
console.error(e)
process.exit(1)
})