- Add rateLimit(1_000, 30) middleware to GET /poll endpoint - Fix Challenge type errors in human-responses test files (missing baseDamage) - Add rate-limit unit test verifying 429 after exceeding limit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
81 lines
2.7 KiB
TypeScript
81 lines
2.7 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { waitForHumanResponse, getPendingChallenge, submitHumanResponse } from './human-responses.js'
|
|
import type { Challenge } from './challenges.js'
|
|
|
|
const testChallenge: Challenge = {
|
|
type: 'bitcoin_trivia',
|
|
label: 'Bitcoin Trivia',
|
|
prompt: 'What year was Bitcoin launched?',
|
|
answers: ['2009'],
|
|
scoring: 'factual',
|
|
timeout_ms: 8000,
|
|
baseDamage: 20,
|
|
choices: ['2009', '2010', '2008'],
|
|
}
|
|
|
|
describe('waitForHumanResponse ordering', () => {
|
|
it('pending challenge is stored synchronously before promise is awaited', () => {
|
|
const fightId = `fight-ordering-${Date.now()}`
|
|
const botId = 'bot-ordering-test'
|
|
|
|
// Call waitForHumanResponse — the pending entry must be stored synchronously
|
|
const { promise, choices } = waitForHumanResponse(fightId, botId, testChallenge, 1)
|
|
|
|
// IMMEDIATELY check that getPendingChallenge returns data (before awaiting)
|
|
const pending = getPendingChallenge(fightId, botId)
|
|
expect(pending).not.toBeNull()
|
|
expect(pending!.prompt).toBe('What year was Bitcoin launched?')
|
|
expect(pending!.roundNumber).toBe(1)
|
|
expect(choices).toBeInstanceOf(Array)
|
|
expect(choices.length).toBe(3)
|
|
|
|
// Clean up: submit answer to resolve the promise
|
|
submitHumanResponse(fightId, botId, '2009')
|
|
// Consume promise to prevent unhandled rejection
|
|
return promise
|
|
})
|
|
|
|
it('choices returned by waitForHumanResponse match pending challenge choices', () => {
|
|
const fightId = `fight-choices-${Date.now()}`
|
|
const botId = 'bot-choices-test'
|
|
|
|
const { promise, choices } = waitForHumanResponse(fightId, botId, testChallenge, 2)
|
|
|
|
const pending = getPendingChallenge(fightId, botId)
|
|
expect(pending).not.toBeNull()
|
|
expect(pending!.choices).toEqual(choices)
|
|
|
|
submitHumanResponse(fightId, botId, '2009')
|
|
return promise
|
|
})
|
|
|
|
it('submitHumanResponse resolves the waiting promise', async () => {
|
|
const fightId = `fight-submit-${Date.now()}`
|
|
const botId = 'bot-submit-test'
|
|
|
|
const { promise } = waitForHumanResponse(fightId, botId, testChallenge, 3)
|
|
|
|
// Submit after a microtask delay to simulate browser response
|
|
setTimeout(() => submitHumanResponse(fightId, botId, '2009', 'nice!'), 10)
|
|
|
|
const result = await promise
|
|
expect(result.answer).toBe('2009')
|
|
expect(result.trashTalk).toBe('nice!')
|
|
expect(result.timedOut).toBe(false)
|
|
})
|
|
|
|
it('pending is cleared after submit', () => {
|
|
const fightId = `fight-clear-${Date.now()}`
|
|
const botId = 'bot-clear-test'
|
|
|
|
const { promise } = waitForHumanResponse(fightId, botId, testChallenge, 4)
|
|
|
|
submitHumanResponse(fightId, botId, '2009')
|
|
|
|
const pending = getPendingChallenge(fightId, botId)
|
|
expect(pending).toBeNull()
|
|
|
|
return promise
|
|
})
|
|
})
|