How to mock this method? - javascript

I want to mock the below line of code. And please explain how I can mock this in detail as I'm new to javascript and writing test cases. The below code would return a promise.
const createPriceConfiguration = (fastify, req) => {
return fastify.pg.transact(client => insertQuery(fastify, client, req));
};
const client = {
query: jest.fn(() => {
return new Promise(resolve => {
resolve({ rows: [req.body] });
});
})
};
My colleague gave a solution which I'm not able to understand.
transact: jest.fn(queryFunction => {
return queryFunction(client);
})

You want to test createPriceConfiguration function which takes fastify object and calls function from it. Mocking this function can be done by mocking the fastify object. You need to mock the transact method in the fastify object passed to return desired response (e.g. promise or result of an other function, ...)
const mockedFastify = {
pg: {
transact: jest.fn(() => new Promise(resolve => {
...desired code
}))
}
};
Then in test case You pass mocked object createPriceConfiguration(mockedFastify);

Related

How to test a function which has calls a another API function in it - NodeJS

I have a function, which has another function in it. And in the second function we are making an API call. So how can I write a unit test for this scenario? I don't want to make an actual API call, I want to mock it.
const getData = async (data) => {
const res = await got.post(url,{
json: {data}
});
const data = res.data;
return data;
}
function firstFunction(args) {
// perform some operation with args and it's stored in variable output.
let output = args;
let oo = getData(args);
console.log(oo)
}
When running unit test you don't have to call real API calls. You have to encapsulate your component and provide any external information.
With jest you can mock the http call and return what you want. And also you can check if the mock has been called.
import { got } from "anyplace/got";
import { firstFunction } from "anyplace2";
jest.mock("anyplace/got", () => ({
// here you provide a mock to any file that imports got to make http calls
got: {
// "mockResolvedValue" tells jest to return a promise resolved
// with the value provided inside. In this case {data: 'what you
// want here'}
post: jest.fn().mockResolvedValue({data: 'what you want here'});
}
}));
describe('My test', () => {
beforeEach(() => {
// This will clear all calls to your mocks. So for every test you will
// have your mocks reset to zero calls
jest.clearAllMocks();
});
it('Should call the API call successfully', () => {
// execute the real method
firstFunction({arg: 1});
// check that the API has been called 1 time
expect(got.post).toHaveBeenCalledTimes(1);
expect(got.post).toHaveBeenCalledwith("myurlhere", {data: {arg: 1}});
})
});
You can simulate it with setTimeout, I further provided a mock response so after 1000ms it will send a Promise with this user array
const getData = () => {
return new Promise((resolve, reject) => {
setTimeout(resolve({
users: [
{ name: "Michael" },
{ name: "Sarah" },
{ name: "Bill" },
]
}), 1000)
})
}

Mocking npm package with different returns

I'm trying to mock an npm package implementation, both to return a Promise that resolves to true and for another test, I want to reject with an error.
At the top of the test file, before the first test description, I define the following code to mock an npm package:
const mockNewFile = (): File => new File(['this is new file content'], 'new-file');
jest.mock('blueimp-load-image', () => () => {
const newFile = mockNewFile();
return new Promise(resolve => {
const data = {
image: {
toBlob: (func: (file: File) => File) => {
func(newFile);
}
}
};
resolve(data);
});
});
With this, I'm able to run my tests successfully for a function that relies on this npm package, called blueimp-load-image
But then I wanted to add a test for what should happen if this blueimp-load-image function fails, that is, when the promise it returns is rejected.
To do this I created a new description block within the main description block of the test file and tried to mock the npm package again there, by having it return a different:
describe('if loadImage returns an error', () => {
beforeEach(() => {
jest.mock('blueimp-load-image', () => () => {
return new Promise((resolve, reject) = reject(new Error('something went wrong')));
});
});
test('return the file back unmodified', async () => {
const expected = {/* file content */};
const result = await theFunctionUsingLoadImage(file);
expect(result).toStrictEqual(expected);
});
});
The test above here fails because no error seems to be thrown, leading me to expect that the mock created in the beforeEach block is not working. I know this because the expected and result should be the same, it would only differ if there was no error.
I've tried to figure this out as well using jest.spyOn instado of Jest.mock but that attempt was a complete failure.
What am I missing?
Jest.mock can be called only once, and should implement the entire interface of the mocked lib.
There are several possible options:
Using mocks, which allows you to write a mock implementation which can expose additional (mock only) methods.
Using jest.mock with global variable which will control if the mock should return success or reject.
This is an example of the second option
const mockNewFile = (): File => new File(['this is new file content'], 'new-file');
let shouldSuccess = true;
jest.mock('blueimp-load-image', () => () => {
const newFile = mockNewFile();
return new Promise((resolve, reject) => {
if(!shouldSuccess) {
return reject('data-of-reject');
}
const data = {
image: {
toBlob: (func: (file: File) => File) => {
func(newFile);
}
}
};
resolve(data);
});
});
Now all you need to do is to change the value of shouldSuccess to false, in order to make your mock implementation to reject.

How do I access promise callback value outside of the function?

It is to my understanding that callback functions are asynchronous and cannot return a value like regular functions. Upon reading about promises, I thought I grasped a good understanding about them, that they are basically an enhanced version of callbacks that allows returning a value like asynchronous function. In my getConnections method, I am attempting to call the find() function on my database through mongoose, and I am attempting to grab this array of objects and send it to the views.
var test = new Promise((resolve, reject) => {
Database.find().then(list => {
resolve(list);
}).catch(err=> {
return reject(err);
})
})
console.log(test)
When I attempt to log to the console outside of the promise function, I get Promise { _U: 0, _V: 0, _W: null, _X: null }
I don't think this is functioning correctly, and I thought I utilized promises correctly. Could anyone point me in the right direction on how to return this array of objects outside of the callback function?
You can simply add await before the promise declaration.
i.e.
var test = await new Promise...
The thing is that when you write a function like this:
const getData = async () => { const response = await fetch(someUrl, {}, {}); return response;}
Then you also need to await that function when you call it. Like this:
const setData = async () => { const dataToSet = await getData(); }
let test = new Promise((resolve, reject) => {
Database.find().then(list => {
resolve(list);
}).catch(err=> {
return reject(err);
})
})
test
.then(result=>console.log(result))
Should solve your problem.
var someValue;
var test = await new Promise((resolve, reject) => {
Database.find().then(list => {
resolve(list);
}).catch(err=> {
return reject(err);
})
}).then(res => {
someValue=res;
})
console.log(someValue);

Sinon Spy not being called with right arguments

Background
I am trying to learn how to do a RESTful API following the TDD paradigm by reading a book on the subject (it is in brazillian):
https://leanpub.com/construindo-apis-testaveis-com-nodejs/read
The author encourages the use a sinon.js together with mocha.js.
I am getting close to the end, but I am failling to pass the test for my gnomeController.
Problem
The problem is that I am using sinon to assert that I am calling the gnomeController's get method using the given reponse object, which is in reallity a spy.
This spy is to make sure I call the reponse method with an "Error", but it appears I am calling the response with no arguments whatsoever, which is very confusing.
Code
gnomeController.js
module.exports = aGnomeModel => {
let Gnome = aGnomeModel;
function get(req, res){
return Gnome.find({})
.then(gnomes => res.send(gnomes))
.catch(err => res.status(400).send(err));
}
return Object.freeze({
get
});
};
gnomeTest.js
const sinon = require("sinon");
const gnomesControllerFactory = require("gnomesController.js");
const Gnome = require("gnomeModel.js");
describe("Controllers: Gnomes", () => {
describe("get() gnomes", () => {
it("should return 400 when an error occurs", () => {
const request = {};
const response = {
send: sinon.spy(),
status: sinon.stub()
};
response.status.withArgs(400).returns(response);
Gnome.find = sinon.stub();
Gnome.find.withArgs({}).rejects("Error");
const gnomesController = gnomesControllerFactory(Gnome);
return gnomesController.get(request, response)
.then(arg => {
console.log(arg);
sinon.assert.calledWith(response.send, "Error");
});
});
});
});
Question
I am using the latest versions of both libraries.
What is wrong in my code, why is the reponse being called with no arguments?
Solution
After much debugging, I found out that the solution is to replace:
function get(req, res){
return Gnome.find({})
.then(gnomes => res.send(gnomes))
.catch(err => res.status(400).send(err));
}
with:
function get(req, res){
return Gnome.find({})
.then(gnomes => res.send(gnomes))
.catch(err => res.status(400).send(err.name));
}
Which is not explained in the book. Kinda wish I could give more feedback on it, but so far it is what it is.

Sinon sequelize stub - Modified object not returned with Promise.resolve()

I am mocking a Sequelize find call, and then modifying the result before returning the object in a Promise.resolve();
Here's my simplified code;
test.js
test('can pass test', t => {
let mock_instance = models.myModel.build({
a_property: 5
});
let Stub = sandbox.stub(models.myModel, 'find', () => {
return Promise.resolve(mock_instance);
});
models.myModel.functionCall(mock_instance.id).then(returned_object => {
let expected = {
a_property: 6
};
t.equal(returned_object.get({plain:true}), expected);
// Expected { a_property: 6 }
// Actual { a_property: 5 }
Stub.restore();
t.end();
});
})
model.js // Class method
classFunction: (id) => {
return new Promise((resolve, reject) => {
return sequelize.models.myModel.find({
where: {
id: id
}
}).then(mymodel => {
mymodel.a_property++;
resolve(mymodel);
}).catch(err => {
reject(err);
});
});
Why is this happening? I assume it's something to do with Sinon intercepting the resolve thinking it's the result of the find() call, but I'm not certain and I don't know how to fix it.
Is this an anti-pattern? Is there a better way?
As I understand it, mymodel.a_property++ won't change the value in the underlying dataValues object (you'd need to call set to do this). When you call returned_object.get({plain:true}) later it rebuilds the object from the underlying values.
Also, your "classFunction" can be a lot simpler. It doesn't need to wrap its result in an extra Promise:
classFunction: (id) => {
return sequelize.models.myModel.find({
where: { id: id }
}).then(mymodel => {
mymodel.set('a_property', mymodel.a_property + 1);
return mymodel;
});
};

Categories

Resources