From 279e1f7ec3f37acd9631d686d050bb9d3e9c2451 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 14 Aug 2025 12:26:00 +0200 Subject: [PATCH] backend-test-utils: fix mockErrorHandler foot-gun Signed-off-by: Patrik Oldsberg --- .changeset/heavy-buckets-attend.md | 13 ++++ packages/backend-test-utils/report.api.md | 5 +- .../src/util/errorHandler.test.ts | 71 +++++++++++++++++++ .../src/util/errorHandler.ts | 8 ++- 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 .changeset/heavy-buckets-attend.md create mode 100644 packages/backend-test-utils/src/util/errorHandler.test.ts diff --git a/.changeset/heavy-buckets-attend.md b/.changeset/heavy-buckets-attend.md new file mode 100644 index 0000000000..9a381a51eb --- /dev/null +++ b/.changeset/heavy-buckets-attend.md @@ -0,0 +1,13 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Updated the type definition of `mockErrorHandler` to ensure that it is used correctly. + +```ts +// This is wrong and will now result in a type error +app.use(mockErrorHandler); + +// This is the correct usage +app.use(mockErrorHandler()); +``` diff --git a/packages/backend-test-utils/report.api.md b/packages/backend-test-utils/report.api.md index 4853ca57c5..fb22e5c850 100644 --- a/packages/backend-test-utils/report.api.md +++ b/packages/backend-test-utils/report.api.md @@ -152,7 +152,10 @@ export interface MockDirectoryContentOptions { } // @public -export function mockErrorHandler(): ErrorRequestHandler< +export function mockErrorHandler( + _options?: {}, + ..._args: never[] +): ErrorRequestHandler< ParamsDictionary, any, any, diff --git a/packages/backend-test-utils/src/util/errorHandler.test.ts b/packages/backend-test-utils/src/util/errorHandler.test.ts new file mode 100644 index 0000000000..a5ed9c1a53 --- /dev/null +++ b/packages/backend-test-utils/src/util/errorHandler.test.ts @@ -0,0 +1,71 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InputError } from '@backstage/errors'; +import express from 'express'; +import request from 'supertest'; +import { mockErrorHandler } from './errorHandler'; + +describe('mockErrorHandler', () => { + it('should return a function', () => { + const errorHandler = mockErrorHandler(); + expect(errorHandler).toBeInstanceOf(Function); + }); + + it('should hint that it must be called', () => { + const app = express(); + + // @ts-expect-error - passing the function directly should result in a type error + app.use(mockErrorHandler); + + app.use(mockErrorHandler()); + + expect('test').toBe('test'); + }); + + it('should convert errors in an express app', async () => { + const errorHandler = mockErrorHandler(); + + const app = express(); + app.get('/plain', () => { + throw new Error('test'); + }); + app.get('/input', () => { + throw new InputError('bad'); + }); + app.use(errorHandler); + + await expect(request(app).get('/plain')).resolves.toMatchObject({ + status: 500, + body: { + error: { + name: 'Error', + message: 'test', + }, + }, + }); + + await expect(request(app).get('/input')).resolves.toMatchObject({ + status: 400, + body: { + error: { + name: 'InputError', + message: 'bad', + }, + }, + }); + }); +}); diff --git a/packages/backend-test-utils/src/util/errorHandler.ts b/packages/backend-test-utils/src/util/errorHandler.ts index 79f4d8fd04..611fef8747 100644 --- a/packages/backend-test-utils/src/util/errorHandler.ts +++ b/packages/backend-test-utils/src/util/errorHandler.ts @@ -20,8 +20,14 @@ import { mockServices } from '../services'; /** * A mock for error handler middleware that can be used in router tests. * @public + * + * @example + * ```ts + * const app = express(); + * app.use(mockErrorHandler()); + * ``` */ -export function mockErrorHandler() { +export function mockErrorHandler(_options?: {}, ..._args: never[]) { return MiddlewareFactory.create({ config: mockServices.rootConfig(), logger: mockServices.rootLogger(),