diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts index 50e218ce85..7367504d93 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts @@ -43,7 +43,11 @@ describe('handleAutocompleteRequest', () => { it('should pass the token to the client', async () => { const accessToken = 'foo'; - await handleAutocompleteRequest(accessToken, 'workspaces', {}); + await handleAutocompleteRequest({ + token: accessToken, + context: {}, + resource: 'workspaces', + }); expect(fromConfig).toHaveBeenCalledWith( expect.objectContaining({ accessToken }), @@ -51,37 +55,57 @@ describe('handleAutocompleteRequest', () => { }); it('should return workspaces', async () => { - const result = await handleAutocompleteRequest('foo', 'workspaces', {}); + const result = await handleAutocompleteRequest({ + token: 'foo', + context: {}, + resource: 'workspaces', + }); - expect(result).toEqual(['workspace1']); + expect(result).toEqual({ results: [{ title: 'workspace1' }] }); }); it('should return projects', async () => { - const result = await handleAutocompleteRequest('foo', 'projects', { - workspace: 'workspace1', + const result = await handleAutocompleteRequest({ + token: 'foo', + context: { + workspace: 'workspace1', + }, + resource: 'projects', }); - expect(result).toEqual(['project1']); + expect(result).toEqual({ results: [{ title: 'project1' }] }); }); it('should return repositories', async () => { - const result = await handleAutocompleteRequest('foo', 'repositories', { - workspace: 'workspace1', - project: 'project1', + const result = await handleAutocompleteRequest({ + token: 'foo', + resource: 'repositories', + context: { + workspace: 'workspace1', + project: 'project1', + }, }); - expect(result).toEqual(['repository1']); + expect(result).toEqual({ results: [{ title: 'repository1' }] }); }); it('should throw an error when passing an invalid resource', async () => { await expect( - handleAutocompleteRequest('token', 'invalid', {}), + handleAutocompleteRequest({ + token: 'token', + resource: 'invalid', + context: {}, + }), ).rejects.toThrow(InputError); }); it('should throw an error when there are missing parameters', async () => { await expect( - handleAutocompleteRequest('token', 'projects', {}), + handleAutocompleteRequest({ + token: 'token', + resource: 'projects', + context: {}, + }), ).rejects.toThrow(InputError); }); }); diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index af6625c8b8..eb977787c2 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -114,6 +114,7 @@ "zod": "^3.22.4" }, "devDependencies": { + "@backstage/backend-app-api": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-scaffolder-node-test-utils": "workspace:^", diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 4bd3847666..f0e78c75c7 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -46,6 +46,8 @@ import { PermissionEvaluator, } from '@backstage/plugin-permission-common'; import { mockCredentials, mockServices } from '@backstage/backend-test-utils'; +import { AutocompleteHandler } from '@backstage/plugin-scaffolder-node/alpha'; +import { MiddlewareFactory } from '@backstage/backend-app-api'; const mockAccess = jest.fn(); @@ -62,8 +64,6 @@ jest.mock('fs-extra', () => ({ remove: jest.fn(), })); -jest.mock('./autocomplete'); - function createDatabase(): PluginDatabaseManager { return DatabaseManager.fromConfig( new ConfigReader({ @@ -1465,26 +1465,72 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ }); describe('GET /v2/autocomplete/:provider/:resource', () => { - it('should handle requests for provider bitbucketCloud', async () => { - jest - .mocked(handleBitbucketCloudRequest) - .mockResolvedValue(['resource1']); + let handleAutocompleteRequest: AutocompleteHandler; - const bbToken = 'foo'; - const resource = 'bar'; + beforeEach(async () => { + handleAutocompleteRequest = jest.fn().mockResolvedValue({ + results: [{ title: 'blob' }], + }); + + const logger = mockServices.logger.mock(); + const middleware = MiddlewareFactory.create({ config, logger }); + const router = await createRouter({ + logger: loggerToWinstonLogger(mockServices.logger.mock()), + config: new ConfigReader({}), + database: createDatabase(), + catalogClient, + reader: mockUrlReader, + taskBroker, + permissions: permissionApi, + auth, + httpAuth, + discovery, + autocompleteHandlers: { + 'test-provider': handleAutocompleteRequest, + }, + }); + + app = express().use(router).use(middleware.error()); + }); + + it('should throw an error when the provider is not registered', async () => { + const response = await request(app) + .post('/v2/autocomplete/unknown-provider/resource') + .send({ + token: 'token', + context: {}, + }); + + expect(response.status).toEqual(400); + expect(response.body).toEqual( + expect.objectContaining({ + error: { + message: 'Unsupported provider: unknown-provider', + name: 'InputError', + }, + }), + ); + }); + + it('should call the autocomplete handler', async () => { + const context = { mock: 'context' }; + const mockToken = 'mocktoken'; const response = await request(app) - .get(`/v2/autocomplete/bitbucketCloud/${resource}`) - .query({ token: bbToken, workspace: 'workspace1' }); - - expect(handleBitbucketCloudRequest).toHaveBeenCalledWith( - bbToken, - resource, - { workspace: 'workspace1' }, - ); + .post('/v2/autocomplete/test-provider/resource') + .send({ + token: mockToken, + context, + }); expect(response.status).toEqual(200); - expect(response.body).toEqual(['resource1']); + + expect(response.body).toEqual({ results: [{ title: 'blob' }] }); + expect(handleAutocompleteRequest).toHaveBeenCalledWith({ + token: mockToken, + context, + resource: 'resource', + }); }); }); }); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index e5f88c3482..9b3f5173c8 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -785,6 +785,7 @@ export async function createRouter( if (!autocompleteHandlers[provider]) { throw new InputError(`Unsupported provider: ${provider}`); } + const { results } = await autocompleteHandlers[provider]({ resource, token, diff --git a/yarn.lock b/yarn.lock index 225004ba7a..9952ad2bbd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7083,6 +7083,7 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-scaffolder-backend@workspace:plugins/scaffolder-backend" dependencies: + "@backstage/backend-app-api": "workspace:^" "@backstage/backend-common": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-tasks": "workspace:^"