// Run: node backend/tests/regression.mjs import assert from 'node:assert/strict'; import crypto from 'node:crypto'; const BASE = process.env.BASE || 'https://dev1.aptivaai.com'; // basic helpers const j = (o)=>JSON.stringify(o); const rand = () => Math.random().toString(36).slice(2,10); const email = `qa+${Date.now()}@aptivaai.com`; const username = `qa_${rand()}`; const password = `Aa1!${rand()}Z`; let cookie = ''; // session cookie set by server1 async function req(path, {method='GET', headers={}, body, stream=false}={}) { const h = { 'Content-Type': 'application/json', ...(cookie ? { Cookie: cookie } : {}), ...headers }; const res = await fetch(`${BASE}${path}`, { method, headers: h, body: body ? j(body): undefined }); if (!stream) { const txt = await res.text(); let json; try { json = JSON.parse(txt); } catch { json = txt; } return { res, json, txt }; } return { res }; // caller handles stream via res.body } function captureSetCookie(headers) { const sc = headers.get('set-cookie'); if (sc) cookie = sc.split(';')[0]; } (async () => { console.log('→ register'); { const { res, json } = await req('/api/register', { method: 'POST', body: { username, password, firstname: 'QA', lastname: 'Bot', email, zipcode: '30024', state: 'GA', area: 'Atlanta', career_situation: 'planning' } }); assert.equal(res.status, 201, 'register should 201'); captureSetCookie(res.headers); assert.ok(cookie, 'session cookie set'); } console.log('→ signin'); { const { res, json } = await req('/api/signin', { method:'POST', body:{ username, password } }); assert.equal(res.status, 200, 'signin should 200'); captureSetCookie(res.headers); } console.log('→ user profile fetch'); { const { res } = await req('/api/user-profile'); assert.equal(res.status, 200, 'profile fetch 200'); } console.log('→ support thread + SSE stream'); // create thread let threadId; { const { res, json } = await req('/api/chat/threads', { method:'POST', body:{ title:'QA run' } }); assert.equal(res.status, 200, 'create thread 200'); threadId = json.id; assert.ok(threadId, 'thread id'); } // start stream { const { res } = await req(`/api/chat/threads/${threadId}/stream`, { method:'POST', headers: { Accept: 'text/event-stream' }, body: { prompt:'hello there', pageContext:'CareerExplorer', snapshot:null }, stream:true }); assert.equal(res.ok, true, 'stream start ok'); const reader = res.body.getReader(); let got = false; let lines = 0; while (true) { const { value, done } = await reader.read(); if (done) break; if (value) { const chunk = new TextDecoder().decode(value); lines += (chunk.match(/\n/g)||[]).length; if (chunk.trim()) got = true; } if (lines > 5) break; // we saw a few lines; good enough } assert.ok(got, 'got streaming content'); } console.log('→ premium: create career_profile + milestone (server3)'); // create scenario let career_profile_id; { const { res, json } = await req('/api/premium/career-profile', { method:'POST', body: { scenario_title: 'QA Scenario', career_name: 'Software Developer', status: 'planned' } }); assert.equal(res.status, 200, 'career-profile upsert 200'); career_profile_id = json.career_profile_id; assert.ok(career_profile_id, 'have career_profile_id'); } // create milestone let milestoneId; { const { res, json } = await req('/api/premium/milestone', { method:'POST', body: { title: 'QA Milestone', description: 'Ensure CRUD works', date: new Date(Date.now()+86400000).toISOString().slice(0,10), career_profile_id: career_profile_id } }); assert.equal(res.status, 201, 'milestone create 201'); milestoneId = (Array.isArray(json) ? json[0]?.id : json?.id); assert.ok(milestoneId, 'milestone id'); } // list milestones { const { res, json } = await req(`/api/premium/milestones?careerProfileId=${career_profile_id}`); assert.equal(res.status, 200, 'milestones list 200'); const found = (json.milestones||[]).some(m => m.id === milestoneId); assert.ok(found, 'created milestone present'); } console.log('✓ REGRESSION PASSED'); })().catch(e => { console.error('✖ regression failed:', e?.message || e); process.exit(1); });