1
votes

I am writing a mock test case with jest in typescript & trying to mock API calls with supertest, but unable to get a mocked response in return, as I'm using Axios on the login function & even tried to mock the Axios call but got no luck.

Here's my code :

auth.controller.ts

import { AxiosService } from "helpers";

export class AuthController {
    constructor() {
       ...
      // Some logic is written here
      this.init()
    }

    public init() {
       // prepared an route for login
       router.post('/api/auth/login', this.login);
    }
  
    login = async function (req: Request, res: Response): Promise<void> {
        // Preparing config for axios call with some logic
        ...

        // created a service for Axios call to some third party.
        AxiosService.call(req, res, config, "login");
    }
  }
    
    

auth.test.ts

import { AuthController } from "../../modules/auth/auth.controller";
jest.mock("../../modules/auth/auth.controller");

beforeAll(async () => {
  const auth = new AuthController();
  mockLogin = jest.spyOn(auth, "login");
});

afterAll(async () => {
  server.stop();
});

test("should give login response", async () => {
    mockLogin.mockImplementation(() => {
      return Promise.resolve({ Success: true, body: "Login" });
    });

      const response = await request(server.app)
        .post("/api/auth/login")
        .send(requestBody)
        .expect(200);

      response.body // Getting the server response instead of mocked one
})
    
    

Tried with this code too, but no luck over there :

jest.mock('../../modules/auth/auth.controller', () => {
  return { 
    AuthController: jest.fn().mockImplementation(() => {
          return {
              login: jest.fn()
          }   
      })
  }
})
            
    

Here's my AxiosService class looks like :

export class AxiosService {

  public static async call(...):Promise<void> { 
    try { 
       const { data } = await axios(...);

       res.status(200).json(data);
    } catch(err) {
       res.status(400).send(err);
     }
  
  }

}

Tried to mock AxiosService call method with the following line :

jest.mock('../../helpers/AxiosService', () => {
  return jest.fn().mockImplementation(() => {
    return { call: () => { return {success:true, data:'mock'}} }
  })
})

However, after mocking the Axios call, I'm getting Async callback was not invoked within the 10000 (which I've given) ms timeout specified by jest.setTimeout

Anyone can help that would be great for me, as I'm new to the mocking concept so maybe I'm missing something here.

Thanks in advance

1
It doesn't make sense to mock AuthController because it's the unit that you test. Mock other units like AxiosService.Estus Flask
@EstusFlask, Thank you for replying, I've tried it but it's not working as expected.Satish Joshi
What did not work? Any way, this is how it needs to be done, the question should be about that attempt and not mocking AuthController for its own test.Estus Flask
@EstusFlask, I mocked the call function of AxiosService, through jest.mock(...), but instead of giving any response it fails to complete the operation by giving “Async callback was not invoked within the 10000 (which I've given) ms timeout specified by jest.setTimeout”. Actually, I'm a bit new to this concept as well maybe I'm missing something here.Satish Joshi
Please, provide stackoverflow.com/help/mcve that can reproduce the problem. It's unknown what was wrong with this.Estus Flask

1 Answers

1
votes

A proper testing strategy that every unit but tested one needs to be mocked.

A timeout happens because Supertest waits for server response and there's none in case of mocked AxiosService, so it needs be mocked like:

...
return { call: (req, res) => { res.status(200).json({success:true, data:'mock'}); }

In this case the test can either mock controller class with mocked service class, or test them together with mocked Axios. Since AuthController doesn't do much alone (AuthController and AxiosService are abstractions over simple Express handler), it can be:

jest.mock('axios', () => jest.fn()) // at top level
...
axios.mockResolvedValue({ data: ... });
const response = await request(server.app)