Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you mock imported functions in TypeScript using Jest?

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?

like image 214
Markus Török Avatar asked Apr 18 '17 13:04

Markus Török


2 Answers

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 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()
like image 74
EmandM Avatar answered Sep 24 '22 04:09

EmandM


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.

like image 40
basarat Avatar answered Sep 24 '22 04:09

basarat