← back to New Items Dashboard
test/auth.test.js
130 lines
// Smoke test: basic-auth gate on new-items-dashboard.
//
// Boots server.js in a child process with a deterministic BASIC_AUTH +
// NODE_ENV=production, hits a few routes via plain http, asserts:
// (a) GET / unauth -> 401
// (b) GET /api/new-wines unauth -> 401
// (c) GET / with valid creds -> 200 (or any non-401; the gate is what matters)
//
// Runs standalone — node test/auth.test.js. No test framework dep.
const { spawn } = require('child_process');
const http = require('http');
const path = require('path');
const PORT = process.env.TEST_PORT || 7299;
const CREDS = 'admin:DW2025Secure!';
const SERVER = path.join(__dirname, '..', 'server.js');
function get(opts) {
return new Promise((resolve, reject) => {
const req = http.request({
hostname: '127.0.0.1',
port: PORT,
method: 'GET',
...opts,
}, (res) => {
let body = '';
res.on('data', (c) => { body += c; });
res.on('end', () => resolve({ status: res.statusCode, body, headers: res.headers }));
});
req.on('error', reject);
req.end();
});
}
function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); }
async function waitForServer(timeoutMs = 5000) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
try {
await get({ path: '/' });
return true;
} catch (e) {
await sleep(100);
}
}
return false;
}
(async () => {
const child = spawn('node', [SERVER], {
env: { ...process.env, PORT: String(PORT), NODE_ENV: 'production', BASIC_AUTH: CREDS },
stdio: ['ignore', 'pipe', 'pipe'],
});
let serverErr = '';
child.stderr.on('data', (c) => { serverErr += c; });
const failures = [];
const ok = (msg) => console.log(' ok -', msg);
const fail = (msg) => { failures.push(msg); console.log(' FAIL -', msg); };
try {
const up = await waitForServer();
if (!up) {
console.error('server failed to come up. stderr:\n', serverErr);
process.exit(1);
}
// (a) unauth on /
{
const r = await get({ path: '/' });
if (r.status === 401) ok('GET / unauth -> 401');
else fail(`GET / unauth -> ${r.status} (expected 401)`);
if (/^Basic/i.test(r.headers['www-authenticate'] || '')) ok('WWW-Authenticate present');
else fail('WWW-Authenticate header missing on /');
}
// (b) unauth on /api/new-wines
{
const r = await get({ path: '/api/new-wines' });
if (r.status === 401) ok('GET /api/new-wines unauth -> 401');
else fail(`GET /api/new-wines unauth -> ${r.status} (expected 401)`);
}
// (b2) unauth on /api/new-handbags
{
const r = await get({ path: '/api/new-handbags' });
if (r.status === 401) ok('GET /api/new-handbags unauth -> 401');
else fail(`GET /api/new-handbags unauth -> ${r.status} (expected 401)`);
}
// (b3) unauth on /api/stats
{
const r = await get({ path: '/api/stats' });
if (r.status === 401) ok('GET /api/stats unauth -> 401');
else fail(`GET /api/stats unauth -> ${r.status} (expected 401)`);
}
// (c) authed on /
{
const auth = 'Basic ' + Buffer.from(CREDS).toString('base64');
const r = await get({ path: '/', headers: { Authorization: auth } });
// 200 if index.html exists; or 404 if not present — but NEVER 401
if (r.status !== 401) ok(`GET / with creds -> ${r.status} (not 401)`);
else fail(`GET / with valid creds -> 401 (gate rejecting good creds)`);
}
// (d) bad creds -> 401
{
const auth = 'Basic ' + Buffer.from('admin:wrong').toString('base64');
const r = await get({ path: '/', headers: { Authorization: auth } });
if (r.status === 401) ok('GET / wrong creds -> 401');
else fail(`GET / wrong creds -> ${r.status} (expected 401)`);
}
} finally {
child.kill('SIGTERM');
}
if (failures.length) {
console.error(`\n${failures.length} failure(s):`);
failures.forEach((f) => console.error(' - ' + f));
process.exit(1);
}
console.log('\nall auth smoke tests passed.');
process.exit(0);
})();