Как проверить пользовательское промежуточное ПО Koa для обработки ошибок?
В рамках миграции более старого приложения с ExpressJs на Koa JS (v1). Я написал часть промежуточного программного обеспечения для обработки любых возникающих ошибок. Это выглядит примерно так:
module.errors = function * (next) {
try {
yield next;
} catch (err) {
switch(err && err.message) {
case: 'Bad Request':
this.status = 400;
this.body = {message: 'Bad Request'};
brea;
default:
this.status = 500;
this.body = {message: 'An error has occurred'};
}
this.app.emit('error', err, this);
}
}
Он включается в мое приложение следующим образом:
const app = require('koa')();
const router = require('koa-router');
const { errors } = require('./middleware/errors');
app.use(errors)
.use(router.routes());
app.get('/some-request', function *(next){
// request that could error
});
app.listen();
Все это прекрасно работает, но я бы хотел протестировать промежуточное ПО с моими модульными тестами, и, возможно, потому что я все еще довольно плохо знаком с функциями Koa и Generator, я изо всех сил пытаюсь выяснить, как это сделать.
Я знаю, что если я импортирую промежуточное программное обеспечение для обработки ошибок, мне нужно передать ему функцию, которая выдаст ошибку, но как мне выполнить переданную функцию? Это должно быть закрытие какого-то описания? Как я могу утверждать / ожидать от значений, установленных для кода состояния и т.п.?
const { expect } = require('chai');
const { errors } = require('../middleware/errors');
describe('errors middleware', () => {
it('returns a 500 on a generic error', () => {
let thrower = function(){ throw new Error() }
let errorHandler = errors(thrower());
// mass of confusion
expect(errorHandler.next()).to.throw(Error);
});
});
2 ответа
Вы можете использовать эту библиотеку https://www.npmjs.com/package/co которая используется koa.js 1.x, чтобы обернуть ваши функции генератора и макетировать объект контекста.
const co = require('co');
const Emitter = require('events');
const { expect } = require('chai');
const { errors } = require('../middleware/errors');
const wrapped = co.wrap(errors);
const mockApp = new Emitter();
describe('errors middleware', () => {
it('returns a 500 on a generic error', (done) => {
const ERROR_MSG = 'middleware error';
const ctx = {app: mockApp};
const next = function* () {
throw new Error(ERROR_MSG);
}
wrapped.call(ctx, next)
.then(() => {
try {
expect(ctx.status).to.equal(500);
expect(ctx.body.message).to.equal(ERROR_MSG);
done();
} catch (err) {
done(err);
}
})
.catch(err => done(err))
});
});
Вот как я решил эту проблему с Jest, я просто создал собственный объект res и передал его в обработчик ошибок:
const error = require('../../../middleware/error');
describe('error middleware', () => {
it(' return 500 if there is unhandled error', async () => {
const res = {
status: (c) => {this.c = c; return {send: (s) => {this.s = s; return this}}} ,
c: 200,
s: 'OK',
};
const req = {};
const next = jest.fn();
const err = () => {
throw new Error()
};
const errorHandler = error(err, req, res, next);
expect(errorHandler).toMatchObject({c: 500, s: 'Something failed'});
});
});
Промежуточные программы Koa являются генераторами (возвращают / дают многократно) и не ведут себя как функции, поэтому довольно странно писать для них модульные тесты. Лично мне хватает сквозных тестовых случаев.
Тем не менее, следующее может работать в вашем случае.
const { expect } = require('chai');
const { errors } = require('../middleware/errors');
describe('errors middleware', () => {
it('returns a 500 on a generic error', () => {
let ctx = { body: {}, status: 404 };
let errorMidIterator = errors().call(ctx, 'NEXT_MID');
// test that it correctly yields to next middleware
expect(errorMidIterator.next().value).should.equal('NEXT_MID');
// simualte an error and test if it correctly sets the body
expect(errorMidIterator.throw(new Error()).done).to.equal(true);
expect(ctx.status).should.equal(500);
});
});
В качестве примечания, я думаю, что лучше экспортировать фабрики промежуточного программного обеспечения из ваших файлов, а не обычные функции генератора промежуточного программного обеспечения. Первый дает вам больше контроля (то есть вы можете ввести некоторые зависимости, в этом случае thrower()
функция, через аргументы функции Factory). Мои файлы промежуточного программного обеспечения выглядят так.
module.exports = function MyMiddleware(options) {
return function *MyMiddleware(next) {
// options.config.foo
// options.httpclient.get(..)
};
}
Наконец, koa оборачивает функции генератора в co, что меняет семантику, поэтому юнит-тесты не так полезны (субъективно)