feat: Default error code to HTTP status code.

This commit is contained in:
Ruben Verborgh 2021-07-14 15:17:58 +01:00
parent cc1e332394
commit b9295f00c2
4 changed files with 23 additions and 4 deletions

View File

@ -57,7 +57,7 @@ export class ErrorToTemplateConverter extends TypedRepresentationConverter {
} }
private async getErrorCodeMessage(error: Error): Promise<string | undefined> { private async getErrorCodeMessage(error: Error): Promise<string | undefined> {
if (HttpError.isInstance(error) && error.errorCode) { if (HttpError.isInstance(error)) {
let template: string; let template: string;
try { try {
const fileName = `${error.errorCode}${this.extension}`; const fileName = `${error.errorCode}${this.extension}`;

View File

@ -14,7 +14,7 @@ export class HttpError extends Error implements HttpErrorOptions {
protected static readonly statusCode: number; protected static readonly statusCode: number;
public readonly statusCode: number; public readonly statusCode: number;
public readonly cause?: unknown; public readonly cause?: unknown;
public readonly errorCode?: string; public readonly errorCode: string;
public readonly details?: NodeJS.Dict<unknown>; public readonly details?: NodeJS.Dict<unknown>;
/** /**
@ -29,7 +29,7 @@ export class HttpError extends Error implements HttpErrorOptions {
this.statusCode = statusCode; this.statusCode = statusCode;
this.name = name; this.name = name;
this.cause = options.cause; this.cause = options.cause;
this.errorCode = options.errorCode; this.errorCode = options.errorCode ?? `H${statusCode}`;
this.details = options.details; this.details = options.details;
} }

View File

@ -41,7 +41,22 @@ describe('An ErrorToTemplateConverter', (): void => {
await expect(prom).rejects.toThrow(InternalServerError); await expect(prom).rejects.toThrow(InternalServerError);
}); });
it('calls the template engine with all error fields.', async(): Promise<void> => { it('works with non-HTTP errors.', async(): Promise<void> => {
const error = new Error('error text');
const representation = new BasicRepresentation([ error ], 'internal/error', false);
const prom = converter.handle({ identifier, representation, preferences });
await expect(prom).resolves.toBeDefined();
const result = await prom;
expect(result.binary).toBe(true);
expect(result.metadata.contentType).toBe('text/html');
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(engine.apply).toHaveBeenCalledTimes(1);
expect(engine.apply).toHaveBeenLastCalledWith(
'{{ template }}', { name: 'Error', message: 'error text', stack: error.stack },
);
});
it('calls the template engine with all HTTP error fields.', async(): Promise<void> => {
const error = new BadRequestHttpError('error text'); const error = new BadRequestHttpError('error text');
const representation = new BasicRepresentation([ error ], 'internal/error', false); const representation = new BasicRepresentation([ error ], 'internal/error', false);
const prom = converter.handle({ identifier, representation, preferences }); const prom = converter.handle({ identifier, representation, preferences });

View File

@ -63,6 +63,10 @@ describe('HttpError', (): void => {
expect(instance.errorCode).toBe(options.errorCode); expect(instance.errorCode).toBe(options.errorCode);
}); });
it('defaults to an HTTP-specific error code.', (): void => {
expect(new constructor().errorCode).toBe(`H${statusCode}`);
});
it('sets the details.', (): void => { it('sets the details.', (): void => {
expect(instance.details).toBe(options.details); expect(instance.details).toBe(options.details);
}); });