I have this code:
const mocha = require("mocha");
const assert = require("assert");
describe("saving records", function (done) {
it("Saves a record to the database", function (done) {
let mx = false;
setTimeout(() => {
mx = false; //#### note this line
}, 6000);
done();
assert(mx === true);
});
});
I am not sure why, but mocha gives a test pass in the terminal that says:
saving records
✓ Saves a record to the database
1 passing (30ms)
Question no.1 : Why is the test passing at this point
The next weird thing is: It doesn't even wait for 6 seconds seconds before the test passes. Since, I've used done parameter, Question no. 2: shouldn't it wait until the execution is done?
Have I misinterpreted some information?
const mocha = require("mocha");
const assert = require("assert");
describe("saving records", function (done) {
it("Saves a record to the database", function (done) {
let mx = false;
setTimeout(() => {
mx = false; //#### note this line
assert(mx === true);
done();
}, 6000);
});
});
In your variant test passes because assert is after done();
Working with async tests described here
Related
One of my unit tests is failing. I think it's because the stubs are returning the wrong response type. Or maybe i'm just testing the wrong thing. Here is my method
let categories = Categories.create();
let totalVideos = await Video.getTotalVideos();
await categories.load();
const data = categories.getData();
if(data.length && totalVideos > 0) {
let videoArray = [];
for (let i = 0, categoryLength = data.length; i < categoryLength; i++) {
let objId = data[i]._id;
let results = await Search.findByCategoryId(objId.valueOf());
...
}
return utils.sendResponse(res, 200, utils.statusCodes.Success, {stats: videoArray});
And here is my test:
describe('GET /v1/search/videos/categories', () => {
let stub, stubVideo, stubData;
beforeEach(() => {
req = httpMocks.createRequest({
url: '/v1/search/videos/categories',
method: 'GET'
});
stub = sinon.stub(Categories.prototype, 'load');
stubData = sinon.stub(Categories.prototype, 'getData');
stubVideo = sinon.stub(Video, 'getTotalVideos');
});
afterEach(() => {
stub.restore();
stubData.restore();
stubVideo.restore();
});
it('should return a 200 if success', async () => {
stub.resolves([{"_id": new ObjectId()}]);
stubData.resolves([{"_id": new ObjectId()}, {"_id": new ObjectId()}]);
stubVideo.resolves(10);
expect(stubVideo).to.be.above(0);
expect(stubData).to.have.length.above(0);
await searchController.getAllVideosByCategory(req, res);
expect(res.statusCode).to.equal(200);
});
});
When the test runs, the assertion response for getTotalVideos is "AssertionError: expected getTotalVideos to be a number or a date". And the assertion response for getting categories array is "AssertionError: expected [Function: proxy] to have a length above 0 but got 0".
For the whole test to work,
videoCount > 0 && categories.length > 0
How do i get the stubs to return the correct response type and value to make this work?
I only added the assertions because await searchController.getAllVideosByCategory(req, res) keeps returning 404, meaning that for some reason the videosCount && categories.length conditions were not being met, and these assertions told me that the necessary values were not being returned to meet those conditions. So if there is another way to return those values so that the method returns 200, please let me know.
I've been trying to understand what you want to achieve.
I found some things to improve in the codes:
Add await in categories.getData() source file.
Use sandbox to simplify stubbing codes
Add resolves for Search.findByCategoryId
No need to check to.be.above etc since you already stubbed it with the intended value.
My Code
describe('GET /v1/search/videos/categories', () => {
let categoryCreateStub;
let categoryLoadStub;
let categoryGetDataStub;
let getTotalVideoStub;
beforeEach(() => {
req = httpMocks.createRequest({
url: '/v1/search/videos/categories',
method: 'GET'
});
sandbox = sinon.sandbox.create(); // use sandbox for multiple stubs
categoryLoadStub = sandbox.stub(Categories.prototype, 'load');
categoryGetDataStub = sandbox.stub(Categories.prototype, 'getData');
getTotalVideoStub = sandbox.stub(Video, 'getTotalVideos');
searchFindByCategoryIdStub = sandbox.stub(Search, 'findByCategoryId');
});
afterEach(() => {
sandbox.restore(); // just need to call this to restore
});
it('should return a 200 if success', async () => {
categoryLoadStub.resolves([{
"_id": new ObjectId()
}]);
categoryGetDataStub.resolves([{
"_id": new ObjectId()
}, {
"_id": new ObjectId()
}]);
getTotalVideoStub.resolves(10);
searchFindByCategoryIdStub.resolves(); // resolve this promise too!
await searchController.getAllVideosByCategory(req, res);
expect(res.statusCode).to.equal(200);
});
});
Hope it helps.
expect(stubVideo).to.be.above(0) asserts that stubVideo is positive number while it's a function that returns positive number. It doesn't make sense to test stubs, they are set by you. But there may be assertions that they were called:
expect(stubVideo).to.have.been.calledOnce;
expect(stubVideo).to.have.been.calledWith();
The test should spy on utils.sendResponse before it's called and assert that it's called with respective arguments.
I am trying to get the script to fail by accessing/redirecting to 2 links first before reaching to the error case. But i am still getting "1 passing" in mocha and then return error when it reaches the assertion. How do I make them wait for the script to completely finish only throw the error in mocha?
describe("youtube", function(){
it("test successful login",function(){
var driver = new webdriver.Builder().forBrowser("chrome").build();
driver.get("http://www.google.com");
const pageLoad = By.id('lga')
return driver.wait(until.elementLocated(pageLoad)).then(()=>{
return setTimeout(function(){
driver.get("http://www.facebook.com");
const signedPageLoad = By.id('pagelet_bluebar')
return driver.wait(until.elementLocated(signedPageLoad)).then(()=>{
//assert.strictEqual(, message);
assert.equal(50, 70); /*AssertionError: 50 == 70 */
})
},1000)
})
})
})
You need to tell mocha when the test should end. You can pass done and mocha will wait for the test result until that function is called
describe("youtube", function(){
it("test successful login",function(done){
var driver = new webdriver.Builder().forBrowser("chrome").build();
driver.get("http://www.google.com");
const pageLoad = By.id('lga')
return driver.wait(until.elementLocated(pageLoad)).then(()=>{
return setTimeout(function(){
driver.get("http://www.facebook.com");
const signedPageLoad = By.id('pagelet_bluebar')
return driver.wait(until.elementLocated(signedPageLoad)).then(()=>{
//assert.strictEqual(, message);
assert.equal(50, 70); /*AssertionError: 50 == 70 */
done(); // call this function to tell mocha that you are done.
})
},1000)
})
})
})
I am new to unit testing and have been reading a few tutorials about this practice with javascript. I will use a silly example to explain my problem.
Let's say John needs to go to school and before knowing if he's ready to go he has to check if he has his bag and his headphones. This would be called with the following function:
john.isReadyToGo;
The implementation of the isReadtToGo() function for a character object is as follows:
characher.isReadyToGo = function() {
return this.hasBag() && this.hasHeadPhones();
}
characher.hasBag = function() {
// return true or false
}
characher.hasHeadPhones = function() {
//return true or false
}
Now, let's say I want to test this function. In unit testing it is recommended to test functions without them being affected by other functions. This means that in this case I would have to test the three functions but the character.isReadyToGo() function would need to have mock values for this.hasBag() and this.hasHeadPhones(). Am I right?
If so, could you give me a hint on how I can mock these two values?
Here's an example:
let character = {};
character.isReadyToGo = function() {
return this.hasBag() && this.hasHeadPhones();
}
character.hasBag = function() {
// return true or false
}
character.hasHeadPhones = function() {
//return true or false
}
const sinon = require('sinon');
const expect = require('chai').expect;
describe('Is character ready?', () => {
beforeEach(() => {
sinon.stub(character, 'hasBag');
sinon.stub(character, 'hasHeadPhones');
});
afterEach(() => {
character.hasBag.restore();
character.hasHeadPhones.restore();
});
it("Not if they don't have a bag or headphones", () => {
character.hasBag.returns(false);
character.hasHeadPhones.returns(false);
expect(character.isReadyToGo()).to.be.false;
});
it("Not if they have headphones but no bag", () => {
character.hasBag.returns(false);
character.hasHeadPhones.returns(true);
expect(character.isReadyToGo()).to.be.false;
});
it("Not if they have a bag but no headphones", () => {
character.hasBag.returns(true);
character.hasHeadPhones.returns(false);
expect(character.isReadyToGo()).to.be.false;
});
it("Yes, if they have a bag and headphones", () => {
character.hasBag.returns(true);
character.hasHeadPhones.returns(true);
expect(character.isReadyToGo()).to.be.true;
});
});
For each test, this stubs character.hasBag and character.hadHeadphones (this is done in beforeEach). This basically replaces the original with a new function (the stub) that you can control.
Depending on the test, the stub is "told" what to return for each function (using .returns()), isReadyToGo is called, and its result is checked against the expectation.
After each test, the stub is restored (meaning that the original function is restored).
I have 2 test cases which test the same function just taking 2 different executions paths, so to illustrate:
MyClass.prototype.functionBeingTested = function() {
if (this.check1()) {
this.isCheck1Called = true;
} else if (this.check2()) {
this.isCheck1Called = false;
} else {
...
}
};
My 2 test cases are as follow:
it('should take check1() execution path', function() {
var myClass= new MyClass({}, {}, {});
var check1Stub sinon.stub(MyClass.prototype, 'check1');
check1Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(true);
});
it('should take check2() execution path', function() {
var myClass= new MyClass({}, {}, {});
var check2Stub sinon.stub(MyClass.prototype, 'check2');
check2Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(false);
});
Now by default, check1() returns false so I don't stub it in the second test case, but by the time the second case is running, the check1() function stub is still active and causes the second case to enter the execution path of the first case as-well, making the second case test fail.
I understand it's a problem of test running in parallel and the first sinon stub still being used by the first test case, is there anyway I can solve this problem?
At the end of the first test, you should restore the original method (which is always a good thing, to prevent tests from being influenced by previous tests):
check1Stub.restore()
Or, alternatively, you can use a Sinon sandbox to run each test in:
describe('MyClass', function() {
beforeEach(function() {
this.sinon = sinon.sandbox.create();
});
afterEach(function() {
this.sinon.restore();
});
it('should take check1() execution path', function() {
var myClass = new MyClass({}, {}, {});
// `this.sinon` is the sandbox
var check1Stub = this.sinon.stub(MyClass.prototype, 'check1');
check1Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(true);
});
it('should take check2() execution path', function() {
var myClass = new MyClass({}, {}, {});
var check2Stub = this.sinon.stub(MyClass.prototype, 'check2');
check2Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(false);
});
});
(See mocha-sinon, which does exactly the same)
I am just wondering if there is a way to simulate a "no connection" event in a mocha unit test. I have a method that return a promise that should wait for an internet connection with a polling strategy and I want to test it out with mocha. There is a method to achieve such a result.
Some code:
it('should wait for connection', function(done)
{
this.timeout(2500);
//simulate an internet connection drop here
wait.connection().then(done);
setTimeout(//activate connection, 2000);
});
Thank you for any response.
[EDIT]: Here there is the code I want to test:
var wait = {
connection: function()
{
'use strict';
var settings = {retry: 1000};
return new Promise(function(resolve)
{
(function poll()
{
needle.get('https://api.ipify.org', function(error, response)
{
if(!error && response.statusCode === 200 && /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(response.body))
resolve();
else
wait.for(settings.retry).then(poll);
});
})();
});
}
};
In this case the Promise will remain pending since a new connection is available. How can I simulate an error on the needle get request?
You can use sinon to stub needle.get
var needle = require("needle");
var sinon = require("sinon");;
before(() => {
sinon.stub(needle, "get", (url, calback) => {
var dummyError = {};
callback(dummyError);
})
});
// Run your 'it' here
after(() => {
needle.get.restore();
});
You can use nock.disableNetConnect(): https://github.com/nock/nock#enabledisable-real-http-requests
If you have no connection or any problems of connection, use the reject() of your promise and catch them. done is a function, and if you call the function with a non-null parameter, it means that your test is not good.
Maybe you have to try:
my_object.wait.connection()
.then(() => done(1))
.catch(() => done());