/** *******************************************************************************************************************
  Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  
  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 React from 'react';
import { render, fireEvent, cleanup, act } from '@testing-library/react';
import validatorTypes from '@data-driven-forms/react-form-renderer/validator-types';
import FormRenderer, { componentTypes } from '.';

describe('FormRenderer', () => {
    afterEach(() => {
        jest.resetAllMocks();
        cleanup();
    });

    const handleCancel = jest.fn();
    const handleSubmit = jest.fn();

    const baseSchema = {
        header: 'header',
        description: 'description',
    };

    describe('Form basic ', () => {
        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.TEXT_FIELD,
                    name: 'name',
                    label: 'Name',
                    isRequired: true,
                },
            ],
        };

        it('should render header and description', () => {
            const { getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByText('header')).toBeVisible();
            expect(getByText('description')).toBeVisible();
        });

        it('should trigger cancel event when user clicks the Cancel button', () => {
            const { getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            fireEvent.click(getByText('Cancel'));
            expect(handleCancel).toHaveBeenCalled();
        });

        it('should trigger submit with the data', () => {
            const { getByLabelText, getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            act(() => {
                fireEvent.change(getByLabelText('Name'), { target: { value: 'my name' } });
                fireEvent.click(getByText('Submit'));
            });

            expect(handleSubmit).toHaveBeenCalledWith({ name: 'my name' }, expect.any(Object), expect.any(Function));
        });

        it('should render custom label for cancel and submit button', () => {
            const customLabelsSchema = {
                ...schema,
                submitLabel: 'Custom Submit Label',
                cancelLabel: 'Custom Cancel Label',
            };
            const { getByText } = render(
                <FormRenderer schema={customLabelsSchema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            expect(getByText('Custom Submit Label')).toBeVisible();
            expect(getByText('Custom Cancel Label')).toBeVisible();
        });

        it('should show a loading spinner while submitting', () => {
            const { queryByRole } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} isSubmitting={true} />
            );

            expect(queryByRole('progressbar')).toBeInTheDocument();
        });

        it('should show a loading spinner while submitting a wizard', () => {
            const { queryByRole } = render(
                <FormRenderer
                    schema={{
                        ...baseSchema,
                        fields: [
                            {
                                component: componentTypes.WIZARD,
                                name: 'wizard',
                                fields: [
                                    {
                                        name: 'step-1',
                                        fields: schema.fields,
                                    },
                                ],
                            },
                        ],
                    }}
                    onSubmit={handleSubmit}
                    onCancel={handleCancel}
                    isSubmitting={true}
                />
            );

            expect(queryByRole('progressbar')).toBeInTheDocument();
        });

        it('should not show a loading spinner by default', () => {
            const { queryByRole } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(queryByRole('progressbar')).not.toBeInTheDocument();
        });

        it('should trigger reset to reset form to initialValues', () => {
            const { getByLabelText, getByText, getByDisplayValue } = render(
                <FormRenderer
                    schema={{ ...schema, canReset: true }}
                    onSubmit={handleSubmit}
                    onCancel={handleCancel}
                    initialValues={{
                        name: 'My name',
                    }}
                />
            );

            act(() => {
                fireEvent.change(getByLabelText('Name'), { target: { value: 'My new name' } });
            });

            expect(getByDisplayValue('My new name')).toBeVisible();

            act(() => {
                fireEvent.click(getByText('Reset'));
            });

            expect(getByDisplayValue('My name')).toBeVisible();
        });

        it('can be accessed by custom test-id', () => {
            const schemaWithTestId = {
                ...schema,
                'data-testid': 'form-renderer-1',
            };
            const { getByTestId } = render(
                <FormRenderer schema={schemaWithTestId} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            expect(getByTestId('form-renderer-1')).toBeInTheDocument();
        });
    });

    describe('Checkbox', () => {
        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.CHECKBOX,
                    name: 'checkbox',
                    label: 'Checkbox',
                    options: [
                        {
                            label: 'Option 1',
                            value: '1',
                        },
                        {
                            label: 'Option 2',
                            value: '2',
                        },
                        {
                            label: 'Option 3',
                            value: '3',
                        },
                    ],
                    isRequired: true,
                    'data-testid': 'checkbox-1',
                    validate: [
                        {
                            type: validatorTypes.REQUIRED,
                        },
                    ],
                },
            ],
        };
        it('should render default checkbox', () => {
            const schema = {
                ...baseSchema,
                fields: [
                    {
                        component: componentTypes.CHECKBOX,
                        name: 'checkbox',
                        label: 'Checkbox',
                        isRequired: true,
                        'data-testid': 'checkbox-1',
                    },
                ],
            };
            const { getByLabelText, getByText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByTestId('checkbox-1')).toBeInTheDocument();

            fireEvent.click(getByLabelText('Checkbox'));
            fireEvent.click(getByText('Submit'));

            expect(handleSubmit).toHaveBeenCalledWith({ checkbox: true }, expect.any(Object), expect.any(Function));
        });

        it('should render checkboxes', () => {
            const { getByLabelText, getByText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByTestId('checkbox-1')).toBeInTheDocument();
            expect(getByTestId('checkbox-1-1')).toBeInTheDocument();
            expect(getByTestId('checkbox-1-2')).toBeInTheDocument();
            expect(getByTestId('checkbox-1-3')).toBeInTheDocument();

            fireEvent.click(getByLabelText('Option 1'));
            fireEvent.click(getByLabelText('Option 3'));
            fireEvent.click(getByText('Submit'));

            expect(handleSubmit).toHaveBeenCalledWith(
                { checkbox: ['1', '3'] },
                expect.any(Object),
                expect.any(Function)
            );
        });

        it('should trigger validation', () => {
            const { getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            fireEvent.click(getByText('Submit'));
            expect(getByText('Required')).toBeVisible();
        });
    });

    describe('Treeview', () => {
        const treeItems = {
            id: '1',
            label: 'Tree Root',
            children: [
                {
                    id: '2',
                    label: 'Node 1.0',
                    children: [
                        { id: '3', label: 'Node 1.1' },
                        { id: '4', label: 'Node 1.3' },
                    ],
                },
                {
                    id: '5',
                    label: 'Node 2.0',
                    children: [
                        {
                            id: '6',
                            label: 'Node 2.1.0',
                            children: [{ id: '7', label: 'Node 2.1.2' }],
                        },
                        { id: '8', label: 'Node 2.2' },
                    ],
                },
            ],
        };

        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.TREE_VIEW,
                    label: 'this is a tree',
                    helperText: 'this is a hint',
                    description: 'this is a description',
                    name: 'tree',
                    treeItems: treeItems,
                    multiSelect: true,
                    defaultExpanded: ['1', '2', '5'],
                    'data-testid': 'tree-view-1',
                    validate: [
                        {
                            type: validatorTypes.REQUIRED,
                        },
                    ],
                },
            ],
        };

        it('should render Treeview', () => {
            const { getByText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByTestId('tree-view-1')).toBeInTheDocument();

            act(() => {
                fireEvent.click(getByText('Node 1.1'));
                fireEvent.click(getByText('Submit'));
            });

            expect(handleSubmit).toHaveBeenCalledWith({ tree: ['3'] }, expect.any(Object), expect.any(Function));
        });

        it('should trigger validation', () => {
            const { getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            fireEvent.click(getByText('Submit'));
            expect(getByText('Required')).toBeVisible();
        });
    });

    describe('Wizard', () => {
        const ReviewTemplate = ({ data }: any) => {
            return (
                <>
                    {data.name}-{data.textarea}
                </>
            );
        };
        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.WIZARD,
                    name: 'wizard',
                    submitButtonText: 'Custom Submit Label',
                    fields: [
                        {
                            name: 'step-1',
                            title: 'Step 1',
                            description: 'Descrirption for Step 1',
                            fields: [
                                {
                                    component: componentTypes.TEXTAREA,
                                    name: 'textarea',
                                    label: 'Textarea',
                                    validate: [
                                        {
                                            type: validatorTypes.REQUIRED,
                                        },
                                    ],
                                },
                            ],
                        },
                        {
                            name: 'step-2',
                            title: 'Step 2',
                            fields: [
                                {
                                    component: componentTypes.TEXT_FIELD,
                                    name: 'name',
                                    label: 'Name',
                                    validate: [
                                        {
                                            type: validatorTypes.REQUIRED,
                                        },
                                    ],
                                },
                            ],
                        },
                        {
                            name: 'step-3',
                            title: 'Review',
                            fields: [
                                {
                                    component: componentTypes.REVIEW,
                                    name: 'review',
                                    Template: ReviewTemplate,
                                },
                            ],
                        },
                    ],
                    'data-testid': 'wizard-1',
                },
            ],
        };

        it('should render Wizard', () => {
            const { getByText, getAllByText, getByLabelText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            expect(getAllByText('Step 1')).toHaveLength(3);
            expect(getByTestId('wizard-1')).toBeInTheDocument();
            expect(getByText('Descrirption for Step 1')).toBeVisible();
            act(() => {
                fireEvent.change(getByLabelText('textarea'), { target: { value: 'my content' } });
                fireEvent.click(getByText('Next'));
            });

            expect(getAllByText('Step 2')).toHaveLength(3);

            act(() => {
                fireEvent.change(getByLabelText('Name'), { target: { value: 'my name' } });
                fireEvent.click(getByText('Next'));
            });

            expect(getAllByText('Review')).toHaveLength(2);
            expect(getByText('my name-my content')).toBeVisible();
            fireEvent.click(getByText('Custom Submit Label'));
            expect(handleSubmit).toHaveBeenCalledWith(
                { name: 'my name', textarea: 'my content' },
                expect.any(Object),
                expect.any(Function)
            );
        });

        it('should handle navigation', () => {
            const { getByText, getAllByText, getByLabelText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            expect(getAllByText('Step 1')).toHaveLength(3);
            act(() => {
                fireEvent.change(getByLabelText('textarea'), { target: { value: 'my content' } });
                fireEvent.click(getByText('Next'));
            });

            expect(getAllByText('Step 2')).toHaveLength(3);

            act(() => {
                fireEvent.click(getByText('Previous'));
            });

            expect(getAllByText('Step 1')).toHaveLength(3);
        });

        it('should trigger validation', () => {
            const { getByText, getAllByText, getByLabelText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            expect(getAllByText('Step 1')).toHaveLength(3);
            expect(getByText('Descrirption for Step 1')).toBeVisible();
            act(() => {
                fireEvent.click(getByText('Next'));
            });
            expect(getByText('Required')).toBeVisible();
            act(() => {
                fireEvent.change(getByLabelText('textarea'), { target: { value: 'my content' } });
                fireEvent.click(getByText('Next'));
            });
            expect(getAllByText('Step 2')).toHaveLength(3);
        });
    });

    describe('Subform', () => {
        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.SUB_FORM,
                    title: 'Subform 1',
                    description: 'This is a subform',
                    name: 'subform1',
                    'data-testid': 'subform-1',
                    fields: [
                        {
                            component: componentTypes.TEXT_FIELD,
                            name: 'name',
                            label: 'Name',
                            validate: [
                                {
                                    type: validatorTypes.REQUIRED,
                                },
                            ],
                        },
                    ],
                },
            ],
        };

        it('should render Subform', () => {
            const { getByText, getByLabelText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            expect(getByTestId('subform-1')).toBeInTheDocument();
            expect(getByText('Subform 1')).toBeVisible();
            expect(getByText('This is a subform')).toBeVisible();
            act(() => {
                fireEvent.change(getByLabelText('Name'), { target: { value: 'my name' } });
                fireEvent.click(getByText('Submit'));
            });
            expect(handleSubmit).toHaveBeenCalledWith({ name: 'my name' }, expect.any(Object), expect.any(Function));
        });

        it('should trigger validate', () => {
            const { getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            fireEvent.click(getByText('Submit'));
            expect(getByText('Required')).toBeVisible();
        });
    });

    const CustomComponentSimple = ({ label }: any) => <>{label}</>;

    const CustomComponentComplex = ({ input }: any) => (
        <input type="text" onChange={input.onChange} value={input.value} data-testid="input" />
    );

    describe('Custom', () => {
        it('renders custom component', () => {
            const schema = {
                ...baseSchema,
                fields: [
                    {
                        component: componentTypes.CUSTOM,
                        name: 'text',
                        label: 'This is the content of custom component',
                        CustomComponent: CustomComponentSimple,
                    },
                ],
            };

            const { getByText } = render(<FormRenderer schema={schema} onSubmit={jest.fn()} onCancel={jest.fn()} />);
            expect(getByText('This is the content of custom component')).toBeVisible();
        });

        it('supports interaction', () => {
            const handleSubmit = jest.fn();
            const schema = {
                ...baseSchema,
                fields: [
                    {
                        component: componentTypes.CUSTOM,
                        name: 'input',
                        CustomComponent: CustomComponentComplex,
                    },
                ],
            };

            const { getByTestId, getByText } = render(
                <FormRenderer
                    schema={schema}
                    onSubmit={handleSubmit}
                    onCancel={jest.fn()}
                    initialValues={{
                        input: 'initial input',
                    }}
                />
            );

            // expect(getByTestId('input')).toHaveValue('initial input');

            act(() => {
                fireEvent.change(getByTestId('input'), { target: { value: 'updated input' } });
                fireEvent.click(getByText('Submit'));
            });

            expect(handleSubmit).toHaveBeenCalledWith(
                {
                    input: 'updated input',
                },
                expect.any(Object),
                expect.any(Function)
            );
        });
    });

    describe('ExpandableSection', () => {
        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.EXPANDABLE_SECTION,
                    title: 'Additional information',
                    description: 'This is for additional information',
                    name: 'additionalInfo',
                    'data-testid': 'expandable-section-1',
                    fields: [
                        {
                            component: componentTypes.TEXT_FIELD,
                            name: 'name',
                            label: 'Name',
                            validate: [
                                {
                                    type: validatorTypes.REQUIRED,
                                },
                            ],
                        },
                    ],
                },
            ],
        };

        it('should render ExpandableSection', () => {
            const { getByText, getByLabelText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            expect(getByText('Additional information')).toBeVisible();
            expect(getByText('This is for additional information')).toBeVisible();
            expect(getByLabelText('Name')).not.toBeVisible();
            expect(getByTestId('expandable-section-1')).toBeInTheDocument();
            act(() => {
                fireEvent.click(getByText('Additional information'));
                fireEvent.change(getByLabelText('Name'), { target: { value: 'my name' } });
                fireEvent.click(getByText('Submit'));
            });
            expect(handleSubmit).toHaveBeenCalledWith(
                {
                    additionalInfo: {
                        name: 'my name',
                    },
                },
                expect.any(Object),
                expect.any(Function)
            );
        });

        it('should trigger valiation', () => {
            const { getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            expect(getByText('Additional information')).toBeVisible();
            expect(getByText('This is for additional information')).toBeVisible();
            fireEvent.click(getByText('Submit'));
            expect(getByText('Required')).toBeVisible();
        });
    });

    describe('Switch', () => {
        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.SWITCH,
                    name: 'switch',
                    label: 'Switch',
                    initialValue: false,
                    'data-testid': 'switch-1',
                },
            ],
        };
        it('should render Switch', async () => {
            const { getByLabelText, getByText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            expect(getByLabelText('Switch')).toBeInTheDocument();
            expect(getByTestId('switch-1')).toBeInTheDocument();

            act(() => {
                fireEvent.click(getByText('Submit'));
            });

            expect(handleSubmit).toHaveBeenCalledWith({ switch: false }, expect.any(Object), expect.any(Function));
        });
    });

    describe('Datepicker', () => {
        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.DATE_PICKER,
                    name: 'datePicker',
                    label: 'Date picker',
                    'data-testid': 'date-picker-1',
                    isRequired: true,
                    validate: [
                        {
                            type: validatorTypes.REQUIRED,
                        },
                    ],
                },
            ],
        };

        it('should render Datepicker', () => {
            const { getByLabelText, getByText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByText('Date picker')).toBeVisible();
            expect(getByTestId('date-picker-1')).toBeInTheDocument();

            act(() => {
                fireEvent.change(getByLabelText('Date picker'), { target: { value: '20200101' } });
            });

            fireEvent.click(getByText('Submit'));
            expect(handleSubmit).toHaveBeenCalledWith(
                { datePicker: expect.any(Date) },
                expect.any(Object),
                expect.any(Function)
            );
        });

        it('should trigger validation', () => {
            const { getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            fireEvent.click(getByText('Submit'));
            expect(getByText('Required')).toBeVisible();
        });

        it('should handle initial value', () => {
            const date = new Date(2020, 0, 1, 1, 1, 1, 1);

            const { getByText, getByLabelText } = render(
                <FormRenderer
                    schema={schema}
                    initialValues={{ datePicker: date }}
                    onSubmit={handleSubmit}
                    onCancel={handleCancel}
                />
            );

            fireEvent.click(getByText('Submit'));
            expect(handleSubmit).toHaveBeenCalledWith({ datePicker: date }, expect.any(Object), expect.any(Function));

            act(() => {
                fireEvent.change(getByLabelText('Date picker'), { target: { value: '2021/02/02' } });
            });

            fireEvent.click(getByText('Submit'));
            expect(handleSubmit).toHaveBeenLastCalledWith(
                { datePicker: new Date(2021, 1, 2) },
                expect.any(Object),
                expect.any(Function)
            );
        });
    });

    describe('TimePicker', () => {
        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.TIME_PICKER,
                    name: 'timePicker',
                    label: 'Time picker',
                    'data-testid': 'time-picker-1',
                    isRequired: true,
                    validate: [
                        {
                            type: validatorTypes.REQUIRED,
                        },
                    ],
                },
            ],
        };

        it('should render a TimePicker', () => {
            const { getByLabelText, getByText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByText('Time picker')).toBeVisible();
            expect(getByTestId('time-picker-1')).toBeInTheDocument();

            act(() => {
                fireEvent.change(getByLabelText('Time picker'), { target: { value: '10:35 AM' } });
            });

            fireEvent.click(getByText('Submit'));
            expect(handleSubmit).toHaveBeenCalledWith(
                { timePicker: expect.stringMatching(/.*T10:35:.*Z$/) },
                expect.any(Object),
                expect.any(Function)
            );
        });

        it('should trigger validation', () => {
            const { getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            fireEvent.click(getByText('Submit'));
            expect(getByText('Required')).toBeVisible();
        });
    });

    describe('Radio', () => {
        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.RADIO,
                    name: 'radio',
                    label: 'Radio',
                    options: [
                        {
                            label: 'Option 1',
                            description: 'Description 1',
                            value: '1',
                        },
                        {
                            label: 'Option 2',
                            value: '2',
                        },
                        {
                            label: 'Option 3',
                            value: '3',
                        },
                    ],
                    'data-testid': 'radio-1',
                    isRequired: true,
                    validate: [
                        {
                            type: validatorTypes.REQUIRED,
                        },
                    ],
                },
            ],
        };
        it('should render radio buttons', () => {
            const { getByLabelText, getByText, getAllByRole, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByText('Radio')).toBeVisible();
            expect(getAllByRole('radio')).toHaveLength(3);
            expect(getByText('Description 1')).toBeVisible();
            expect(getByTestId('radio-1')).toBeInTheDocument();
            expect(getByTestId('radio-1-1')).toBeInTheDocument();
            expect(getByTestId('radio-1-2')).toBeInTheDocument();
            expect(getByTestId('radio-1-3')).toBeInTheDocument();

            fireEvent.click(getByLabelText('Option 3'));
            fireEvent.click(getByText('Submit'));

            expect(handleSubmit).toHaveBeenCalledWith({ radio: '3' }, expect.any(Object), expect.any(Function));
        });

        it('should trigger validation', () => {
            const { getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            fireEvent.click(getByText('Submit'));
            expect(getByText('Required')).toBeVisible();
        });
    });

    describe('Select', () => {
        const field = {
            component: componentTypes.SELECT,
            name: 'select',
            label: 'Select',
            placeholder: 'Choose an option',
            options: [
                {
                    label: 'Option 1',
                    value: '1',
                },
                {
                    label: 'Option 2',
                    value: '2',
                },
                {
                    label: 'Option 3',
                    value: '3',
                },
            ],
            isRequired: true,
            validate: [
                {
                    type: validatorTypes.REQUIRED,
                },
            ],
        };

        it('should render Select', () => {
            const schema = {
                ...baseSchema,
                'data-testid': 'select-1',
                fields: [field],
            };

            const { getByText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByText('Select')).toBeVisible();
            expect(getByTestId('select-1')).toBeInTheDocument();
        });

        it('should render Autosuggest when isSearchable is true', () => {
            const schema = {
                ...baseSchema,
                fields: [{ ...field, isSearchable: true }],
            };
            const { getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByTestId('autosuggest')).toBeInTheDocument();
        });

        it('should render Multiselect when multiSelect is true', () => {
            const schema = {
                ...baseSchema,
                fields: [{ ...field, multiSelect: true }],
            };
            const { getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByTestId('multiselect')).toBeInTheDocument();
        });

        it('should trigger validation', () => {
            const schema = {
                ...baseSchema,
                fields: [field],
            };
            const { getByText } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );
            fireEvent.click(getByText('Submit'));
            expect(getByText('Required')).toBeVisible();
        });
    });

    describe('FieldArray', () => {
        const fieldArrayName = 'fieldArray';
        const fieldArrayTestId = 'field-array-1';
        const schema = {
            ...baseSchema,
            fields: [
                {
                    component: componentTypes.FIELD_ARRAY,
                    label: 'Attribute Editor',
                    description: 'This is a form array',
                    name: fieldArrayName,
                    helperText: 'You can add up to 6 more items.',
                    minItems: 1,
                    maxItems: 3,
                    noItemsMessage: 'Please add new item',
                    'data-testid': fieldArrayTestId,
                    defaultItem: {
                        key: 'key',
                        value: 'value',
                    },
                    validate: [
                        {
                            type: validatorTypes.MIN_ITEMS,
                            threshold: 1,
                        },
                        {
                            type: validatorTypes.REQUIRED,
                        },
                    ],
                    fields: [
                        {
                            component: componentTypes.TEXT_FIELD,
                            name: 'key',
                            label: 'Key',
                            validate: [
                                {
                                    type: validatorTypes.REQUIRED,
                                },
                            ],
                        },
                        {
                            component: componentTypes.TEXT_FIELD,
                            name: 'value',
                            label: 'Value',
                            validate: [
                                {
                                    type: validatorTypes.REQUIRED,
                                },
                            ],
                        },
                    ],
                },
            ],
        };

        const fieldArrayTest = (schema: any) => {
            const { getByText, getAllByRole, getByLabelText, getByTestId } = render(
                <FormRenderer schema={schema} onSubmit={handleSubmit} onCancel={handleCancel} />
            );

            expect(getByText('Attribute Editor')).toBeVisible();
            expect(getByText('This is a form array')).toBeVisible();
            expect(getByText('You can add up to 6 more items.')).toBeVisible();
            expect(getByText('Please add new item'));
            expect(getByTestId(fieldArrayTestId)).toBeInTheDocument();
            expect(getByTestId(`${fieldArrayTestId}-add-button`)).toBeInTheDocument();

            act(() => {
                fireEvent.click(getAllByRole('button')[0]);
            });

            expect(getByText('Key')).toBeVisible();
            expect(getByText('Value')).toBeVisible();
            expect(getByTestId(`${fieldArrayTestId}-${fieldArrayName}[0]`)).toBeInTheDocument();
            expect(
                getByTestId(`${fieldArrayTestId}-${fieldArrayName}[0]-${fieldArrayName}[0].key`)
            ).toBeInTheDocument();
            expect(
                getByTestId(`${fieldArrayTestId}-${fieldArrayName}[0]-${fieldArrayName}[0].value`)
            ).toBeInTheDocument();
            expect(getByTestId(`${fieldArrayTestId}-${fieldArrayName}[0]-remove-button`)).toBeInTheDocument();
            act(() => {
                fireEvent.change(getByLabelText('Key'), { target: { value: 'key' } });
                fireEvent.change(getByLabelText('Value'), { target: { value: 'value' } });
                fireEvent.click(getByText('Submit'));
            });

            expect(handleSubmit).toHaveBeenCalledWith(
                {
                    fieldArray: [
                        {
                            key: 'key',
                            value: 'value',
                        },
                    ],
                },
                expect.any(Object),
                expect.any(Function)
            );
        };

        it('should render FieldArray', () => {
            fieldArrayTest(schema);
        });

        it('should render FieldArray with grid', () => {
            fieldArrayTest({ ...schema, layout: 'grid' });
        });

        it('should render FieldArray with stack', () => {
            fieldArrayTest({ ...schema, layout: 'stack' });
        });
    });
});
