8

Suppose I have an index.ts that will import Database.ts and run some queries. To test this index.ts file, I want to mock the Database.ts because I don't want to connect to any real database.

This is my index.ts:

import { connect } from './Database'

export async function runSomeQuery() {
  const connection = await connect()
  const result = await connection.query('SOME QUERY')
  return result
}

and here is the mock of database (__mocks__/Database.ts)

const mockConnection = {
  query: jest.fn()
}

export const connect = jest.fn(
  () => Promise.resolve(mockConnection)
)

export function __getMockConnection() {
  return mockConnection
}

you can see that I expose a __getMockConnection so that I can get the mockConnection in my tests (index.spec.ts) (this pattern is learnt from the official doc):

import { connect, __getMockConnection } from '../Database'
//                ^^^^ getting type error here 
import { runSomeQuery } from '../index'

jest.mock('../Database')

test('runSomeQuery', async () => {
  await runSomeQuery()
  const mockConnection = __getMockConnection()
  expect(connect).toBeCalled()
  expect(mockConnection.query).toBeCalledWith('SOME QUERY')
  expect(mockConnection.query).toBeCalledWith('SOME QUERY')
})

The test case does pass as expected, but I'm getting this TypeScript error

Module '"/project/path/Database"' has no exported member '__getMockConnection'. [2305]

TypeScript doesn't know that I'm importing Database from the mock. Also for this reason I have to disable the diagnostics of ts-jest which complains the same issue.

How can I solve this? Change the import path to '../__mocks__/Database' doesn't work.

Here is the repo: https://github.com/CodinCat/ts-jest-mock-issue

Open __tests__/index.spec.ts with an editor that supports TypeScript like VS Code and you will see the error.

skyboyer
  • 22,209
  • 7
  • 57
  • 64
CodinCat
  • 15,530
  • 5
  • 49
  • 60

2 Answers2

10

Since typescript is not aware of jest mocking, you will need to manually type cast whenever your mocks are different than your actual code:

import * as MockDatabase from "../__mocks__/Database";
import * as Database from "../Database";

import { runSomeQuery } from "../index";
jest.mock("../Database");

// Type cast since Database is automatically mocked by jest
const { connect, __getMockConnection } = Database as typeof MockDatabase;

test("runSomeQuery", async () => {
  await runSomeQuery();
  const mockConnection = __getMockConnection();
  expect(connect).toBeCalled();
  expect(mockConnection.query).toBeCalledWith("SOME QUERY");
});
lucascaro
  • 16,550
  • 4
  • 37
  • 47
  • If change the import to `../__mocks__/Database` then the database mock will not be used at all. `index.ts` will import the real `Database.ts` and both line 10 and 11 will fail. – CodinCat Nov 09 '18 at 09:16
  • 1
    @CodinCat I finally understand what you meant :) updated the answer which seems to work on my end, hope it helps! – lucascaro Nov 09 '18 at 19:52
  • @CodinCat have you tried this? does the answer make sense? – lucascaro Nov 11 '18 at 05:44
0

Update 29 Sept 2022:

The mocked function has been integrated into jest and is not available in ts-jest anymore.


Original answer:

Another option is to use ts-jest's mocked() helper. The helper will make sure you have access to the mock test methods. For details have a look at the post here: Import function from a Jest manual mock with Typescript

Tobi
  • 1,492
  • 1
  • 13
  • 20