简体   繁体   中英

Mock imported class in typescript with jest

I am trying to use jest to mock an imported class inside a typescript class, the following code is used for the main program(I removed some code from inside the functions but it shoud still be clear what I am trying to do)

import * as SocketIO from "socket.io";

import {AuthenticatedDao} from "../../dao/authenticated.dao";

export default class AuthenticationService {
    private readonly _authenticatedDao: AuthenticatedDao = AuthenticatedDao.Instance;
    private readonly _io;

    constructor(socketIo: SocketIO.Server) {
        this._io = socketIo;
    }

    public authenticateUser(username: string, password: string, clientSocketId: string): void {
        this._authenticatedDao.authenticateUser(username, password).then((authenticatedUser) => {

        }).catch(rejected => {

        });
    }
}


import {createServer, Server} from 'http';
import * as express from 'express';
import * as socketIo from 'socket.io';
import {LogincredentialsDto} from "./models/dto/logincredentials.dto";
import {config} from './config/config';
import AuthenticationService from "./services/implementation/authentication.service";
import {Logger} from "./helperclasses/logger";
import {format} from "util";

export class ClassA {
    private readonly _configPort = config.socketServerPort;

    private readonly _logger: Logger = Logger.Instance;
    private _app: express.Application;
    private _server: Server;
    private _io: socketIo.Server;
    private _socketServerPort: string | number;
    private _authenticationService: AuthenticationService;


    constructor() {
        this.configure();
        this.socketListener();
    }

    private configure(): void {
        this._app = express();

        //this._server = createServer(config.sslCredentials, this._app);
        this._server = createServer(this._app);

        this._socketServerPort = process.env.PORT || this._configPort;
        this._io = socketIo(this._server);

        this._server.listen(this._socketServerPort, () => {
            this._logger.log(format('Server is running on port: %s', this._socketServerPort));
        });

        this._authenticationService = new AuthenticationService(this._io);
    }


    private socketListener(): void {
        this._io.on('connection', (client) => {
                client.on('authenticate', (loginCreds: LogincredentialsDto) => {
                    console.log(loginCreds.username, loginCreds.password, client.id);
                    this._authenticationService.authenticateUser(loginCreds.username, loginCreds.password, client.id);
                });
            }
        );
    }
}

I am trying to mock the function "authenticateUser" in "AuthenticationService", instead of calling the normal code I want to mock the promise. I tried using the examples provided in https://jestjs.io/docs/en/es6-class-mocks but when I try doing the following:

import AuthenticationService from '../src/services/implementation/authentication.service';
jest.mock('./services/implementation/authentication.service');

beforeEach(() => {
    AuthenticationService.mockClear();
});

it('test', () => {

    // mock.instances is available with automatic mocks:
    const authServerInstance = AuthenticationService.mock.instances[0];

I get this error: Error:(62, 31) TS2339: Property 'mock' does not exist on type 'typeof AuthenticationService'.

What am I doing wrong here? Should I be mocking the class/function differently since it's using promises?

Issue

The typing for AuthenticationService does not include the mock property so TypeScript throws an error.


Details

jest.mock creates an automatic mock of the module which "replaces the ES6 class with a mock constructor, and replaces all of its methods with mock functions that always return undefined ".

In this case the default export of authentication.service.ts is an ES6 class so it is replaced with a mock constructor.

The mock constructor has a mock property but TypeScript doesn't know about it and is still treating AuthenticationService as the original type.


Solution

Use jest.Mocked to let TypeScript know about the typing changes caused by jest.mock :

import * as original from './services/implementation/authentication.service';  // import module
jest.mock('./services/implementation/authentication.service');

const mocked = original as jest.Mocked<typeof original>;  // Let TypeScript know mocked is an auto-mock of the module
const AuthenticationService = mocked.default;  // AuthenticationService has correct TypeScript typing

beforeEach(() => {
  AuthenticationService.mockClear();
});

it('test', () => {

    // mock.instances is available with automatic mocks:
    const authServerInstance = AuthenticationService.mock.instances[0];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM