Updated smoke-test.mjs with 136 additions
--- a/smoke-test.mjs
+++ b/smoke-test.mjs
@@ -1,0 +1,136 @@
+import request from 'supertest';
+import assert from 'assert';
+import { execSync } from 'child_process';
+import fs from 'fs';
+
+// Clean up previous test data
+try {
+  fs.unlinkSync('database.db');
+  fs.unlinkSync('sessions.db');
+} catch (e) {
+  // ignore if files don't exist
+}
+
+// Start the server in a child process
+const serverProcess = execSync('node server.mjs &', { encoding: 'utf8' });
+// Give the server a moment to start up (adjust as needed)
+await new Promise(resolve => setTimeout(resolve, 2000));
+
+const app = 'http://localhost:3000'; // Assuming server runs on port 3000
+
+describe('Task Manager API Smoke Test', () => {
+  let agent;
+  let userId;
+
+  beforeAll(() => {
+    agent = request.agent(app);
+  });
+
+  it('should respond to /health', async () => {
+    const res = await agent.get('/health');
+    assert.strictEqual(res.statusCode, 200);
+    assert.deepStrictEqual(res.body, { status: 'ok' });
+  });
+
+  it('should register a new user', async () => {
+    const res = await agent.post('/register')
+      .send({ username: 'testuser', password: 'password123' });
+    assert.strictEqual(res.statusCode, 201);
+    assert.strictEqual(res.body.message, 'User registered successfully');
+  });
+
+  it('should not register a duplicate user', async () => {
+    const res = await agent.post('/register')
+      .send({ username: 'testuser', password: 'anotherpassword' });
+    assert.strictEqual(res.statusCode, 409);
+    assert.strictEqual(res.body.message, 'Username already exists');
+  });
+
+  it('should login the registered user', async () => {
+    const res = await agent.post('/login')
+      .send({ username: 'testuser', password: 'password123' });
+    assert.strictEqual(res.statusCode, 200);
+    assert.strictEqual(res.body.message, 'Logged in successfully');
+
+    const sessionRes = await agent.get('/session');
+    assert.strictEqual(sessionRes.statusCode, 200);
+    assert.strictEqual(sessionRes.body.authenticated, true);
+    userId = sessionRes.body.userId; // Capture userId for later tests
+    assert.ok(userId);
+  });
+
+  it('should not login with invalid credentials', async () => {
+    const res = await agent.post('/login')
+      .send({ username: 'testuser', password: 'wrongpassword' });
+    assert.strictEqual(res.statusCode, 401);
+    assert.strictEqual(res.body.message, 'Invalid credentials');
+  });
+
+  it('should create a new task', async () => {
+    const res = await agent.post('/tasks')
+      .send({ title: 'Buy groceries' });
+    assert.strictEqual(res.statusCode, 201);
+    assert.strictEqual(res.body.title, 'Buy groceries');
+    assert.strictEqual(res.body.completed, 0);
+    assert.ok(res.body.id);
+  });
+
+  it('should get tasks for the logged-in user', async () => {
+    const res = await agent.get('/tasks');
+    assert.strictEqual(res.statusCode, 200);
+    assert.ok(Array.isArray(res.body));
+    assert.strictEqual(res.body.length, 1);
+    assert.strictEqual(res.body[0].title, 'Buy groceries');
+  });
+
+  it('should update a task', async () => {
+    const tasksRes = await agent.get('/tasks');
+    const taskId = tasksRes.body[0].id;
+
+    const res = await agent.put(`/tasks/${taskId}`)
+      .send({ title: 'Buy groceries and milk', completed: true });
+    assert.strictEqual(res.statusCode, 200);
+    assert.strictEqual(res.body.message, 'Task updated successfully');
+
+    const updatedTasksRes = await agent.get('/tasks');
+    assert.strictEqual(updatedTasksRes.body[0].title, 'Buy groceries and milk');
+    assert.strictEqual(updatedTasksRes.body[0].completed, 1);
+  });
+
+  it('should delete a task', async () => {
+    const tasksRes = await agent.get('/tasks');
+    const taskId = tasksRes.body[0].id;
+
+    const res = await agent.delete(`/tasks/${taskId}`);
+    assert.strictEqual(res.statusCode, 200);
+    assert.strictEqual(res.body.message, 'Task deleted successfully');
+
+    const emptyTasksRes = await agent.get('/tasks');
+    assert.strictEqual(emptyTasksRes.body.length, 0);
+  });
+
+  it('should logout the user', async () => {
+    const res = await agent.post('/logout');
+    assert.strictEqual(res.statusCode, 200);
+    assert.strictEqual(res.body.message, 'Logged out successfully');
+
+    const sessionRes = await agent.get('/session');
+    assert.strictEqual(sessionRes.statusCode, 200);
+    assert.strictEqual(sessionRes.body.authenticated, false);
+  });
+
+  afterAll(() => {
+    // Kill the server process
+    // This is a bit hacky, but execSync doesn't return a child process object
+    // In a real scenario, you'd manage the child process more gracefully
+    try {
+      execSync('kill $(lsof -t -i:3000)'); // Kills process listening on port 3000
+    } catch (e) {
+      console.error('Could not kill server process:', e.message);
+    }
+    // Clean up test databases
+    fs.unlinkSync('database.db');
+    fs.unlinkSync('sessions.db');
+  });
+});
+