10

I am having a module called map-creation.service.ts:

export const createMap = (asyncJobId: string, resourceUrl: string, s3DestFolder: string) => {

};

Which is used in my endpoint:

import {createMap} from './services/map-creation.service';

const router = express.Router();
const routePrefix = config.get('server.routePrefix');

router.post(`/${routePrefix}`, validate(validation), (req: express.Request, res: express.Response) => {
    createMap(req.body.asyncJobId, req.body.resourceUrl, req.body.s3DestFolder);
    res.status(201).json({message: 'Created'});
});

When I am trying to mock this module in my tests, and want to test if it was called when requesting the endpoint, I still get: Expected mock function to have been called with: ... But it was not called.

jest.mock('../../../src/services/map-creation.service');
import {createMap} from '../../../src/services/map-creation.service';

And here's my test:

it('should call the map-creation service', () => {
        return request(server)
            .post(`/${routePrefix}`)
            .send({
                asyncJobId,
                resourceUrl,
                s3DestFolder
            })
            .then(res => {
                expect(createMap).toBeCalledWith(asyncJobId, resourceUrl, s3DestFolder);
            });
    });

If I am mocking the method like this:

import {createMap} from '../../../src/services/map-creation.service';
createMap = jest.fn();

The test passes, but tslint is complaining: Cannot assign to 'createMap' because it is not a variable. So what would be the proper way to mock this method in TypeScript and Jest?

4
  • I believe you have to call jest.mock giving it same param as when importing. Thus if using import {createMap} from './services/map-creation.service'; Then mock it as jest.mock('./services/map-creation.service');, which forces you to locate your test in the same directory with the module (which is common practice). Commented Apr 18, 2017 at 13:18
  • Another option is to configure TS to use non-relative module imports link (idea behind that is that jest does not actually understand that these two paths you use for import and mock, are the same) Commented Apr 18, 2017 at 13:23
  • Any solutions besides using DI? Commented Mar 20, 2018 at 9:43
  • ts-mock-imports Is a library I created that allows you to mock out a class import with typescript. Commented May 28, 2018 at 10:29

2 Answers 2

4

So what would be the proper way to mock this method in TypeScript and Jest?

Use dependency injection to inject the mock vs. real version of functions as needed.

Recommended framework for DI: http://inversify.io/

but tslint is complaining: Cannot assign to 'createMap' because it is not a variable

Please don't do this. Imports should be considered immutable. You will get a compile time TypeScript error for this as well and when module support becomes native you will get a runtime error.

Sign up to request clarification or add additional context in comments.

1 Comment

I was running into a similar problem and was able to use jest's spyOn to mock the module while still being able to track calls to, and mock the implementation of, functions exported from the module. See jestjs.io/docs/en/jest-object#jestspyonobject-methodname for documentation. The test code ended up looking something like: ``` import * as ModuleName from 'path/to/module'; ... methodSpy = jest.spyOn(ModuleName, 'methodName').mockImplementation(jest.fn()); ... expect(methodSpy).toBeCalled(); ```
4

The issue with dependency injection is that it requires you to restructure all of your existing solution in order for your code to behave appropriately under test. It also ignores the fact that ES6 already has an import/export system that can be hijacked.

ts-mock-imports is a library (which I created) that is designed to handle mocking imports without dependency injection.

In your test file:

import * as createMapModule from '../../../src/services/map-creation.service';
import { ImportMock } from 'ts-mock-imports';

const mockHandler = ImportMock.mockOther(createMapModule, 'createMap', jest.fn());

<-- Test Code Here --->

// Ensure you restore the mock once the tests are complete
mockHandler.restore()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.