Jest: mocking a method from a better-sqlite3 using Typescript

17 Views Asked by At

I'm trying to test a function that is calling a resolved method from better-sqlite3 but it always tells me it's trying to read undefined.

These are my files.

./src/db.ts

import Database from "better-sqlite3";

//Create database
export const db = new Database("polychess.db");

./src/controllers/db-controllers.ts

import { db } from "../db";

const getAllPlayersDb = db.prepare("SELECT * FROM player");

export async function getDbStatus() {
  const status = await db.open;
  return {
    message: `Database is ${status ? "online" : "offline"}`,
    isOnline: status,
  };
}

export async function getAllPlayersFromDB() {
  return await getAllPlayersDb.all();
}

./src/__ test __/controllers/db-controllers.spec.ts

import {
  getDbStatus,
  getAllPlayersFromDB,
} from "../../controllers";

jest.mock("../../db");

const fakeTables = { players:[/*some players here*/] };

describe("Database controllers tests: ", () => {
  afterAll(() => {
    jest.resetAllMocks();
  });

  describe("Test getDbStatus()", () => {
    it("Should return online status if DB is online", async () => {
      db.open = true;
      const dbStatus = await getDbStatus();
      expect(dbStatus).toEqual({
        message: `Database is online`,
        isOnline: true,
      });
    });

    it("Should return offline status if DB is offline", async () => {
      db.open = false;
      const dbStatus = await getDbStatus();
      expect(dbStatus).toEqual({
        message: `Database is offline`,
        isOnline: false,
      });
    });
  });

  describe("Test getAllPlayersFromDB()", () => {
    it("Should return all players", async () => {
      db.prepare = jest.fn().mockImplementationOnce(() => {
        return {
          all: jest.fn(() => {
            return fakeTables.players;
          }),
        };
      });
      expect(await getAllPlayersFromDB()).toEqual(fakeTables.players);
    });
  });
});

I tried different things like using requireActual but that breaks my first two tests. Also tried specifying "prepare" when mocking but I need to change its implementation for other functions I have planned...

It returns TypeError: Cannot read properties of undefined (reading 'all')

When I change to use "require actual" my getDbStatus() returns TypeError: Cannot set property open of #<Database> which has only a getter

When requiring actual I tried using jest.spyOn(db, "open", "get").mockReturnValueOnce(true); but it returns Property 'open' is not declared configurable

Also tried

jest.mock("../../db", () => {
  const originalDb =
    jest.createMockFromModule<typeof import("../../db")>("../../db");
  return {
    db: {
      open: false,
      prepare: jest.fn(() => {
        return { all: jest.fn(() => {return fakeTables.players;}) };
      }),
    },
  };
});

But it changes implementation for all and I need different ones depending on my queries.

0

There are 0 best solutions below