Files
ttrpg-initiative-tracker/server/server.test.js
T

114 lines
4.8 KiB
JavaScript
Raw Normal View History

// Integration smoke for server. Spin on random port, hit REST, check WS broadcast.
'use strict';
const http = require('http');
const { createServer } = require('./index');
let BASE;
let handle;
beforeEach(async () => {
handle = createServer({ dbPath: ':memory:' });
await new Promise(r => handle.server.listen(0, r));
const addr = handle.server.address();
BASE = `http://127.0.0.1:${addr.port}`;
});
afterEach(async () => {
await new Promise(r => handle.close(r));
});
async function req(method, path, body) {
const res = await fetch(`${BASE}${path}`, {
method,
headers: body ? { 'Content-Type': 'application/json' } : undefined,
body: body ? JSON.stringify(body) : undefined,
});
const text = await res.text();
const json = text ? JSON.parse(text) : null;
return { status: res.status, json };
}
describe('server REST', () => {
test('health', async () => {
const { status, json } = await req('GET', '/health');
expect(status).toBe(200);
expect(json.ok).toBe(true);
});
test('campaign create + list', async () => {
const { json: c } = await req('POST', '/api/campaigns', { name: 'Test', backgroundUrl: '' });
expect(c.name).toBe('Test');
const { json: list } = await req('GET', '/api/campaigns');
expect(list).toHaveLength(1);
expect(list[0].id).toBe(c.id);
});
test('encounter create + add monster + start', async () => {
const { json: c } = await req('POST', '/api/campaigns', { name: 'C' });
const { json: e } = await req('POST', `/api/campaigns/${c.id}/encounters`, { name: 'E' });
expect(e.participants).toEqual([]);
const { json: addRes } = await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/participants`, {
type: 'monster', name: 'Goblin', maxHp: 7, initMod: 2, isNpc: false,
});
expect(addRes.encounter.participants).toHaveLength(1);
expect(addRes.encounter.participants[0].name).toBe('Goblin');
expect(addRes.roll.total).toBeGreaterThan(2);
const { json: started } = await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/start`);
expect(started.isStarted).toBe(true);
expect(started.round).toBe(1);
expect(started.currentTurnParticipantId).toBe(addRes.encounter.participants[0].id);
});
test('next turn advances', async () => {
const { json: c } = await req('POST', '/api/campaigns', { name: 'C' });
const { json: e } = await req('POST', `/api/campaigns/${c.id}/encounters`, { name: 'E' });
const ids = [];
for (let i = 0; i < 3; i++) {
const { json: r } = await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/participants`, {
type: 'monster', name: `M${i}`, maxHp: 10, initMod: i,
});
ids.push(r.encounter.participants[r.encounter.participants.length - 1].id);
}
await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/start`);
const { json: t1 } = await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/nextTurn`);
expect(t1.currentTurnParticipantId).not.toBe(t1.turnOrderIds[0]);
});
test('damage to 0 deactivates', async () => {
const { json: c } = await req('POST', '/api/campaigns', { name: 'C' });
const { json: e } = await req('POST', `/api/campaigns/${c.id}/encounters`, { name: 'E' });
const { json: r } = await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/participants`, {
type: 'monster', name: 'Orc', maxHp: 5, initMod: 0,
});
const pid = r.encounter.participants[0].id;
await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/start`);
const { json: after } = await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/participants/${pid}/hp`, {
changeType: 'damage', amount: 5,
});
expect(after.participants[0].currentHp).toBe(0);
expect(after.participants[0].isActive).toBe(false);
});
test('error: start with no participants', async () => {
const { json: c } = await req('POST', '/api/campaigns', { name: 'C' });
const { json: e } = await req('POST', `/api/campaigns/${c.id}/encounters`, { name: 'E' });
const { status, json } = await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/start`);
expect(status).toBe(400);
expect(json.error).toMatch(/participants/i);
});
test('logs recorded on actions', async () => {
const { json: c } = await req('POST', '/api/campaigns', { name: 'C' });
const { json: e } = await req('POST', `/api/campaigns/${c.id}/encounters`, { name: 'E' });
await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/participants`, {
type: 'monster', name: 'Goblin', maxHp: 7, initMod: 2,
});
await req('POST', `/api/campaigns/${c.id}/encounters/${e.id}/start`);
const { json: logs } = await req('GET', '/api/logs');
expect(logs.length).toBeGreaterThanOrEqual(2);
expect(logs.some(l => /Combat started/.test(l.message))).toBe(true);
});
});