- Add content migration (003_content.sql): zones, monsters, items, loot tables - Add inventory migration (004_inventory.sql) and logs migration (006_logs.sql) - Add Mulberry32 PRNG (src/utils/rng.js) for deterministic combat - Add combat system (src/game/combat.js) with turn order, crit, mage bonus, 20-round cap - Add rewards/loot system (src/game/rewards.js) and leveling (src/game/leveling.js) - Add hunt endpoint (POST /api/hunt) with full combat flow in DB transaction - Add hunt integration tests and unit tests for rewards/leveling/combat - Fix session middleware to use memory store in tests (avoids cleanup hang) - Fix huntService transaction (db.transaction() returns wrapper, must call separately) - Add huntService to helpers.js cache invalidation for test isolation
101 lines
3.2 KiB
JavaScript
101 lines
3.2 KiB
JavaScript
// Integration tests for POST /api/hunt.
|
|
const { describe, it, before, after } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const { setup, teardown, cleanup } = require('../helpers');
|
|
|
|
/**
|
|
* Helper: register a user and return the session cookie string.
|
|
*/
|
|
async function registerUser(baseUrl, username, password) {
|
|
const res = await fetch(`${baseUrl}/api/auth/register`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ username, password: password || 'password123' }),
|
|
});
|
|
assert.strictEqual(res.status, 201);
|
|
const setCookie = res.headers.get('set-cookie');
|
|
assert.ok(setCookie, 'No Set-Cookie header');
|
|
return setCookie.split(';')[0]; // e.g. "sid=abc123"
|
|
}
|
|
|
|
/**
|
|
* Helper: create a character and return the response data.
|
|
*/
|
|
async function createCharacter(baseUrl, cookie, name) {
|
|
const res = await fetch(`${baseUrl}/api/character`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', Cookie: cookie },
|
|
body: JSON.stringify({ name, class: 'warrior' }),
|
|
});
|
|
assert.strictEqual(res.status, 201);
|
|
return res.json();
|
|
}
|
|
|
|
describe('POST /api/hunt', () => {
|
|
let baseUrl;
|
|
|
|
before(async () => {
|
|
baseUrl = await setup();
|
|
});
|
|
|
|
after(async () => {
|
|
await teardown();
|
|
cleanup();
|
|
});
|
|
|
|
it('requires authentication', async () => {
|
|
const res = await fetch(`${baseUrl}/api/hunt`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ zoneId: 1 }),
|
|
});
|
|
assert.strictEqual(res.status, 401);
|
|
});
|
|
|
|
it('hunts in zone 1 successfully', async () => {
|
|
const cookie = await registerUser(baseUrl, 'huntest1');
|
|
await createCharacter(baseUrl, cookie, 'HuntTest');
|
|
|
|
const res = await fetch(`${baseUrl}/api/hunt`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', Cookie: cookie },
|
|
body: JSON.stringify({ zoneId: 1 }),
|
|
});
|
|
assert.strictEqual(res.status, 200);
|
|
const data = await res.json();
|
|
assert.ok(data.ok);
|
|
assert.ok(data.data.winner === 'hero' || data.data.winner === 'monster');
|
|
assert.ok(Array.isArray(data.data.rounds));
|
|
assert.ok(data.data.rounds.length > 0);
|
|
assert.ok('xpGained' in data.data);
|
|
assert.ok('goldGained' in data.data);
|
|
assert.ok('hpRemaining' in data.data);
|
|
assert.ok('zone' in data.data);
|
|
assert.ok('monster' in data.data);
|
|
});
|
|
|
|
it('rejects invalid zone ID', async () => {
|
|
const cookie = await registerUser(baseUrl, 'huntest2');
|
|
await createCharacter(baseUrl, cookie, 'HuntTest2');
|
|
|
|
const res = await fetch(`${baseUrl}/api/hunt`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', Cookie: cookie },
|
|
body: JSON.stringify({ zoneId: 999 }),
|
|
});
|
|
assert.strictEqual(res.status, 404);
|
|
});
|
|
|
|
it('rejects missing zone ID', async () => {
|
|
const cookie = await registerUser(baseUrl, 'huntest3');
|
|
await createCharacter(baseUrl, cookie, 'HuntTest3');
|
|
|
|
const res = await fetch(`${baseUrl}/api/hunt`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', Cookie: cookie },
|
|
body: JSON.stringify({}),
|
|
});
|
|
assert.strictEqual(res.status, 400);
|
|
});
|
|
});
|