简体   繁体   中英

@testing-library/react test form onSubmit

In a simple scenario like so

function onSubmit() { e.preventDefault(); /* Some Submit Logic */ }

<form data-testid="form" onSubmit={(e) => onSubmit(e)}>
   <button type="submit" data-testid="submit-button">Submit</button>
</form>

How do I make sure that the form gets submitted when the submit button is clicked?

const { queryByTestId } = render(<LoginForm/>);
const LoginForm = queryByTestId("form")
const SubmitButton = queryByTestId("submit-button")
fireEvent.click(SubmitButton)

???

How do I test if onSubmit() has been called or maybe form has been submitted?

Basically, here is what I "solved" it:

// LoginForm.js

export function LoginForm({ handleSubmit }) {

     const [name, setName] = useState('');

     function handleChange(e) {
         setName(e.target.value)
     }

     return (
         <form data-testid="form" onSubmit={() => handleSubmit({ name })}>
              <input required data-testid="input" type="text" value={name} onChange={(e) => handleChange(e)}/>
              <button type="submit" data-testid="submit-button">Submit</button>
         </form>
     )
}

export default function LoginPage() {

    function handleSubmit(e) {
        // submit stuff
    }

    return <LoginForm handleSubmit={(e) => handleSubmit(e)}/>

}

Now the test's file:

// LoginForm.test.js

import React from 'react';
import { render, fireEvent } from "@testing-library/react";
import LoginPage, { LoginForm } from "./LoginPage";

it("Form can be submited & input field is modifiable", () => {

    const mockSubmit = jest.fn();
    const { debug, queryByTestId } = render(<LoginForm handleSubmit={mockSubmit}/>);

    fireEvent.change(queryByTestId("input"), { target: { value: 'Joe Doe' } }); // invoke handleChange
    fireEvent.submit(queryByTestId("form"));

    expect(mockSubmit).toHaveBeenCalled(); // Test if handleSubmit has been called 
    expect(mockSubmit.mock.calls).toEqual([[{name: 'Joe Doe'}]]); // Test if handleChange works

});

I'd suggest to use nock to intercept request sending from form and return mocked response after. For example:

nock('https://foo.bar').post('/sign-up', formValues).reply(201);

But I would like to know a better solutions tho.

getByRole('form', { name: /formname/i })

RTL is meant to move away from using id's. An ideal solution is to name your form which does two things. It allow you to uniquely name it making it useful to screen readers and also gets the browser to assign it a role of form. Without the name, getByRole('form') will do nothing.

MDN: <form> element

Implicit ARIA role - form if the form has an accessible name, otherwise no corresponding role

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