diff --git a/src/application.ts b/src/application.ts index aca15b935..6c67c197b 100644 --- a/src/application.ts +++ b/src/application.ts @@ -187,10 +187,16 @@ export class Application extends Emitter { * @private */ protected async handleRequest(ctx: ContextDelegation, fnMiddleware: (ctx: ContextDelegation) => Promise) { + this.emit('request', ctx); const res = ctx.res; res.statusCode = 404; const onerror = (err: any) => ctx.onerror(err); - onFinished(res, onerror); + onFinished(res, (err: any) => { + if (err) { + onerror(err); + } + this.emit('response', ctx); + }); try { await fnMiddleware(ctx); return this._respond(ctx); diff --git a/test/application/index.test.ts b/test/application/index.test.ts index 56764c8e4..d02765f51 100644 --- a/test/application/index.test.ts +++ b/test/application/index.test.ts @@ -4,7 +4,6 @@ import CreateError from 'http-errors'; import Koa from '../../src/index.js'; describe('app', () => { - // ignore test on Node.js v18 it('should handle socket errors', done => { const app = new Koa(); @@ -25,6 +24,36 @@ describe('app', () => { }); }); + it('should emit request and response event', done => { + const app = new Koa(); + let requestCount = 0; + let responseCount = 0; + app.on('request', ctx => { + assert.equal(ctx.url, '/'); + requestCount++; + }); + app.on('response', ctx => { + assert.equal(ctx.url, '/'); + assert.equal(ctx.status, 404); + responseCount++; + if (responseCount === 2) { + assert.equal(requestCount, 2); + done(); + } + }); + + request(app.callback()) + .get('/') + .end(() => { + // empty + }); + request(app.callback()) + .get('/') + .end(() => { + // empty + }); + }); + it('should not .writeHead when !socket.writable', done => { const app = new Koa();