Files
Emberfall/tests/integration/zones-log.test.js
2026-10-20 21:31:12 +11:00

156 lines
5.1 KiB
JavaScript

// Integration tests for GET /api/zones and GET /api/combat-log.
const { describe, it, before, after } = require('node:test');
const assert = require('node:assert/strict');
const { setup, teardown, cleanup } = require('../helpers');
/**
* Register a user and log them in, returning the session cookie string.
* Node.js fetch doesn't persist cookies across calls, so we extract and reuse them.
*/
async function registerAndLogin(baseUrl, username, password) {
// Register
await fetch(`${baseUrl}/api/auth/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
// Login — extract the session cookie from Set-Cookie
const res = await fetch(`${baseUrl}/api/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
assert.equal(res.status, 200);
const json = await res.json();
assert.equal(json.ok, true);
// Extract session cookie (express-session sets a cookie like "connect.sid=...; Path=/")
const setCookie = res.headers.get('set-cookie');
assert.ok(setCookie, 'Login should set a session cookie');
const cookie = setCookie.split(';')[0]; // "connect.sid=..."
return cookie;
}
function authHeaders(cookie) {
return { Cookie: cookie };
}
async function createCharacter(baseUrl, cookie, name = 'TestHero', cls = 'warrior') {
const res = await fetch(`${baseUrl}/api/character`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Cookie: cookie },
body: JSON.stringify({ name, class: cls }),
});
assert.equal(res.status, 201);
const json = await res.json();
assert.equal(json.ok, true);
return json;
}
describe('zones endpoint', () => {
let baseUrl;
before(async () => {
baseUrl = await setup();
});
after(async () => {
await teardown();
cleanup();
});
it('returns all zones with unlocked flag for a level-1 character', async () => {
const cookie = await registerAndLogin(baseUrl, 'zoneuser1', 'password123');
await createCharacter(baseUrl, cookie, 'ZoneHero1');
const res = await fetch(`${baseUrl}/api/zones`, { headers: authHeaders(cookie) });
assert.equal(res.status, 200);
const json = await res.json();
assert.equal(json.ok, true);
const zones = json.data;
assert.ok(Array.isArray(zones));
assert.ok(zones.length >= 3);
// First zone (Whispering Meadows, min_level=1) should be unlocked for level-1 hero
const meadows = zones.find((z) => z.slug === 'whispering-meadows');
assert.ok(meadows);
assert.equal(meadows.unlocked, true);
assert.equal(meadows.energy_cost, 5);
assert.equal(meadows.min_level, 1);
// Gloomroot Forest (min_level=5) should be locked
const forest = zones.find((z) => z.slug === 'gloomroot-forest');
assert.ok(forest);
assert.equal(forest.unlocked, false);
assert.equal(forest.min_level, 5);
// Ashfang Crags (min_level=10) should be locked
const crags = zones.find((z) => z.slug === 'ashfang-crag');
assert.ok(crags);
assert.equal(crags.unlocked, false);
assert.equal(crags.min_level, 10);
});
it('returns unlocked=true when character level meets zone requirement', async () => {
const cookie = await registerAndLogin(baseUrl, 'zoneuser2', 'password123');
await createCharacter(baseUrl, cookie, 'ZoneHero2');
// Level up the character to 5
const db = require('../../src/db').getDb();
db.prepare(
'UPDATE characters SET level = 5, xp = 0, unspent_points = 0 WHERE user_id = (SELECT id FROM users WHERE username = ?)'
).run('zoneuser2');
const res = await fetch(`${baseUrl}/api/zones`, { headers: authHeaders(cookie) });
assert.equal(res.status, 200);
const json = await res.json();
const forest = json.data.find((z) => z.slug === 'gloomroot-forest');
assert.equal(forest.unlocked, true);
const crags = json.data.find((z) => z.slug === 'ashfang-crag');
assert.equal(crags.unlocked, false);
});
it('rejects without authentication', async () => {
const res = await fetch(`${baseUrl}/api/zones`);
assert.equal(res.status, 401);
const json = await res.json();
assert.equal(json.ok, false);
assert.equal(json.error.code, 'UNAUTHENTICATED');
});
});
describe('combat-log endpoint', () => {
let baseUrl;
before(async () => {
baseUrl = await setup();
});
after(async () => {
await teardown();
cleanup();
});
it('returns empty list when no combat has occurred', async () => {
const cookie = await registerAndLogin(baseUrl, 'loguser', 'password123');
await createCharacter(baseUrl, cookie, 'LogHero', 'mage');
const res = await fetch(`${baseUrl}/api/combat-log?limit=10`, { headers: authHeaders(cookie) });
assert.equal(res.status, 200);
const json = await res.json();
assert.equal(json.ok, true);
assert.equal(json.data.length, 0);
});
it('rejects without authentication', async () => {
const res = await fetch(`${baseUrl}/api/combat-log`);
assert.equal(res.status, 401);
const json = await res.json();
assert.equal(json.ok, false);
});
});