From 3e5acb5e97c59ecdd2d63dd13ed64fe7c6b47ed2 Mon Sep 17 00:00:00 2001 From: asheen1234 Date: Mon, 30 Mar 2026 14:34:07 -0400 Subject: [PATCH 01/10] Add GitLabRepoOwnerPicker and tests Signed-off-by: asheen1234 --- .changeset/legal-results-kneel.md | 5 + .../GitLabRepoOwnerPicker.test.tsx | 149 ++++++++++++++++++ .../RepoOwnerPicker/GitLabRepoOwnerPicker.tsx | 113 +++++++++++++ .../RepoOwnerPicker/RepoOwnerPicker.tsx | 17 ++ 4 files changed, 284 insertions(+) create mode 100644 .changeset/legal-results-kneel.md create mode 100644 plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx create mode 100644 plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx diff --git a/.changeset/legal-results-kneel.md b/.changeset/legal-results-kneel.md new file mode 100644 index 0000000000..68b8c582cc --- /dev/null +++ b/.changeset/legal-results-kneel.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Added to field extension 'RepoOwnerPicker' for retrieving GitLab repository owners. diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx new file mode 100644 index 0000000000..ff4e5c151c --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx @@ -0,0 +1,149 @@ +/* + * 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 { + ScaffolderApi, + scaffolderApiRef, +} from '@backstage/plugin-scaffolder-react'; +import { GitLabRepoOwnerPicker } from './GitLabRepoOwnerPicker'; +import { act, fireEvent, waitFor, screen } from '@testing-library/react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import userEvent from '@testing-library/user-event'; + +describe('GitLabRepoOwnerPicker', () => { + const scaffolderApiMock: Partial = { + autocomplete: jest + .fn() + .mockResolvedValue({ results: [{ id: 'owner1' }, { id: 'owner2' }] }), + }; + + it('renders an input field', async () => { + const { getByRole } = await renderInTestApp( + + + , + ); + + expect(getByRole('textbox')).toBeInTheDocument(); + expect(getByRole('textbox')).toHaveValue('owner1'); + }); + + it('input field disabled', async () => { + await renderInTestApp( + + + , + ); + + const input = screen.getByRole('textbox'); + + // Expect input to be disabled + expect(input).toBeDisabled(); + expect(input).toHaveValue('owner1'); + }); + + it('calls onChange when the input field changes', async () => { + const onChange = jest.fn(); + + const { getByRole } = await renderInTestApp( + + + , + ); + + const input = getByRole('textbox'); + + act(() => { + input.focus(); + fireEvent.change(input, { + target: { value: 'owner2' }, + }); + input.blur(); + }); + + expect(onChange).toHaveBeenCalledWith({ owner: 'owner2' }); + }); + + it('should populate owners', async () => { + const onChange = jest.fn(); + + const { getByRole, getByText } = await renderInTestApp( + + + , + ); + + // Open the Autocomplete dropdown + const input = getByRole('textbox'); + await userEvent.click(input); + + // Verify that the available owners are shown + await waitFor(() => expect(getByText('owner1')).toBeInTheDocument()); + + // Verify that selecting an option calls onChange + await userEvent.click(getByText('owner1')); + expect(onChange).toHaveBeenCalledWith({ + owner: 'owner1', + }); + }); + + it('should filter out excluded owners', async () => { + const onChange = jest.fn(); + + const { getByRole, getByText } = await renderInTestApp( + + + , + ); + + // Open the Autocomplete dropdown + const input = getByRole('textbox'); + await userEvent.click(input); + + // Verify that the excluded owners are not shown + await waitFor(() => expect(getByText('owner2')).toBeInTheDocument()); + expect(screen.queryByText('owner1')).not.toBeInTheDocument(); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx new file mode 100644 index 0000000000..8bc626c0a5 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx @@ -0,0 +1,113 @@ +/* + * 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 { useApi } from '@backstage/core-plugin-api'; +import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; +import FormControl from '@material-ui/core/FormControl'; +import FormHelperText from '@material-ui/core/FormHelperText'; +import TextField from '@material-ui/core/TextField'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import { useCallback, useState } from 'react'; +import useDebounce from 'react-use/esm/useDebounce'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; + +import { BaseRepoOwnerPickerProps } from './types'; +import { scaffolderTranslationRef } from '../../../translation'; + +/** + * The underlying component that is rendered in the form for the `GitLabRepoOwnerPicker` + * field extension. + * + * @public + * + */ +export const GitLabRepoOwnerPicker = ({ + onChange, + state, + rawErrors, + accessToken, + isDisabled, + required, + schema, + excludedOwners = [], +}: BaseRepoOwnerPickerProps<{ + accessToken?: string; + excludedOwners?: string[]; +}>) => { + const { host, owner } = state; + + const [availableOwners, setAvailableOwners] = useState([]); + + const scaffolderApi = useApi(scaffolderApiRef); + const { t } = useTranslationRef(scaffolderTranslationRef); + + const updateAvailableOwners = useCallback(() => { + if (!scaffolderApi.autocomplete || !accessToken || !host) { + setAvailableOwners([]); + return; + } + + scaffolderApi + .autocomplete({ + token: accessToken, + resource: 'groups', + provider: 'gitlab', + context: { host }, + }) + .then(({ results }) => { + const owners = results + .map(r => r.id) + .filter(id => !excludedOwners.includes(id)); + + setAvailableOwners(owners); + }) + .catch(() => { + setAvailableOwners([]); + }); + }, [host, accessToken, scaffolderApi, excludedOwners]); + + useDebounce(updateAvailableOwners, 500, [updateAvailableOwners]); + + return ( + 0 && !owner} + > + { + onChange({ owner: newValue || '' }); + }} + disabled={isDisabled} + options={availableOwners} + renderInput={params => ( + + )} + freeSolo + autoSelect + /> + + {schema?.description ?? t('fields.repoOwnerPicker.description')} + + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx index bcb1a0001c..ad88b3a02a 100644 --- a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx @@ -27,6 +27,7 @@ import { RepoOwnerPickerProps } from './schema'; import { RepoOwnerPickerState } from './types'; import { DefaultRepoOwnerPicker } from './DefaultRepoOwnerPicker'; import { GitHubRepoOwnerPicker } from './GitHubRepoOwnerPicker'; +import { GitLabRepoOwnerPicker } from './GitLabRepoOwnerPicker'; /** * The underlying component that is rendered in the form for the `RepoOwnerPicker` @@ -120,6 +121,22 @@ export const RepoOwnerPicker = (props: RepoOwnerPickerProps) => { excludedOwners={excludedOwners} /> ); + case 'gitlab': + return ( + + ); default: return ( Date: Mon, 30 Mar 2026 19:24:56 -0400 Subject: [PATCH 02/10] fix: switch from id to title Signed-off-by: asheen1234 --- .../fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx | 4 +++- .../fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx index ff4e5c151c..863e9e5a96 100644 --- a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx @@ -27,7 +27,9 @@ describe('GitLabRepoOwnerPicker', () => { const scaffolderApiMock: Partial = { autocomplete: jest .fn() - .mockResolvedValue({ results: [{ id: 'owner1' }, { id: 'owner2' }] }), + .mockResolvedValue({ + results: [{ title: 'owner1' }, { title: 'owner2' }], + }), }; it('renders an input field', async () => { diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx index 8bc626c0a5..1136186ab5 100644 --- a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx @@ -69,8 +69,8 @@ export const GitLabRepoOwnerPicker = ({ }) .then(({ results }) => { const owners = results - .map(r => r.id) - .filter(id => !excludedOwners.includes(id)); + .map(r => r.title!) + .filter(title => !excludedOwners.includes(title)); setAvailableOwners(owners); }) From 7eeadfa8e311058a09a67a80b034be1c7449fd9b Mon Sep 17 00:00:00 2001 From: asheen1234 Date: Mon, 30 Mar 2026 21:12:40 -0400 Subject: [PATCH 03/10] feat: add RepoOwnerPicker tests and prettier linting Signed-off-by: asheen1234 --- .../GitLabRepoOwnerPicker.test.tsx | 8 +- .../RepoOwnerPicker/RepoOwnerPicker.test.tsx | 158 ++++++++++++++++++ 2 files changed, 161 insertions(+), 5 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx index 863e9e5a96..7fb9ea21d6 100644 --- a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx @@ -25,11 +25,9 @@ import userEvent from '@testing-library/user-event'; describe('GitLabRepoOwnerPicker', () => { const scaffolderApiMock: Partial = { - autocomplete: jest - .fn() - .mockResolvedValue({ - results: [{ title: 'owner1' }, { title: 'owner2' }], - }), + autocomplete: jest.fn().mockResolvedValue({ + results: [{ title: 'owner1' }, { title: 'owner2' }], + }), }; it('renders an input field', async () => { diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx index c51d74416b..12cdd34359 100644 --- a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx @@ -38,6 +38,10 @@ describe('RepoOwnerPicker', () => { byHost: () => ({ type: 'github' }), }; + const mockIntegrationsApiGitLab: Partial = { + byHost: () => ({ type: 'gitlab' }), + }; + let mockScmAuthApi: Partial; beforeEach(() => { @@ -305,4 +309,158 @@ describe('RepoOwnerPicker', () => { expect(getByText('abc123')).toBeInTheDocument(); }); }); + + describe('requestUserCredentialsGitLab', () => { + it('should call the scmAuthApi with the correct params', async () => { + const secretsKey = 'testKey'; + + const SecretsComponent = () => { + const { secrets } = useTemplateSecrets(); + const secret = secrets[secretsKey]; + return secret ?
{secret}
: null; + }; + + const { getByText } = await renderInTestApp( + + +
, + }} + /> + + + , + ); + + await act(async () => { + // need to wait for the debounce to finish + await new Promise(resolve => setTimeout(resolve, 600)); + }); + + expect(mockScmAuthApi.getCredentials).toHaveBeenCalledWith({ + url: 'https://gitlab.com', + additionalScope: { + repoWrite: true, + customScopes: { + gitlab: ['workflow'], + }, + }, + }); + + expect(getByText('abc123')).toBeInTheDocument(); + }); + + it('should call the scmAuthApi with the correct params if workspace is nested', async () => { + await renderInTestApp( + + + , + }} + /> + + , + ); + + await act(async () => { + // need to wait for the debounce to finish + await new Promise(resolve => setTimeout(resolve, 600)); + }); + + expect(mockScmAuthApi.getCredentials).toHaveBeenCalledWith({ + url: 'https://gitlab.com', + additionalScope: { + repoWrite: true, + }, + }); + }); + + it('should not call the scmAuthApi if secret is available in the state', async () => { + const secretsKey = 'testKey'; + + const SecretsComponent = () => { + const { secrets } = useTemplateSecrets(); + const secret = secrets[secretsKey]; + return secret ?
{secret}
: null; + }; + + const { getByText } = await renderInTestApp( + + + , + }} + /> + + + , + ); + + await act(async () => { + // need to wait for the debounce to finish + await new Promise(resolve => setTimeout(resolve, 600)); + }); + + // as we already have a secret in the state, getCredentials should not be called again. + expect(mockScmAuthApi.getCredentials).toHaveBeenCalledTimes(0); + + expect(getByText('abc123')).toBeInTheDocument(); + }); + }); }); From 0a09b718c813712ee48c94985518c9d6be905bb5 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 31 Mar 2026 10:28:41 +0200 Subject: [PATCH 04/10] Update .changeset/legal-results-kneel.md Signed-off-by: Patrik Oldsberg --- .changeset/legal-results-kneel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/legal-results-kneel.md b/.changeset/legal-results-kneel.md index 68b8c582cc..52a9af46ef 100644 --- a/.changeset/legal-results-kneel.md +++ b/.changeset/legal-results-kneel.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder': minor --- -Added to field extension 'RepoOwnerPicker' for retrieving GitLab repository owners. +Extended the `RepoOwnerPicker` implementation with a custom variant for GitLab. From 06648f6b9716b15d09d2711560b31cbb31a06505 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 31 Mar 2026 10:29:04 +0200 Subject: [PATCH 05/10] Update .changeset/legal-results-kneel.md Signed-off-by: Patrik Oldsberg From f6c794ae08ee4ab41766f65e02c90ead8fc754e0 Mon Sep 17 00:00:00 2001 From: asheen Date: Tue, 31 Mar 2026 09:06:25 -0400 Subject: [PATCH 06/10] Update .changeset/legal-results-kneel.md Co-authored-by: Patrik Oldsberg Signed-off-by: asheen From 1d24a4cfce856681c1fc4d21ed4200a96cdfcc8e Mon Sep 17 00:00:00 2001 From: asheen1234 Date: Tue, 12 May 2026 10:51:12 -0400 Subject: [PATCH 07/10] fix: align with main Signed-off-by: asheen1234 --- .../RepoOwnerPicker/RepoOwnerPicker.tsx | 94 +++++++++---------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx index ad88b3a02a..024f7f03a1 100644 --- a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx @@ -103,53 +103,49 @@ export const RepoOwnerPicker = (props: RepoOwnerPickerProps) => { const hostType = (host && integrationApi.byHost(host)?.type) ?? null; - const renderRepoOwnerPicker = () => { - switch (hostType) { - case 'github': - return ( - - ); - case 'gitlab': - return ( - - ); - default: - return ( - - ); - } - }; - - return renderRepoOwnerPicker(); + switch (hostType) { + case 'github': + return ( + + ); + case 'gitlab': + return ( + + ); + default: + return ( + + ); + } }; From 66a472267c9abfbb9568a6f0ab53c2db3a400544 Mon Sep 17 00:00:00 2001 From: asheen1234 Date: Tue, 12 May 2026 11:09:37 -0400 Subject: [PATCH 08/10] fix: add Bui theme Signed-off-by: asheen1234 --- .../RepoOwnerPicker/GitLabRepoOwnerPicker.tsx | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx index 1136186ab5..1ebb2567be 100644 --- a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.tsx @@ -18,14 +18,17 @@ import { useApi } from '@backstage/core-plugin-api'; import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; -import TextField from '@material-ui/core/TextField'; -import Autocomplete from '@material-ui/lab/Autocomplete'; +import MuiTextField from '@material-ui/core/TextField'; +import MuiAutocomplete from '@material-ui/lab/Autocomplete'; import { useCallback, useState } from 'react'; import useDebounce from 'react-use/esm/useDebounce'; import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; import { BaseRepoOwnerPickerProps } from './types'; import { scaffolderTranslationRef } from '../../../translation'; +import { useScaffolderTheme } from '@backstage/plugin-scaffolder-react/alpha'; +import { Autocomplete as BuiAutocomplete } from '../Autocomplete'; +import type { Key } from 'react-aria-components'; /** * The underlying component that is rendered in the form for the `GitLabRepoOwnerPicker` @@ -47,6 +50,7 @@ export const GitLabRepoOwnerPicker = ({ accessToken?: string; excludedOwners?: string[]; }>) => { + const theme = useScaffolderTheme(); const { host, owner } = state; const [availableOwners, setAvailableOwners] = useState([]); @@ -81,13 +85,37 @@ export const GitLabRepoOwnerPicker = ({ useDebounce(updateAvailableOwners, 500, [updateAvailableOwners]); + if (theme === 'bui') { + const options = availableOwners.map(o => ({ label: o, value: o })); + + return ( + onChange({ owner: value })} + onSelectionChange={(key: Key | null) => { + if (key !== null) { + onChange({ owner: String(key) }); + } + }} + options={options} + isDisabled={isDisabled} + isRequired={required} + isInvalid={rawErrors?.length > 0 && !owner} + /> + ); + } + return ( 0 && !owner} > - { onChange({ owner: newValue || '' }); @@ -95,7 +123,7 @@ export const GitLabRepoOwnerPicker = ({ disabled={isDisabled} options={availableOwners} renderInput={params => ( - Date: Tue, 12 May 2026 12:08:58 -0400 Subject: [PATCH 09/10] test: add missing test for gitlab autocomplete Signed-off-by: asheen1234 --- .../RepoOwnerPicker/RepoOwnerPicker.test.tsx | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx index 12cdd34359..d7f8d2f71d 100644 --- a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx @@ -29,6 +29,7 @@ import { scaffolderApiRef, useTemplateSecrets, ScaffolderRJSFField, + ScaffolderApi, } from '@backstage/plugin-scaffolder-react'; import { act, fireEvent, screen } from '@testing-library/react'; import { RepoOwnerPicker } from './RepoOwnerPicker'; @@ -462,5 +463,51 @@ describe('RepoOwnerPicker', () => { expect(getByText('abc123')).toBeInTheDocument(); }); + + it('should route to GitLabRepoOwnerPicker and call autocomplete with gitlab provider and groups resource', async () => { + const secretsKey = 'testKey'; + const mockScaffolderApi: Partial = { + autocomplete: jest.fn().mockResolvedValue({ results: [] }), + }; + + await renderInTestApp( + + + , + }} + /> + + , + ); + + await act(async () => { + // wait for both the RepoOwnerPicker and GitLabRepoOwnerPicker debounces + await new Promise(resolve => setTimeout(resolve, 600)); + }); + + expect(mockScaffolderApi.autocomplete).toHaveBeenCalledWith({ + token: 'abc123', + resource: 'groups', + provider: 'gitlab', + context: { host: 'gitlab.com' }, + }); + }); }); }); From 191bdbfa51b4366fbc921c6d6bfddafb3f407101 Mon Sep 17 00:00:00 2001 From: asheen Date: Tue, 12 May 2026 13:26:52 -0400 Subject: [PATCH 10/10] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: asheen --- .../GitLabRepoOwnerPicker.test.tsx | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx index 7fb9ea21d6..fe60e1b376 100644 --- a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitLabRepoOwnerPicker.test.tsx @@ -91,34 +91,51 @@ describe('GitLabRepoOwnerPicker', () => { }); it('should populate owners', async () => { + jest.useFakeTimers(); + const user = userEvent.setup({ + advanceTimers: jest.advanceTimersByTime, + }); const onChange = jest.fn(); - const { getByRole, getByText } = await renderInTestApp( - - - , - ); + try { + const { getByRole } = await renderInTestApp( + + + , + ); - // Open the Autocomplete dropdown - const input = getByRole('textbox'); - await userEvent.click(input); + // Open the Autocomplete dropdown + const input = getByRole('textbox'); + await user.click(input); - // Verify that the available owners are shown - await waitFor(() => expect(getByText('owner1')).toBeInTheDocument()); + // Flush the component debounce and any pending async updates + act(() => { + jest.advanceTimersByTime(500); + }); + await act(async () => { + await Promise.resolve(); + }); - // Verify that selecting an option calls onChange - await userEvent.click(getByText('owner1')); - expect(onChange).toHaveBeenCalledWith({ - owner: 'owner1', - }); + // Verify that the available owners are shown + expect(await screen.findByText('owner1')).toBeInTheDocument(); + + // Verify that selecting an option calls onChange + await user.click(screen.getByText('owner1')); + expect(onChange).toHaveBeenCalledWith({ + owner: 'owner1', + }); + } finally { + jest.runOnlyPendingTimers(); + jest.useRealTimers(); + } }); it('should filter out excluded owners', async () => {