Chai HTTP: File Uploads, Redirects & Test Structure
File Uploads
it('uploads a document', async () => {
const res = await chai.request(app)
.post('/api/upload')
.attach('document', fs.readFileSync('test-fixtures/report.pdf'), 'report.pdf')
.field('description', 'Q3 report')
expect(res).to.have.status(200)
})Redirects
it('redirects to the dashboard after login', async () => {
const res = await chai.request(app).post('/login').send(validCreds)
expect(res).to.redirect
expect(res.redirects[0]).to.include('/dashboard')
})Structuring Tests with Mocha
describe('POST /api/users', () => {
beforeEach(async () => {
// Resets DB state so one test's data doesn't leak into the next
await db.reset()
})
it('creates a user with valid data', async () => {
const res = await chai.request(app).post('/api/users').send(validUser)
expect(res).to.have.status(201)
})
})Avoid Brittle Exact-Match Assertions
// FRAGILE -- id and createdAt vary between test runs
expect(res.body).to.deep.equal({ id: 1, name: 'Alice', createdAt: '2024-01-01T00:00:00Z' })
// BETTER -- assert only the deterministic fields that actually matter
expect(res.body).to.have.property('name', 'Alice')Why Integration Tests Beyond Unit Tests
Testing via Chai HTTP exercises the full request pipeline -- middleware, routing, and handler logic together -- catching bugs (an auth middleware applied to the wrong routes, a route registered with the wrong path) that a handler-only unit test bypassing middleware would miss.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free