Chai HTTP
02 / 02

Chai HTTP: File Uploads, Redirects & Test Structure

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