简体   繁体   中英

What is the proper way to test a form with a lot of input fields using Jest and react-testing-library?

I have this form with a lot of inputs, the questions is, is there a way to simplify handling of all those single input variables, cause their listing looks very ugly. Tests for a form with two inputs are looking clean and elegant, but this one looks like I'm doing something wrong. Also there is a 'specialties' data variable, I don't think it belongs in mocks folder, as it is not a mocked api call, just a prop for the form. Is there a convention as to where do I put such variables in the tests folder? I would appreciate any other feedback on what I'm doing wrong, thank you.

import React from 'react'
import { Provider } from 'react-redux'
import { render, screen } from '@testing-library/react'
import store from '../../../store'
import PupilForm from '../../../components/forms/PupilForm'
import specialties from '../../../__mocks__/specialties.json'

const mockHandleFormData = jest.fn()
const mockOpenInfoModal = jest.fn()

describe('<PupilForm /> component', () => {
    // eslint-disable-next-line
    let view
    // inputs
    let nameInput
    let specialtyInput
    let genderInput
    let birthDateInput
    let mainSchoolClassInput
    let benefitsInput
    let mainSchoolInput
    let homeAddressInput
    let phoneNumberInput
    let applicantNameInput
    let contactEmailInput
    let fathersNameInput
    let fathersPhoneInput
    let fathersEmploymentInfoInput
    let mothersNameInput
    let mothersPhoneInput
    let mothersEmploymentInfoInput
    // checkboxes
    let docsCheck
    let processDataCheck
    let paymentObligationsCheck
    // buttons
    let submitButton
    let resetButton


    beforeEach(() => {
        view = render(
            <Provider store={store}>
                <PupilForm
                    handleFormData={mockHandleFormData}
                    openInfoModal={mockOpenInfoModal}
                    specialties={specialties.map(spec => spec.title)}
                    mode="public"
                />
            </Provider>
        )

        nameInput = screen.getByRole('textbox', { name: /Прізвище та повне ім'я учня/ })
        specialtyInput = screen.getByRole('combobox', { name: /Фах/ })
        genderInput = screen.getByRole('combobox', { name: /Стать/ })
        birthDateInput = screen.getByLabelText(/Дата народження/)
        mainSchoolClassInput = screen.getByRole('combobox', { name: /Клас ЗОШ/ })
        benefitsInput = screen.getByRole('combobox', { name: /Пільги %/ })
        mainSchoolInput = screen.getByRole('textbox', { name: /В якому закладі навчается/ })
        homeAddressInput = screen.getByRole('textbox', { name: /Домашня адреса/ })
        phoneNumberInput = screen.getByRole('textbox', { name: /Телефонний номер учня/ })
        applicantNameInput = screen.getByRole('textbox', { name: /Ім'я особи, яка звертається із заявою/ })
        contactEmailInput = screen.getByRole('textbox', { name: /Контактна електронна пошта/ })

        fathersNameInput = screen.getByRole('textbox', { name: /Ім'я батька/ })
        fathersPhoneInput = screen.getByRole('textbox', { name: /Телефонний номер батька/ })
        fathersEmploymentInfoInput = screen.getByRole('textbox', { name: /Місце роботи батька/ })

        mothersNameInput = screen.getByRole('textbox', { name: /Ім'я матері/ })
        mothersPhoneInput = screen.getByRole('textbox', { name: /Телефонний номер матері/ })
        mothersEmploymentInfoInput = screen.getByRole('textbox', { name: /Місце роботи матері/ })

        docsCheck = screen.getByRole('checkbox', { name: /Я зобов'язаний надати ці документи/ })
        processDataCheck = screen.getByRole('checkbox', { name: /Я згоден на збір та обробку/ })
        paymentObligationsCheck = screen.getByRole('checkbox', { name: /Зобов'язання про оплату/ })

        submitButton = screen.getByRole('button', { name: /Відправити/ })
        resetButton = screen.getByRole('button', { name: /Очистити/ })
    })

    it('in renders all fields correctly', () => {
        expect(/Дані\/інформація про учня/).toBeInTheDocument
        expect(nameInput).toHaveAttribute('type', 'text')
        expect(specialtyInput).toHaveClass('custom-select')
        expect(genderInput).toHaveClass('custom-select')
        expect(birthDateInput).toHaveAttribute('type', 'date')
        expect(mainSchoolClassInput).toHaveClass('custom-select')
        expect(benefitsInput).toHaveClass('custom-select')
        expect(mainSchoolInput).toHaveAttribute('type', 'text')
        expect(homeAddressInput).toHaveAttribute('type', 'text')
        expect(phoneNumberInput).toHaveAttribute('type', 'text')
        expect(applicantNameInput).toHaveAttribute('type', 'text')
        expect(contactEmailInput).toHaveAttribute('type', 'email')

        expect(/Дані\/інформація о батьках/).toBeInTheDocument
        expect(fathersNameInput).toHaveAttribute('type', 'text')
        expect(fathersPhoneInput).toHaveAttribute('type', 'text')
        expect(fathersEmploymentInfoInput).toHaveAttribute('type', 'text')
        expect(mothersNameInput).toHaveAttribute('type', 'text')
        expect(mothersPhoneInput).toHaveAttribute('type', 'text')
        expect(mothersEmploymentInfoInput).toHaveAttribute('type', 'text')

        expect(docsCheck).toHaveAttribute('type', 'checkbox')
        expect(processDataCheck).toHaveAttribute('type', 'checkbox')
        expect(paymentObligationsCheck).toHaveAttribute('type', 'checkbox')

        expect(submitButton).toHaveAttribute('type', 'submit')
        expect(resetButton).toHaveAttribute('type', 'reset')
    })

    /*
    it('some other test that uses the same inputs', () => {
        // expect all inputs to be able to change their values on user input
    })
    */
})

is there a way to simplify handling of all those single input variables?

I don't think so. I personally would get rid of all field variables and access them via screen only. But do what feels right for you.

You could also try shortening a few queries. Since you are using regex, you don't need to specify the whole element name .


but this one looks like I'm doing something wrong

The test looks fine. I would point out that you probably don't need to test certain things like expect(nameInput).toHaveAttribute('type', 'text') since you are already getting most of that for free with nameInput = screen.getByRole('textbox', { name: /Прізвище та повне ім'я учня/ }) .

You will also be using something like userEvent.type on it so, I think it's safe enough already.


Also there is a 'specialties' data variable, I don't think it belongs in mocks folder, as it is not a mocked api call, just a prop for the form

I also don't see any problems on having data for the test under a mocks folder, even if it is not mocking an API call.

Perhaps you could name the folder fixtures if you think that is more semantically appropriate. Or you can just keep it in the test file that will use it. This seems like a code style preference and everyone will have a different opinion on it.


Is there a convention as to where do I put such variables in the tests folder?

__mocks__ , fixtures , data , you name it. I would recommend you to move it around until it feels right, then consult with a team member.

This question is very similar

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM