From 8761109a343cdf1fb1d22dc469c669f501fdf7c6 Mon Sep 17 00:00:00 2001 From: akashseth-ifp Date: Tue, 24 Feb 2026 20:00:35 +0530 Subject: [PATCH] test(base): added test coverage to form components (#32436) --- .../form/components/base/base-field.spec.tsx | 293 ++++++++++++++++++ .../form/components/base/base-form.spec.tsx | 120 +++++++ .../base/form/components/base/index.spec.tsx | 11 + .../form/components/field/checkbox.spec.tsx | 34 ++ .../components/field/custom-select.spec.tsx | 49 +++ .../form/components/field/file-types.spec.tsx | 127 ++++++++ .../components/field/file-uploader.spec.tsx | 82 +++++ .../field/input-type-select/hooks.spec.tsx | 20 ++ .../field/input-type-select/index.spec.tsx | 37 +++ .../field/input-type-select/option.spec.tsx | 22 ++ .../field/input-type-select/trigger.spec.tsx | 28 ++ .../field/input-type-select/types.spec.ts | 12 + .../mixed-variable-text-input/index.spec.tsx | 17 + .../placeholder.spec.tsx | 74 +++++ .../components/field/number-input.spec.tsx | 33 ++ .../components/field/number-slider.spec.tsx | 46 +++ .../form/components/field/options.spec.tsx | 45 +++ .../form/components/field/select.spec.tsx | 49 +++ .../form/components/field/text-area.spec.tsx | 33 ++ .../base/form/components/field/text.spec.tsx | 33 ++ .../components/field/upload-method.spec.tsx | 64 ++++ .../field/variable-or-constant-input.spec.tsx | 47 +++ .../field/variable-selector.spec.tsx | 29 ++ .../form/components/form/actions.spec.tsx | 75 +++++ .../base/form/components/label.spec.tsx | 44 +-- 25 files changed, 1405 insertions(+), 19 deletions(-) create mode 100644 web/app/components/base/form/components/base/base-field.spec.tsx create mode 100644 web/app/components/base/form/components/base/base-form.spec.tsx create mode 100644 web/app/components/base/form/components/base/index.spec.tsx create mode 100644 web/app/components/base/form/components/field/checkbox.spec.tsx create mode 100644 web/app/components/base/form/components/field/custom-select.spec.tsx create mode 100644 web/app/components/base/form/components/field/file-types.spec.tsx create mode 100644 web/app/components/base/form/components/field/file-uploader.spec.tsx create mode 100644 web/app/components/base/form/components/field/input-type-select/hooks.spec.tsx create mode 100644 web/app/components/base/form/components/field/input-type-select/index.spec.tsx create mode 100644 web/app/components/base/form/components/field/input-type-select/option.spec.tsx create mode 100644 web/app/components/base/form/components/field/input-type-select/trigger.spec.tsx create mode 100644 web/app/components/base/form/components/field/input-type-select/types.spec.ts create mode 100644 web/app/components/base/form/components/field/mixed-variable-text-input/index.spec.tsx create mode 100644 web/app/components/base/form/components/field/mixed-variable-text-input/placeholder.spec.tsx create mode 100644 web/app/components/base/form/components/field/number-input.spec.tsx create mode 100644 web/app/components/base/form/components/field/number-slider.spec.tsx create mode 100644 web/app/components/base/form/components/field/options.spec.tsx create mode 100644 web/app/components/base/form/components/field/select.spec.tsx create mode 100644 web/app/components/base/form/components/field/text-area.spec.tsx create mode 100644 web/app/components/base/form/components/field/text.spec.tsx create mode 100644 web/app/components/base/form/components/field/upload-method.spec.tsx create mode 100644 web/app/components/base/form/components/field/variable-or-constant-input.spec.tsx create mode 100644 web/app/components/base/form/components/field/variable-selector.spec.tsx create mode 100644 web/app/components/base/form/components/form/actions.spec.tsx diff --git a/web/app/components/base/form/components/base/base-field.spec.tsx b/web/app/components/base/form/components/base/base-field.spec.tsx new file mode 100644 index 0000000000..7c50b524a5 --- /dev/null +++ b/web/app/components/base/form/components/base/base-field.spec.tsx @@ -0,0 +1,293 @@ +import type { AnyFieldApi } from '@tanstack/react-form' +import type { FormSchema } from '@/app/components/base/form/types' +import { useForm } from '@tanstack/react-form' +import { fireEvent, render, screen } from '@testing-library/react' +import { FormItemValidateStatusEnum, FormTypeEnum } from '@/app/components/base/form/types' +import BaseField from './base-field' + +const mockDynamicOptions = vi.fn() + +vi.mock('@/hooks/use-i18n', () => ({ + useRenderI18nObject: () => (content: Record) => content.en_US ?? Object.values(content)[0] ?? '', +})) + +vi.mock('@/service/use-triggers', () => ({ + useTriggerPluginDynamicOptions: (...args: unknown[]) => mockDynamicOptions(...args), +})) + +const renderBaseField = ({ + formSchema, + defaultValues, + fieldState, + onChange, + showCurrentValue = false, +}: { + formSchema: FormSchema + defaultValues?: Record + fieldState?: { + validateStatus?: FormItemValidateStatusEnum + errors?: string[] + warnings?: string[] + } + onChange?: (field: string, value: unknown) => void + showCurrentValue?: boolean +}) => { + const TestComponent = () => { + const form = useForm({ + defaultValues: defaultValues ?? { [formSchema.name]: '' }, + onSubmit: async () => {}, + }) + + return ( + <> + + {field => ( + + )} + + {showCurrentValue && ( + state.values[formSchema.name]}> + {value =>
{String(value)}
} +
+ )} + + ) + } + + return render() +} + +describe('BaseField', () => { + beforeEach(() => { + vi.clearAllMocks() + mockDynamicOptions.mockReturnValue({ + data: undefined, + isLoading: false, + error: null, + }) + }) + + it('should render text input and propagate changes', () => { + const onChange = vi.fn() + renderBaseField({ + formSchema: { + type: FormTypeEnum.textInput, + name: 'title', + label: 'Title', + required: true, + }, + defaultValues: { title: 'Hello' }, + onChange, + }) + + const input = screen.getByDisplayValue('Hello') + expect(input).toHaveValue('Hello') + + fireEvent.change(input, { target: { value: 'Updated' } }) + expect(onChange).toHaveBeenCalledWith('title', 'Updated') + expect(screen.getByText('Title')).toBeInTheDocument() + expect(screen.getAllByText('*')).toHaveLength(1) + }) + + it('should render only options that satisfy show_on conditions', () => { + renderBaseField({ + formSchema: { + type: FormTypeEnum.select, + name: 'mode', + label: 'Mode', + required: false, + options: [ + { label: 'Alpha', value: 'alpha' }, + { label: 'Beta', value: 'beta', show_on: [{ variable: 'enabled', value: 'yes' }] }, + ], + }, + defaultValues: { mode: 'alpha', enabled: 'no' }, + }) + + fireEvent.click(screen.getByText('Alpha')) + expect(screen.queryByText('Beta')).not.toBeInTheDocument() + }) + + it('should render dynamic select loading state', () => { + mockDynamicOptions.mockReturnValue({ + data: undefined, + isLoading: true, + error: null, + }) + + renderBaseField({ + formSchema: { + type: FormTypeEnum.dynamicSelect, + name: 'plugin', + label: 'Plugin', + required: false, + }, + defaultValues: { plugin: '' }, + }) + + expect(screen.getByText('common.dynamicSelect.loading')).toBeInTheDocument() + }) + + it('should update value when users click a radio option', () => { + const onChange = vi.fn() + renderBaseField({ + formSchema: { + type: FormTypeEnum.radio, + name: 'visibility', + label: 'Visibility', + required: false, + options: [ + { label: 'Public', value: 'public' }, + { label: 'Private', value: 'private' }, + ], + }, + defaultValues: { visibility: 'public' }, + onChange, + }) + + fireEvent.click(screen.getByText('Private')) + expect(onChange).toHaveBeenCalledWith('visibility', 'private') + }) + + it('should show validation message when field state has an error', () => { + renderBaseField({ + formSchema: { + type: FormTypeEnum.textInput, + name: 'name', + label: 'Name', + required: false, + }, + fieldState: { + validateStatus: FormItemValidateStatusEnum.Error, + errors: ['Name is required'], + }, + }) + + expect(screen.getByText('Name is required')).toBeInTheDocument() + }) + + it('should render description and help link when provided', () => { + renderBaseField({ + formSchema: { + type: FormTypeEnum.textInput, + name: 'doc', + label: 'Documentation', + required: false, + description: 'Read the description', + url: 'https://example.com/help', + help: 'Open help docs', + }, + defaultValues: { doc: '' }, + }) + + expect(screen.getByText('Read the description')).toBeInTheDocument() + expect(screen.getByRole('link', { name: 'Open help docs' })).toHaveAttribute('href', 'https://example.com/help') + }) + + it('should render secret input with password type', () => { + renderBaseField({ + formSchema: { + type: FormTypeEnum.secretInput, + name: 'token', + label: 'Token', + required: false, + }, + defaultValues: { token: 'abc' }, + }) + + expect(screen.getByDisplayValue('abc')).toHaveAttribute('type', 'password') + }) + + it('should render number input with number type', () => { + renderBaseField({ + formSchema: { + type: FormTypeEnum.textNumber, + name: 'count', + label: 'Count', + required: false, + }, + defaultValues: { count: 7 }, + }) + + expect(screen.getByDisplayValue('7')).toHaveAttribute('type', 'number') + }) + + it('should render translated object label content', () => { + renderBaseField({ + formSchema: { + type: FormTypeEnum.textInput, + name: 'title_i18n', + label: { en_US: 'Localized title', zh_Hans: '标题' }, + required: false, + }, + defaultValues: { title_i18n: '' }, + }) + + expect(screen.getByText('Localized title')).toBeInTheDocument() + }) + + it('should render dynamic options and allow selecting one', () => { + mockDynamicOptions.mockReturnValue({ + data: { + options: [ + { label: { en_US: 'Option A', zh_Hans: '选项A' }, value: 'a' }, + ], + }, + isLoading: false, + error: null, + }) + + renderBaseField({ + formSchema: { + type: FormTypeEnum.dynamicSelect, + name: 'plugin_option', + label: 'Plugin option', + required: false, + }, + defaultValues: { plugin_option: '' }, + }) + + fireEvent.click(screen.getByText('common.placeholder.input')) + fireEvent.click(screen.getByText('Option A')) + expect(screen.getByText('Option A')).toBeInTheDocument() + }) + + it('should update boolean field when users choose false', () => { + renderBaseField({ + formSchema: { + type: FormTypeEnum.boolean, + name: 'enabled', + label: 'Enabled', + required: false, + }, + defaultValues: { enabled: true }, + showCurrentValue: true, + }) + + expect(screen.getByTestId('field-value')).toHaveTextContent('true') + fireEvent.click(screen.getByText('False')) + expect(screen.getByTestId('field-value')).toHaveTextContent('false') + }) + + it('should render warning message when field state has a warning', () => { + renderBaseField({ + formSchema: { + type: FormTypeEnum.textInput, + name: 'warning_field', + label: 'Warning field', + required: false, + }, + fieldState: { + validateStatus: FormItemValidateStatusEnum.Warning, + warnings: ['This is a warning'], + }, + }) + + expect(screen.getByText('This is a warning')).toBeInTheDocument() + }) +}) diff --git a/web/app/components/base/form/components/base/base-form.spec.tsx b/web/app/components/base/form/components/base/base-form.spec.tsx new file mode 100644 index 0000000000..5d2c662aa3 --- /dev/null +++ b/web/app/components/base/form/components/base/base-form.spec.tsx @@ -0,0 +1,120 @@ +import type { FormRefObject, FormSchema } from '@/app/components/base/form/types' +import { act, fireEvent, render, screen } from '@testing-library/react' +import { FormTypeEnum } from '@/app/components/base/form/types' +import BaseForm from './base-form' + +vi.mock('@/service/use-triggers', () => ({ + useTriggerPluginDynamicOptions: () => ({ + data: undefined, + isLoading: false, + error: null, + }), +})) + +const baseSchemas: FormSchema[] = [ + { + type: FormTypeEnum.textInput, + name: 'kind', + label: 'Kind', + required: false, + default: 'show', + }, + { + type: FormTypeEnum.textInput, + name: 'title', + label: 'Title', + required: true, + default: 'Initial title', + show_on: [{ variable: 'kind', value: 'show' }], + }, +] + +describe('BaseForm', () => { + it('should render nothing when no schemas are provided', () => { + const { container } = render() + expect(container.firstChild).toBeNull() + }) + + it('should render fields with default values from schema', () => { + render() + + expect(screen.getByDisplayValue('show')).toBeInTheDocument() + expect(screen.getByDisplayValue('Initial title')).toBeInTheDocument() + }) + + it('should hide conditional fields when show_on conditions are not met', () => { + render( + , + ) + + expect(screen.getByDisplayValue('hide')).toBeInTheDocument() + expect(screen.queryByDisplayValue('Hidden title')).not.toBeInTheDocument() + }) + + it('should prevent default submit behavior when preventDefaultSubmit is true', () => { + const onSubmit = vi.fn((event: React.FormEvent) => { + expect(event.defaultPrevented).toBe(true) + }) + const { container } = render( + , + ) + + fireEvent.submit(container.querySelector('form') as HTMLFormElement) + expect(onSubmit).toHaveBeenCalled() + }) + + it('should expose ref API for updating values and field states', () => { + const formRef = { current: null } as { current: FormRefObject | null } + render( + , + ) + + expect(formRef.current).not.toBeNull() + + act(() => { + formRef.current?.setFields([ + { + name: 'title', + value: 'Changed title', + errors: ['Title is invalid'], + }, + ]) + }) + + expect(screen.getByDisplayValue('Changed title')).toBeInTheDocument() + expect(screen.getByText('Title is invalid')).toBeInTheDocument() + expect(formRef.current?.getForm()).toBeTruthy() + expect(formRef.current?.getFormValues({})).toBeTruthy() + }) + + it('should derive warning status when setFields receives warnings only', () => { + const formRef = { current: null } as { current: FormRefObject | null } + render( + , + ) + + act(() => { + formRef.current?.setFields([ + { + name: 'title', + warnings: ['Title warning'], + }, + ]) + }) + + expect(screen.getByText('Title warning')).toBeInTheDocument() + }) +}) diff --git a/web/app/components/base/form/components/base/index.spec.tsx b/web/app/components/base/form/components/base/index.spec.tsx new file mode 100644 index 0000000000..16f9806b27 --- /dev/null +++ b/web/app/components/base/form/components/base/index.spec.tsx @@ -0,0 +1,11 @@ +import { BaseField, BaseForm } from '.' + +describe('base component exports', () => { + it('should export BaseField', () => { + expect(BaseField).toBeDefined() + }) + + it('should export BaseForm', () => { + expect(BaseForm).toBeDefined() + }) +}) diff --git a/web/app/components/base/form/components/field/checkbox.spec.tsx b/web/app/components/base/form/components/field/checkbox.spec.tsx new file mode 100644 index 0000000000..ee7d8ee6ab --- /dev/null +++ b/web/app/components/base/form/components/field/checkbox.spec.tsx @@ -0,0 +1,34 @@ +import { fireEvent, render, screen } from '@testing-library/react' +import CheckboxField from './checkbox' + +const mockField = { + name: 'checkbox-field', + state: { + value: false, + }, + handleChange: vi.fn(), +} + +vi.mock('../..', () => ({ + useFieldContext: () => mockField, +})) + +describe('CheckboxField', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('should toggle on when unchecked users click the checkbox', () => { + mockField.state.value = false + render() + fireEvent.click(screen.getByTestId('checkbox-checkbox-field')) + expect(mockField.handleChange).toHaveBeenCalledWith(true) + }) + + it('should toggle off when checked users click the label', () => { + mockField.state.value = true + render() + fireEvent.click(screen.getByText('Enable feature')) + expect(mockField.handleChange).toHaveBeenCalledWith(false) + }) +}) diff --git a/web/app/components/base/form/components/field/custom-select.spec.tsx b/web/app/components/base/form/components/field/custom-select.spec.tsx new file mode 100644 index 0000000000..97f13758ec --- /dev/null +++ b/web/app/components/base/form/components/field/custom-select.spec.tsx @@ -0,0 +1,49 @@ +import { fireEvent, render, screen } from '@testing-library/react' +import CustomSelectField from './custom-select' + +const mockField = { + name: 'custom-select-field', + state: { + value: 'small', + }, + handleChange: vi.fn(), +} + +vi.mock('../..', () => ({ + useFieldContext: () => mockField, +})) + +describe('CustomSelectField', () => { + beforeEach(() => { + vi.clearAllMocks() + mockField.state.value = 'small' + }) + + it('should render select placeholder or selected value', () => { + render( + , + ) + expect(screen.getByText('Small')).toBeInTheDocument() + }) + + it('should update value when users select another option', () => { + render( + , + ) + fireEvent.click(screen.getByText('Small')) + fireEvent.click(screen.getByText('Large')) + expect(mockField.handleChange).toHaveBeenCalledWith('large') + }) +}) diff --git a/web/app/components/base/form/components/field/file-types.spec.tsx b/web/app/components/base/form/components/field/file-types.spec.tsx new file mode 100644 index 0000000000..0c2a95c655 --- /dev/null +++ b/web/app/components/base/form/components/field/file-types.spec.tsx @@ -0,0 +1,127 @@ +import { fireEvent, render, screen } from '@testing-library/react' +import { SupportUploadFileTypes } from '@/app/components/workflow/types' +import FileTypesField from './file-types' + +type FileTypeValue = { + allowedFileTypes: string[] + allowedFileExtensions: string[] +} + +const mockField = { + name: 'allowed-types', + state: { + value: { + allowedFileTypes: [], + allowedFileExtensions: [], + } as FileTypeValue, + }, + handleChange: vi.fn(), +} + +vi.mock('../..', () => ({ + useFieldContext: () => mockField, +})) + +vi.mock('@/app/components/workflow/nodes/_base/components/file-type-item', () => ({ + default: ({ + type, + onToggle, + customFileTypes = [], + onCustomFileTypesChange, + }: { + type: SupportUploadFileTypes + onToggle: (type: SupportUploadFileTypes) => void + customFileTypes?: string[] + onCustomFileTypesChange?: (types: string[]) => void + }) => ( +
+ + {onCustomFileTypesChange && ( + onCustomFileTypesChange( + e.target.value.split(',').map(v => v.trim()).filter(Boolean), + )} + /> + )} +
+ ), +})) + +describe('FileTypesField', () => { + beforeEach(() => { + vi.clearAllMocks() + mockField.state.value = { + allowedFileTypes: [], + allowedFileExtensions: [], + } + }) + + it('should render the label and available type options', () => { + render() + + expect(screen.getByText('Allowed file types')).toBeInTheDocument() + expect(screen.getByRole('button', { name: SupportUploadFileTypes.document })).toBeInTheDocument() + expect(screen.getByRole('button', { name: SupportUploadFileTypes.image })).toBeInTheDocument() + expect(screen.getByRole('button', { name: SupportUploadFileTypes.audio })).toBeInTheDocument() + expect(screen.getByRole('button', { name: SupportUploadFileTypes.video })).toBeInTheDocument() + expect(screen.getByRole('button', { name: SupportUploadFileTypes.custom })).toBeInTheDocument() + }) + + it('should keep only custom when users choose custom types', () => { + mockField.state.value.allowedFileTypes = [SupportUploadFileTypes.document] + render() + + fireEvent.click(screen.getByRole('button', { name: SupportUploadFileTypes.custom })) + expect(mockField.handleChange).toHaveBeenCalledWith({ + allowedFileTypes: [SupportUploadFileTypes.custom], + allowedFileExtensions: [], + }) + }) + + it('should remove custom and add selected standard type', () => { + mockField.state.value.allowedFileTypes = [SupportUploadFileTypes.custom] + render() + + fireEvent.click(screen.getByRole('button', { name: SupportUploadFileTypes.image })) + expect(mockField.handleChange).toHaveBeenCalledWith({ + allowedFileTypes: [SupportUploadFileTypes.image], + allowedFileExtensions: [], + }) + }) + + it('should remove custom when users click custom again', () => { + mockField.state.value.allowedFileTypes = [SupportUploadFileTypes.custom] + render() + + fireEvent.click(screen.getByRole('button', { name: SupportUploadFileTypes.custom })) + expect(mockField.handleChange).toHaveBeenCalledWith({ + allowedFileTypes: [], + allowedFileExtensions: [], + }) + }) + + it('should remove a selected standard type when users click it again', () => { + mockField.state.value.allowedFileTypes = [SupportUploadFileTypes.image] + render() + + fireEvent.click(screen.getByRole('button', { name: SupportUploadFileTypes.image })) + expect(mockField.handleChange).toHaveBeenCalledWith({ + allowedFileTypes: [], + allowedFileExtensions: [], + }) + }) + + it('should update custom extensions when users type custom extension values', () => { + render() + + fireEvent.change(screen.getByRole('textbox', { name: 'custom file extensions' }), { + target: { value: 'csv,pdf' }, + }) + expect(mockField.handleChange).toHaveBeenCalledWith({ + allowedFileTypes: [], + allowedFileExtensions: ['csv', 'pdf'], + }) + }) +}) diff --git a/web/app/components/base/form/components/field/file-uploader.spec.tsx b/web/app/components/base/form/components/field/file-uploader.spec.tsx new file mode 100644 index 0000000000..c32d370346 --- /dev/null +++ b/web/app/components/base/form/components/field/file-uploader.spec.tsx @@ -0,0 +1,82 @@ +import { fireEvent, render, screen } from '@testing-library/react' +import { SupportUploadFileTypes } from '@/app/components/workflow/types' +import { TransferMethod } from '@/types/app' +import FileUploaderField from './file-uploader' + +const mockField = { + name: 'files', + state: { + value: [ + { + id: 'file-1', + name: 'report.pdf', + size: 1024, + type: 'application/pdf', + progress: 100, + transferMethod: TransferMethod.local_file, + supportFileType: SupportUploadFileTypes.document, + uploadedId: 'uploaded-1', + url: 'https://example.com/report.pdf', + }, + ], + }, + handleChange: vi.fn(), +} + +vi.mock('../..', () => ({ + useFieldContext: () => mockField, +})) + +vi.mock('next/navigation', () => ({ + useParams: () => ({ token: 'test-token' }), +})) + +describe('FileUploaderField', () => { + beforeEach(() => { + vi.clearAllMocks() + mockField.state.value = [ + { + id: 'file-1', + name: 'report.pdf', + size: 1024, + type: 'application/pdf', + progress: 100, + transferMethod: TransferMethod.local_file, + supportFileType: SupportUploadFileTypes.document, + uploadedId: 'uploaded-1', + url: 'https://example.com/report.pdf', + }, + ] + }) + + it('should render existing uploaded file name', () => { + render( + , + ) + + expect(screen.getByText('Attachments')).toBeInTheDocument() + expect(screen.getByText('report.pdf')).toBeInTheDocument() + }) + + it('should update field value when users remove a file', () => { + render( + , + ) + + const deleteButtons = screen.getAllByRole('button') + fireEvent.click(deleteButtons[1]) + expect(mockField.handleChange).toHaveBeenCalledWith([]) + }) +}) diff --git a/web/app/components/base/form/components/field/input-type-select/hooks.spec.tsx b/web/app/components/base/form/components/field/input-type-select/hooks.spec.tsx new file mode 100644 index 0000000000..a556697db1 --- /dev/null +++ b/web/app/components/base/form/components/field/input-type-select/hooks.spec.tsx @@ -0,0 +1,20 @@ +import { renderHook } from '@testing-library/react' +import { useInputTypeOptions } from './hooks' + +describe('useInputTypeOptions', () => { + it('should include file options when supportFile is true', () => { + const { result } = renderHook(() => useInputTypeOptions(true)) + const values = result.current.map(item => item.value) + + expect(values).toContain('file') + expect(values).toContain('file-list') + }) + + it('should exclude file options when supportFile is false', () => { + const { result } = renderHook(() => useInputTypeOptions(false)) + const values = result.current.map(item => item.value) + + expect(values).not.toContain('file') + expect(values).not.toContain('file-list') + }) +}) diff --git a/web/app/components/base/form/components/field/input-type-select/index.spec.tsx b/web/app/components/base/form/components/field/input-type-select/index.spec.tsx new file mode 100644 index 0000000000..e31cf17af5 --- /dev/null +++ b/web/app/components/base/form/components/field/input-type-select/index.spec.tsx @@ -0,0 +1,37 @@ +import { fireEvent, render, screen } from '@testing-library/react' +import InputTypeSelectField from './index' + +const mockField = { + name: 'input-type', + state: { + value: 'text-input', + }, + handleChange: vi.fn(), +} + +vi.mock('../../..', () => ({ + useFieldContext: () => mockField, +})) + +describe('InputTypeSelectField', () => { + beforeEach(() => { + vi.clearAllMocks() + mockField.state.value = 'text-input' + }) + + it('should render label and selected option', () => { + render() + + expect(screen.getByText('Input type')).toBeInTheDocument() + expect(screen.getByText('appDebug.variableConfig.text-input')).toBeInTheDocument() + }) + + it('should update value when users choose another input type', () => { + render() + + fireEvent.click(screen.getByText('appDebug.variableConfig.text-input')) + fireEvent.click(screen.getByText('appDebug.variableConfig.number')) + + expect(mockField.handleChange).toHaveBeenCalledWith('number') + }) +}) diff --git a/web/app/components/base/form/components/field/input-type-select/option.spec.tsx b/web/app/components/base/form/components/field/input-type-select/option.spec.tsx new file mode 100644 index 0000000000..475ef20410 --- /dev/null +++ b/web/app/components/base/form/components/field/input-type-select/option.spec.tsx @@ -0,0 +1,22 @@ +import { render, screen } from '@testing-library/react' +import Option from './option' + +const MockIcon = () => + +describe('InputTypeSelect Option', () => { + it('should render option label and type', () => { + render( +