diff --git a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts
index 92e3261410..f625f0daf8 100644
--- a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts
+++ b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.test.ts
@@ -116,7 +116,7 @@ describe('BitbucketCloudClient', () => {
const response = {
values: [
{
- type: 'repository',
+ type: 'project',
slug: 'project1',
} as Models.Project,
],
diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx
index f799d68c2d..9dae5b24a6 100644
--- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx
+++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx
@@ -16,7 +16,13 @@
import React from 'react';
import { BitbucketRepoPicker } from './BitbucketRepoPicker';
-import { render, fireEvent } from '@testing-library/react';
+import { render, fireEvent, waitFor } from '@testing-library/react';
+import { setupServer } from 'msw/node';
+import { rest } from 'msw';
+import { Models } from '@backstage/plugin-bitbucket-cloud-common';
+import userEvent from '@testing-library/user-event';
+
+const server = setupServer();
describe('BitbucketRepoPicker', () => {
it('renders a select if there is a list of allowed owners', async () => {
@@ -136,4 +142,129 @@ describe('BitbucketRepoPicker', () => {
expect(await findByText('project2')).toBeInTheDocument();
});
});
+
+ describe('autocompletion', () => {
+ beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
+ beforeEach(() => {
+ // BitbucketCloudClient.listWorkspaces()
+ server.use(
+ rest.get('https://api.bitbucket.org/2.0/workspaces', (_, res, ctx) => {
+ const response = {
+ values: [
+ {
+ type: 'workspace',
+ slug: 'workspace1',
+ } as Models.Workspace,
+ ],
+ };
+ return res(ctx.json(response));
+ }),
+ );
+
+ // BitbucketCloudClient.listProjectsByWorkspace()
+ server.use(
+ rest.get(
+ 'https://api.bitbucket.org/2.0/workspaces/workspace1/projects',
+ (_, res, ctx) => {
+ const response = {
+ values: [
+ {
+ type: 'project',
+ key: 'project1',
+ } as Models.Project,
+ ],
+ };
+ return res(ctx.json(response));
+ },
+ ),
+ );
+
+ // BitbucketCloudClient.listRepositoriesByWorkspace()
+ server.use(
+ rest.get(
+ 'https://api.bitbucket.org/2.0/repositories/workspace1',
+ (_, res, ctx) => {
+ const response = {
+ values: [
+ {
+ type: 'repository',
+ slug: 'repo1',
+ } as Models.Repository,
+ ],
+ };
+ return res(ctx.json(response));
+ },
+ ),
+ );
+ });
+ afterAll(() => server.close());
+ afterEach(() => server.resetHandlers());
+
+ it('should populate workspaces if host is set and accessToken is provided', async () => {
+ const onChange = jest.fn();
+ const { getAllByRole, getByText } = render(
+ ,
+ );
+
+ // Open the Autcomplete dropdown
+ const workspaceInput = getAllByRole('textbox')[0];
+ await userEvent.click(workspaceInput);
+
+ // Verify that the available workspaces are shown
+ await waitFor(() => expect(getByText('workspace1')).toBeInTheDocument());
+
+ // Verify that selecting an option calls onChange
+ await userEvent.click(getByText('workspace1'));
+ expect(onChange).toHaveBeenCalledWith({ workspace: 'workspace1' });
+ });
+
+ it('should populate projects if host and workspace are set and accessToken is provided', async () => {
+ const onChange = jest.fn();
+ const { getAllByRole, getByText } = render(
+ ,
+ );
+
+ // Open the Autcomplete dropdown
+ const projectInput = getAllByRole('textbox')[1];
+ await userEvent.click(projectInput);
+
+ // Verify that the available projects are shown
+ await waitFor(() => expect(getByText('project1')).toBeInTheDocument());
+
+ // Verify that selecting an option calls onChange
+ await userEvent.click(getByText('project1'));
+ expect(onChange).toHaveBeenCalledWith({ project: 'project1' });
+ });
+
+ it('should populate repositories if host, workspace and project are set and accessToken is provided', async () => {
+ const onChange = jest.fn();
+ render(
+ ,
+ );
+
+ // Verify that the available repos are updated
+ await waitFor(() =>
+ expect(onChange).toHaveBeenCalledWith({ availableRepos: ['repo1'] }),
+ );
+ });
+ });
});
diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx
index a56e1ad9ad..67e82abc3f 100644
--- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx
+++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx
@@ -103,6 +103,33 @@ export const BitbucketRepoPicker = (props: {
[client, host],
);
+ // Update available projects when workspace changes
+ useDebounce(
+ () => {
+ const updateAvailableProjects = async () => {
+ if (client)
+ if (!workspace) {
+ setAvailableProjects([]);
+ } else {
+ const result: string[] = [];
+
+ for await (const page of client
+ .listProjectsByWorkspace(workspace)
+ .iteratePages()) {
+ const keys = [...page.values!].map(p => p.key!);
+ result.push(...keys);
+ }
+
+ setAvailableProjects(result);
+ }
+ };
+
+ updateAvailableProjects().catch(() => setAvailableProjects([]));
+ },
+ 500,
+ [client, workspace],
+ );
+
// Update available repositories when workspace or project changes
useDebounce(
() => {
@@ -134,33 +161,6 @@ export const BitbucketRepoPicker = (props: {
[client, workspace, project, onChange],
);
- // Update available projects when workspace changes
- useDebounce(
- () => {
- const updateAvailableProjects = async () => {
- if (client)
- if (!workspace) {
- setAvailableProjects([]);
- } else {
- const result: string[] = [];
-
- for await (const page of client
- .listProjectsByWorkspace(workspace)
- .iteratePages()) {
- const keys = [...page.values!].map(p => p.key!);
- result.push(...keys);
- }
-
- setAvailableProjects(result);
- }
- };
-
- updateAvailableProjects().catch(() => setAvailableProjects([]));
- },
- 500,
- [client, workspace],
- );
-
return (
<>
{host === 'bitbucket.org' && (