#!/usr/bin/env node // Smoke test for WT-A: hits the running server on :3001 and checks // (1) /api/health 200 // (2) /api/auth/login returns token + offline_jwt_secret // (3) /api/auth/me/credentials works (regression check on the existing fix) // (4) a 2MB JSON body returns 413 (body limit) // (5) CORS rejects an evil origin in prod-like mode (skipped here; dev allows any) const http = require('http'); function request(method, path, { body, headers, expectStatus } = {}) { return new Promise((resolve, reject) => { const opts = { host: 'localhost', port: 3001, path, method, headers: { 'Content-Type': 'application/json', ...(headers || {}) }, }; if (body) { opts.headers['Content-Length'] = Buffer.byteLength(body); } const req = http.request(opts, (res) => { let data = ''; res.on('data', (c) => (data += c)); res.on('end', () => { const ok = expectStatus == null || res.statusCode === expectStatus; resolve({ status: res.statusCode, body: data, ok }); }); }); req.on('error', reject); if (body) req.write(body); req.end(); }); } (async () => { const results = []; // (1) health let r = await request('GET', '/api/health', { expectStatus: 200 }); results.push(['GET /api/health → 200', r.ok, r.status]); // (2) login r = await request('POST', '/api/auth/login', { body: JSON.stringify({ email: 'admin@school.com', password: 'admin123' }), expectStatus: 200, }); let loginBody = null; try { loginBody = JSON.parse(r.body); } catch (e) { /* ignore */ } const hasToken = !!loginBody?.token; const hasOffline = loginBody?.offline_jwt_secret != null; // dev default true results.push(['POST /api/auth/login returns token', hasToken, hasToken ? 'present' : 'missing']); results.push(['POST /api/auth/login returns offline_jwt_secret', hasOffline, hasOffline ? 'present' : 'missing/null']); // (3) /api/auth/me/credentials with the token if (hasToken) { r = await request('GET', '/api/auth/me/credentials', { headers: { Authorization: `Bearer ${loginBody.token}` }, expectStatus: 200, }); results.push(['GET /api/auth/me/credentials (with token) → 200', r.ok, r.status]); } // (4) 2MB JSON body → 413 const big = JSON.stringify({ data: 'x'.repeat(2 * 1024 * 1024) }); r = await request('POST', '/api/auth/login', { body: big, // We expect either 400 (bad credentials parsed first) or 413 (body too large) // We accept any 4xx — what matters is it's NOT 500 and NOT 200. }); const is4xx = r.status >= 400 && r.status < 500; results.push(['2MB JSON body rejected (4xx)', is4xx, r.status]); // Print results let pass = 0; let fail = 0; for (const [name, ok, detail] of results) { const mark = ok ? '✓' : '✗'; console.log(`${mark} ${name} — ${detail}`); if (ok) pass++; else fail++; } console.log(`\n${pass}/${results.length} checks passed.`); process.exit(fail === 0 ? 0 : 1); })().catch((err) => { console.error('Smoke test crashed:', err.message); process.exit(2); });