156 lines
5.1 KiB
JavaScript
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);
|
|
});
|
|
});
|