backend-test-utils: add service mock helpers
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -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.
|
||||
@@ -3,24 +3,52 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
/// <reference types="jest" />
|
||||
|
||||
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<CacheService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<CacheService> | undefined) => {
|
||||
factory: ServiceFactory<CacheService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
get: jest.MockInstance<
|
||||
Promise<JsonValue | undefined>,
|
||||
[key: string],
|
||||
unknown
|
||||
>;
|
||||
set: jest.MockInstance<
|
||||
Promise<void>,
|
||||
[
|
||||
key: string,
|
||||
value: JsonValue,
|
||||
options?: CacheServiceSetOptions | undefined,
|
||||
],
|
||||
unknown
|
||||
>;
|
||||
delete: jest.MockInstance<Promise<void>, [key: string], unknown>;
|
||||
withOptions: jest.MockInstance<
|
||||
CacheService,
|
||||
[options: CacheServiceOptions],
|
||||
unknown
|
||||
>;
|
||||
} & CacheService;
|
||||
}
|
||||
// (undocumented)
|
||||
export namespace database {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<DatabaseService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<DatabaseService> | undefined) => {
|
||||
factory: ServiceFactory<DatabaseService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
getClient: jest.MockInstance<Promise<Knex<any, any[]>>, [], unknown>;
|
||||
migrations?:
|
||||
| {
|
||||
skip?: boolean | undefined;
|
||||
}
|
||||
| undefined;
|
||||
} & DatabaseService;
|
||||
}
|
||||
// (undocumented)
|
||||
export namespace httpRouter {
|
||||
@@ -45,6 +109,12 @@ export namespace mockServices {
|
||||
factory: (
|
||||
options?: HttpRouterFactoryOptions | undefined,
|
||||
) => ServiceFactory<HttpRouterService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<HttpRouterService> | undefined) => {
|
||||
factory: ServiceFactory<HttpRouterService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
use: jest.MockInstance<void, [handler: Handler], unknown>;
|
||||
} & HttpRouterService;
|
||||
}
|
||||
// (undocumented)
|
||||
export function identity(): IdentityService;
|
||||
@@ -52,21 +122,99 @@ export namespace mockServices {
|
||||
export namespace identity {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<IdentityService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<IdentityService> | undefined) => {
|
||||
factory: ServiceFactory<IdentityService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
getIdentity: jest.MockInstance<
|
||||
Promise<BackstageIdentityResponse | undefined>,
|
||||
[options: IdentityApiGetIdentityRequest],
|
||||
unknown
|
||||
>;
|
||||
} & IdentityService;
|
||||
}
|
||||
// (undocumented)
|
||||
export namespace lifecycle {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<LifecycleService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<LifecycleService> | undefined) => {
|
||||
factory: ServiceFactory<LifecycleService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
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<LoggerService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<LoggerService> | undefined) => {
|
||||
factory: ServiceFactory<LoggerService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
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, [meta: JsonObject], unknown>;
|
||||
} & LoggerService;
|
||||
}
|
||||
// (undocumented)
|
||||
export namespace permissions {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<PermissionsService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<PermissionsService> | undefined) => {
|
||||
factory: ServiceFactory<PermissionsService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
authorize: jest.MockInstance<
|
||||
Promise<DefinitivePolicyDecision[]>,
|
||||
[
|
||||
requests: AuthorizePermissionRequest[],
|
||||
options?: EvaluatorRequestOptions | undefined,
|
||||
],
|
||||
unknown
|
||||
>;
|
||||
authorizeConditional: jest.MockInstance<
|
||||
Promise<PolicyDecision[]>,
|
||||
[
|
||||
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<RootLifecycleService, 'root'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<RootLifecycleService> | undefined) => {
|
||||
factory: ServiceFactory<RootLifecycleService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
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<LoggerService, 'root'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<RootLoggerService> | undefined) => {
|
||||
factory: ServiceFactory<RootLoggerService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
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, [meta: JsonObject], unknown>;
|
||||
} & RootLoggerService;
|
||||
}
|
||||
// (undocumented)
|
||||
export namespace scheduler {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<SchedulerService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<SchedulerService> | undefined) => {
|
||||
factory: ServiceFactory<SchedulerService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
triggerTask: jest.MockInstance<Promise<void>, [id: string], unknown>;
|
||||
scheduleTask: jest.MockInstance<
|
||||
Promise<void>,
|
||||
[task: TaskScheduleDefinition & TaskInvocationDefinition],
|
||||
unknown
|
||||
>;
|
||||
createScheduledTaskRunner: jest.MockInstance<
|
||||
TaskRunner,
|
||||
[schedule: TaskScheduleDefinition],
|
||||
unknown
|
||||
>;
|
||||
getScheduledTasks: jest.MockInstance<
|
||||
Promise<TaskDescriptor[]>,
|
||||
[],
|
||||
unknown
|
||||
>;
|
||||
} & SchedulerService;
|
||||
}
|
||||
// (undocumented)
|
||||
export function tokenManager(): TokenManagerService;
|
||||
@@ -110,11 +326,48 @@ export namespace mockServices {
|
||||
export namespace tokenManager {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<TokenManagerService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<TokenManagerService> | undefined) => {
|
||||
factory: ServiceFactory<TokenManagerService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
getToken: jest.MockInstance<
|
||||
Promise<{
|
||||
token: string;
|
||||
}>,
|
||||
[],
|
||||
unknown
|
||||
>;
|
||||
authenticate: jest.MockInstance<
|
||||
Promise<void>,
|
||||
[token: string],
|
||||
unknown
|
||||
>;
|
||||
} & TokenManagerService;
|
||||
}
|
||||
// (undocumented)
|
||||
export namespace urlReader {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<UrlReaderService, 'plugin'>;
|
||||
const // (undocumented)
|
||||
mock: (partialImpl?: Partial<UrlReaderService> | undefined) => {
|
||||
factory: ServiceFactory<UrlReaderService, 'root' | 'plugin'>;
|
||||
} & {
|
||||
readUrl: jest.MockInstance<
|
||||
Promise<ReadUrlResponse>,
|
||||
[url: string, options?: ReadUrlOptions | undefined],
|
||||
unknown
|
||||
>;
|
||||
readTree: jest.MockInstance<
|
||||
Promise<ReadTreeResponse>,
|
||||
[url: string, options?: ReadTreeOptions | undefined],
|
||||
unknown
|
||||
>;
|
||||
search: jest.MockInstance<
|
||||
Promise<SearchResponse>,
|
||||
[url: string, options?: SearchOptions | undefined],
|
||||
unknown
|
||||
>;
|
||||
} & UrlReaderService;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
"testcontainers": "^8.1.2",
|
||||
"uuid": "^8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/jest": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@types/supertest": "^2.0.8",
|
||||
|
||||
@@ -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<TService, any>;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function simpleMock<TService>(
|
||||
ref: ServiceRef<TService, any>,
|
||||
mockFactory: () => jest.Mocked<TService>,
|
||||
): (
|
||||
partialImpl?: Partial<TService>,
|
||||
) => { factory: ServiceFactory<TService> } & jest.Mocked<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,
|
||||
})(),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @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(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user