Files
Emberfall/tests/integration/step-10.14.test.js
T
2026-10-23 05:54:46 +11:00

191 lines
7.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Integration tests for step 10.14: Material sell prices use item-level formula.
const { describe, it, before, after } = require('node:test');
const assert = require('node:assert/strict');
const { setup, teardown, cleanup } = require('../helpers');
describe('step-10.14 material sell prices (item-level)', () => {
let baseUrl, userSeq = 0;
before(async () => { baseUrl = await setup(); });
after(async () => { teardown(); cleanup(); });
// ─── helpers ──────────────────────────────────────────────────────────
async function registerAndLogin(username, password) {
await fetch(`${baseUrl}/api/auth/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
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);
return res.headers.get('set-cookie') || '';
}
async function createHero(cookie, name, cls) {
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 { data } = await res.json();
return data.character.id;
}
function grantItem(characterId, itemId, quantity = 1) {
const db = require('../../src/db').getDb();
const NOW = 1_700_000_000_000;
const existing = db.prepare(
'SELECT id, quantity FROM inventory WHERE character_id = ? AND item_id = ?'
).get(characterId, itemId);
if (existing) {
db.prepare('UPDATE inventory SET quantity = quantity + ? WHERE id = ?').run(quantity, existing.id);
} else {
db.prepare(
'INSERT INTO inventory (character_id, item_id, quantity, equipped_slot, acquired_at) VALUES (?, ?, ?, NULL, ?)'
).run(characterId, itemId, quantity, NOW);
}
}
// ─── Rat Tail (common, min_level 1) — always 2g regardless of hero level ──
it('Rat Tail sells for 2g at hero level 1', async () => {
const cookie = await registerAndLogin(`s14a${userSeq++}`, 'pass1234');
const characterId = await createHero(cookie, 'S14A', 'warrior');
grantItem(characterId, 17, 1); // Rat Tail
const res = await fetch(`${baseUrl}/api/shop/sell`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Cookie: cookie },
body: JSON.stringify({ itemId: 17, quantity: 1 }),
});
const body = await res.json();
assert.equal(res.status, 200);
assert.equal(body.ok, true);
// Character starts with 50g (DB default), sells Rat Tail → 52g
assert.equal(body.data.character.gold, 52);
});
it('Rat Tail sells for 2g at hero level 10', async () => {
const cookie = await registerAndLogin(`s14b${userSeq++}`, 'pass1234');
const characterId = await createHero(cookie, 'S14B', 'warrior');
grantItem(characterId, 17, 1); // Rat Tail
const res = await fetch(`${baseUrl}/api/shop/sell`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Cookie: cookie },
body: JSON.stringify({ itemId: 17, quantity: 1 }),
});
const body = await res.json();
assert.equal(res.status, 200);
assert.equal(body.ok, true);
assert.equal(body.data.character.gold, 52);
});
it('Rat Tail sells for 2g at hero level 50', async () => {
const cookie = await registerAndLogin(`s14c${userSeq++}`, 'pass1234');
const characterId = await createHero(cookie, 'S14C', 'warrior');
grantItem(characterId, 17, 1); // Rat Tail
const res = await fetch(`${baseUrl}/api/shop/sell`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Cookie: cookie },
body: JSON.stringify({ itemId: 17, quantity: 1 }),
});
const body = await res.json();
assert.equal(res.status, 200);
assert.equal(body.ok, true);
assert.equal(body.data.character.gold, 52);
});
// ─── Drake Scale (rare, min_level 14) — always 112g regardless of hero level ──
it('Drake Scale sells for 112g at hero level 14', async () => {
const cookie = await registerAndLogin(`s14d${userSeq++}`, 'pass1234');
const characterId = await createHero(cookie, 'S14D', 'warrior');
grantItem(characterId, 21, 1); // Drake Scale
const res = await fetch(`${baseUrl}/api/shop/sell`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Cookie: cookie },
body: JSON.stringify({ itemId: 21, quantity: 1 }),
});
const body = await res.json();
assert.equal(res.status, 200);
assert.equal(body.ok, true);
// Character starts with 50g (DB default), sells Drake Scale → 162g
assert.equal(body.data.character.gold, 162);
});
it('Drake Scale sells for 112g at hero level 50', async () => {
const cookie = await registerAndLogin(`s14e${userSeq++}`, 'pass1234');
const characterId = await createHero(cookie, 'S14E', 'warrior');
grantItem(characterId, 21, 1); // Drake Scale
const res = await fetch(`${baseUrl}/api/shop/sell`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Cookie: cookie },
body: JSON.stringify({ itemId: 21, quantity: 1 }),
});
const body = await res.json();
assert.equal(res.status, 200);
assert.equal(body.ok, true);
assert.equal(body.data.character.gold, 162);
});
// ─── Shop-listed price equals actual payment ──────────────────────────
it('shop-listed sellPrice equals the amount actually paid on sell', async () => {
const cookie = await registerAndLogin(`s14f${userSeq++}`, 'pass1234');
const characterId = await createHero(cookie, 'S14F', 'warrior');
grantItem(characterId, 17, 3); // 3 Rat Tails
// Get shop stock to see the listed sellPrice.
const stockRes = await fetch(`${baseUrl}/api/shop`, {
headers: { Cookie: cookie },
});
const stockBody = await stockRes.json();
assert.equal(stockRes.status, 200);
const ratTail = stockBody.data.stock.find((i) => i.itemId === 17);
assert.ok(ratTail, 'Rat Tail should be in stock');
const listedPrice = ratTail.sellPrice;
assert.equal(listedPrice, 2, 'listed sellPrice for Rat Tail should be 2');
// Sell 1 Rat Tail.
const sellRes = await fetch(`${baseUrl}/api/shop/sell`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Cookie: cookie },
body: JSON.stringify({ itemId: 17, quantity: 1 }),
});
const sellBody = await sellRes.json();
assert.equal(sellRes.status, 200);
assert.equal(sellBody.ok, true);
// Gold should increase by exactly the listed price (50 + 2 = 52).
assert.equal(sellBody.data.character.gold, 50 + listedPrice);
});
// ─── Multi-quantity sell ──────────────────────────────────────────────
it('selling 5 Rat Tails yields exactly 10g (5 × 2g)', async () => {
const cookie = await registerAndLogin(`s14g${userSeq++}`, 'pass1234');
const characterId = await createHero(cookie, 'S14G', 'warrior');
grantItem(characterId, 17, 5);
const res = await fetch(`${baseUrl}/api/shop/sell`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Cookie: cookie },
body: JSON.stringify({ itemId: 17, quantity: 5 }),
});
const body = await res.json();
assert.equal(res.status, 200);
assert.equal(body.ok, true);
// 50 + 5*2 = 60
assert.equal(body.data.character.gold, 60);
});
});