From 9fb3b5373c453a257817c71cce5df68e1f064ab9 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 17 Aug 2023 14:40:29 +0200 Subject: [PATCH 1/3] backend-test-utils: add service mock helpers Signed-off-by: Patrik Oldsberg --- .changeset/old-geese-drive.md | 5 + packages/backend-test-utils/api-report.md | 253 ++++++++++++++++++ packages/backend-test-utils/package.json | 3 + .../src/next/services/mockServices.ts | 85 ++++++ yarn.lock | 2 + 5 files changed, 348 insertions(+) create mode 100644 .changeset/old-geese-drive.md diff --git a/.changeset/old-geese-drive.md b/.changeset/old-geese-drive.md new file mode 100644 index 0000000000..ddaa7ad30a --- /dev/null +++ b/.changeset/old-geese-drive.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Extended `mockService` to also include mocked variants, for example `mockServices.lifecycle.mock()`. The returned mocked implementation will have a `factory` property which is a service factory for itself. You can also pass a partial implementation of the service to the mock function to use a mock implementation of specific methods. diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index d086b1d2ae..f87181f635 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -3,24 +3,52 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// + +import { AuthorizePermissionRequest } from '@backstage/plugin-permission-common'; import { Backend } from '@backstage/backend-app-api'; import { BackendFeature } from '@backstage/backend-plugin-api'; +import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { CacheService } from '@backstage/backend-plugin-api'; +import { CacheServiceOptions } from '@backstage/backend-plugin-api'; +import { CacheServiceSetOptions } from '@backstage/backend-plugin-api'; import { DatabaseService } from '@backstage/backend-plugin-api'; +import { DefinitivePolicyDecision } from '@backstage/plugin-permission-common'; +import { EvaluatorRequestOptions } from '@backstage/plugin-permission-common'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { Handler } from 'express'; import { HttpRouterFactoryOptions } from '@backstage/backend-app-api'; import { HttpRouterService } from '@backstage/backend-plugin-api'; +import { IdentityApiGetIdentityRequest } from '@backstage/plugin-auth-node'; import { IdentityService } from '@backstage/backend-plugin-api'; import { JsonObject } from '@backstage/types'; +import { JsonValue } from '@backstage/types'; import { Knex } from 'knex'; import { LifecycleService } from '@backstage/backend-plugin-api'; +import { LifecycleServiceShutdownHook } from '@backstage/backend-plugin-api'; +import { LifecycleServiceShutdownOptions } from '@backstage/backend-plugin-api'; +import { LifecycleServiceStartupHook } from '@backstage/backend-plugin-api'; +import { LifecycleServiceStartupOptions } from '@backstage/backend-plugin-api'; import { LoggerService } from '@backstage/backend-plugin-api'; import { PermissionsService } from '@backstage/backend-plugin-api'; +import { PolicyDecision } from '@backstage/plugin-permission-common'; +import { QueryPermissionRequest } from '@backstage/plugin-permission-common'; +import { ReadTreeOptions } from '@backstage/backend-plugin-api'; +import { ReadTreeResponse } from '@backstage/backend-plugin-api'; +import { ReadUrlOptions } from '@backstage/backend-plugin-api'; +import { ReadUrlResponse } from '@backstage/backend-plugin-api'; import { RootConfigService } from '@backstage/backend-plugin-api'; import { RootLifecycleService } from '@backstage/backend-plugin-api'; +import { RootLoggerService } from '@backstage/backend-plugin-api'; import { SchedulerService } from '@backstage/backend-plugin-api'; +import { SearchOptions } from '@backstage/backend-plugin-api'; +import { SearchResponse } from '@backstage/backend-plugin-api'; import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { TaskDescriptor } from '@backstage/backend-tasks'; +import { TaskInvocationDefinition } from '@backstage/backend-tasks'; +import { TaskRunner } from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { TokenManagerService } from '@backstage/backend-plugin-api'; import { UrlReaderService } from '@backstage/backend-plugin-api'; @@ -33,11 +61,47 @@ export namespace mockServices { export namespace cache { const // (undocumented) factory: () => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + get: jest.MockInstance< + Promise, + [key: string], + unknown + >; + set: jest.MockInstance< + Promise, + [ + key: string, + value: JsonValue, + options?: CacheServiceSetOptions | undefined, + ], + unknown + >; + delete: jest.MockInstance, [key: string], unknown>; + withOptions: jest.MockInstance< + CacheService, + [options: CacheServiceOptions], + unknown + >; + } & CacheService; } // (undocumented) export namespace database { const // (undocumented) factory: () => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + getClient: jest.MockInstance>, [], unknown>; + migrations?: + | { + skip?: boolean | undefined; + } + | undefined; + } & DatabaseService; } // (undocumented) export namespace httpRouter { @@ -45,6 +109,12 @@ export namespace mockServices { factory: ( options?: HttpRouterFactoryOptions | undefined, ) => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + use: jest.MockInstance; + } & HttpRouterService; } // (undocumented) export function identity(): IdentityService; @@ -52,21 +122,99 @@ export namespace mockServices { export namespace identity { const // (undocumented) factory: () => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + getIdentity: jest.MockInstance< + Promise, + [options: IdentityApiGetIdentityRequest], + unknown + >; + } & IdentityService; } // (undocumented) export namespace lifecycle { const // (undocumented) factory: () => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + addStartupHook: jest.MockInstance< + void, + [ + hook: LifecycleServiceStartupHook, + options?: LifecycleServiceStartupOptions | undefined, + ], + unknown + >; + addShutdownHook: jest.MockInstance< + void, + [ + hook: LifecycleServiceShutdownHook, + options?: LifecycleServiceShutdownOptions | undefined, + ], + unknown + >; + } & LifecycleService; } // (undocumented) export namespace logger { const // (undocumented) factory: () => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + error: jest.MockInstance< + void, + [message: string, meta?: Error | JsonObject | undefined], + unknown + >; + warn: jest.MockInstance< + void, + [message: string, meta?: Error | JsonObject | undefined], + unknown + >; + info: jest.MockInstance< + void, + [message: string, meta?: Error | JsonObject | undefined], + unknown + >; + debug: jest.MockInstance< + void, + [message: string, meta?: Error | JsonObject | undefined], + unknown + >; + child: jest.MockInstance; + } & LoggerService; } // (undocumented) export namespace permissions { const // (undocumented) factory: () => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + authorize: jest.MockInstance< + Promise, + [ + requests: AuthorizePermissionRequest[], + options?: EvaluatorRequestOptions | undefined, + ], + unknown + >; + authorizeConditional: jest.MockInstance< + Promise, + [ + requests: QueryPermissionRequest[], + options?: EvaluatorRequestOptions | undefined, + ], + unknown + >; + } & PermissionsService; } // (undocumented) export function rootConfig(options?: rootConfig.Options): RootConfigService; @@ -85,6 +233,27 @@ export namespace mockServices { export namespace rootLifecycle { const // (undocumented) factory: () => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + addStartupHook: jest.MockInstance< + void, + [ + hook: LifecycleServiceStartupHook, + options?: LifecycleServiceStartupOptions | undefined, + ], + unknown + >; + addShutdownHook: jest.MockInstance< + void, + [ + hook: LifecycleServiceShutdownHook, + options?: LifecycleServiceShutdownOptions | undefined, + ], + unknown + >; + } & RootLifecycleService; } // (undocumented) export function rootLogger(options?: rootLogger.Options): LoggerService; @@ -98,11 +267,58 @@ export namespace mockServices { factory: ( options?: Options | undefined, ) => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + error: jest.MockInstance< + void, + [message: string, meta?: Error | JsonObject | undefined], + unknown + >; + warn: jest.MockInstance< + void, + [message: string, meta?: Error | JsonObject | undefined], + unknown + >; + info: jest.MockInstance< + void, + [message: string, meta?: Error | JsonObject | undefined], + unknown + >; + debug: jest.MockInstance< + void, + [message: string, meta?: Error | JsonObject | undefined], + unknown + >; + child: jest.MockInstance; + } & RootLoggerService; } // (undocumented) export namespace scheduler { const // (undocumented) factory: () => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + triggerTask: jest.MockInstance, [id: string], unknown>; + scheduleTask: jest.MockInstance< + Promise, + [task: TaskScheduleDefinition & TaskInvocationDefinition], + unknown + >; + createScheduledTaskRunner: jest.MockInstance< + TaskRunner, + [schedule: TaskScheduleDefinition], + unknown + >; + getScheduledTasks: jest.MockInstance< + Promise, + [], + unknown + >; + } & SchedulerService; } // (undocumented) export function tokenManager(): TokenManagerService; @@ -110,11 +326,48 @@ export namespace mockServices { export namespace tokenManager { const // (undocumented) factory: () => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + getToken: jest.MockInstance< + Promise<{ + token: string; + }>, + [], + unknown + >; + authenticate: jest.MockInstance< + Promise, + [token: string], + unknown + >; + } & TokenManagerService; } // (undocumented) export namespace urlReader { const // (undocumented) factory: () => ServiceFactory; + const // (undocumented) + mock: (partialImpl?: Partial | undefined) => { + factory: ServiceFactory; + } & { + readUrl: jest.MockInstance< + Promise, + [url: string, options?: ReadUrlOptions | undefined], + unknown + >; + readTree: jest.MockInstance< + Promise, + [url: string, options?: ReadTreeOptions | undefined], + unknown + >; + search: jest.MockInstance< + Promise, + [url: string, options?: SearchOptions | undefined], + unknown + >; + } & UrlReaderService; } } diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 02cb1d5cf9..21946be36c 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -57,6 +57,9 @@ "testcontainers": "^8.1.2", "uuid": "^8.0.0" }, + "peerDependencies": { + "@types/jest": "*" + }, "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index 0455b9f1ae..d0bb79dd2e 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -40,6 +40,7 @@ import { JsonObject } from '@backstage/types'; import { MockIdentityService } from './MockIdentityService'; import { MockRootLoggerService } from './MockRootLoggerService'; +/** @internal */ function simpleFactory< TService, TScope extends 'root' | 'plugin', @@ -57,6 +58,34 @@ function simpleFactory< })) as (...options: TOptions) => ServiceFactory; } +/** @internal */ +function simpleMock( + ref: ServiceRef, + mockFactory: () => jest.Mocked, +): ( + partialImpl?: Partial, +) => { factory: ServiceFactory } & jest.Mocked { + 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, + })(), + }); + }; +} + /** * @public */ @@ -79,6 +108,13 @@ export namespace mockServices { }; export const factory = simpleFactory(coreServices.rootLogger, rootLogger); + export const mock = simpleMock(coreServices.rootLogger, () => ({ + child: jest.fn(), + debug: jest.fn(), + error: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + })); } export function tokenManager(): TokenManagerService { @@ -98,6 +134,10 @@ export namespace mockServices { coreServices.tokenManager, tokenManager, ); + export const mock = simpleMock(coreServices.tokenManager, () => ({ + authenticate: jest.fn(), + getToken: jest.fn(), + })); } export function identity(): IdentityService { @@ -105,6 +145,9 @@ export namespace mockServices { } export namespace identity { export const factory = simpleFactory(coreServices.identity, identity); + export const mock = simpleMock(coreServices.identity, () => ({ + getIdentity: jest.fn(), + })); } // TODO(Rugvip): Not all core services have implementations available here yet. @@ -112,29 +155,71 @@ export namespace mockServices { // re-implement functioning mock versions here. export namespace cache { export const factory = cacheServiceFactory; + export const mock = simpleMock(coreServices.cache, () => ({ + delete: jest.fn(), + get: jest.fn(), + set: jest.fn(), + withOptions: jest.fn(), + })); } export namespace database { export const factory = databaseServiceFactory; + export const mock = simpleMock(coreServices.database, () => ({ + getClient: jest.fn(), + })); } export namespace httpRouter { export const factory = httpRouterServiceFactory; + export const mock = simpleMock(coreServices.httpRouter, () => ({ + use: jest.fn(), + })); } export namespace lifecycle { export const factory = lifecycleServiceFactory; + export const mock = simpleMock(coreServices.lifecycle, () => ({ + addShutdownHook: jest.fn(), + addStartupHook: jest.fn(), + })); } export namespace logger { export const factory = loggerServiceFactory; + export const mock = simpleMock(coreServices.logger, () => ({ + child: jest.fn(), + debug: jest.fn(), + error: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + })); } export namespace permissions { export const factory = permissionsServiceFactory; + export const mock = simpleMock(coreServices.permissions, () => ({ + authorize: jest.fn(), + authorizeConditional: jest.fn(), + })); } export namespace rootLifecycle { export const factory = rootLifecycleServiceFactory; + export const mock = simpleMock(coreServices.rootLifecycle, () => ({ + addShutdownHook: jest.fn(), + addStartupHook: jest.fn(), + })); } export namespace scheduler { export const factory = schedulerServiceFactory; + export const mock = simpleMock(coreServices.scheduler, () => ({ + createScheduledTaskRunner: jest.fn(), + getScheduledTasks: jest.fn(), + scheduleTask: jest.fn(), + triggerTask: jest.fn(), + })); } export namespace urlReader { export const factory = urlReaderServiceFactory; + export const mock = simpleMock(coreServices.urlReader, () => ({ + readTree: jest.fn(), + readUrl: jest.fn(), + search: jest.fn(), + })); } } diff --git a/yarn.lock b/yarn.lock index ec0379375a..fd3d589b8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3514,6 +3514,8 @@ __metadata: supertest: ^6.1.3 testcontainers: ^8.1.2 uuid: ^8.0.0 + peerDependencies: + "@types/jest": "*" languageName: unknown linkType: soft From 9df5afff8ebfb6f2ec812dae694c1410c113639d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 17 Aug 2023 14:40:57 +0200 Subject: [PATCH 2/3] refactor plugin tests to use mocks from mockServices Signed-off-by: Patrik Oldsberg --- .../catalogModuleAwsS3EntityProvider.test.ts | 29 ++++--------------- ...logModuleAzureDevOpsEntityProvider.test.ts | 23 ++++----------- ...ModuleBitbucketCloudEntityProvider.test.ts | 23 ++++----------- ...oduleBitbucketServerEntityProvider.test.ts | 23 ++++----------- .../catalogModuleGerritEntityProvider.test.ts | 23 ++++----------- .../catalogModuleGithubEntityProvider.test.ts | 23 ++++----------- ...oduleGitlabDiscoveryEntityProvider.test.ts | 23 ++++----------- ...IncrementalIngestionEntityProvider.test.ts | 19 ++++-------- ...uleMicrosoftGraphOrgEntityProvider.test.ts | 23 ++++----------- ...atalogModulePuppetDbEntityProvider.test.ts | 23 ++++----------- ...oduleAwsSqsConsumingEventPublisher.test.ts | 15 ++-------- 11 files changed, 62 insertions(+), 185 deletions(-) diff --git a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts index c9fea8aa28..ad1e94cad6 100644 --- a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts +++ b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts @@ -14,15 +14,7 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { - PluginTaskScheduler, - TaskScheduleDefinition, -} from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; @@ -40,12 +32,12 @@ describe('catalogModuleAwsS3EntityProvider', () => { }, }; const runner = jest.fn(); - const scheduler = { - createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { usedSchedule = schedule; - return runner; + return { run: runner }; }, - } as unknown as PluginTaskScheduler; + }); const config = { catalog: { @@ -66,16 +58,7 @@ describe('catalogModuleAwsS3EntityProvider', () => { features: [ catalogModuleAwsS3EntityProvider(), mockServices.rootConfig.factory({ data: config }), - createServiceFactory(() => ({ - service: coreServices.logger, - deps: {}, - factory: getVoidLogger, - }))(), - createServiceFactory(() => ({ - service: coreServices.scheduler, - deps: {}, - factory: () => scheduler, - }))(), + scheduler.factory, ], }); diff --git a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts index 3147a0871b..a20921fa3f 100644 --- a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts +++ b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts @@ -14,14 +14,7 @@ * limitations under the License. */ -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { - PluginTaskScheduler, - TaskScheduleDefinition, -} from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; @@ -39,12 +32,12 @@ describe('catalogModuleAzureDevOpsEntityProvider', () => { }, }; const runner = jest.fn(); - const scheduler = { - createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { usedSchedule = schedule; - return runner; + return { run: runner }; }, - } as unknown as PluginTaskScheduler; + }); const config = { catalog: { @@ -69,11 +62,7 @@ describe('catalogModuleAzureDevOpsEntityProvider', () => { catalogModuleAzureDevOpsEntityProvider(), mockServices.rootConfig.factory({ data: config }), mockServices.logger.factory(), - createServiceFactory(() => ({ - deps: {}, - service: coreServices.scheduler, - factory: async () => scheduler, - })), + scheduler.factory, ], }); diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts index 83769fc3f5..c771a40acc 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts @@ -14,14 +14,7 @@ * limitations under the License. */ -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { - PluginTaskScheduler, - TaskScheduleDefinition, -} from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { startTestBackend, mockServices } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; @@ -46,12 +39,12 @@ describe('catalogModuleBitbucketCloudEntityProvider', () => { }, }; const runner = jest.fn(); - const scheduler = { - createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { usedSchedule = schedule; - return runner; + return { run: runner }; }, - } as unknown as PluginTaskScheduler; + }); await startTestBackend({ extensionPoints: [ @@ -75,11 +68,7 @@ describe('catalogModuleBitbucketCloudEntityProvider', () => { }, }, }), - createServiceFactory({ - service: coreServices.scheduler, - deps: {}, - factory: async () => scheduler, - }), + scheduler.factory, ], }); diff --git a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts index ae4a636008..ab92e24fd7 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts @@ -14,14 +14,7 @@ * limitations under the License. */ -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { - PluginTaskScheduler, - TaskScheduleDefinition, -} from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { catalogModuleBitbucketServerEntityProvider } from './catalogModuleBitbucketServerEntityProvider'; @@ -39,12 +32,12 @@ describe('catalogModuleBitbucketServerEntityProvider', () => { }, }; const runner = jest.fn(); - const scheduler = { - createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { usedSchedule = schedule; - return runner; + return { run: runner }; }, - } as unknown as PluginTaskScheduler; + }); const config = { catalog: { @@ -73,11 +66,7 @@ describe('catalogModuleBitbucketServerEntityProvider', () => { catalogModuleBitbucketServerEntityProvider(), mockServices.rootConfig.factory({ data: config }), mockServices.logger.factory(), - createServiceFactory({ - service: coreServices.scheduler, - deps: {}, - factory: async () => scheduler, - }), + scheduler.factory, ], }); diff --git a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts index 9807814f61..4afcd8e2d4 100644 --- a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts @@ -14,14 +14,7 @@ * limitations under the License. */ -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { - PluginTaskScheduler, - TaskScheduleDefinition, -} from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; @@ -39,12 +32,12 @@ describe('catalogModuleGerritEntityProvider', () => { }, }; const runner = jest.fn(); - const scheduler = { - createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { usedSchedule = schedule; - return runner; + return { run: runner }; }, - } as unknown as PluginTaskScheduler; + }); const config = { catalog: { @@ -79,11 +72,7 @@ describe('catalogModuleGerritEntityProvider', () => { catalogModuleGerritEntityProvider(), mockServices.rootConfig.factory({ data: config }), mockServices.logger.factory(), - createServiceFactory({ - service: coreServices.scheduler, - deps: {}, - factory: async () => scheduler, - }), + scheduler.factory, ], }); diff --git a/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts index 9e36966eec..171a641fc7 100644 --- a/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts @@ -14,19 +14,12 @@ * limitations under the License. */ -import { - PluginTaskScheduler, - TaskScheduleDefinition, -} from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleGithubEntityProvider } from './catalogModuleGithubEntityProvider'; import { GithubEntityProvider } from '../providers/GithubEntityProvider'; -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; describe('catalogModuleGithubEntityProvider', () => { it('should register provider at the catalog extension point', async () => { @@ -39,12 +32,12 @@ describe('catalogModuleGithubEntityProvider', () => { }, }; const runner = jest.fn(); - const scheduler = { - createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { usedSchedule = schedule; - return runner; + return { run: runner }; }, - } as unknown as PluginTaskScheduler; + }); const config = { catalog: { @@ -65,11 +58,7 @@ describe('catalogModuleGithubEntityProvider', () => { features: [ catalogModuleGithubEntityProvider(), mockServices.rootConfig.factory({ data: config }), - createServiceFactory({ - service: coreServices.scheduler, - deps: {}, - factory: async () => scheduler, - }), + scheduler.factory, ], }); diff --git a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts index 22759cafa0..46cfe403e8 100644 --- a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts @@ -14,14 +14,7 @@ * limitations under the License. */ -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { - PluginTaskScheduler, - TaskScheduleDefinition, -} from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; @@ -39,12 +32,12 @@ describe('catalogModuleGitlabDiscoveryEntityProvider', () => { }, }; const runner = jest.fn(); - const scheduler = { - createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { usedSchedule = schedule; - return runner; + return { run: runner }; }, - } as unknown as PluginTaskScheduler; + }); const config = { integrations: { @@ -78,11 +71,7 @@ describe('catalogModuleGitlabDiscoveryEntityProvider', () => { catalogModuleGitlabDiscoveryEntityProvider(), mockServices.rootConfig.factory({ data: config }), mockServices.logger.factory(), - createServiceFactory({ - deps: {}, - service: coreServices.scheduler, - factory: async () => scheduler, - }), + scheduler.factory, ], }); diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts index ed0c776fa8..7d76ddf480 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts @@ -14,12 +14,8 @@ * limitations under the License. */ -import { - coreServices, - createBackendModule, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { startTestBackend } from '@backstage/backend-test-utils'; +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { IncrementalEntityProvider } from '../types'; import { @@ -40,18 +36,15 @@ describe('catalogModuleIncrementalIngestionEntityProvider', () => { }; const addEntityProvider = jest.fn(); - const httpRouterUse = jest.fn(); + + const httpRouterMock = mockServices.httpRouter.mock(); await startTestBackend({ extensionPoints: [ [catalogProcessingExtensionPoint, { addEntityProvider }], ], features: [ - createServiceFactory({ - service: coreServices.httpRouter, - deps: {}, - factory: () => ({ use: httpRouterUse }), - }), + httpRouterMock.factory, catalogModuleIncrementalIngestionEntityProvider(), createBackendModule({ pluginId: 'catalog', @@ -79,6 +72,6 @@ describe('catalogModuleIncrementalIngestionEntityProvider', () => { expect(addEntityProvider.mock.calls[0][0].getProviderName()).toBe( 'provider1', ); - expect(httpRouterUse).toHaveBeenCalledTimes(1); + expect(httpRouterMock.use).toHaveBeenCalledTimes(1); }); }); diff --git a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts index 96fec41cbe..d36995b1c8 100644 --- a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts @@ -14,14 +14,7 @@ * limitations under the License. */ -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { - PluginTaskScheduler, - TaskScheduleDefinition, -} from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; @@ -39,12 +32,12 @@ describe('catalogModuleMicrosoftGraphOrgEntityProvider', () => { }, }; const runner = jest.fn(); - const scheduler = { - createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { usedSchedule = schedule; - return runner; + return { run: runner }; }, - } as unknown as PluginTaskScheduler; + }); const config = { catalog: { @@ -70,11 +63,7 @@ describe('catalogModuleMicrosoftGraphOrgEntityProvider', () => { features: [ catalogModuleMicrosoftGraphOrgEntityProvider(), mockServices.rootConfig.factory({ data: config }), - createServiceFactory(() => ({ - deps: {}, - service: coreServices.scheduler, - factory: async () => scheduler, - })), + scheduler.factory, ], }); diff --git a/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts b/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts index 3ea54d8c8f..f931b2c741 100644 --- a/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts +++ b/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts @@ -14,14 +14,7 @@ * limitations under the License. */ -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { - PluginTaskScheduler, - TaskScheduleDefinition, -} from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { catalogModulePuppetDbEntityProvider } from './catalogModulePuppetDbEntityProvider'; @@ -38,12 +31,12 @@ describe('catalogModulePuppetDbEntityProvider', () => { }, }; const runner = jest.fn(); - const scheduler = { - createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { usedSchedule = schedule; - return runner; + return { run: runner }; }, - } as unknown as PluginTaskScheduler; + }); const config = { catalog: { @@ -64,11 +57,7 @@ describe('catalogModulePuppetDbEntityProvider', () => { features: [ catalogModulePuppetDbEntityProvider(), mockServices.rootConfig.factory({ data: config }), - createServiceFactory(() => ({ - deps: {}, - service: coreServices.scheduler, - factory: async () => scheduler, - })), + scheduler.factory, ], }); diff --git a/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts b/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts index a76817c3c0..57e1831667 100644 --- a/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts +++ b/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts @@ -14,11 +14,6 @@ * limitations under the License. */ -import { - coreServices, - createServiceFactory, - SchedulerService, -} from '@backstage/backend-plugin-api'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; @@ -34,9 +29,7 @@ describe('eventsModuleAwsSqsConsumingEventPublisher', () => { }, }; - const scheduler = { - scheduleTask: jest.fn(), - } as unknown as SchedulerService; + const scheduler = mockServices.scheduler.mock(); await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], @@ -68,11 +61,7 @@ describe('eventsModuleAwsSqsConsumingEventPublisher', () => { }, }, }), - createServiceFactory({ - service: coreServices.scheduler, - deps: {}, - factory: () => scheduler, - }), + scheduler.factory, ], }); From 1fbad39b2deeb156085052c7b675fc991b0a31ab Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 17 Aug 2023 16:50:45 +0200 Subject: [PATCH 3/3] backend-test-utils: introduce ServiceMock type to clean up external API Signed-off-by: Patrik Oldsberg --- packages/backend-test-utils/api-report.md | 286 +++--------------- .../src/next/services/index.ts | 2 +- .../src/next/services/mockServices.ts | 18 +- 3 files changed, 63 insertions(+), 243 deletions(-) diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index f87181f635..95f67da35f 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -5,50 +5,25 @@ ```ts /// -import { AuthorizePermissionRequest } from '@backstage/plugin-permission-common'; import { Backend } from '@backstage/backend-app-api'; import { BackendFeature } from '@backstage/backend-plugin-api'; -import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { CacheService } from '@backstage/backend-plugin-api'; -import { CacheServiceOptions } from '@backstage/backend-plugin-api'; -import { CacheServiceSetOptions } from '@backstage/backend-plugin-api'; import { DatabaseService } from '@backstage/backend-plugin-api'; -import { DefinitivePolicyDecision } from '@backstage/plugin-permission-common'; -import { EvaluatorRequestOptions } from '@backstage/plugin-permission-common'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; -import { Handler } from 'express'; import { HttpRouterFactoryOptions } from '@backstage/backend-app-api'; import { HttpRouterService } from '@backstage/backend-plugin-api'; -import { IdentityApiGetIdentityRequest } from '@backstage/plugin-auth-node'; import { IdentityService } from '@backstage/backend-plugin-api'; import { JsonObject } from '@backstage/types'; -import { JsonValue } from '@backstage/types'; import { Knex } from 'knex'; import { LifecycleService } from '@backstage/backend-plugin-api'; -import { LifecycleServiceShutdownHook } from '@backstage/backend-plugin-api'; -import { LifecycleServiceShutdownOptions } from '@backstage/backend-plugin-api'; -import { LifecycleServiceStartupHook } from '@backstage/backend-plugin-api'; -import { LifecycleServiceStartupOptions } from '@backstage/backend-plugin-api'; import { LoggerService } from '@backstage/backend-plugin-api'; import { PermissionsService } from '@backstage/backend-plugin-api'; -import { PolicyDecision } from '@backstage/plugin-permission-common'; -import { QueryPermissionRequest } from '@backstage/plugin-permission-common'; -import { ReadTreeOptions } from '@backstage/backend-plugin-api'; -import { ReadTreeResponse } from '@backstage/backend-plugin-api'; -import { ReadUrlOptions } from '@backstage/backend-plugin-api'; -import { ReadUrlResponse } from '@backstage/backend-plugin-api'; import { RootConfigService } from '@backstage/backend-plugin-api'; import { RootLifecycleService } from '@backstage/backend-plugin-api'; import { RootLoggerService } from '@backstage/backend-plugin-api'; import { SchedulerService } from '@backstage/backend-plugin-api'; -import { SearchOptions } from '@backstage/backend-plugin-api'; -import { SearchResponse } from '@backstage/backend-plugin-api'; import { ServiceFactory } from '@backstage/backend-plugin-api'; -import { TaskDescriptor } from '@backstage/backend-tasks'; -import { TaskInvocationDefinition } from '@backstage/backend-tasks'; -import { TaskRunner } from '@backstage/backend-tasks'; -import { TaskScheduleDefinition } from '@backstage/backend-tasks'; import { TokenManagerService } from '@backstage/backend-plugin-api'; import { UrlReaderService } from '@backstage/backend-plugin-api'; @@ -62,46 +37,18 @@ export namespace mockServices { const // (undocumented) factory: () => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - get: jest.MockInstance< - Promise, - [key: string], - unknown - >; - set: jest.MockInstance< - Promise, - [ - key: string, - value: JsonValue, - options?: CacheServiceSetOptions | undefined, - ], - unknown - >; - delete: jest.MockInstance, [key: string], unknown>; - withOptions: jest.MockInstance< - CacheService, - [options: CacheServiceOptions], - unknown - >; - } & CacheService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export namespace database { const // (undocumented) factory: () => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - getClient: jest.MockInstance>, [], unknown>; - migrations?: - | { - skip?: boolean | undefined; - } - | undefined; - } & DatabaseService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export namespace httpRouter { @@ -110,11 +57,9 @@ export namespace mockServices { options?: HttpRouterFactoryOptions | undefined, ) => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - use: jest.MockInstance; - } & HttpRouterService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export function identity(): IdentityService; @@ -123,98 +68,36 @@ export namespace mockServices { const // (undocumented) factory: () => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - getIdentity: jest.MockInstance< - Promise, - [options: IdentityApiGetIdentityRequest], - unknown - >; - } & IdentityService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export namespace lifecycle { const // (undocumented) factory: () => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - addStartupHook: jest.MockInstance< - void, - [ - hook: LifecycleServiceStartupHook, - options?: LifecycleServiceStartupOptions | undefined, - ], - unknown - >; - addShutdownHook: jest.MockInstance< - void, - [ - hook: LifecycleServiceShutdownHook, - options?: LifecycleServiceShutdownOptions | undefined, - ], - unknown - >; - } & LifecycleService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export namespace logger { const // (undocumented) factory: () => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - error: jest.MockInstance< - void, - [message: string, meta?: Error | JsonObject | undefined], - unknown - >; - warn: jest.MockInstance< - void, - [message: string, meta?: Error | JsonObject | undefined], - unknown - >; - info: jest.MockInstance< - void, - [message: string, meta?: Error | JsonObject | undefined], - unknown - >; - debug: jest.MockInstance< - void, - [message: string, meta?: Error | JsonObject | undefined], - unknown - >; - child: jest.MockInstance; - } & LoggerService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export namespace permissions { const // (undocumented) factory: () => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - authorize: jest.MockInstance< - Promise, - [ - requests: AuthorizePermissionRequest[], - options?: EvaluatorRequestOptions | undefined, - ], - unknown - >; - authorizeConditional: jest.MockInstance< - Promise, - [ - requests: QueryPermissionRequest[], - options?: EvaluatorRequestOptions | undefined, - ], - unknown - >; - } & PermissionsService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export function rootConfig(options?: rootConfig.Options): RootConfigService; @@ -234,26 +117,9 @@ export namespace mockServices { const // (undocumented) factory: () => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - addStartupHook: jest.MockInstance< - void, - [ - hook: LifecycleServiceStartupHook, - options?: LifecycleServiceStartupOptions | undefined, - ], - unknown - >; - addShutdownHook: jest.MockInstance< - void, - [ - hook: LifecycleServiceShutdownHook, - options?: LifecycleServiceShutdownOptions | undefined, - ], - unknown - >; - } & RootLifecycleService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export function rootLogger(options?: rootLogger.Options): LoggerService; @@ -268,57 +134,18 @@ export namespace mockServices { options?: Options | undefined, ) => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - error: jest.MockInstance< - void, - [message: string, meta?: Error | JsonObject | undefined], - unknown - >; - warn: jest.MockInstance< - void, - [message: string, meta?: Error | JsonObject | undefined], - unknown - >; - info: jest.MockInstance< - void, - [message: string, meta?: Error | JsonObject | undefined], - unknown - >; - debug: jest.MockInstance< - void, - [message: string, meta?: Error | JsonObject | undefined], - unknown - >; - child: jest.MockInstance; - } & RootLoggerService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export namespace scheduler { const // (undocumented) factory: () => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - triggerTask: jest.MockInstance, [id: string], unknown>; - scheduleTask: jest.MockInstance< - Promise, - [task: TaskScheduleDefinition & TaskInvocationDefinition], - unknown - >; - createScheduledTaskRunner: jest.MockInstance< - TaskRunner, - [schedule: TaskScheduleDefinition], - unknown - >; - getScheduledTasks: jest.MockInstance< - Promise, - [], - unknown - >; - } & SchedulerService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export function tokenManager(): TokenManagerService; @@ -327,50 +154,33 @@ export namespace mockServices { const // (undocumented) factory: () => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - getToken: jest.MockInstance< - Promise<{ - token: string; - }>, - [], - unknown - >; - authenticate: jest.MockInstance< - Promise, - [token: string], - unknown - >; - } & TokenManagerService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } // (undocumented) export namespace urlReader { const // (undocumented) factory: () => ServiceFactory; const // (undocumented) - mock: (partialImpl?: Partial | undefined) => { - factory: ServiceFactory; - } & { - readUrl: jest.MockInstance< - Promise, - [url: string, options?: ReadUrlOptions | undefined], - unknown - >; - readTree: jest.MockInstance< - Promise, - [url: string, options?: ReadTreeOptions | undefined], - unknown - >; - search: jest.MockInstance< - Promise, - [url: string, options?: SearchOptions | undefined], - unknown - >; - } & UrlReaderService; + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; } } +// @public (undocumented) +export type ServiceMock = { + factory: ServiceFactory; +} & { + [Key in keyof TService]: TService[Key] extends ( + this: infer This, + ...args: infer Args + ) => infer Return + ? TService[Key] & jest.MockInstance + : TService[Key]; +}; + // @public export function setupRequestMockHandlers(worker: { listen: (t: any) => void; diff --git a/packages/backend-test-utils/src/next/services/index.ts b/packages/backend-test-utils/src/next/services/index.ts index f562150efa..97a22567fd 100644 --- a/packages/backend-test-utils/src/next/services/index.ts +++ b/packages/backend-test-utils/src/next/services/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { mockServices } from './mockServices'; +export { mockServices, type ServiceMock } from './mockServices'; diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index d0bb79dd2e..3edc3e0894 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -58,13 +58,23 @@ function simpleFactory< })) as (...options: TOptions) => ServiceFactory; } +/** @public */ +export type ServiceMock = { + factory: ServiceFactory; +} & { + [Key in keyof TService]: TService[Key] extends ( + this: infer This, + ...args: infer Args + ) => infer Return + ? TService[Key] & jest.MockInstance + : TService[Key]; +}; + /** @internal */ function simpleMock( ref: ServiceRef, mockFactory: () => jest.Mocked, -): ( - partialImpl?: Partial, -) => { factory: ServiceFactory } & jest.Mocked { +): (partialImpl?: Partial) => ServiceMock { return partialImpl => { const mock = mockFactory(); if (partialImpl) { @@ -82,7 +92,7 @@ function simpleMock( deps: {}, factory: () => mock, })(), - }); + }) as ServiceMock; }; }