0

I have a following .ts module

import client from './client'; export default class DefaultRequest implements IRequest { make(req: Request): Promise<Response> { return new Promise<Response>((resolve, reject) => { client.post(req, (error: Error | null, res: Response) => { if (error) { return reject(error); } else { return resolve(res); } }); }); } } 

I am trying to write a unit test for this class with ts-jest, so that client is mocked (and returns some valid Response).

Here is how I am doing it:

import {mocked} from 'ts-jest/utils'; import client from './client'; import DefaultRequest from './request' const mockedClient = mocked(client, true); const testRequest = new DefaultRequest(); jest.mock('./client', () => { return { RestClient: jest.fn().mockImplementation(() => { return { post: () => {return someValidResponse();}, }; }) }; }); describe('My Tests', () => { it('Unit Test 1', async () => { let res: Response = await testRequest.make(buildReq()); }); }); 

But the mockedClient is still not mocked. This is what ./client.ts looks like:

import { RestClient } from '@rest/client'; export default new RestClient(); 

Can the internal client module that class DefaultRequest uses be mocked in this manner?

EDIT: I also tried jest.spyOn

const spiedMethod= jest.spyOn(client, 'post'); const call: Request = new Request(); const response: Response = await call.make(buildRequest()); expect(spiedReleaseMethod).toHaveBeenCalled(); expect(response.getResponsecode()).toBe(200); 

And it still calls the original method and not the spied method.

1 Answer 1

1

You are testing the request.ts module that depends on the client.ts module. So you need to mock the client.ts module and its post method rather than the @rest/client package.

E.g.

request.ts:

import client from './client'; interface IRequest { make(req: Request): Promise<Response>; } export default class DefaultRequest implements IRequest { make(req: Request): Promise<Response> { return new Promise<Response>((resolve, reject) => { client.post(req, (error: Error | null, res: Response) => { if (error) { return reject(error); } else { return resolve(res); } }); }); } } 

client.ts: (No matter what package implementation client uses, as long as the interfaces exposed by the module are the same)

export default { post(req, callback) { console.log('real implementation'); }, }; 

request.test.ts:

import { mocked } from 'ts-jest/utils'; import client from './client'; import DefaultRequest from './request'; jest.mock('./client'); const mockedClient = mocked(client); describe('68115300', () => { afterAll(() => { jest.resetAllMocks(); }); it('should pass', () => { mockedClient.post.mockImplementationOnce((req, callback) => { callback(null, 'mocked response'); }); const testRequest = new DefaultRequest(); testRequest.make(('req' as unknown) as Request); expect(mockedClient.post).toBeCalledWith('req', expect.any(Function)); }); }); 

test result:

 PASS examples/68115300/request.test.ts (12.448 s) 68115300 ✓ should pass (3 ms) ------------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ------------|---------|----------|---------|---------|------------------- All files | 77.78 | 50 | 75 | 77.78 | client.ts | 50 | 100 | 0 | 50 | 3 request.ts | 85.71 | 50 | 100 | 85.71 | 12 ------------|---------|----------|---------|---------|------------------- Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 14.61 s 
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks this worked. It looks freakishly similar to my initial implementation, just that you used jest.method.mockImplementation and I used jest.fn
What happens here post method in client.ts has a return value other than void?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.