forest-express
Version:
Official package for all Forest Express Lianas
156 lines (130 loc) • 4.3 kB
JavaScript
const sinon = require('sinon');
const errorHandler = require('../../../src/services/exposed/error-handler');
const ForbiddenError = require('../../../src/utils/errors/forbidden-error').default;
class FakePayloadError extends ForbiddenError {
constructor(...args) {
super(...args);
this.data = {
property: 'value',
};
}
}
describe('services › exposed › error-handler', () => {
function mockResponse() {
return {
status: sinon.stub().returnsThis(),
send: sinon.stub().returnsThis(),
};
}
it('calls next if there is no error', () => {
const next = sinon.stub();
const handleError = errorHandler();
handleError(undefined, undefined, undefined, next);
expect(next.callCount).toBe(1);
});
it('uses the first error\'s message as the message if the error contains multiple errors', () => {
const error = {
errors: [{
message: 'First message',
name: 'FirstNameError',
}, {
message: 'Second message',
}],
message: 'Root message',
};
const next = sinon.stub();
const response = mockResponse();
const handleError = errorHandler();
handleError(error, undefined, response, next);
expect(next.callCount).toBe(0);
expect(response.status.callCount).toBe(1);
expect(response.status.firstCall.args).toStrictEqual([500]);
expect(response.send.callCount).toBe(1);
expect(response.send.firstCall.args).toStrictEqual([{
errors: [{
status: 500,
detail: 'First message',
name: 'FirstNameError',
}],
}]);
});
it('uses the first error\'s name as the name if the error contains multiple errors', () => {
const error = {
errors: [{
message: 'First message',
name: 'FirstNameError',
}, {
message: 'Second message',
name: 'SecondNameError',
}],
name: 'Root name',
};
const next = sinon.stub();
const response = mockResponse();
const handleError = errorHandler();
handleError(error, undefined, response, next);
expect(response.send.firstCall.args).toStrictEqual([{
errors: [{
status: 500,
detail: 'First message',
name: 'FirstNameError',
}],
}]);
});
it('logs the unexpected error if the error does not have a status', () => {
const error = new Error('The error');
const logger = { error: sinon.stub() };
const handleError = errorHandler({ logger });
const next = sinon.stub();
const response = mockResponse();
handleError(error, undefined, response, next);
expect(logger.error.callCount).toBe(1);
expect(logger.error.firstCall.args).toStrictEqual(['Unexpected error: ', error]);
});
it("uses the error's message, name and status to construct the JSON response", () => {
const response = mockResponse();
const error = new Error('Something bad happened');
error.status = 666;
const handleError = errorHandler();
const next = sinon.stub();
handleError(error, undefined, response, next);
expect(next.callCount).toBe(0);
expect(response.status.callCount).toBe(1);
expect(response.status.firstCall.args).toStrictEqual([
666,
]);
expect(response.send.callCount).toBe(1);
expect(response.send.firstCall.args).toStrictEqual([{
errors: [{
detail: 'Something bad happened',
status: 666,
name: 'Error',
}],
}]);
});
describe('with an error that supports data (payload)', () => {
it('should add data to the body JSON response', () => {
const response = mockResponse();
const error = new FakePayloadError('message');
const handleError = errorHandler();
const next = sinon.stub();
handleError(error, undefined, response, next);
expect(next.callCount).toBe(0);
expect(response.status.callCount).toBe(1);
expect(response.status.firstCall.args).toStrictEqual([
403,
]);
expect(response.send.callCount).toBe(1);
expect(response.send.firstCall.args).toStrictEqual([{
errors: [{
detail: 'message',
status: 403,
name: 'FakePayloadError',
data: {
property: 'value',
},
}],
}]);
});
});
});