mocking admin.firestore() and admin.firestore.FieldValue.serverTimestamp() - unit-testing

I've been trying to mock
admin.firestore.FieldValue.serverTimestamp().
However once I've
mocked admin.firestore(), all the calls just hit that stub instead.
So the error runnning the test is... Trying to stub property 'serverTimestamp' of undefined
const admin = require("firebase-admin")
const test = require("firebase-functions-test")()
describe("Unit test", () => {
let allFunctions, adminFirestoreStub
beforeAll(() => {
adminFirestoreStub = sinon.stub(admin, "initializeApp")
allFunctions = require("../index")
})
describe("Main", () => {
it("Test", async () => {
const dbStub = sinon.stub()
const collStub = sinon.stub()
sinon.stub(admin, "firestore").get(() => dbStub)
dbStub.returns({
collection: collStub,
})
sinon.stub(admin.firestore.FieldValue, "serverTimestamp").returns(Date())
const wrapped = test.wrap(allFunctions.my_func)
await wrapped(data, context)
})
})
})

Thanks Doug, put a const to serverTimestamp() above the actual function and it worked.

Related

vitest failed to mock quasar

I am having vue3 app with vite and vitest and trying to mock the Quasar useQuasar composable which I am using in my custom Composable like:
// useLoginRequestBuilder.ts
import { makeUserAuthentication } from "#/main/factories"
import { useQuasar } from "quasar"
export function useLoginRequestBuilder() {
const $q = useQuasar()
async function login() {
try {
$q.loading.show()
const auth = makeUserAuthentication()
return await auth.signinRedirect()
} catch (e) {
console.log(e)
$q.loading.hide()
$q.notify({
color: "red-4",
textColor: "white",
icon: "o_warning",
message: "Login Failed!",
})
}
}
return {
login,
}
}
and I am trying to mock quasar in tests like:
// useLoginRequestBuilder.spec.ts
import { useLoginRequestBuilder } from "#/main/builders"
vi.mock("quasar", () => ({ // <--- this is not really mocking quasar
useQuasar: () => ({
loading: {
show: () => true,
hide: () => true,
},
}),
}))
const spyAuth = vi.fn(() => Promise.resolve(true))
vi.mock("#/main/factories", () => ({
makeUserAuthentication: () => ({
signinRedirect: () => spyAuth(),
}),
}))
describe("test useLoginRequestBuilder", () => {
test("should call signinRedirect", async () => {
const { login } = useLoginRequestBuilder()
const sut = await login()
expect(sut).toBe(true)
})
})
vi.mock("quasar"... is failing to mock quasar and I am getting below error. That means, it failed to mock and failed to get the $q.loading.... object.
TypeError: Cannot read properties of undefined (reading 'loading')
I understand that there is a separate testing lib for quasar, here but I think this is not really the case here.
Bordering on a necro-post, but I had a similar issue that the mocking factory wasn't creating the plugins being used in non-Vue components, and had to mock each call individually in the end.
Though I'd add it here for anyone else
vitest.mock("quasar", () => vi.fn()); // this doesn't mock out calls
// use individual mocks as below
import { Loading } from "quasar";
vi.spyOn(Loading, "show").mockImplementation(() => vi.fn());
vi.spyOn(Loading, "hide").mockImplementation(() => vi.fn());

Jest - mock function in 'child_process' package

I'm writing unit tests and which to mock the 'exec' method in package 'child_process'.
__mocks__/child_process.js
const child_process = jest.genMockFromModule('child_process');
child_process.exec = jest.fn()
module.exports = child_process;
This is the test file:
const fs = require('fs-extra'),
child_process = require('child_process'),
runCassandraMigration = require('../../lib/runCassandraMigration.js')
const defaultArguments = () => {
return {
migration_script_path: './home',
logger: {
error: function () {}
}
};
}
jest.mock("fs-extra")
jest.mock("child_process")
describe('Running cassandra migration tests', function () {
describe('successful flow', function () {
it('Should pass without any errors ', async function () {
let args = defaultArguments();
let loggerSpy = jest.spyOn(args.logger, 'error')
fs.remove.mockImplementation(() => {Promise.resolve()})
child_process.exec.mockImplementation(() => {Promise.resolve()})
await runCassandraMigration(args.migration_script_path, args.logger)
});
});
When I run the test I get the following error:
child_process.exec.mockImplementation is not a function
The module I test
const fs = require('fs-extra')
const promisify = require('util').promisify
const execAsync = promisify(require('child_process').exec)
module.exports = async (migration_script_path, logger) => {
try {
console.log()
const {stdout, stderr} = await execAsync(`cassandra-migration ${migration_script_path}`)
logger.info({stdout: stdout, stderr: stderr}, 'Finished runing cassandra migration')
await fs.remove(migration_script_path)
} catch (e) {
logger.error(e, 'Failed to run cassandra migration')
throw Error()
}
}
Please advise.
A late... answer?...
Yesterday I got the same error and the problem was that I wasn't calling jest.mock('child_process') in my test file.
Jest documentation says that when mocking Node's core modules calling jest.mock('child_process') is required. I see you do this but for some reason it is not working (maybe Jest is not hoisting it to the top).
Anyways, with Jest version 24.9.0 I don't get the child_process.exec.mockImplementation is not a function error but get some other errors because your test is not well implemented.
To make your test work I:
Added info: function () {}, inside logger
Updated the implementation of exec to child_process.exec.mockImplementation((command, callback) => callback(null, {stdout: 'ok'}))
And also (not necessary for the test to pass) updated the implementation of fs.remove to fs.remove.mockImplementation(() => Promise.resolve())
Like this:
const fs = require('fs-extra'),
child_process = require('child_process'),
runCassandraMigration = require('./stack')
const defaultArguments = () => {
return {
migration_script_path: './home',
logger: {
info: function () {},
error: function () {}
}
};
}
jest.mock("fs-extra")
jest.mock("child_process")
describe('Running cassandra migration tests', function () {
describe('successful flow', function () {
it('Should pass without any errors ', async function () {
let args = defaultArguments();
let loggerSpy = jest.spyOn(args.logger, 'error')
fs.remove.mockImplementation(() => Promise.resolve())
child_process.exec.mockImplementation((command, callback) => callback(null, {stdout: 'ok'}))
await runCassandraMigration(args.migration_script_path, args.logger)
});
});
});

Jest test redux action with thunk doesn't cover statemets

Hello i have been trying to test a function with thunk and all the test passes but can't figure it out why the coverage doesn't not update or the test function does not cover the statement.
This is my function:
export const setFinished = (campaignId, userId, actionId, callback) => {
return async (dispatch, getState) => {
await axios.post(`http://bazuca.com:9000/campaigns/${campaignId}/progress`, {
userId,
actionId
}, { headers: { token: getState().app.token } })
.then((response) => {
})
.catch((error) => {
})
callback();
}
}
This is my last test (I have done like 3 different types and cant get the coverage to work)
describe("setFinished", () => {
it("works", () => {
const dispatch = jest.fn();
const callback = jest.fn(() => 'callback');
const getState = jest.fn();
let a = setFinished(1, 1, 1, callback)
expect(a).toHaveBeenCalledWith(1, 1, 1, callback);
a(dispatch, getState);
expect(callback).toHaveBeenCalled();
});
});
and i just get this in the coverage:
Maybe im doing it wrong? or should use another library?
There might be some things missing in your test setup. Especially the way you're making an assertion about the dispatch mock looks unusual. Without going into too much detail, just consider the following:
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { setFinished } from 'path/to/your/actions';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('setFinished', () => {
it('works', () => {
// You have to make sure axios calls are mocked out properly
// at this point. I don't have a snippet handy for this so I
// left it out. But it would be similar to the following:
axios.mockImplementationOnce(() => ({
// Let the promise return whatever your response is for a
// positive test case
post: () => Promise.resolve({ isFinished: true })
}));
const expected = [
// I'm assuming something like this is dispatched in the
// .then handler of your action:
{ type: 'SET_FINISHED_SUCCESS' }
];
const store = mockStore({});
// Mock some arguments here
return store.dispatch(setFinished(1, 2, 3, () => null))
.then(() => expect(store.getActions()).toEqual(expected));
});
});
If axios is mocked out correctly, this will definitely achieve 100% coverage for this action if you also add a negative test case for the catch block.

How to mock functions deeper in the code with jest

Im trying to mock this mail function so I dont send mails everytime I test my code. But the mocking is not working. This code gives me the error: mockImplementation is not a function.
It's the add function that calls sendUserInvitationMail(). The mailer module export looks like this:
module.exports = {
sendUserInvitationMail,
};
this is the test code:
require('dotenv').config();
const { startWithCleanDb } = require('../../../utils/test.helpers');
const { add } = require('../invitation.service');
const { ADMIN_LEVELS, TABLES } = require('../../../constants');
const { AuthorizationError } = require('../../../errors');
const knex = require('../../../../db/connection');
const mailer = require('../../../mailer/index');
jest.mock('../../../mailer/index');
beforeEach(() => startWithCleanDb());
mailer.sendUserInvitationMail.mockImplementation(() => console.log('Mocked mail function called'));
mailer.sendUserInvitationMail();
describe('invitation.service', () => {
describe('add', () => {
it('adds an invitation to the db', async () => {
expect.assertions(2);
const result = await add(
{
email: 'tester#test.be',
badgeNumber: '344d33843',
},
{ currentZoneId: 1 },
ADMIN_LEVELS.ADMINISTRATOR,
);
const invitation = (await knex.select('*').from(TABLES.INVITATIONS))[0];
expect(invitation.id).toEqual(result.id);
expect(invitation.email).toEqual(result.email);
});
});
});
In mailer, sendUserInvitationMail is undefined, so it has no property mockImplementation.
Try:
mailer.sendUserInvitationMail = jest.fn().mockImplementation(() => console.log('Mocked mail function called'));
or
mailer.sendUserInvitationMail = jest.fn(() => console.log('Mocked mail function called'));

How to mock pg-promise library with jest

I am trying to mock the pg promise library. I want to be able mock return whether the promise rejects or resolves. Here is an example function and test:
const pgp = require('pg-promise')({});
const someFunc = callback => {
const db = pgp('connectionString');
db
.none('create database test;')
.then(() => {
callback(null, 'success');
})
.catch(err => {
callback(err);
});
};
module.exports = {
someFunc
};
And i wanna test it like so:
const { someFunc } = require('./temp');
let pgp = require('pg-promise')({
noLocking: true
});
// HOW TO MOCK?
describe('test', () => {
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
});
it('should test', () => {
let db = pgp('connectionString');
// how to mock this?
db.none = jest.fn();
db.none.mockReturnValue(Promise.reject('mock'));
const callback = jest.fn();
someFunc(callback);
return new Promise(resolve => setImmediate(resolve)).then(() => {
expect(callback.mock.calls.length).toEqual(1);
});
});
});
You can mock the pgp object with a dumb mock like so:
const { someFunc } = require('./temp');
let pgp = jest.fn(() => ({
none: jest.fn(),
})
jest.mock('pg-promise') // Jest will hoist this line to the top of the file
// and prevent you from accidentially calling the
// real package.
describe('test', () => {
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
});
it('should test', () => {
let db = pgp('connectionString');
db.none.mockRejectedValue('mock'); // This is the mock
const callback = jest.fn();
someFunc(callback);
return new Promise(resolve => setImmediate(resolve)).then(() => {
expect(callback.mock.calls.length).toEqual(1);
});
});
});
Its an old question, but here is a new answer:
You can have a look at pg-mem, a library I released recently which emulates an in-memory postgres instance.
It supports most of the usual SQL queries (but will fail on less frequent syntaxes - file an issue if you encounter such a situation).
I wrote an article about it here
For your use case, see the this section