mikemaccana
mikemaccana

Reputation: 123118

ES6 imports and 'is not a constructor' in Jest.mock

Similar to Jest TypeError: is not a constructor in Jest.mock, except I am using ES6 imports - and the answer given to that question is not working on my situation.

Following the Jest .mock() documentation I am attempting to mock the constructor Client from the pg module.

I have a constructor, Client, imported from an ES6 module called pg. Instances of Client should have a query method.

import { Client } from "pg";
new Client({ connectionString: 'postgresql://postgres:postgres@localhost:5432/database' });

export async function doThing(client): Promise<string[]> {
  var first = await client.query('wooo')
  var second = await client.query('wooo')
  return [first, second]
}

Here's my __tests__/test.ts

const log = console.log.bind(console)

jest.mock("pg", () => {
  return {
    query: jest
      .fn()
      .mockReturnValueOnce('one')
      .mockReturnValueOnce('two'),
  };
});

import { Client } from "pg";
import { doThing } from "../index";

it("works", async () => {
  let client = new Client({});
  var result = await doThing(client);
  expect(result).toBe(['one', 'two'])
});

This is similar to the answer given in Jest TypeError: is not a constructor in Jest.mock, but it's failing here.

The code, just:

const mockDbClient = new Client({ connectionString: env.DATABASE_URL });

fails with:

TypeError: pg_1.Client is not a constructor

I note the docs mention __esModule: true is required when using default exports, but Client is not a default export from pg (I've checked).

How can I make the constructor work properly?

Some additional notes after getting an answer

Here's a slightly longer-form version of the answer, with comments about what's happening on each line - I hope people reading this find it useful!

jest.mock("pg", () => {
  // Return the fake constructor function we are importing
  return {
    Client: jest.fn().mockImplementation(() => {
      // The consturctor function returns various fake methods
      return {
        query: jest.fn()
          .mockReturnValueOnce(firstResponse)
          .mockReturnValueOnce(secondResponse),
        connect: jest.fn()
      }
    })
  }
})

Upvotes: 6

Views: 9388

Answers (1)

Jacob
Jacob

Reputation: 78850

When you mock the module, it needs to have the same shape as the actual module. Change:

jest.mock("pg", () => {
  return {
    query: jest
      .fn()
      .mockReturnValueOnce('one')
      .mockReturnValueOnce('two'),
  };
});

...to:

jest.mock("pg", () => ({
  Client: jest.fn().mockImplementation(() => ({
    query: jest.fn()
      .mockReturnValueOnce('one')
      .mockReturnValueOnce('two')
  }))
}));

Upvotes: 14

Related Questions