Get test coverage on an Express/Node API fast — the first 5 tests that catch
94
90%
Does it follow best practices?
Impact
100%
1.26xAverage score across 5 eval scenarios
Passed
No known issues
You're onboarding at a company maintaining a Node/Express support ticket management system. The API has been running for over a year with no tests. The team wants to add a test suite but there's limited time — they need you to focus on the routes most likely to contain bugs, not to cover everything.
Your tech lead has pulled the git commit history and shared the output with you (see Input Files below). They also noted that the /api/tickets route handles ticket creation and status transitions, which directly affects billing since closed tickets stop the SLA clock. The /api/agents and /api/config endpoints were set up at launch and have barely been touched.
Your task is to set up testing infrastructure and write the first focused test suite. Document your reasoning — the team wants to understand why you picked the routes you did.
Produce the following files in your working directory:
package.json — updated with testing dependencies and all required scriptsvitest.config.ts — vitest configurationsrc/server.ts — updated server file (exportable for testing)src/db.ts — database module with test isolation__tests__/api.test.ts — focused test filetesting-strategy.md — explanation of which routes were chosen and why, what was left out, and the testing approach usedThe following files are provided as inputs. Extract them before beginning.
=============== FILE: git-log.txt =============== commit a9f3b12 2024-11-14 src/routes/tickets.ts commit 88e2c41 2024-11-12 src/routes/tickets.ts commit 7d4a09e 2024-11-10 src/routes/tickets.ts src/middleware/auth.ts commit 6e1bc34 2024-11-08 src/routes/tickets.ts commit 5c9d2af 2024-11-05 src/routes/tickets.ts src/routes/comments.ts commit 4b8e1cd 2024-11-03 src/routes/comments.ts commit 3a7f0bc 2024-10-31 src/routes/tickets.ts commit 2d6e9ab 2024-10-28 src/routes/comments.ts src/routes/tickets.ts commit 1e5d8ba 2024-10-25 src/routes/tickets.ts commit 0f4c7a9 2024-10-22 src/routes/comments.ts commit 9e3b6f8 2024-09-15 src/routes/agents.ts src/routes/config.ts commit 8d2a5e7 2024-08-01 src/routes/agents.ts commit 7c1f4d6 2024-07-12 src/routes/config.ts src/routes/agents.ts
=============== FILE: src/server.ts =============== import express from 'express'; import Database from 'better-sqlite3';
const db = new Database('./support.db');
db.exec( CREATE TABLE IF NOT EXISTS tickets ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, status TEXT DEFAULT 'open' ); CREATE TABLE IF NOT EXISTS comments ( id INTEGER PRIMARY KEY AUTOINCREMENT, ticket_id INTEGER NOT NULL, body TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS agents ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL ););
const app = express(); app.use(express.json());
// Tickets — high churn, handles SLA-critical status app.get('/api/tickets', (req, res) => { const rows = db.prepare('SELECT * FROM tickets').all(); res.json({ data: rows }); });
app.post('/api/tickets', (req, res) => { const { title } = req.body; if (!title) return res.status(400).json({ error: { message: 'title is required' } }); const result = db.prepare('INSERT INTO tickets (title) VALUES (?)').run(title); const ticket = db.prepare('SELECT * FROM tickets WHERE id = ?').get(result.lastInsertRowid); res.status(201).json({ data: ticket }); });
app.patch('/api/tickets/:id/status', (req, res) => {
const { status } = req.body;
const valid = ['open', 'in_progress', 'closed'];
if (!valid.includes(status)) {
return res.status(400).json({ error: { message: status must be one of: ${valid.join(', ')} } });
}
const result = db.prepare('UPDATE tickets SET status = ? WHERE id = ?').run(status, req.params.id);
if (result.changes === 0) return res.status(404).json({ error: { message: 'Ticket not found' } });
const ticket = db.prepare('SELECT * FROM tickets WHERE id = ?').get(req.params.id);
res.json({ data: ticket });
});
// Comments — moderate churn app.post('/api/comments', (req, res) => { const { ticket_id, body } = req.body; if (!ticket_id || !body) return res.status(400).json({ error: { message: 'ticket_id and body are required' } }); const result = db.prepare('INSERT INTO comments (ticket_id, body) VALUES (?, ?)').run(ticket_id, body); const comment = db.prepare('SELECT * FROM comments WHERE id = ?').get(result.lastInsertRowid); res.status(201).json({ data: comment }); });
// Agents — rarely changes, low risk app.get('/api/agents', (req, res) => { const rows = db.prepare('SELECT * FROM agents').all(); res.json({ data: rows }); });
// Config — static, never changes app.get('/api/config', (req, res) => { res.json({ data: { version: '1.4.2', max_tickets_per_agent: 50 } }); });
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(Support API on port ${PORT}));
=============== FILE: package.json =============== { "name": "support-api", "version": "1.0.0", "type": "module", "scripts": { "start": "node src/server.ts" }, "dependencies": { "express": "^4.18.2", "better-sqlite3": "^9.4.3" }, "devDependencies": { "@types/express": "^4.17.21", "@types/better-sqlite3": "^7.6.8" } }