Got Received number of calls: 0 error for login functionality

Viewed 400

I am writing unit test case for login.

I am unsure about how to test handle submit as it contains one of the service call in the form of getToken() method, it would be greate if someone can guide me through how to handle this situation.

export const getToken = (credentials) => {
  const token = 'abccss';
  if (
    credentials.username === 'test@test.com' &&
    credentials.password === '123'
  ) {
    return token;
  } else {
    return null;
  }
};

The above code fetches user name and password and sends it to login in handleSubmit() function

//all imports(loginservice,auth etc etc)
import './Login.scss';




const Login = () => {
  const [email, setEmail] = useState('');
  const [pwd, setPwd] = useState('');
  const authCon = useContext(AuthContext);

  const handleSubmit = (e) => {
    e.preventDefault();
    const token = getToken({ username: email, password: pwd });
    if (token) {
      authCon.login(token);
      window.location.href = '/dashboard';
    }
  };

  return (
    <div className="div-login">
      <div className="div-login-logo">
        <img src={logo} alt="Logo"></img>
      </div>
      <div>
        <form onSubmit={handleSubmit}>
          <input
            className="credentials-input"
            type="email"
            value={email}
            placeholder="Email Address"
            required
            onChange={(e) => setEmail(e.target.value)}
          />
          <input
            className="credentials-input"
            type="password"
            value={pwd}
            placeholder="Password"
            required
            onChange={(e) => setPwd(e.target.value)}
          />
          <button className="login-button" type="submit">
            Log In
          </button>
        </form>
      </div>
    </div>
  );
};

export default Login;



Test Code

test('Submit shoud work successfully', () => {
  const mockLogin = jest.fn();
  const { getByRole } = render(<Login handleSubmit={mockLogin} />);
  const login_button = getByRole('button');
  fireEvent.submit(login_button);
  expect(mockLogin).toHaveBeenCalledTimes(1);
});


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

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

As I am new to React, help will be appreciated.

1 Answers

The actual issue is handleSubmit is not a props of Login component.

Also you can't test the internal methods of a component using React testing Library, you have to move the handleSubmit method to either parent component or a common file and pass it to the login component or import it so that you can mock the method and perform the test.

Move the getToken and handleSubmit to a common file like below,

common.ts

export const getToken = (credentials:any) => {
    const token = 'abccss';
    if (
      credentials.username === 'test@test.com' &&
      credentials.password === '123'
    ) {
      return token;
    } else {
      return null;
    }
  };

  export const handleSubmit = (e:any, email:string, pwd: string) => {
    e.preventDefault();
    const token = getToken({ username: email, password: pwd });
    if (token) {
      // authCon.login(token);
      window.location.href = '/dashboard';
    }
  };

Modify Login.ts as like below ( see below handleSubmit is not internal and its imported from common.ts file so we that we can mock it)

import React, { useContext, useState } from 'react';
import { getToken, handleSubmit } from './common';

const Login = () => {
  const [email, setEmail] = useState('');
  const [pwd, setPwd] = useState('');
  // const authCon = useContext(AuthContext);

  return (
    <div className="div-login">
      <div className="div-login-logo">
        {/* <img src={logo} alt="Logo"></img> */}
      </div>
      <div>
        <form onSubmit={(e) => handleSubmit(e, email, pwd)}>
          <input
            className="credentials-input"
            type="email"
            value={email}
            placeholder="Email Address"
            required
            onChange={(e) => setEmail(e.target.value)}
          />
          <input
            className="credentials-input"
            type="password"
            value={pwd}
            placeholder="Password"
            required
            onChange={(e) => setPwd(e.target.value)}
          />
          <button className="login-button" type="submit">
            Log In
          </button>
        </form>
      </div>
    </div>
  );
};

export default Login;

And finally Login.test.tsx shown below


import { fireEvent, render, screen } from '@testing-library/react';
import Login from './Login';
import * as CommonModule from './common';

jest.mock('./common');

test('Submit shoud work successfully', () => {
    const mockLogin = jest.spyOn(CommonModule,'handleSubmit').mockImplementation();
    const { getByRole } = render(<Login />);
    const login_button = getByRole('button');
    fireEvent.submit(login_button);
    expect(mockLogin).toHaveBeenCalledTimes(1);
  });

Test Result : enter image description here

Related