Files
blackstream/backend/recommendation-engine/index.test.js

91 lines
2.9 KiB
JavaScript

const http = require('http');
const { describe, it, before, after } = require('node:test');
const assert = require('node:assert');
const app = require('./recommendation-engine');
let server;
let baseUrl;
before((_, done) => {
server = app.listen(0, () => {
baseUrl = `http://localhost:${server.address().port}`;
done();
});
});
after((_, done) => {
server.close(done);
});
async function get(path) {
const res = await fetch(`${baseUrl}${path}`);
return { status: res.status, body: await res.json() };
}
async function post(path, body) {
const res = await fetch(`${baseUrl}${path}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
return { status: res.status, body: await res.json() };
}
describe('Recommendation Engine', () => {
it('health check', async () => {
const { status, body } = await get('/');
assert.strictEqual(status, 200);
assert.strictEqual(body.service, 'BlackStream Recommendation Engine');
assert.strictEqual(body.catalog, 15);
});
it('cold start returns top-rated', async () => {
const { body } = await get('/recommendations');
assert.ok(body.recommendations.length > 0);
assert.ok(body.recommendations.length <= 5);
// First should be highest rated (Breaking Bad 9.5)
assert.strictEqual(body.recommendations[0].title, 'Breaking Bad');
});
it('similar shows returns related content', async () => {
const { status, body } = await get('/similar/5'); // Game of Thrones
assert.strictEqual(status, 200);
assert.strictEqual(body.source.title, 'Game of Thrones');
// House of the Dragon should be highly similar (Fantasy + medieval + war)
const titles = body.similar.map(s => s.title);
assert.ok(titles.includes('House of the Dragon'));
});
it('similar 404 for invalid id', async () => {
const { status } = await get('/similar/999');
assert.strictEqual(status, 404);
});
it('like records preference', async () => {
const { status, body } = await post('/like', { user: 'test1', itemId: 1 });
assert.strictEqual(status, 200);
assert.deepStrictEqual(body.liked, [1]);
});
it('recommendations use preferences', async () => {
await post('/like', { user: 'test2', itemId: 1 }); // The Office (Comedy)
await post('/like', { user: 'test2', itemId: 7 }); // Ted Lasso (Comedy)
const { body } = await get('/recommendations?user=test2');
// Should not include liked items
const ids = body.recommendations.map(r => r.id);
assert.ok(!ids.includes(1));
assert.ok(!ids.includes(7));
});
it('like rejects missing fields', async () => {
const { status } = await post('/like', { user: 'test' });
assert.strictEqual(status, 400);
});
it('genres endpoint returns distribution', async () => {
const { body } = await get('/genres');
assert.ok(body.genres['Comedy'] >= 2);
assert.ok(body.genres['Sci-Fi'] >= 3);
});
});