React Test doesnt find element by text after state change

3k views Asked by At

I have an LoginForm component which accepts a login callback and renders a login form. When login returns a rejected promise the message is displayed in the component. This is the behavior I want to test.

Im using create-react-app environment with jest, enzyme and @testing-library/react.

I have manually tested the component in UI (Browser) and ensured it works and the message is displayed but the test is not working and the last assertion fails:

TestingLibraryElementError: Unable to find an element with the text: There was an error. 
This could be because the text is broken up by multiple elements. 
In this case, you can provide a function for your text matcher to make your matcher more flexible.

I have checked the message when rendered in Browser and it is present as literal "There was an error" without any elements between. Only wrapped by styled component. I cannot get the test to work can anyone help?

My test is the following:

    it("should display error text in login form when login fails", async () => {
        const errorText = "There was an error";
        const login = jest.fn(() => {
            return Promise.reject(errorText);
        });

        const result = render(<LoginForm login={login} />);


        const form = result.container.querySelector("form");
        const email = await result.findByLabelText("Email");
        const password = await result.findByLabelText("Password");

        fireEvent.change(email, {target: {name: "email", value: "1"}});
        fireEvent.change(password, {target: {name: "password", value: "1"}});

        expect(form).toBeDefined();

        fireEvent.submit(form!, {});

        expect(login).toBeCalledTimes(1);
 
        // This assertion fails
        expect(result.getByText(errorText)).toBeInTheDocument();
    });

My components render is the following:

render() {
        const {error, email, password} = this.state;

        return (
            <Form noValidate onSubmit={this.onSubmit}>
                <InputWrapper>
                    <Label htmlFor="email">Email</Label>
                    <InputEmail id="email" name="email" value={email} onChange={this.onChange}/>
                </InputWrapper>

                <InputWrapper>
                    <Label htmlFor="password">Password</Label>
                    <InputPassword id="password" name="password" value={password} onChange={this.onChange}/>
                </InputWrapper>

                // LoginError is a styled-component
                {error && (<LoginError>{error}</LoginError>)}

                {this.props.children}

                <Button>Login</Button>
            </Form>
        );


    }
1

There are 1 answers

2
heyitsvajid On BEST ANSWER

Try using wait or waitFor methods after fireEvent.submit(form!, {}); to wait for promised to resolve and re-rendering happens.

Ref: testing-library.com/docs/dom-testing-library/api-async#waitfor