Nodejs, Sinon: How to test some functions are called upon an event - javascript

Say I have an object in my code, let's say a User.
User is an eventEmitter so in many places in the code I do like:
User.on('register', notifyFriends);
User.on('register', sendWelcomeEmail);
This lines are in different files in principal.
I want to make sure that the relevant functions are called in my test so I do something like this:
describe('User Events', () => {
before(() => {
sinon.stub(userListeners, 'notifyFriends').callsFake(async () => {});
});
after(() => {
userListeners.notifyFriends.restore();
});
describe('register', () => {
it('should trigger the "notifyFriends" handler once user is registered', () => {
UserModel.emit('register');
expect(userListeners.notifyFriends).to.be.calledOnce();
});
});
});
Problem is the the function is run after the expect statement so the test fails obviously.
An easy way to solve it is to run the expect inside a Timeout block and hope that the function is called within the given time.
But I want to know if there is a better, more elegant way to do it.

The issue was different.
The code that registers to the handlers was executed before the stub was made. (So the function wasn't a spy yet)
So make sure to run the stub, only after run the rest of the code in the application that registers to the evetns.

Related

JS/Jest: how to mock a simple function to remove an event listener

I am using video.js and have code that uses on listener for on play and fires a getNames callback. At the end of that, I call video.off and pass in play and getNames . I saw in the docs that this is the proper way to have an event fire once and then remove it from happening again. My issue is mocking video.off in my test file though.
code.js
video.on('play', function getNames() {
// do stuff
video.off('play', getNames);
});
Below, I have my video.on mocked where it fires a callback when the event is play.
code.test.js
video.on = mockOn;
const mockOn = jest.fn().mockImplementation((event, callback) => {
if (event === 'play') {
callback();
}
}),
What would video.off look like though? Would it just be as simple as video.off = jest.fn() since it's not firing a callback like the on is?

Webdriver.io : Wait for method

I have a problem in my automatic test scenario when I try to call my function costumtra using webdriver.io.
I want that the scenario waits until the method call finish
describe('senario', function() {
it('can click submit button', function() {
// Do something
browser.costumtra(browser.element('#submit'));
// Do something
}
});
browser.addCommand("costumtra", function(element) {
// Do something
}
any solution please ?
You can define custom commands at any point in your test suite, just make sure that the command is defined before you first use it (the before hook in your wdio.conf.js might be a good point to create them). Also to note: custom commands, like all WebdriverIO commmands, can only be called inside a test hook or it block. May be your are calling the test method before define it. change it as given below.
browser.addCommand("costumtra", function(element) {
// Do something
}
describe('senario', function() {
it('can click submit button', function() {
// Do something
browser.costumtra(browser.element('#submit'));
// Do something
}
});

Qunit error: assertion outside test context

I've searched all over and it appears this error is due to not using asyncTest properly. However, per the documentation, it appears that I am doing it correctly. I'm guessing I'm missing a small detail somewhere and need an extra pair of eyes...
I'm trying to test some code that makes an ajax request to get a page and then loads it in a lightbox. lightbox-content does not show up in the DOM until after the ajax call has completed and can be displayed. So, I can only check for it in my onComplete call back, which is where I have my test to see if it loaded it correctly.
Here is my code:
asyncTest('mytest', 1, function() {
utils.lightbox.show('/login', {
onComplete: function() {
ok($('#lighbox-content').is(':visible'), 'Lightbox loaded the /login page.');
start();
}
});
});
I get the error:
Uncaught Error: assertion outside test context, was at HTMLDivElement.window.utils
Can anyone see where I'm going wrong?
I agree that your code matches the documentation as far as I can tell.
Update
Even though the documentation doesn't show it, I wonder if you must tell QUnit to stop at some point so it knows to wait after the test function returns. I would think that QUnit assumes this since it's an async test, but it's worth a shot.
asyncTest('mytest', 1, function() {
stop();
...
});
I've been using Sinon.JS to avoid making the AJAX calls in the first place. This has three immediate benefits:
I don't depend on a server to respond to the requests.
I can specify different results for each test.
The tests run much faster.
The mocking can be done at the XMLHttpRequest level or on the jQuery method and is quite easy. Here's an example from one of my tests:
module("geo", {
setup: function () {
this.server = sinon.fakeServer.create();
},
teardown: function () {
this.server.restore();
}
}
test("returns detected ZIP code", function () {
this.server.respondWith("/geo/detect-zip-from-ip",
[ 200, { "Content-Type": "text/html" }, '90210' ]);
geo.detectZip(function (zip) {
assertThat(zip, is('90210'));
});
this.server.respond();
});
I have found a solution for my case, hope your problem has the same source.
Explaining in words:
I have a complicated asynchronous test
I have delayed events, and there are ok and equal assertions inside
Of course, all this is wrapped inside asyncTest
But, when the test is "completed" and I call start(), the event handlers remain there
After calling start(), all further calls of ok inside that asyncTest become illegal
And throw exceptions
I wonder what happens if the number in expect(in your example it's the second parameter) is exceeded. The same exception?
Explaining in code:
asyncTest('mytest', /*1,*/ function() {
function imgLoadedOrFailed (result) {
clearTimeout(imageTimeToLive);
img.off();
ok(result, 'Image in carousel pane has been loaded');
}
var imageTimeToLive = setTimeout(
imgLoadedOrFailed.bind(this, false),
5000),
img = panes[index].find('img:first');
if (img) {
img.on('load', imgLoadedOrFailed.bind(this, true));
img.on('error', imgLoadedOrFailed.bind(this, false));
}
});
// at some point I call: start();
In this example, when I "finish" the test calling start(), the onload and onerror events can still happen.

How to run mocha tests in a chronological order?

I've got a set of modules that run based on a global event emitter. They run based on a chronological chain of events, like so:
boot.ready
server created (because of boot.ready event)
server configured (because of server.created event)
As such, I need to create a server-test.js that performs tests in a chronological order.
Is this possible with Mocha? Something like the following?
var EventEmitter2 = require('eventemitter2').EventEmitter2,
should = require('should');
describe('server', function() {
var mediator = new EventEmitter2({
wildcard: false
});
require('../../src/routines/server/creator')(mediator);
require('../../src/routines/server/configurer')(mediator);
it('should be created after boot', function(done) {
mediator.once('server.created', function(server) {
server.should.exist;
done();
});
it('should be configured after created', function(done) {
mediator.once('server.configured', function() {
done();
});
});
mediator.emit('boot.ready');
});
});
Because there seemed to be some confusion about the way this global event emitter works, this is the server/creator.js module:
module.exports = function(mediator) {
var express = require('express');
mediator.once('boot.ready', function() {
var server = express.createServer();
//event: server created
mediator.emit('server.created', server);
});
};
As you can see, the server is created after boot.ready. This fires server.created, after which the configurer will run which will then fire server.configured.
This chain of events needs to be tested by mocha.
If I'm testing a chain of events the quick way is to do it is nested eventEmitter.once calls like this:
it('executes in the right sequence', function(done) {
mediator.once('boot.ready', function() {
mediator.once('server.created', function() {
done()
})
})
})
edit: as pointed out server.created will be fired before the test's boot.ready handler is fired. Here's a workaround:
it('executes in the right sequence', function(done) {
var bootReadyFired = false
mediator.once('boot.ready', function() {
bootReadyFired = true
})
mediator.once('server.created', function() {
assert.ok(bootReadyFired)
done()
})
})
Hope this helps.
Actually mocha use function.length to your it callbacks to know if you want them asynchronously, so with function(done) you can't known in which order they're run. function() without done argument will run them synchronously.
EDIT
Your mediator is an EventEmitter2 meaning that when you emit something, the handler will be run async. Like I said they's no way to known the order in which the are executed.
The problem is in you required modules, each event should probably be emitted in the handler of the previous. Code is better than words :
// require('../../src/routines/server/creator')(mediator);
// I guess this module creates the server, then it should emit server.created
// require('../../src/routines/server/configurer')(mediator)
// This one should listen to server.created then configure the server
// and finally emit server.configured
// So in it you should have something like this:
mediator.once('server.created', function(server) {
// Here you should configure you're server
// Once it is configured then you emit server.configured
});
Also you should know that emit is immediate in node so you'd better add your listeners before emitting.
Hope this is clear.

How to unit test this code

I googled on how to unit test but examples are so simple. the examples always show functions that return something or do ajax that returns something - but never have i seen examples that do callbacks, nested callbacks and functions that are "one-way", that they just store something and never return anything.
say i have a code like this, how should i go about testing it?
(function(){
var cache = {};
function dependencyLoader(dependencies,callback2){
//loads a script to the page, and notes it in the cache
if(allLoaded){
callback2()
}
}
function moduleLoader(dependencies, callback1){
dependencyLoader(dependencies,function(){
//do some setup
callback1()
});
}
window.framework = {
moduleLoader : moduleLoader
}
}());
framework.moduleLoader(['foo','bar','baz'],function(){
//call when all is loaded
})
This illustrates a problem with keeping things private in an anonymous function in javascript. It's a bit difficult to validate that things are working internally.
If this was done test first then the cache, dependencyLoader and moduleLoader should be publicly available on the framework object. Or else it would be difficult to validate that the cache was handled properly.
To get things going I'd recommend you take a gander on BDD, that conveniently gives you an approach to help you start by letting you spell out the behaviour with a given-when-then convention. I like to use Jasmine, which is a javascript BDD framework (that integrates with jstestdriver), for this kind of thing and the unit tests I'd make for the sample you have above would be:
describe('given the moduleloader is clear', function() {
beforeEach(function() {
// clear cache
// remove script tag
});
describe('when one dependency is loaded', function() {
beforeEach(function() {
// load a dependency
});
it('then should be in cache', function() {
// check the cache
});
it('then should be in a script tag', function() {
// check the script tag
});
describe('when the same dependency is loaded', function() {
beforeEach(function () {
// attempt to load the same dependency again
});
it('then should only occur once in cache', function() {
// validate it only occurs once in the cache
});
it('then should only occur once in script tag', function() {
// validate it only occurs once in the script tag
});
});
});
// I let the exercise of writing tests for loading multiple modules to the OP
});
Hope these tests are self explanatory. I tend to rewrite the tests so that they nest nicely, and usually the actual calls are done in the beforeEach functions while the validation are done in the it functions.

Categories

Resources