diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 0aa4b5b1c8..eccae89620 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "@backstage/config": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "yaml": "^2.3.3" diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts index ea892882ea..b66f842688 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -29,6 +29,8 @@ describe('sentry:project:create action', () => { }), }); + let fetch: jest.Func; + const mockFetch = (response = {}) => { const mockedResponse = { status: 201, @@ -42,10 +44,8 @@ describe('sentry:project:create action', () => { text: async () => Promise.resolve('Unexpected error.'), ...response, }; - global.fetch = jest - .fn() - .mockImplementation(() => Promise.resolve(mockedResponse)); + fetch = jest.fn().mockImplementation(() => Promise.resolve(mockedResponse)); return mockedResponse; }; @@ -74,7 +74,10 @@ describe('sentry:project:create action', () => { }); test('should request sentry project create with specified parameters.', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig()); + const action = createSentryCreateProjectAction(createScaffolderConfig(), { + fetch, + }); + const actionContext = getActionContext(); await action.handler(actionContext); @@ -96,14 +99,17 @@ describe('sentry:project:create action', () => { }); test('should request sentry project create with added optional specified project slug', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig()); + const action = createSentryCreateProjectAction(createScaffolderConfig(), { + fetch, + }); + const actionContext = getActionContext(); actionContext.input = { ...actionContext.input, slug: 'project-slug' }; await action.handler(actionContext); - expect(global.fetch).toHaveBeenNthCalledWith( + expect(fetch).toHaveBeenNthCalledWith( 1, `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, { @@ -128,6 +134,7 @@ describe('sentry:project:create action', () => { token: sentryScaffolderConfigToken, }, }), + { fetch }, ); const actionContext = getActionContext(); @@ -153,7 +160,9 @@ describe('sentry:project:create action', () => { }); test('should throw InputError when auth token is missing from input parameters and scaffolder config.', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig()); + const action = createSentryCreateProjectAction(createScaffolderConfig(), { + fetch, + }); const actionContext = getActionContext(); actionContext.input.authToken = undefined; @@ -166,7 +175,6 @@ describe('sentry:project:create action', () => { }); test('should throw InputError when sentry API returns unexpected content-type.', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig()); const actionContext = getActionContext(); const mockedFetchResponse = mockFetch({ @@ -175,6 +183,10 @@ describe('sentry:project:create action', () => { }, }); + const action = createSentryCreateProjectAction(createScaffolderConfig(), { + fetch, + }); + expect.assertions(1); await expect(async () => { @@ -187,13 +199,16 @@ describe('sentry:project:create action', () => { }); test('should throw InputError when sentry API returns unexpected status code.', async () => { - const action = createSentryCreateProjectAction(createScaffolderConfig()); const actionContext = getActionContext(); const mockedFetchResponse = mockFetch({ status: 400, }); + const action = createSentryCreateProjectAction(createScaffolderConfig(), { + fetch, + }); + expect.assertions(1); await expect(async () => { diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts index 504084b9df..bb2ee6039e 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -18,6 +18,7 @@ import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; import { InputError } from '@backstage/errors'; import { Config } from '@backstage/config'; import { examples } from './createProject.examples'; +import { FetchApi } from '@backstage/core-plugin-api'; /** * Creates the `sentry:create-project` Scaffolder action. @@ -27,9 +28,13 @@ import { examples } from './createProject.examples'; * See {@link https://backstage.io/docs/features/software-templates/writing-custom-actions}. * * @param options - Configuration of the Sentry API. + * @param fetchApi - fetch implementation to use for calling Sentry service. * @public */ -export function createSentryCreateProjectAction(options: { config: Config }) { +export function createSentryCreateProjectAction( + options: { config: Config }, + fetchApi?: FetchApi, +) { const { config } = options; return createTemplateAction<{ @@ -90,7 +95,7 @@ export function createSentryCreateProjectAction(options: { config: Config }) { throw new InputError(`No valid sentry token given`); } - const response = await fetch( + const response = await (fetchApi?.fetch ?? fetch)( `https://sentry.io/api/0/teams/${organizationSlug}/${teamSlug}/projects/`, { method: 'POST', diff --git a/yarn.lock b/yarn.lock index 968acd6f80..7a0ca3c78a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8660,6 +8660,7 @@ __metadata: dependencies: "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/types": "workspace:^"