How to mock SQL Server connection pool using Jest? - javascript

I am trying to write a jest unit test for a function that utilizes mssql.
import * as sql from "mssql";
let pool: sql.ConnectionPool = null;
export async function handler() {
if (pool === null) {
try {
pool = new sql.ConnectionPool("");
await pool
.request()
.input("SomeInput", sql.NVarChar(255), "input")
.execute("SomeStoredProcedure");
} catch (err) {
console.error(err);
}
}
}
What would be the simplest way to mock the sql methods and assert they have been called?
import { handler } from "../src/main";
describe("test handler", () => {
it("should succeed", async () => {
const requestFn = jest.fn();
const executeFn = jest.fn();
const inputFn = jest.fn();
// Mock mssql connection pool with above functions
// *????????*
await handler();
// Expect the functions have been called
expect(requestFn).toHaveBeenCalled();
expect(executeFn).toHaveBeenCalled();
expect(inputFn).toHaveBeenCalled();
});
});
Sandbox

You can mock the mssql package by using an jest ES6 Class Mocks. You can achive that by using:
const mockExecute = jest.fn();
const mockInput = jest.fn(() => ({ execute: mockExecute }));
const mockRequest = jest.fn(() => ({ input: mockInput }));
jest.mock('mssql', () => ({
ConnectionPool: jest.fn(() => ({
request: mockRequest
})),
NVarChar: jest.fn()
}));
Have a look at the Stackblitz project and run jest in the terminal. You should see that the tests are passing.

You need to mock the return value of each function in the chain. You can do this using jest.fn().mockImplementation(implementation)
Expanding you example to use this give us the following
import { handler } from "../src/main";
let pool;
describe("test handler", () => {
it("should succeed", async () => {
const requestFn = jest.fn();
const executeFn = jest.fn();
const inputFn = jest.fn();
pool = {
request: requestFn,
execute: executeFn,
inputFn: inputFn,
};
requestFn.mockImplementation(() => pool);
executeFn.mockImplementation(() => pool);
inputFn.mockImplementation(() => pool);
await handler();
// Expect the functions have been called
expect(requestFn).toHaveBeenCalled();
expect(executeFn).toHaveBeenCalled();
expect(inputFn).toHaveBeenCalled();
});
});

Related

Why is this not working? Testing non exported-function with Rewire / Jest

Pretty much running the exact same code elsewhere however, this time, I am using rewire to test a non-exported function at helper.js.
When debugging the following I get to return await db.collection('foo') which returns undefined and throwing when attempting 'undefined.findOne()' naturally. My understanding is that db.collection('foo') should return mockDbConnect in this case allowing to chain findOne, which it is not doing...
Help is appreciated.
foo.test.js
const rewire = require('rewire');
const helper = rewire('../../../src/models/helper/helpers');
describe('model helpers', () => {
describe('searchValue', () => {
it('should return an instance', async () => {
const searchValue = helper.__get__('searchValue')
const mockFoo = { foo: '1' }
const fooId = '1';
const mockDbConnect = {
collection: jest.fn().mockReturnThis(),
findOne: jest.fn().mockReturnValue(mockFoo)
}
try {
const res = await searchValue(fooId, mockDbConnect);
expect(mockDbConnect.collection).toHaveBeenCalledWith('foos');
} catch (err) {
throw err;
}
});
})
})
helpers.js
const searchValue = async (fooId, db) => {
return await db
.collection('foos')
.findOne({ fooId: fooId });
};

Jest mock function not working as expected

I'm trying to create a mock for a function createClient where it should return a specific object.
However, for some reason the mock is ignored and it runs the function instead of receiving the mock value.
authorization.js
// some requires here
const createClient = req => {
if (!(req.user && req.user.access_token)) {
throw new Error('Not authorized');
}
...
return { ... }
}
const getUser = async client => { ... }
module.exports = options => {
...
createClient(req) is called here
...
}
authorization.test.js
import authorization from '../../server/middlewares/authorization';
describe('authorization.js', () => {
it('Should do something', async done => {
authorization.createClient = jest.fn(() => ({
client: 'test',
}));
// ACT
const authorizationMiddleware = authorization();
const result = await authorizationMiddleware(someOptions);
// ASSERT
expect(result).toBe('authorized');
done();
});
The error
It seems that the mock for createClient is not working as I wanted to be. It should return the object { client: 'test' }
Your code is incomplete, so I try to give a demo for your case. If you want to mock a private variable in the module scope, the createClient function for your case. You can use rewire package to do that.
E.g.
authorization.js
let createClient = (req) => {
if (!(req.user && req.user.access_token)) {
throw new Error('Not authorized');
}
function getUser() {
return 'real user';
}
return { getUser };
};
const getUser = async (client) => {
return client.getUser();
};
module.exports = (options) => {
const client = createClient(options.req);
return () => getUser(client);
};
authorization.test.js:
const rewire = require('rewire');
describe('61076881', () => {
it('should get user', async () => {
const authorization = rewire('./authorization');
const mClient = { getUser: jest.fn().mockReturnValueOnce('fake user') };
const mCreateClient = jest.fn(() => mClient);
authorization.__set__('createClient', mCreateClient);
const options = { req: { user: { access_token: '123' } } };
const authorizationMiddleware = authorization(options);
const user = await authorizationMiddleware();
expect(user).toEqual('fake user');
expect(mCreateClient).toBeCalledWith(options.req);
expect(mClient.getUser).toBeCalledTimes(1);
});
});
unit test results:
PASS stackoverflow/61076881/authorization.test.js (7.601s)
61076881
✓ should get user (10ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.54s, estimated 9s
source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/61076881

Jest: How to properly test a Javascript service using MongoDB

I'm a total beginner with Jest.
I've got a UserService using Dependency Injection.
public async getAll() {
const userRecords = await this.userModel.find().select('name').catch((e) => {
throw new HttpException(500, 'Error while fetching users.', e)
});
return <[IUser]>userRecords;
}
I would like to test this feature. Here are the tests I could run:
Calling the route, and checking if the resulting JSON is OK
Ggetting DB content, and checking if it is as expected
Just test the getAll function
I think 1 and 2 are obvious, and cover different kind of things. 1 covers the request part, 2 covers the DB part. But what about number 3? How to "just test" the getAll function?
I've tried this:
const userModel = {
find: (user) => {
return [
{ id: 'user1' },
{ id: 'user2' }
]
},
};
const userService = new UserService(userModel);
const userRecords = await userService.getAll();
expect(argumentRecord).toBeDefined();
But obviously it's failing because select is undefined.
Should I also mock select()? Should I organize my code differently?
If were to write this test I would mock the functions using jest.fn(implementation) so that expectations can be enforced on the function calls.
const userQuery = {
select: jest.fn(() => Promise.resolve([]))
};
const userModel = {
find: jest.fn(() => userQuery)
};
const userService = new UserService(userModel);
const userRecords = await userService.getAll();
expect(userRecords).toEqual([]);
expect(userModel.find).toHaveBeenCalled();
expect(userQuery.select).toHaveBeenCalledWith('name');
Performing expectations on the function calls may sound like overkill, but it explicitly verifies that the mock is actually being used by getAll.
I would also structure the tests in such a way that I can test the various code paths without re-implementing the entire mock.
describe('getAll()', () => {
let userQuery, userModel, userService;
beforeEach(() => {
userQuery = {
select: jest.fn(() => Promise.resolve([]))
};
userModel = {
find: jest.fn(() => userQuery)
};
userService = new UserService(userModel);
});
afterEach(() => {
expect(userModel.find).toHaveBeenCalled();
expect(userQuery.select).toHaveBeenCalledWith('name');
});
it('should get the user names', async () => {
const users = [{
name: 'john'
}, {
name: 'jane'
}];
userQuery.select.mockImplementation(() => Promise.resolve(users));
await expect(userService.getAll()).resolves.toBe(users);
});
it('should handle errors', async () => {
const error = new Error('Fake model error');
userQuery.select.mockImplementation(() => Promise.reject(error));
await expect(userService.getAll()).rejects.toMatch({
status: 500,
message: 'Error while fetching users.',
cause: error
});
});
});
This code is untested, so it may not work correctly, but hopefully it outlines the idea sufficiently.
While this is not directly related to your question I would avoid mixing async/await with traditional promise handling.
public async getAll() {
try {
return <[IUser]> await this.userModel.find().select('name');
} catch (e) {
throw new HttpException(500, 'Error while fetching users.', e)
}
}
Yes, you should mock select. And not only that, but everything that is used inside the function and test if they are executed properly. I would do this:
class SomeClass {
public async getAll() {
const userRecords = await this.userModel.find().select('name').catch(this.errorHandler);
return <[IUser]>userRecords;
}
public errorHandler(e) {
throw new HttpException(500, 'Error while fetching users.', e);
}
}
// this is just an example, it should be the same type as your expected returned output
const whatever = Math.random();
const fakeCatch = jest.fn(() => whatever);
const fakeSelect = jest.fn(() => {
return {
catch: fakeCatch
}
});
const fakeFind = jest.fn(() => {
return {
select: fakeSelect
};
});
const fakeUserModel = {
find: fakeFind,
}
const userService = new UserService(fakeUserModel);
const userRecords = await userService.getAll();
// should return the correct result
expect(userRecords).toEqual(whatever);
// should execute find
expect(fakeFind).toHaveBeenCalledTimes(1);
// should execute select with 'name' parameter
expect(fakeSelect).toHaveBeenCalledTimes(1);
expect(fakeSelect).toHaveBeenCalledWith('name');
// should execute catch with this.errorHandler
expect(fakeCatch).toHaveBeenCalledWith(userService.errorHandler);

is there a function to test an object instance that has a callback in js?

Im using sinon to stub an instance of an object that has inside a function with a callback, how can i test it?.
i dont know how to test this, that throws me an error.
this is using js with sinon and mocha.
the function is:
import tracker from 'pivotaltracker';
export async function getPivotalProjects(token) {
const clientTracker = new tracker.Client(token);
const userProjects = () => new Promise((resolve, reject) => {
clientTracker.projects.all((error, projects) => (projects ? resolve(projects) : reject(error)));
});
return userProjects();
and the test is:
import tracker from 'pivotaltracker';
let spyTracker;
beforeEach(() => {
spyTracker = sinon.stub(tracker, 'Client');
});
it('should do the request to get the activities from projects.', async () => {
spyTracker.callsArgWith(1, null, [true, 'token']);
// spyTracker.projects.all.returns('token');
await PivotalTrackerApi.getPivotalProjects('token');
sinon.assert.threw(spyTracker);
spyTracker.restore();
});
what is wrong on that? if anyone could helpme will be great.
getPivotalProjects can be simplified to this:
export async function getPivotalProjects(token) {
const clientTracker = new tracker.Client(token);
await new Promise((resolve, reject) => {
clientTracker.projects.all((error, projects) => (projects ? resolve(projects) : reject(error)));
});
}
...and it can be tested like this:
let clientStub;
beforeEach(() => {
clientStub = sinon.stub(tracker, 'Client');
});
it('should do the request to get the activities from projects.', async () => {
const allSpy = sinon.spy();
clientStub.callsFake((token) => ({ projects: { all: allSpy } }));
const promise = PivotalTrackerApi.getPivotalProjects('token');
sinon.assert.calledWith(clientStub, 'token'); // Success!
sinon.assert.called(allSpy); // Success!
const callback = allSpy.lastCall.args[0];
callback(null, 'my projects');
const result = await promise;
expect(result).to.equal('my projects'); // Success!
});

how to write test cases for redux async actions using axios?

Following is a sample async action creator.
export const GET_ANALYSIS = 'GET_ANALYSIS';
export function getAllAnalysis(user){
let url = APIEndpoints["getAnalysis"];
const request = axios.get(url);
return {
type:GET_ANALYSIS,
payload: request
}
}
Now following is the test case I have wrote:
describe('All actions', function description() {
it('should return an action to get All Analysis', (done) => {
const id = "costnomics";
const expectedAction = {
type: actions.GET_ANALYSIS
};
expect(actions.getAllAnalysis(id).type).to.eventually.equal(expectedAction.type).done();
});
})
I am getting the following error:
All actions should return an action to get All Analysis:
TypeError: 'GET_ANALYSIS' is not a thenable.
at assertIsAboutPromise (node_modules/chai-as-promised/lib/chai-as-promised.js:29:19)
at .<anonymous> (node_modules/chai-as-promised/lib/chai-as-promised.js:47:13)
at addProperty (node_modules/chai/lib/chai/utils/addProperty.js:43:29)
at Context.<anonymous> (test/actions/index.js:50:5)
Why is this error coming and how can it be solved?
I suggest you to take a look at moxios. It is axios testing library written by axios creator.
For asynchronous testing you can use mocha async callbacks.
As you are doing async actions, you need to use some async helper for Redux. redux-thunk is most common Redux middleware for it (https://github.com/gaearon/redux-thunk). So assuming you'll change your action to use dispatch clojure:
const getAllAnalysis => (user) => dispatch => {
let url = APIEndpoints["getAnalysis"];
const request = axios.get(url)
.then(response => disptach({
type:GET_ANALYSIS,
payload: response.data
}));
}
Sample test can look like this:
describe('All actions', function description() {
beforeEach("fake server", () => moxios.install());
afterEach("fake server", () => moxios.uninstall());
it("should return an action to get All Analysis", (done) => {
// GIVEN
const disptach = sinon.spy();
const id = "costnomics";
const expectedAction = { type: actions.GET_ANALYSIS };
const expectedUrl = APIEndpoints["getAnalysis"];
moxios.stubRequest(expectedUrl, { status: 200, response: "dummyResponse" });
// WHEN
actions.getAllAnalysis(dispatch)(id);
// THEN
moxios.wait(() => {
sinon.assert.calledWith(dispatch, {
type:GET_ANALYSIS,
payload: "dummyResponse"
});
done();
});
});
});
I found out it was because, I had to use a mock store for the testing along with "thunk" and "redux-promises"
Here is the code which made it solve.
const {expect} = require('chai');
const actions = require('../../src/actions/index')
import ReduxPromise from 'redux-promise'
import thunk from 'redux-thunk'
const middlewares = [thunk,ReduxPromise]
import configureStore from 'redux-mock-store'
const mockStore = configureStore(middlewares)
describe('store middleware',function description(){
it('should execute fetch data', () => {
const store = mockStore({})
// Return the promise
return store.dispatch(actions.getAllDashboard('costnomics'))
.then(() => {
const actionss = store.getActions()
console.log('actionssssssssssssssss',JSON.stringify(actionss))
// expect(actionss[0]).toEqual(success())
})
})
})

Categories

Resources