feat(scaffolder): implement scaffolderServiceRef for credentials aware communication (#33044)
* add scaffolderServiceRef to scaffolder-node Signed-off-by: benjdlambert <ben@blam.sh> * make ScaffolderApi methods required, add tests Signed-off-by: benjdlambert <ben@blam.sh> * use request objects for single-string params in ScaffolderService Signed-off-by: benjdlambert <ben@blam.sh> * add scaffolderServiceMock test utility Signed-off-by: benjdlambert <ben@blam.sh> * adjust review comments Signed-off-by: benjdlambert <ben@blam.sh> * add scaffolderApiMock test utility to scaffolder-react Signed-off-by: benjdlambert <ben@blam.sh> * use items/totalItems response shape for listTasks Signed-off-by: benjdlambert <ben@blam.sh> * pass credentials through for autocomplete Signed-off-by: benjdlambert <ben@blam.sh> --------- Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
@@ -25,3 +25,4 @@ export * from './tasks';
|
||||
export * from './files';
|
||||
export * from './types';
|
||||
export * from './extensions';
|
||||
export * from './scaffolderService';
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright 2025 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 {
|
||||
createBackendModule,
|
||||
createServiceFactory,
|
||||
createServiceRef,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import {
|
||||
ServiceFactoryTester,
|
||||
mockCredentials,
|
||||
mockServices,
|
||||
registerMswTestHooks,
|
||||
startTestBackend,
|
||||
} from '@backstage/backend-test-utils';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { scaffolderServiceRef } from './scaffolderService';
|
||||
|
||||
describe('scaffolderServiceRef', () => {
|
||||
const server = setupServer();
|
||||
registerMswTestHooks(server);
|
||||
|
||||
it('should return a scaffolder service', async () => {
|
||||
expect.assertions(1);
|
||||
const testModule = createBackendModule({
|
||||
moduleId: 'test',
|
||||
pluginId: 'test',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
scaffolder: scaffolderServiceRef,
|
||||
},
|
||||
async init({ scaffolder }) {
|
||||
expect(scaffolder.getTask).toBeDefined();
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
await startTestBackend({
|
||||
features: [testModule],
|
||||
});
|
||||
});
|
||||
|
||||
it('should inject token from user credentials', async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
server.use(
|
||||
rest.get('*/api/scaffolder/v2/tasks/:taskId', (req, res, ctx) => {
|
||||
expect(req.headers.get('authorization')).toBe(
|
||||
mockCredentials.service.header({
|
||||
onBehalfOf: mockCredentials.user(),
|
||||
targetPluginId: 'scaffolder',
|
||||
}),
|
||||
);
|
||||
return res(
|
||||
ctx.json({
|
||||
id: 'task-1',
|
||||
spec: {},
|
||||
status: 'completed',
|
||||
createdAt: '2025-01-01T00:00:00Z',
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
const tester = ServiceFactoryTester.from(
|
||||
createServiceFactory({
|
||||
service: createServiceRef<void>({ id: 'unused-dummy' }),
|
||||
deps: {},
|
||||
factory() {},
|
||||
}),
|
||||
{ dependencies: [mockServices.discovery.factory()] },
|
||||
);
|
||||
|
||||
const scaffolder = await tester.getService(scaffolderServiceRef);
|
||||
|
||||
await scaffolder.getTask(
|
||||
{ taskId: 'task-1' },
|
||||
{
|
||||
credentials: mockCredentials.user(),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should inject token from service credentials', async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
server.use(
|
||||
rest.get('*/api/scaffolder/v2/tasks/:taskId', (req, res, ctx) => {
|
||||
expect(req.headers.get('authorization')).toBe(
|
||||
mockCredentials.service.header({
|
||||
onBehalfOf: mockCredentials.service(),
|
||||
targetPluginId: 'scaffolder',
|
||||
}),
|
||||
);
|
||||
return res(
|
||||
ctx.json({
|
||||
id: 'task-1',
|
||||
spec: {},
|
||||
status: 'completed',
|
||||
createdAt: '2025-01-01T00:00:00Z',
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
const tester = ServiceFactoryTester.from(
|
||||
createServiceFactory({
|
||||
service: createServiceRef<void>({ id: 'unused-dummy' }),
|
||||
deps: {},
|
||||
factory() {},
|
||||
}),
|
||||
{ dependencies: [mockServices.discovery.factory()] },
|
||||
);
|
||||
|
||||
const scaffolder = await tester.getService(scaffolderServiceRef);
|
||||
|
||||
await scaffolder.getTask(
|
||||
{ taskId: 'task-1' },
|
||||
{
|
||||
credentials: mockCredentials.service(),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should pass credentials for direct HTTP calls like getLogs', async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
server.use(
|
||||
rest.get('*/api/scaffolder/v2/tasks/:taskId/events', (req, res, ctx) => {
|
||||
expect(req.headers.get('authorization')).toBe(
|
||||
mockCredentials.service.header({
|
||||
onBehalfOf: mockCredentials.user(),
|
||||
targetPluginId: 'scaffolder',
|
||||
}),
|
||||
);
|
||||
return res(ctx.json([]));
|
||||
}),
|
||||
);
|
||||
|
||||
const tester = ServiceFactoryTester.from(
|
||||
createServiceFactory({
|
||||
service: createServiceRef<void>({ id: 'unused-dummy' }),
|
||||
deps: {},
|
||||
factory() {},
|
||||
}),
|
||||
{ dependencies: [mockServices.discovery.factory()] },
|
||||
);
|
||||
|
||||
const scaffolder = await tester.getService(scaffolderServiceRef);
|
||||
|
||||
await scaffolder.getLogs(
|
||||
{ taskId: 'task-1' },
|
||||
{ credentials: mockCredentials.user() },
|
||||
);
|
||||
});
|
||||
|
||||
it('should pass createdBy and pagination params for listTasks', async () => {
|
||||
expect.assertions(4);
|
||||
|
||||
server.use(
|
||||
rest.get('*/api/scaffolder/v2/tasks', (req, res, ctx) => {
|
||||
expect(req.url.searchParams.get('createdBy')).toBe(
|
||||
'user:default/guest',
|
||||
);
|
||||
expect(req.url.searchParams.get('limit')).toBe('10');
|
||||
expect(req.url.searchParams.get('offset')).toBe('5');
|
||||
return res(ctx.json({ tasks: [], totalTasks: 0 }));
|
||||
}),
|
||||
);
|
||||
|
||||
const tester = ServiceFactoryTester.from(
|
||||
createServiceFactory({
|
||||
service: createServiceRef<void>({ id: 'unused-dummy' }),
|
||||
deps: {},
|
||||
factory() {},
|
||||
}),
|
||||
{ dependencies: [mockServices.discovery.factory()] },
|
||||
);
|
||||
|
||||
const scaffolder = await tester.getService(scaffolderServiceRef);
|
||||
|
||||
const result = await scaffolder.listTasks(
|
||||
{ createdBy: 'user:default/guest', limit: 10, offset: 5 },
|
||||
{ credentials: mockCredentials.user() },
|
||||
);
|
||||
|
||||
expect(result).toEqual({ items: [], totalItems: 0 });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright 2025 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 {
|
||||
AuthService,
|
||||
BackstageCredentials,
|
||||
coreServices,
|
||||
createServiceFactory,
|
||||
createServiceRef,
|
||||
DiscoveryService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import {
|
||||
ListActionsResponse,
|
||||
ListTemplatingExtensionsResponse,
|
||||
LogEvent,
|
||||
ScaffolderClient,
|
||||
ScaffolderDryRunOptions,
|
||||
ScaffolderDryRunResponse,
|
||||
ScaffolderRequestOptions,
|
||||
ScaffolderScaffoldOptions,
|
||||
ScaffolderScaffoldResponse,
|
||||
ScaffolderTask,
|
||||
ScaffolderTaskStatus,
|
||||
} from '@backstage/plugin-scaffolder-common';
|
||||
import type { TemplateParameterSchema } from '@backstage/plugin-scaffolder-common';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface ScaffolderServiceRequestOptions {
|
||||
credentials: BackstageCredentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* A backend service interface for the scaffolder that uses
|
||||
* {@link @backstage/backend-plugin-api#BackstageCredentials} instead of tokens.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ScaffolderService {
|
||||
getTemplateParameterSchema(
|
||||
request: { templateRef: string },
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<TemplateParameterSchema>;
|
||||
|
||||
scaffold(
|
||||
request: ScaffolderScaffoldOptions,
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<ScaffolderScaffoldResponse>;
|
||||
|
||||
getTask(
|
||||
request: { taskId: string },
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<ScaffolderTask>;
|
||||
|
||||
cancelTask(
|
||||
request: { taskId: string },
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<{ status?: ScaffolderTaskStatus }>;
|
||||
|
||||
retry(
|
||||
request: { taskId: string },
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<{ id: string }>;
|
||||
|
||||
listTasks(
|
||||
request: {
|
||||
createdBy?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
},
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<{ items: ScaffolderTask[]; totalItems: number }>;
|
||||
|
||||
listActions(
|
||||
request?: {},
|
||||
options?: ScaffolderServiceRequestOptions,
|
||||
): Promise<ListActionsResponse>;
|
||||
|
||||
listTemplatingExtensions(
|
||||
request?: {},
|
||||
options?: ScaffolderServiceRequestOptions,
|
||||
): Promise<ListTemplatingExtensionsResponse>;
|
||||
|
||||
getLogs(
|
||||
request: {
|
||||
taskId: string;
|
||||
after?: number;
|
||||
},
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<LogEvent[]>;
|
||||
|
||||
dryRun(
|
||||
request: ScaffolderDryRunOptions,
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<ScaffolderDryRunResponse>;
|
||||
|
||||
autocomplete(
|
||||
request: {
|
||||
token: string;
|
||||
provider: string;
|
||||
resource: string;
|
||||
context: Record<string, string>;
|
||||
},
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<{ results: { title?: string; id: string }[] }>;
|
||||
}
|
||||
|
||||
class DefaultScaffolderService implements ScaffolderService {
|
||||
readonly #auth: AuthService;
|
||||
readonly #client: ScaffolderClient;
|
||||
readonly #discovery: DiscoveryService;
|
||||
|
||||
constructor(options: {
|
||||
auth: AuthService;
|
||||
client: ScaffolderClient;
|
||||
discovery: DiscoveryService;
|
||||
}) {
|
||||
this.#auth = options.auth;
|
||||
this.#client = options.client;
|
||||
this.#discovery = options.discovery;
|
||||
}
|
||||
|
||||
async getTemplateParameterSchema(
|
||||
request: { templateRef: string },
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<TemplateParameterSchema> {
|
||||
return this.#client.getTemplateParameterSchema(
|
||||
request.templateRef,
|
||||
await this.#getOptions(options),
|
||||
);
|
||||
}
|
||||
|
||||
async scaffold(
|
||||
request: ScaffolderScaffoldOptions,
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<ScaffolderScaffoldResponse> {
|
||||
return this.#client.scaffold(request, await this.#getOptions(options));
|
||||
}
|
||||
|
||||
async getTask(
|
||||
request: { taskId: string },
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<ScaffolderTask> {
|
||||
return this.#client.getTask(
|
||||
request.taskId,
|
||||
await this.#getOptions(options),
|
||||
);
|
||||
}
|
||||
|
||||
async cancelTask(
|
||||
request: { taskId: string },
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<{ status?: ScaffolderTaskStatus }> {
|
||||
return this.#client.cancelTask(
|
||||
request.taskId,
|
||||
await this.#getOptions(options),
|
||||
);
|
||||
}
|
||||
|
||||
async retry(
|
||||
request: { taskId: string },
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<{ id: string }> {
|
||||
return this.#client.retry(request.taskId, await this.#getOptions(options));
|
||||
}
|
||||
|
||||
async listTasks(
|
||||
request: {
|
||||
createdBy?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
},
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<{ items: ScaffolderTask[]; totalItems: number }> {
|
||||
const { token } = await this.#getOptions(options);
|
||||
const baseUrl = await this.#discovery.getBaseUrl('scaffolder');
|
||||
|
||||
const params = new URLSearchParams();
|
||||
if (request.createdBy) {
|
||||
params.set('createdBy', request.createdBy);
|
||||
}
|
||||
if (request.limit !== undefined) {
|
||||
params.set('limit', String(request.limit));
|
||||
}
|
||||
if (request.offset !== undefined) {
|
||||
params.set('offset', String(request.offset));
|
||||
}
|
||||
|
||||
const query = params.toString();
|
||||
const url = `${baseUrl}/v2/tasks${query ? `?${query}` : ''}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token && { Authorization: `Bearer ${token}` }),
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
|
||||
const body = await response.json();
|
||||
return {
|
||||
items: body.tasks,
|
||||
totalItems: body.totalTasks ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
async listActions(
|
||||
_request?: {},
|
||||
options?: ScaffolderServiceRequestOptions,
|
||||
): Promise<ListActionsResponse> {
|
||||
return this.#client.listActions(
|
||||
options ? await this.#getOptions(options) : {},
|
||||
);
|
||||
}
|
||||
|
||||
async listTemplatingExtensions(
|
||||
_request?: {},
|
||||
options?: ScaffolderServiceRequestOptions,
|
||||
): Promise<ListTemplatingExtensionsResponse> {
|
||||
return this.#client.listTemplatingExtensions(
|
||||
options ? await this.#getOptions(options) : {},
|
||||
);
|
||||
}
|
||||
|
||||
async getLogs(
|
||||
request: {
|
||||
taskId: string;
|
||||
after?: number;
|
||||
},
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<LogEvent[]> {
|
||||
const { token } = await this.#getOptions(options);
|
||||
const baseUrl = await this.#discovery.getBaseUrl('scaffolder');
|
||||
|
||||
const params = new URLSearchParams();
|
||||
if (request.after !== undefined) {
|
||||
params.set('after', String(request.after));
|
||||
}
|
||||
|
||||
const query = params.toString();
|
||||
const taskId = encodeURIComponent(request.taskId);
|
||||
const url = `${baseUrl}/v2/tasks/${taskId}/events${
|
||||
query ? `?${query}` : ''
|
||||
}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token && { Authorization: `Bearer ${token}` }),
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async dryRun(
|
||||
request: ScaffolderDryRunOptions,
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<ScaffolderDryRunResponse> {
|
||||
return this.#client.dryRun(request, await this.#getOptions(options));
|
||||
}
|
||||
|
||||
async autocomplete(
|
||||
request: {
|
||||
token: string;
|
||||
provider: string;
|
||||
resource: string;
|
||||
context: Record<string, string>;
|
||||
},
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<{ results: { title?: string; id: string }[] }> {
|
||||
return this.#client.autocomplete(request, await this.#getOptions(options));
|
||||
}
|
||||
|
||||
async #getOptions(
|
||||
options: ScaffolderServiceRequestOptions,
|
||||
): Promise<ScaffolderRequestOptions> {
|
||||
return this.#auth.getPluginRequestToken({
|
||||
onBehalfOf: options.credentials,
|
||||
targetPluginId: 'scaffolder',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A service ref for the scaffolder client, to be used by backend plugins
|
||||
* and modules that need to interact with the scaffolder API.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const scaffolderServiceRef = createServiceRef<ScaffolderService>({
|
||||
id: 'scaffolder-client',
|
||||
defaultFactory: async service =>
|
||||
createServiceFactory({
|
||||
service,
|
||||
deps: {
|
||||
auth: coreServices.auth,
|
||||
discovery: coreServices.discovery,
|
||||
config: coreServices.rootConfig,
|
||||
},
|
||||
async factory({ auth, discovery, config }) {
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
const client = new ScaffolderClient({
|
||||
discoveryApi: discovery,
|
||||
fetchApi: { fetch },
|
||||
scmIntegrationsApi: integrations,
|
||||
});
|
||||
return new DefaultScaffolderService({
|
||||
auth,
|
||||
client,
|
||||
discovery,
|
||||
});
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Backend test helpers for the Scaffolder plugin.
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export type {
|
||||
ScaffolderService,
|
||||
ScaffolderServiceRequestOptions,
|
||||
} from './scaffolderService';
|
||||
export { scaffolderServiceMock } from './testUtils/scaffolderServiceMock';
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2025 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 { scaffolderServiceMock } from './scaffolderServiceMock';
|
||||
|
||||
describe('scaffolderServiceMock', () => {
|
||||
it('creates a mock with all methods as jest.fn()', () => {
|
||||
const mock = scaffolderServiceMock.mock();
|
||||
|
||||
expect(mock.getTask).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('supports overriding individual methods', async () => {
|
||||
const mock = scaffolderServiceMock.mock({
|
||||
getTask: jest.fn().mockResolvedValue({ id: 'task-1' }),
|
||||
});
|
||||
|
||||
await expect(
|
||||
mock.getTask({ taskId: 'task-1' }, { credentials: expect.anything() }),
|
||||
).resolves.toEqual(expect.objectContaining({ id: 'task-1' }));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2025 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 { createServiceMock } from '@backstage/backend-test-utils';
|
||||
import { scaffolderServiceRef, ScaffolderService } from '../scaffolderService';
|
||||
|
||||
/**
|
||||
* A collection of mock functionality for the scaffolder service.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export namespace scaffolderServiceMock {
|
||||
/**
|
||||
* Creates a scaffolder service whose methods are mock functions, possibly with
|
||||
* some of them overloaded by the caller.
|
||||
*/
|
||||
export const mock = createServiceMock<ScaffolderService>(
|
||||
scaffolderServiceRef,
|
||||
() => ({
|
||||
getTemplateParameterSchema: jest.fn(),
|
||||
scaffold: jest.fn(),
|
||||
getTask: jest.fn(),
|
||||
cancelTask: jest.fn(),
|
||||
retry: jest.fn(),
|
||||
listTasks: jest.fn(),
|
||||
listActions: jest.fn(),
|
||||
listTemplatingExtensions: jest.fn(),
|
||||
getLogs: jest.fn(),
|
||||
dryRun: jest.fn(),
|
||||
autocomplete: jest.fn(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user