Jest mock function is called. but the mock's state is not updated?

Viewed 2197

Im new to javascript, react and jest. I wanted to mock a function which is gonna be passed as a context value. Im able to pass the mock function and im able to see that the mock function is triggered but when I try to inspect the mock to assert the results. im getting error which is attached below.

This is my class to be tested:

class Login extends Component {
    constructor(props) {
        super(props);
        this.state = {
            authInProgress: true,
            authSuccess: false
        };
    }

    componentDidMount() {
        if (this.context.isAuthenticated) {
            this.setState({
                authInProgress: false,
                authSuccess: true
            });
        } else {
            isUserLoggedIn().then((response) => {
                this.context.logIn();
                this.setState({
                    authInProgress: false,
                    authSuccess: true
                });
            }).catch((err) => {
                console.log(err);
            });
        }
    }

    render() {
        if (this.state.authInProgress) {
            return <div>Rendering login</div>;
        } else if (this.state.authSuccess) {
            return <Redirect to={ROOT}/>;
        }
    }
}

Login.contextType = Context;

export default Login;

this is my test:

it("When user is logged In, then update the context and redirect to ROOT.", () => {
    const resp = {
        data: {
            responseCode: 600
        }
    };
    isUserLoggedIn.mockResolvedValue(resp);
    const mockLogIn = jest.fn(() => console.log("im hit"));

    act(() => {
        render(
            <MemoryRouter>
                <Context.Provider value={{isAuthenticated: false, logIn: mockLogIn}}>
                    <Login/>
                </Context.Provider>
            </MemoryRouter>
            , container);
    });
    expect(mockLogIn.mock.calls.length).toBe(1);
});

This is the test results:

 console.log src/__tests__/auth/components/Login.test.jsx:62
    im hit


Error: expect(received).toBe(expected) // Object.is equality

Expected: 1
Received: 0
<Click to see difference>

I see that the mock function is triggered. but the mock's state is not updated. what am I doing wrong here?

Is it something to do with the scopes? I tried calling the mock function outside of the act block and that state is updated to the mock. when the same call happens inside the block, its not working.

1 Answers

Well the async was the problem here. I started using the awesome react-testing-library and added waits for my tests. then it worked as expected.

Now my test looks like this,

it("When the user's session is still active (auth tokens are valid), then refresh the tokens and the user is redirected to root.", async () => {
    const resp = {
        data: {
            responseCode: 600
        }
    };
    isUserLoggedIn.mockResolvedValue(resp);
    refreshAuthData.mockImplementation();
    const mockLogin = jest.fn();

    const {history} = renderWithContextAndRouter(
        <Login/>, {
            route: "/login",
            context: {
                isAuthenticated: false,
                logIn: mockLogin
            }
        }
    );
    await waitFor(() => {
        expect(history.location.pathname).toBe("/");
        expect(mockLogin.mock.calls.length).toBe(1);
    });
});

renderWithContextAndRouter is a HOC that injects my context and routes. and my actual test doesn't even have this verification as those are just the implementation details. this is just to help some fellow beginners :)

Related