Add createServiceMock to backend-test-utils

Exports the internal simpleMock utility as createServiceMock, allowing
plugin authors to define mock creators for their own service refs
following the same pattern as the built-in mockServices mocks.

Also updates catalog-node to use createServiceMock instead of its own
copy, and simplifies the gateway-backend test to use the mock's
.factory property directly.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2026-02-09 22:29:07 +01:00
parent 9848734ce6
commit 42abfb1b85
14 changed files with 138 additions and 145 deletions
+8
View File
@@ -71,6 +71,14 @@
"lodash": "^4.17.21",
"yaml": "^2.0.0"
},
"peerDependencies": {
"@backstage/backend-test-utils": "workspace:^"
},
"peerDependenciesMeta": {
"@backstage/backend-test-utils": {
"optional": true
}
},
"devDependencies": {
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
@@ -17,41 +17,14 @@
import {
createServiceFactory,
ServiceFactory,
ServiceRef,
} from '@backstage/backend-plugin-api';
import { InMemoryCatalogClient } from '@backstage/catalog-client/testUtils';
import { Entity } from '@backstage/catalog-model';
import { catalogServiceRef } from '@backstage/plugin-catalog-node';
// eslint-disable-next-line @backstage/no-undeclared-imports
import { ServiceMock } from '@backstage/backend-test-utils';
import { createServiceMock } from '@backstage/backend-test-utils';
import { CatalogServiceMock } from './types';
/** @internal */
function simpleMock<TService>(
ref: ServiceRef<TService, any>,
mockFactory: () => jest.Mocked<TService>,
): (partialImpl?: Partial<TService>) => ServiceMock<TService> {
return partialImpl => {
const mock = mockFactory();
if (partialImpl) {
for (const [key, impl] of Object.entries(partialImpl)) {
if (typeof impl === 'function') {
(mock as any)[key].mockImplementation(impl);
} else {
(mock as any)[key] = impl;
}
}
}
return Object.assign(mock, {
factory: createServiceFactory({
service: ref,
deps: {},
factory: () => mock,
}),
}) as ServiceMock<TService>;
};
}
/**
* Creates a fake catalog client that handles entities in memory storage. Note
* that this client may be severely limited in functionality, and advanced
@@ -86,23 +59,26 @@ export namespace catalogServiceMock {
* Creates a catalog client whose methods are mock functions, possibly with
* some of them overloaded by the caller.
*/
export const mock = simpleMock<CatalogServiceMock>(catalogServiceRef, () => ({
getEntities: jest.fn(),
getEntitiesByRefs: jest.fn(),
queryEntities: jest.fn(),
getEntityAncestors: jest.fn(),
getEntityByRef: jest.fn(),
removeEntityByUid: jest.fn(),
refreshEntity: jest.fn(),
getEntityFacets: jest.fn(),
getLocations: jest.fn(),
getLocationById: jest.fn(),
getLocationByRef: jest.fn(),
addLocation: jest.fn(),
removeLocationById: jest.fn(),
getLocationByEntity: jest.fn(),
validateEntity: jest.fn(),
analyzeLocation: jest.fn(),
streamEntities: jest.fn(),
}));
export const mock = createServiceMock<CatalogServiceMock>(
catalogServiceRef,
() => ({
getEntities: jest.fn(),
getEntitiesByRefs: jest.fn(),
queryEntities: jest.fn(),
getEntityAncestors: jest.fn(),
getEntityByRef: jest.fn(),
removeEntityByUid: jest.fn(),
refreshEntity: jest.fn(),
getEntityFacets: jest.fn(),
getLocations: jest.fn(),
getLocationById: jest.fn(),
getLocationByRef: jest.fn(),
addLocation: jest.fn(),
removeLocationById: jest.fn(),
getLocationByEntity: jest.fn(),
validateEntity: jest.fn(),
analyzeLocation: jest.fn(),
streamEntities: jest.fn(),
}),
);
}
+1 -8
View File
@@ -19,7 +19,6 @@ import { mockServices } from '@backstage/backend-test-utils';
import {
coreServices,
createBackendPlugin,
createServiceFactory,
} from '@backstage/backend-plugin-api';
import { Router } from 'express';
import { EventSource } from 'eventsource';
@@ -68,13 +67,7 @@ describe('gateway', () => {
);
backend.add(mockServices.auth.factory());
backend.add(mockServices.httpAuth.factory());
backend.add(
createServiceFactory({
service: coreServices.discovery,
deps: {},
factory: () => discovery,
}),
);
backend.add(discovery.factory);
backend.add(dummyPlugin);
backend.add(import('./'));