import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import { DELETE, GET, POST } from '../../src/app/api/projects/route'; async function withTempUserProfile(run: (userProfile: string) => Promise): Promise { const previous = process.env.USERPROFILE; const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'beadboard-api-')); process.env.USERPROFILE = tempDir; try { await run(tempDir); } finally { if (previous === undefined) { delete process.env.USERPROFILE; } else { process.env.USERPROFILE = previous; } await fs.rm(tempDir, { recursive: true, force: true }); } } async function readJson(response: Response): Promise { return response.json(); } test('GET /api/projects returns empty list initially', async () => { await withTempUserProfile(async () => { const response = await GET(); assert.equal(response.status, 200); const body = (await readJson(response)) as { projects: unknown[] }; assert.deepEqual(body.projects, []); }); }); test('POST /api/projects validates payload and path', async () => { await withTempUserProfile(async () => { const missing = await POST(new Request('http://localhost/api/projects', { method: 'POST', body: '{}' })); assert.equal(missing.status, 400); const missingBody = (await readJson(missing)) as { error: string }; assert.match(missingBody.error, /path/i); const invalidPath = await POST( new Request('http://localhost/api/projects', { method: 'POST', body: JSON.stringify({ path: '/tmp/project' }), headers: { 'content-type': 'application/json' }, }), ); assert.equal(invalidPath.status, 400); }); }); test('POST deduplicates and GET returns normalized path', async () => { await withTempUserProfile(async () => { const first = await POST( new Request('http://localhost/api/projects', { method: 'POST', body: JSON.stringify({ path: 'c:/Users/test/project/beadboard/' }), headers: { 'content-type': 'application/json' }, }), ); assert.equal(first.status, 201); const dup = await POST( new Request('http://localhost/api/projects', { method: 'POST', body: JSON.stringify({ path: 'C:\\users\\test\\project\\beadboard' }), headers: { 'content-type': 'application/json' }, }), ); assert.equal(dup.status, 200); const list = await GET(); const body = (await readJson(list)) as { projects: Array<{ path: string }> }; assert.deepEqual(body.projects, [{ path: 'C:/Users/test/project/beadboard' }]); }); }); test('DELETE /api/projects removes by normalized path', async () => { await withTempUserProfile(async () => { await POST( new Request('http://localhost/api/projects', { method: 'POST', body: JSON.stringify({ path: 'D:/Repos/One' }), headers: { 'content-type': 'application/json' }, }), ); const removed = await DELETE( new Request('http://localhost/api/projects', { method: 'DELETE', body: JSON.stringify({ path: 'd:\\repos\\one\\' }), headers: { 'content-type': 'application/json' }, }), ); assert.equal(removed.status, 200); const list = await GET(); const body = (await readJson(list)) as { projects: unknown[] }; assert.deepEqual(body.projects, []); }); });