Back to Repositories

Testing Middleware Composition and Execution Flow in Koa.js

This test suite examines the middleware composition functionality in Koa.js, focusing on the app.use() method implementation. It verifies both synchronous and asynchronous middleware chains, error handling, and input validation to ensure proper middleware execution flow.

Test Coverage Overview

The test suite provides comprehensive coverage of Koa’s middleware system, focusing on the core app.use() functionality.

Key areas tested include:
  • Synchronous middleware composition and execution order
  • Mixed sync/async middleware handling
  • Error handling in non-async functions
  • Input validation for middleware functions

Implementation Analysis

The testing approach employs Jest’s describe/it pattern to structure test cases logically. It leverages async/await patterns extensively to handle asynchronous middleware flows and uses array-based call tracking to verify execution order.

The implementation demonstrates sophisticated promise chaining and middleware composition patterns specific to Koa’s architecture.

Technical Details

Testing tools and setup:
  • Node’s built-in test runner (node:test)
  • Supertest for HTTP request simulation
  • Node’s assert module for assertions
  • Koa instance setup with various middleware configurations

Best Practices Demonstrated

The test suite exemplifies several testing best practices in Node.js applications.

Notable practices include:
  • Isolated test cases with clear arrangements
  • Comprehensive error case coverage
  • Explicit assertion of execution order
  • Edge case handling for invalid inputs
  • Clean setup and teardown patterns

koajs/koa

__tests__/application/use.test.js

            
'use strict'

const { describe, it } = require('node:test')
const request = require('supertest')
const assert = require('assert')
const Koa = require('../..')

describe('app.use(fn)', () => {
  it('should compose middleware', async () => {
    const app = new Koa()
    const calls = []

    app.use((ctx, next) => {
      calls.push(1)
      return next().then(() => {
        calls.push(6)
      })
    })

    app.use((ctx, next) => {
      calls.push(2)
      return next().then(() => {
        calls.push(5)
      })
    })

    app.use((ctx, next) => {
      calls.push(3)
      return next().then(() => {
        calls.push(4)
      })
    })

    await request(app.callback())
      .get('/')
      .expect(404)

    assert.deepStrictEqual(calls, [1, 2, 3, 4, 5, 6])
  })

  it('should compose mixed middleware', async () => {
    const app = new Koa()
    const calls = []

    app.use((ctx, next) => {
      calls.push(1)
      return next().then(() => {
        calls.push(6)
      })
    })

    app.use(async (ctx, next) => {
      calls.push(2)
      await next()
      calls.push(5)
    })

    app.use((ctx, next) => {
      calls.push(3)
      return next().then(() => {
        calls.push(4)
      })
    })

    await request(app.callback())
      .get('/')
      .expect(404)

    assert.deepStrictEqual(calls, [1, 2, 3, 4, 5, 6])
  })

  // https://github.com/koajs/koa/pull/530#issuecomment-148138051
  it('should catch thrown errors in non-async functions', () => {
    const app = new Koa()

    app.use(ctx => ctx.throw(404, 'Not Found'))

    return request(app.callback()).get('/').expect(404)
  })

  it('should throw error for non-function', () => {
    const app = new Koa();

    [null, undefined, 0, false, 'not a function'].forEach(v => {
      assert.throws(() => app.use(v), /middleware must be a function!/)
    })
  })
})