diff --git a/sample-app/src/app.test.ts b/sample-app/src/app.test.ts index c2d8dfe..e0601c4 100644 --- a/sample-app/src/app.test.ts +++ b/sample-app/src/app.test.ts @@ -12,17 +12,36 @@ describe('Task API', () => { it('creates and then lists a task', async () => { const app = createApp(); - + const created = await request(app).post('/tasks').send({ title: 'Demo task' }); expect(created.status).toBe(201); expect(created.body.title).toBe('Demo task'); expect(created.body.completed).toBe(false); - + const list = await request(app).get('/tasks'); expect(list.status).toBe(200); expect(list.body).toHaveLength(1); }); - + + it.each([ + { name: 'missing title', payload: {} }, + { name: 'empty title', payload: { title: '' } }, + { name: 'whitespace-only title', payload: { title: ' ' } }, + { name: 'non-string title', payload: { title: 42 } }, + ])('rejects invalid title payload: $name', async ({ payload }) => { + const app = createApp(); + + const before = await request(app).get('/tasks'); + expect(before.body).toHaveLength(0); + + const res = await request(app).post('/tasks').send(payload); + expect(res.status).toBe(400); + expect(res.body).toEqual({ error: 'Title must be a non-empty string' }); + + const after = await request(app).get('/tasks'); + expect(after.body).toHaveLength(0); + }); + it('marks a task completed via PATCH', async () => { const app = createApp(); const created = await request(app).post('/tasks').send({ title: 'Finish slides' }); diff --git a/sample-app/src/tasks/routes.ts b/sample-app/src/tasks/routes.ts index e3eabca..70d1f6b 100644 --- a/sample-app/src/tasks/routes.ts +++ b/sample-app/src/tasks/routes.ts @@ -10,11 +10,19 @@ export function createTaskRouter(store: TaskStore): Router { }); router.post('/', (req, res) => { - // Exercise 1: validate that req.body.title is a non-empty string and - // return 400 with a helpful message when it is not. const { title } = req.body ?? {}; - const task = store.create(title); - res.status(201).json(task); + + if (typeof title !== 'string') { + return res.status(400).json({ error: 'Title must be a non-empty string' }); + } + + const trimmedTitle = title.trim(); + if (trimmedTitle.length === 0) { + return res.status(400).json({ error: 'Title must be a non-empty string' }); + } + + const task = store.create(trimmedTitle); + return res.status(201).json(task); }); router.get('/:id', (req, res) => {