diff --git a/libs/pages/application/src/lib/feature/page-settings-terraform-arguments-feature/page-settings-terraform-arguments-feature.spec.tsx b/libs/pages/application/src/lib/feature/page-settings-terraform-arguments-feature/page-settings-terraform-arguments-feature.spec.tsx index 6c4edbbcdad..22e6b249150 100644 --- a/libs/pages/application/src/lib/feature/page-settings-terraform-arguments-feature/page-settings-terraform-arguments-feature.spec.tsx +++ b/libs/pages/application/src/lib/feature/page-settings-terraform-arguments-feature/page-settings-terraform-arguments-feature.spec.tsx @@ -1,10 +1,20 @@ import { wrapWithReactHookForm } from '__tests__/utils/wrap-with-react-hook-form' -import { useEditService, useService } from '@qovery/domains/services/feature' +import * as servicesDomain from '@qovery/domains/services/feature' import { terraformFactoryMock } from '@qovery/shared/factories' import { renderWithProviders, screen } from '@qovery/shared/util-tests' import { PageSettingsTerraformArgumentsFeature } from './page-settings-terraform-arguments-feature' -jest.mock('@qovery/domains/services/feature') +const useServiceSpy = jest.spyOn(servicesDomain, 'useService') as jest.Mock +const useEditServiceSpy = jest.spyOn(servicesDomain, 'useEditService') as jest.Mock + +jest.mock('@qovery/domains/variables/feature', () => ({ + ...jest.requireActual('@qovery/domains/variables/feature'), + DropdownVariable: ({ children, onChange }: any) => ( +
onChange('MY_VARIABLE')}> + {children} +
+ ), +})) // Mocking the Terraform service const mockService = terraformFactoryMock(1)[0] @@ -19,12 +29,12 @@ const mockEditService = jest.fn() describe('PageSettingsTerraformArgumentsFeature', () => { beforeEach(() => { - useService.mockReturnValue({ + useServiceSpy.mockReturnValue({ data: mockService, isFetched: true, isLoading: false, }) - useEditService.mockReturnValue({ + useEditServiceSpy.mockReturnValue({ mutate: mockEditService, isLoading: false, }) @@ -77,4 +87,93 @@ describe('PageSettingsTerraformArgumentsFeature', () => { }, }) }) + + it('should render variable interpolation wand button for each command', () => { + renderWithProviders(wrapWithReactHookForm()) + + // Check that the wand button appears for each terraform command + const wandButtons = screen.getAllByTestId('dropdown-variable') + expect(wandButtons).toHaveLength(5) // init, validate, plan, apply, destroy + }) + + it('should add variable interpolation to empty input when wand is clicked', async () => { + const { userEvent } = renderWithProviders(wrapWithReactHookForm()) + + const inputLabelForPlan = screen.getByText('Arguments for plan') + const inputForPlan = inputLabelForPlan.closest('div')?.querySelector('input') + expect(inputForPlan).toHaveValue('') + + const wandButtons = screen.getAllByTestId('dropdown-variable') + const wandButtonForPlan = wandButtons[2] + + // Click the wand button to add a variable + await userEvent.click(wandButtonForPlan) + + // Check that the variable was added with correct interpolation syntax + expect(inputForPlan).toHaveValue('{{MY_VARIABLE}}') + }) + + it('should append variable interpolation to existing input when wand is clicked', async () => { + const { userEvent } = renderWithProviders(wrapWithReactHookForm()) + + // Get the input for init command (which has default value '-auto-approve') + const inputLabelForInit = screen.getByText('Arguments for init') + const inputForInit = inputLabelForInit.closest('div')?.querySelector('input') + expect(inputForInit).toHaveValue('-auto-approve') + + // Find the wand button for the init input (1st command) + const wandButtons = screen.getAllByTestId('dropdown-variable') + const wandButtonForInit = wandButtons[0] + + // Click the wand button to add a variable + await userEvent.click(wandButtonForInit) + + // Check that the variable was appended to existing value with space delimiter + expect(inputForInit).toHaveValue('-auto-approve {{MY_VARIABLE}}') + }) + + it('should correctly submit form with variable interpolation', async () => { + const { userEvent } = renderWithProviders(wrapWithReactHookForm()) + + // Get the apply input and add a variable using the wand + const inputLabelForApply = screen.getByText('Arguments for apply') + const inputForApply = inputLabelForApply.closest('div')?.querySelector('input') + const wandButtons = screen.getAllByTestId('dropdown-variable') + const wandButtonForApply = wandButtons[3] // 0=init, 1=validate, 2=plan, 3=apply + + // Add some text first + if (inputForApply) { + await userEvent.type(inputForApply, '-auto-approve') + } + + // Click the wand button to add a variable + await userEvent.click(wandButtonForApply) + + // Submit the form + const submitButton = screen.getByText('Save') + await userEvent.click(submitButton) + + // Verify that the variable interpolation is correctly submitted + expect(mockEditService).toHaveBeenCalledWith({ + serviceId: mockService.id, + payload: { + ...mockService, + terraform_files_source: { + git_repository: { + url: mockService.terraform_files_source?.git?.git_repository?.url ?? '', + branch: mockService.terraform_files_source?.git?.git_repository?.branch ?? '', + git_token_id: mockService.terraform_files_source?.git?.git_repository?.git_token_id ?? '', + root_path: mockService.terraform_files_source?.git?.git_repository?.root_path ?? '', + }, + }, + action_extra_arguments: { + init: ['-auto-approve'], + validate: [], + plan: [], + apply: ['-auto-approve', '{{MY_VARIABLE}}'], + destroy: ['bye'], + }, + }, + }) + }) }) diff --git a/libs/pages/application/src/lib/feature/page-settings-terraform-arguments-feature/page-settings-terraform-arguments-feature.tsx b/libs/pages/application/src/lib/feature/page-settings-terraform-arguments-feature/page-settings-terraform-arguments-feature.tsx index 21a089afe3b..a71c90966b7 100644 --- a/libs/pages/application/src/lib/feature/page-settings-terraform-arguments-feature/page-settings-terraform-arguments-feature.tsx +++ b/libs/pages/application/src/lib/feature/page-settings-terraform-arguments-feature/page-settings-terraform-arguments-feature.tsx @@ -1,8 +1,10 @@ import { Controller, FormProvider, useForm } from 'react-hook-form' import { useParams } from 'react-router-dom' import { useEditService, useService } from '@qovery/domains/services/feature' +import { DropdownVariable } from '@qovery/domains/variables/feature' import { NeedHelp } from '@qovery/shared/assistant/feature' -import { Button, Heading, InputText, Section } from '@qovery/shared/ui' +import { Button, Heading, Icon, InputText, Section } from '@qovery/shared/ui' +import { twMerge } from '@qovery/shared/util-js' import { buildEditServicePayload } from '@qovery/shared/util-services' const DELIMETER = ' ' @@ -138,6 +140,25 @@ export function PageSettingsTerraformArgumentsFeature() { onChange={(e) => field.onChange(e.target.value.split(DELIMETER).filter((arg) => arg !== ''))} label={`Arguments for ${command.name}`} hint={command.hint} + rightElement={ + { + const currentValue = field.value?.join(DELIMETER) || '' + const newValue = currentValue ? `${currentValue} {{${val}}}` : `{{${val}}}` + field.onChange(newValue.split(DELIMETER).filter((arg) => arg !== '')) + }} + > + + + } /> )} />