Mock imported class in typescript with jest
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];
devran
Updated on June 11, 2022Comments
-
devran almost 2 years
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?
-
devran over 5 yearsThank you for your help, by using your code I figured out how to mock a function within a class, thanks for including the details as well, it makes it more clear now.
-
Mithir about 5 years@brian-lives-outdoors I tried this but for some reason typescript still looks at the Mocked instance as the actual type it is mocking... any ideas? (trying to mock an interface)
-
Chris Watts almost 5 yearsThis actually doesn't work for me because TypeScript is telling me I need to cast it to unknown first. i.e.
original as unknown as jest.Mocked<typeof original>
Does anyone know a way around this? -
rsan almost 5 yearsThis isn't working for me. AuthenticationService.mockClear(); produces -> property mockClear does not exist in bla bla. Inspecting the object it have mockClear, mock, etc. But the types are not known to typescript.
-
Stefan Frye about 4 yearsI had to replace
const AuthenticationService = mocked.default;
withconst AuthenticationService = mocked.AuthenticationService
, then it worked for me. I'm using ts-jest 25.2.1. -
Alexey Sh. almost 3 yearsTS2339: Property 'default' does not exist on type 'Mocked '.
-
Lee Goddard about 2 yearsProperty 'Mocked' does not exist on type 'typeof jest'. Did you mean 'mocked'?ts(2551)