///////////////////////////////////////////////////////////// // // pgAdmin 4 - PostgreSQL Tools // // Copyright (C) 2013 - 2024, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // ////////////////////////////////////////////////////////////// import React from 'react'; import { withTheme } from '../fake_theme'; import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; import {FormInputText, FormInputFileSelect, FormInputSQL, FormInputSwitch, FormInputCheckbox, FormInputToggle, FormInputSelect, FormInputColor, FormFooterMessage, MESSAGE_TYPE} from '../../../pgadmin/static/js/components/FormComponents'; import * as showFileManager from '../../../pgadmin/static/js/helpers/showFileManager'; /* MUI Components need to be wrapped in Theme for theme vars */ describe('FormComponents', ()=>{ let onAccessibility = ()=> { const input = screen.getByTestId('input-text'); expect(input.getAttribute('id')).toBe('inpCid'); expect(input.getAttribute('aria-describedby')).toBe('hinpCid'); }; describe('FormInputText', ()=>{ let ThemedFormInputText = withTheme(FormInputText), ctrl; const ctrlRerender = (props)=>{ ctrl.rerender( ); }; beforeEach(()=>{ ctrl = render( ); }); it('init', ()=>{ expect(screen.getByLabelText('First')).toBeInTheDocument(); const input = screen.getByDisplayValue('thevalue'); expect(input).toBeInTheDocument(); expect(input.hasAttribute('readonly')).toBe(false); expect(input.hasAttribute('disabled')).toBe(false); expect(screen.getByText('some help message')).toBeInTheDocument(); }); it('props change', ()=>{ let onChange = ()=>{/*This is intentional (SonarQube)*/}; ctrlRerender({ readonly: true, disabled: true, value: 'new value', onChange: onChange, }); const input = screen.getByDisplayValue('new value'); expect(input).toBeInTheDocument(); expect(input.hasAttribute('readonly')).toBe(true); expect(input.hasAttribute('disabled')).toBe(true); }); it('accessibility', ()=>{ onAccessibility(); }); }); describe('FormInputFileSelect', ()=>{ let ThemedFormInputFileSelect = withTheme(FormInputFileSelect), ctrl; const ctrlRerender = (props)=>{ ctrl.rerender( ); }; beforeEach(()=>{ jest.spyOn(showFileManager, 'showFileManager').mockImplementation((controlProps, onFileSelect)=>{ onFileSelect('selected/file'); }); ctrl = render( ); }); it('init', ()=>{ expect(screen.getByLabelText('First')).toBeInTheDocument(); const input = screen.getByDisplayValue('thevalue'); expect(input).toBeInTheDocument(); expect(input.hasAttribute('readonly')).toBe(false); expect(input.hasAttribute('disabled')).toBe(false); expect(screen.getByText('some help message')).toBeInTheDocument(); }); it('props change', ()=>{ ctrlRerender({ readonly: true, disabled: true, value: 'new value', }); const input = screen.getByDisplayValue('new value'); expect(input).toBeInTheDocument(); expect(input.hasAttribute('readonly')).toBe(true); expect(input.hasAttribute('disabled')).toBe(true); }); it('file select', ()=>{ let onChange = jest.fn(); ctrlRerender({ onChange: onChange, }); fireEvent.click(screen.getByRole('button')); expect(onChange).toHaveBeenCalledWith('selected/file'); }); it('accessibility', ()=>{ onAccessibility(); }); }); describe('FormInputSQL', ()=>{ let ThemedFormInputSQL = withTheme(FormInputSQL); beforeEach(()=>{ render( ); }); it('init', ()=>{ expect(screen.getByLabelText('First')).toBeInTheDocument(); expect(screen.getByText('thevalue')).toBeInTheDocument(); expect(screen.getByText('some help message')).toBeInTheDocument(); }); }); describe('FormInputSwitch', ()=>{ let ThemedFormInputSwitch = withTheme(FormInputSwitch), ctrl, onChange=()=>{return 1;}; const ctrlRerender = (props)=>{ ctrl.rerender( ); }; beforeEach(()=>{ ctrl = render( ); }); it('init', ()=>{ expect(screen.getByLabelText('First')).toBeInTheDocument(); const input = ctrl.container.querySelector('.MuiSwitch-switchBase'); expect(input).toBeInTheDocument(); expect(input.className.includes('Mui-checked')).toBe(false); expect(screen.getByText('some help message')).toBeInTheDocument(); }); it('props change', ()=>{ ctrlRerender({ readonly: true, value: true, }); const input = ctrl.container.querySelector('.MuiSwitch-switchBase'); expect(input.className.includes('Mui-checked')).toBe(true); }); it('accessibility', ()=>{ const input = ctrl.container.querySelector('input'); expect(input.getAttribute('id')).toBe('inpCid'); expect(input.getAttribute('aria-describedby')).toBe('hinpCid'); }); }); describe('FormInputCheckbox', ()=>{ let ThemedFormInputCheckbox = withTheme(FormInputCheckbox), ctrl, onChange=()=>{return 1;}; const ctrlRerender = (props)=>{ ctrl.rerender( ); }; beforeEach(()=>{ ctrl = render( ); }); it('init', ()=>{ expect(screen.getByLabelText('First')).toBeInTheDocument(); expect(screen.getByLabelText('Second')).toBeInTheDocument(); const input = ctrl.container.querySelector('.MuiCheckbox-root'); expect(input).toBeInTheDocument(); expect(input.className.includes('Mui-checked')).toBe(false); expect(screen.getByText('some help message')).toBeInTheDocument(); }); it('props change', ()=>{ ctrlRerender({ readonly: true, value: true, }); const input = ctrl.container.querySelector('.MuiCheckbox-root'); expect(input).toBeInTheDocument(); expect(input.className.includes('Mui-checked')).toBe(true); }); it('accessibility', ()=>{ const input = ctrl.container.querySelector('input'); expect(input.getAttribute('id')).toBe('inpCid'); expect(input.getAttribute('aria-describedby')).toBe('hinpCid'); }); }); describe('FormInputToggle', ()=>{ let ThemedFormInputToggle = withTheme(FormInputToggle), ctrl, onChange=()=>{return 1;}; const ctrlRerender = (props)=>{ ctrl.rerender( ); }; beforeEach(()=>{ ctrl = render( ); }); it('init', ()=>{ expect(screen.getByLabelText('First')).toBeInTheDocument(); expect(screen.getAllByRole('button').length).toBe(3); expect(screen.getAllByRole('button').at(0).className.includes('primaryButton')).toBe(false); expect(screen.getAllByRole('button').at(1).className.includes('primaryButton')).toBe(true); expect(screen.getAllByRole('button').at(2).className.includes('primaryButton')).toBe(false); expect(screen.getByText('some help message')).toBeInTheDocument(); }); it('props change', ()=>{ ctrlRerender({ value: 1, }); expect(screen.getAllByRole('button').at(0).className.includes('primaryButton')).toBe(true); expect(screen.getAllByRole('button').at(1).className.includes('primaryButton')).toBe(false); expect(screen.getAllByRole('button').at(2).className.includes('primaryButton')).toBe(false); }); it('accessibility', ()=>{ const input = ctrl.container.querySelector('input'); expect(input.getAttribute('id')).toBe('inpCid'); expect(input.getAttribute('aria-describedby')).toBe('hinpCid'); }); }); describe('FormInputSelect', ()=>{ let ThemedFormInputSelect = withTheme(FormInputSelect), ctrl, onChange=jest.fn(); const ctrlRerender = (props)=>{ act(()=>{ ctrl.rerender( ); }); }; beforeEach(async ()=>{ await act(async ()=>{ ctrl = await render( ); }); }); it('init', ()=>{ expect(screen.getByLabelText('First')).toBeInTheDocument(); expect(screen.getByText('Op1')).toBeInTheDocument(); expect(screen.getByText('some help message')).toBeInTheDocument(); }); it('no-clear with multi', ()=>{ ctrlRerender({ controlProps: { allowClear: false, multiple: true, }, value: [2, 3], }); expect(screen.getByText('Op2')).toBeInTheDocument(); expect(screen.getByText('Op3')).toBeInTheDocument(); }); it('creatable with multi', ()=>{ ctrlRerender({ controlProps: { creatable: true, multiple: true, }, value: ['val1', 'val2'], }); expect(screen.getByText('val1')).toBeInTheDocument(); expect(screen.getByText('val2')).toBeInTheDocument(); }); it('promise options', async ()=>{ let optionsLoaded = jest.fn(); let res = [ {label: 'PrOp1', value: 1}, {label: 'PrOp2', value: 2}, {label: 'PrOp3', value: 3}, ]; /* For options change, remount needed */ ctrlRerender({ options: ()=>Promise.resolve(res), optionsReloadBasis: 3, value: 3, optionsLoaded: optionsLoaded, }); // expect(screen.getByText('PrOp3')).toBeInTheDocument() await waitFor(()=>expect(screen.getByText('PrOp3')).toBeInTheDocument(), {timeout: 500}); }); it('accessibility', ()=>{ const input = ctrl.container.querySelectorAll('input')[1]; expect(input.getAttribute('id')).toBe('inpCid'); expect(input.getAttribute('aria-describedby')).toBe('hinpCid'); }); }); describe('FormInputColor', ()=>{ let pickrObj = React.createRef(); let ThemedFormInputColor = withTheme(FormInputColor), ctrl, onChange=jest.fn(); const ctrlRerender = (props)=>{ ctrl.rerender( pickrObj.current=obj} {...props} />); }; beforeEach(()=>{ ctrl = render( pickrObj.current=obj} />); }); it('init', ()=>{ expect(screen.getAllByRole('button').at(0).style.backgroundColor).toEqual('rgb(255, 0, 255)'); }); it('no color', ()=>{ ctrlRerender({ value: null, }); const btn = screen.getAllByRole('button').at(0); expect(btn.style.backgroundColor).toBe(''); }); }); describe('FormFooterMessage', ()=>{ let ThemedFormFooterMessage = withTheme(FormFooterMessage), ctrl, onClose=jest.fn(); const ctrlRerender = (props)=>{ ctrl.rerender( ); }; beforeEach(()=>{ ctrl = render( ); }); it('init', ()=>{ expect(screen.getByTestId(MESSAGE_TYPE.SUCCESS)).toBeInTheDocument(); expect(screen.getByText('Some message')).toBeInTheDocument(); }); it('change types', ()=>{ ctrlRerender({ type: MESSAGE_TYPE.ERROR, }); expect(screen.getByTestId(MESSAGE_TYPE.ERROR)).toBeInTheDocument(); ctrlRerender({ type: MESSAGE_TYPE.INFO, }); expect(screen.getByTestId(MESSAGE_TYPE.INFO)).toBeInTheDocument(); ctrlRerender({ type: MESSAGE_TYPE.WARNING, }); expect(screen.getByTestId(MESSAGE_TYPE.WARNING)).toBeInTheDocument(); }); it('closable', ()=>{ ctrlRerender({ closable: true, }); const btn = screen.getByTestId('Close'); expect(btn).toBeInTheDocument(); fireEvent.click(btn); expect(onClose).toHaveBeenCalled(); }); it('no message', ()=>{ ctrlRerender({ message: '', }); expect(ctrl.container).toBeEmptyDOMElement(); }); }); });