step 4.5: done
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
// 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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user