I have a node module which exports a few classes, one of which is Client
, which I use to create a client (having a few APIs as methods).
I'm trying to test my module which uses this node module as a dependency using Jest. However, I've been unable to successfully mock the one method (say search()
) in the Client class.
Here is my spec for myModule
:
//index.spec.ts
import * as nock from 'nock';
import * as externalModule from 'node-module-name';
import { createClient } from './../../src/myModule';
describe(() => {
beforeAll(() => {
nock.disableNetConnect();
});
it('test search method in my module', () => {
jest.mock('node-module-name');
const mockedClient = <jest.Mock<externalModule.Client>>externalModule.Client;
const myClient = createClient({/*params*/}); //returns instance of Client class present in node module by executing Client() constructor
myClient.searchByName('abc'); //calls search API - I need to track calls to this API
expect(mockedClient).toHaveBeenCalled();
expect(mockedClient.prototype.search).toHaveBeenCalledWith('abc');
});
});
This, however, doesn't create a mock at all and triggers a nock error since the search API tries to connect to the url (given through params).
I've also tried mocking the Client class like the following. While successfully creating a mock for the Client class and also the search API (verified that search()
is also mocked through console logs), it gives me an error while I try to check if search()
has been called.
externalModule.Client = jest.fn(() => { return { search: jest.fn(() => Promise.resolve('some response')) } });
//creates the mock successfully, but not sure how to track calls to 'search' property
const client = myModule.createClient(/*params*/);
client.searchByName('abc');
expect(externalModule.Client).toHaveBeenCalled(); //Successful
expect(externalModule.Client.prototype.search).toHaveBeenCalled(); //returns error saying "jest.fn() value must be a mock function or spy, Received: undefined"
I'm not sure what I'm doing wrong. Thank you in advance.
Try moving jest.mock
to the top of file
//index.spec.ts
const search = jest.fn();
jest.mock('node-module-name', () => ({
Client: jest.fn(() => ({ search }))
}));
import * as nock from 'nock';
import * as externalModule from 'node-module-name';
import { createClient } from './../../src/myModule';
describe(() => {
beforeAll(() => {
nock.disableNetConnect();
});
it('test search method in my module', () => {
const myClient = createClient({/*params*/});
myClient.searchByName('abc');
expect(externalModule.Client).toHaveBeenCalled();
expect(search).toHaveBeenCalledWith('abc');
externalModule.Client.mockClear();
search.mockClear();
});
});
Create search
constant and track it.
const search = jest.fn();
externalModule.Client = jest.fn(() => ({ search }));
const client = myModule.createClient(/*params*/);
client.searchByName('abc');
expect(externalModule.Client).toHaveBeenCalled();
expect(search).toHaveBeenCalled();
Here is how I mocked it. I had to change naming and removing some code to avoid exposing original source.
jest.mock('../foo-client', () => {
return { FooClient: () => ({ post: mockPost }) }
})
Full code.
// foo-client.ts
export class FooClient {
constructor(private config: any)
post() {}
}
// foo-service.ts
import { FooClient } from './foo-client'
export class FooLabelService {
private client: FooClient
constructor() {
this.client = new FooClient()
}
createPost() {
return this.client.post()
}
}
// foo-service-test.ts
import { FooService } from '../foo-service'
const mockPost = jest.fn()
jest.mock('../foo-client', () => {
return { FooClient: () => ({ post: mockPost }) }
})
describe('FooService', () => {
let fooService: FooService
beforeEach(() => {
jest.resetAllMocks()
fooService = new FooService()
})
it('something should happened', () => {
mockPost.mockResolvedValue()
fooService.createPost()
})
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With