diff --git a/.changeset/eighty-rabbits-fail.md b/.changeset/eighty-rabbits-fail.md new file mode 100644 index 0000000000..5f15d79ef4 --- /dev/null +++ b/.changeset/eighty-rabbits-fail.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Don't merge with previous from state on form changes. diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx index 3cdf6c9738..2a21e9da72 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx @@ -17,12 +17,13 @@ import { ApiProvider, ApiRegistry, errorApiRef } from '@backstage/core'; import { renderInTestApp, renderWithEffects } from '@backstage/test-utils'; import { lightTheme } from '@backstage/theme'; import { ThemeProvider } from '@material-ui/core'; +import { fireEvent, within } from '@testing-library/react'; import React from 'react'; import { act } from 'react-dom/test-utils'; import { MemoryRouter, Route } from 'react-router'; import { ScaffolderApi, scaffolderApiRef } from '../../api'; import { rootRouteRef } from '../../routes'; -import { TemplatePage, createValidator } from './TemplatePage'; +import { createValidator, TemplatePage } from './TemplatePage'; jest.mock('react-router-dom', () => { return { @@ -123,6 +124,78 @@ describe('TemplatePage', () => { ).not.toBeInTheDocument(); expect(rendered.queryByText('This is root')).toBeInTheDocument(); }); + + it('display template with oneOf', async () => { + scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({ + title: 'my-schema', + steps: [ + { + title: 'Fill in some steps', + schema: { + oneOf: [ + { + title: 'First', + properties: { + name: { + title: 'Name', + type: 'string', + }, + }, + required: ['name'], + }, + { + title: 'Second', + properties: { + something: { + title: 'Something', + type: 'string', + }, + }, + required: ['something'], + }, + ], + }, + }, + ], + }); + + const { + findByText, + findByLabelText, + findAllByRole, + findByRole, + } = await renderInTestApp( + + + , + { + mountedRoutes: { + '/create/actions': rootRouteRef, + }, + }, + ); + + expect(await findByText('Fill in some steps')).toBeInTheDocument(); + + // Fill the first option + fireEvent.change(await findByLabelText('Name', { exact: false }), { + target: { value: 'my-name' }, + }); + + // Switch to second option + fireEvent.mouseDown((await findAllByRole('button'))[0]); + const listbox = within(await findByRole('listbox')); + fireEvent.click(listbox.getByText(/Second/i)); + + // Fill the second option + fireEvent.change(await findByLabelText('Something', { exact: false }), { + target: { value: 'my-something' }, + }); + + // Go to the final page + fireEvent.click(await findByText('Next step')); + expect(await findByText('Reset')).toBeInTheDocument(); + }); }); describe('createValidator', () => { diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx index ba71b38d75..12930db2cc 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx @@ -150,8 +150,8 @@ export const TemplatePage = () => { const handleFormReset = () => setFormState({}); const handleChange = useCallback( - (e: IChangeEvent) => setFormState({ ...formState, ...e.formData }), - [setFormState, formState], + (e: IChangeEvent) => setFormState(e.formData), + [setFormState], ); const handleCreate = async () => {