How to mock firestore query with mocha and sinon? - node.js

W.r.t. How to mock firestore with mocha how do I mock the following firestore query using sinon?
import * as admin from "firebase-admin";
const db: FirebaseFirestore.Firestore = admin.firestore();
const storeSnapshot: = await db
.doc(`/Client/${clientId}/Store/${storeId}`)
.get();
I tried:
import * as _sinon from 'sinon';
it('Query Client collection not empty test', async () => {
const clientStoreDocStub = _sinon.stub(db, "doc");
clientStoreDocStub.withArgs("/Client/123/Store/789").resolves({
id: "789",
settings: [ {setting1: "Setting1-value", setting2: "Setting2-value"}, {setting1: "Setting3-value", setting2: "Setting4-value"}]
});
clientStoreDocStub.withArgs("/Client/456/Store/012").resolves({
id: "012",
settings: [ {setting1: "Setting5-value", setting2: "Setting6-value"}, {setting1: "Setting7-value", setting2: "Setting8-value"}]
});
const storeSnapshot: FirebaseFirestore.DocumentSnapshot = await db
.doc("/Client/123/Store/789")
.get();
const store = storeSnapshot.data();
});
but get the following error:
1) Mock firebase firestore Tests
Query Client collection not empty test:
TypeError: dbInit_1.db.doc(...).get is not a function

import * as _chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
import * as admin from "firebase-admin";
import * as _sinon from 'sinon';
_chai.use(chaiAsPromised);
var expect = _chai.expect;
const db: FirebaseFirestore.Firestore = admin.firestore();
describe("Test with mock firestore", () => {
var docRefStub;
beforeEach(() => { docRefStub = _sinon.stub(db, "doc");});
afterEach(() => {db.doc.restore();});
it("Test should pass with valid request params", async () => {
const expectedString = "Hello World!!!";
const testCollection = {
"/Client/123/Store/789": {
data: 1,
moreData: "Hello World!!!"
}
}
const setSpy = _sinon.spy();
docRefStub.callsFake(fakeFsDoc(testCollection, setSpy));
await callAFunction("123", "789");
expect(setSpy.called).to.be.true;
expect(setSpy.getCall(0).args[0].data).to.not.be.null;
expect(setSpy.getCall(0).args[0].moreData).to.deep.equal(expectedString);
}
});
export function fakeFsDoc(database, setSpy = null) {
return docId => {
const data = database[docId] ?? undefined;
return {
get: async () => ({
data: () => data
}),
set: setSpy
}
}
}

Related

Sinon Stub on MongoDB FindById

I have an endpoint like this:
Router.ts
router.get('/endpoint', async (req: Request, res: Response, next: NextFunction) => {
const myId = req.params.myId;
const data = await getData(myId);
});
controller.ts
export async function getData(myId: string): Promise<ICollectionDocument> {
return myModel.findById(myId).lean(); // pay attention to .lean()
}
It is working as expected, but when I try to write a test for this, I get:
.findById(...).lean is not a function",
Test
import * as request from 'supertest';
import * as sinon from 'sinon';
import * as chai from 'chai';
import * as express from 'express';
import * as applicationSetup from '../src/app'
import * as db from '../src/db';
import { User } from ''../src/models/user;
describe('Request Handler', () => {
let UserStub: sinon.stub;
let app: express.Application;
before(async () => {
UserStub = sinon.stub(User, 'findOne');
app = await applicationSetup.init();
await db.init();
});
it('Should do something', async() => {
// Also tried with and without this piece of code
UserStub.returns({
exec: sinon.stub().resolves(),
});
const resp = await request(app)
.get('/endpoint')
.send()
resp.status.should.be.equal(200);
})
});

How to use UseEffect for Custom React hook?

Hello I have custom hook
code is like below
import * as React from 'react'
export const myCustomHook = (props?: boolean) => {
const [value, setValue] = React.useState([]);
React.useEffect(() => {
return (async (p1) => {
// ....
setValue(someValues)
})
}, [])
const myFun = async (prop1) => {
// ... some operations
return {id: id}
}
return { myFun, value }
}
I am using the above like this
const { value, myFun } = myCustomHook();
const foofun = async (pp) => {
const myfunRes = await myFun(prop1);
}
Now I want to put myFun in useEffect
Please help me with this.

Tests haphazardly fail when using graphql-request and MSW

I am trying to set up tests to test a Remix loader and noticed that the request function from graphql-request haphazardly fails when using MSW. If I replace this and use a simple fetch for the requests the tests pass.
Is there any configuration I need to change? I have created a sample repo that demonstrates the bug. The bug gets worse the more tests you have that are using the same mocked request.
Sample repo: https://github.com/charklewis/sb9or3
Here is a summary of the code I am using:
//modules/database.server
import { GraphQLClient } from "graphql-request";
const client = new GraphQLClient("http://some-graphql-api.com/api/graphql", {});
export const fetchQuery = async (query: any, variables: any) => {
try {
const response = await client.request(query, variables || {});
return response;
} catch (error) {
return {};
}
};
//routes/index
import type { LoaderFunction } from "remix";
import { json } from "remix";
import { gql } from "graphql-request";
import { fetchQuery } from "~/modules/database.server";
export const loader: LoaderFunction = async () => {
const query = gql`
query MyQuery {
demoQuery {
value
}
}
`;
const response = await fetchQuery(query, {});
return json({ value: response.demoQuery.value });
};
//routes/__tests__/index
import { graphql } from "msw";
import { setupServer } from "msw/node";
import { loader } from "~/routes/index";
const createServer = (handlers: any[] = []) => {
const server = setupServer(...handlers);
beforeAll(() => server.listen({ onUnhandledRequest: "bypass" }));
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
return server;
};
const createDemoQueryHandler = ({ value = true } = {}) => {
return graphql.query("MyQuery", (req, res, ctx) => {
return res(ctx.data({ demoQuery: { value } }));
});
};
createServer([createDemoQueryHandler()]);
test("the loader returns data (round 1)", async () => {
const response = await loader({
request: new Request("/", { method: "GET" }),
params: {},
context: {},
});
const data = await response.json();
expect(data.value).toBe(true);
});
My vitest configuration is:
/// <reference types="vitest" />
/// <reference types="vite/client" />
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
plugins: [react(), tsconfigPaths()],
test: {
globals: true,
environment: "jsdom",
setupFiles: "./app/test-utils.ts",
testTimeout: 20000
}
});

Testing multiple routes causes Jest mocked function to be undefined

I would like to know the best way to test multiple routes in expressJS with jest.
My current problem is when I try testing multiple routes that uses same mocked function, the last route throws an undefined error.
Here's the context in code.
app.ts
import * as express from "express";
import controllerOne from "./controllers/one";
import controllerTwo from "./controllers/two";
const app = express();
app.use("/one", controllerOne);
app.use("/two", controllerTwo);
export default app;
controllers/one.ts
import getDbConnection from "../db";
import * as express from "express";
const router = express.Router();
const db = getDbConnection();
router.get("/", async (_, res) => {
const sql = "SELECT * from table";
const result = await db.query(sql);
res.status(200).json(result);
});
export default router;
controllers/two.ts
import getDbConnection from "../db";
import * as express from "express";
const router = express.Router();
const db = getDbConnection();
router.get("/", async (_, res) => {
const sql = "SELECT * from table";
const result = await db.query(sql);
res.status(200).json(result);
});
export default router;
tests/one.ts
import * as request from "supertest";
import { mocked } from "ts-jest/utils";
import db from "../db";
jest.mock("../db");
const mockedDB = mocked(db);
const data = ["data"];
describe("Controller One", () => {
afterAll(() => {
jest.restoreAllMocks();
jest.resetModules();
});
beforeEach(() => {
const mockedQueryFn = {
query: jest.fn().mockResolvedValueOnce(data),
};
mockedDB.mockReturnValueOnce(mockedQueryFn);
});
it("should retrieve one", async () => {
const mod = require("../src/app");
const app = (mod as any).default;
await request(app)
.get("/one")
.expect(200)
.expect(function (res) {
expect(res.body).toEqual(data);
});
});
});
tests/two.ts
import * as request from "supertest";
import { mocked } from "ts-jest/utils";
import db from "../db";
jest.mock("../db");
const mockedDB = mocked(db);
const data = ["data"];
describe("Controller One", () => {
afterAll(() => {
jest.restoreAllMocks();
jest.resetModules();
});
beforeEach(() => {
const mockedQueryFn = {
query: jest.fn().mockResolvedValueOnce(data),
};
mockedDB.mockReturnValueOnce(mockedQueryFn);
});
it("should retrieve one", async () => {
const mod = require("../src/app");
const app = (mod as any).default;
await request(app)
.get("/two")
.expect(200)
.expect(function (res) {
expect(res.body).toEqual(data);
});
});
});
Now my problem is if I run the test, test/one.ts would pass test/two.ts would fail with the error TypeError: Cannot read property 'query' of undefined referencing this line const result = await db.query(sql)
When I switch up the controller imports
import controllerTwo from "./controllers/two";
import controllerOne from "./controllers/one";
then test/two.ts passes and test/one.ts fails with same error.
I would like to also mention that with/without reseting jest mock, I get same result.
It may have to do with the fact that you’re not calling done at the end of your test. Inside the expect part of the test, call done(). You also need to change the callback so that it like this:
it("should retrieve one", async (done) => {

How to mock Prisma (via Proxy) in Jest 27

Our Prisma setup is as follows:
// server/database/prisma.ts
import { Prisma } from 'database/generated/prisma-client';
const client = new Prisma({
endpoint: PRISMA_ENDPOINT,
secret: PRISMA_SECRET,
debug: PRISMA_DEBUG,
});
// Add a proxy 'middleware' to the Prisma client to record query execution time
const prismaProxy = new Proxy(client, {
get(client, endpoint) {
const endTimer = metrics.prisma_call_duration_seconds.startTimer({ endpoint });
return function (...args) {
const result: Prisma = client[endpoint](...args);
endTimer();
return result;
};
},
});
export const prisma = prismaProxy;
I then have a utility that uses prisma that I would like to test:
// utils.ts
import { prisma } from 'database/prisma';
export const myFunc = async () => {
const result = await prisma.items();
if (items && items.length > 0) {
return true;
}
return false;
};
How do I mock prisma in a test? In Jest 26, this worked:
// utils.test.ts
jest.mock('server/database/prisma');
import { prisma } from 'server/database/prisma';
import { myFunc } from 'server/utils';
describe.only('my test', () => {
beforeAll(() => {
prisma.items.mockImplementation(() =>
Promise.resolve([
{
foo: 'bar',
},
])
);
});
test('it works', async () => {
const items = await myFunc();
expect(items).toBeTruthy();
});
});
This no longer works in Jest 27 it seems. Having made no changes except upgrading Jest from v26 -> v27 the mocks no longer seem to take hold.
What is the proper way to mock prisma here?

Resources