0

I built a react form for my portfolio that receives a name, email and message. I have started to learn tests and have been getting a lot of errors when doing so and I can't figure out this one.

Whenever I test if my onSubmit was called, it says it wasn't

Form:

const ContactForm = () => {
    const [messageInput, setMessageInput] = useState("");
    const [isThanksRendered, setThanksRendered] = useState(false);
    const pageYOffset = useWindowYOffset();
    const screenWidth = useWindowWidth();

    const textAreaRef = useRef<HTMLTextAreaElement>(null);
    const form = useRef<HTMLFormElement>(null as any);

    useAutosizeTextArea(textAreaRef.current, messageInput);

    const sendEmail = (event: any) => {
        event.preventDefault();

        setThanksRendered(true);

        const email = {
            name: form.current.user_name.value,
            email: form.current.user_email.value,
            message: form.current.message.value,
        }

        emailjs.send('service_mqqjzhj', 'template_yascyt3', email, 'vxsbnr4XFI-SFNKvG')
            .then((result: any) => {
                console.log(result.text);
            }, (error: any) => {
                console.log(error.text);
            }
        );
    };

    return (
        <>
            {isThanksRendered ? (
                <ThanksContainer>
                    <Thanks>Thank you for reaching out. I will get back to you as soon as possible : &#41;</Thanks>
                </ThanksContainer>
            ) : (
                <FormContainer
                    textAreaHeight={textAreaRef?.current?.offsetHeight}
                    ref={form}
                    onSubmit={sendEmail}
                    pageYOffset={pageYOffset}
                    screenWidth={screenWidth}
                    data-testid='form-submit'
                >
                    <Title>Contact Me</Title>
                    <Label htmlFor='name' >
                        <ImageWrapper>
                            <Image src={name} alt='name icon' />
                        </ImageWrapper>
                        <Input
                            type="text"
                            placeholder='Full Name'
                            name="user_name"
                            autoComplete="off"
                            required
                            data-testid='form-name'
                        />
                    </Label>

                    <Label htmlFor='email'>
                        <ImageWrapper>
                            <Image src={email} alt='name icon' />
                        </ImageWrapper>
                        <Input
                            type="email"
                            placeholder='example@email.com'
                            name="user_email"
                            pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"
                            autoComplete="off"
                            required
                            data-testid='form-email'
                        />
                    </Label>

                    <Label htmlFor='message'>
                        <ImageWrapper>
                            <Image src={message} alt='name icon' />
                        </ImageWrapper>
                        <TextArea
                            ref={textAreaRef}
                            placeholder='Write your message here'
                            onChange={(event) => setMessageInput(event?.target.value)}
                            rows={1}
                            name='message'
                            value={messageInput}
                            minLength={30}
                            required
                            data-testid='form-message'
                        />
                    </Label>

                    <SubmitButton
                        type="submit"
                        value='Submit'
                        data-testid='form-button'
                    />
                </FormContainer>
            )}
        </>
    )
}

export default ContactForm

Test: (I have a block commented because it wasn't working either, and I wanted to divide the problemas and work on each at a time)

import React from "react";
import "@testing-library/jest-dom/extend-expect";
import { screen, render, waitFor } from "@testing-library/react";
import ContactForm from '../ContactForm'
import user from '@testing-library/user-event';

describe("ContactForm", () => {
    const onSubmit = jest.fn();

    beforeEach(() => {
        onSubmit.mockClear();
        render(<ContactForm />)
    })

    it("onSubmit is called when all fields are filled and pass validations", async () => {
        const fullName = screen.getByTestId('form-name');
        user.type(fullName, 'Full Name')

        const email = screen.getByTestId('form-email');
        user.type(email, 'example@email.com')

        const message = screen.getByTestId('form-message');
        user.type(message, 'random message with more than 30 characters due to requirements')

        const button = screen.getByTestId('form-button');
        user.click(button);

        
        // await waitFor(() => {
        //     expect(onSubmit).toHaveBeenCalledWith({
        //         "email": "example@email.com",
        //         "message": "random message with more than 30 characters due to requirements",
        //         "name": "Full Name"
        //     });
        // });
        
        expect(onSubmit).toHaveBeenCalledTimes(1);
    });
});

I was following this tutorial, and I think everything looks the same.

Error message:

    expect(jest.fn()).toHaveBeenCalledTimes(expected)

    Expected number of calls: 1
    Received number of calls: 0

      37 |         // });
      38 |
    > 39 |         expect(onSubmit).toHaveBeenCalledTimes(1);
         |                          ^
      40 |     });
      41 | });

      at Object.toHaveBeenCalledTimes (components/ContactForm/__tests__/ContactForm.test.tsx:39:26)

Am I testing the onSubmit call incorrectly?

As previously said, I was following a tutorial and tried the same thing. Somehow when the person ran its first test .toHaveBeenCalledWWith(1) was already working correctly...

I have been to other question like: Enzyme/Jest onSubmit not calling Submit Function Jest mock function not being called ... but still can't figure it out

Luis Couto
  • 23
  • 6

1 Answers1

0

There is an essential difference between your code and the example you follow. In the example, you follow the onSubmit function is passed to the component. In your case, the onSubmit function is inside your component. You can't mock the functions inside the component you test. Otherwise, there will have no point. You have 2 options: -move the sendMail function to a parent component and pass it to your component:

<ContactForm onSubmit={sendMail}>

-or you can mock the function emailjs.send that is inside your sendEmail. Use jest for that. Then you can make sure the function is called. You can also check that it is called with the correct arguments. I think option 2 is a little harder to setup but gives you a little more confidence about what is happening in your code. If you do that you can also test that <Thanks>Thank you for reaching out. I will get back to you as soon as possible : &#41;</Thanks> get displayed with:

const text = screen.queryByText(">Thank you for reaching out. I will get back to you as soon as possible :")
expect(text).notToBeNull();
Letincel
  • 197
  • 1
  • 8