I am trying to write a test using AVA but I can't seem to get it to work write. fn passes the callback function through all of my functions and calls it once it's done everything. My test is
import test from 'ava';
import fn from './index.js';
test('NonLiteral && Literal', function (t) {
fn('test.txt', '', function (res) {
console.log(res);
t.is(res, '');
});
});
The res is
This is a test
How is it going
So far!!!
but it is saying that my test is passing. I've been following this test. Here is the snippet I've been looking at
test('throwing a named function will report the to the console', function (t) {
execCli('fixture/throw-named-function.js', function (err, stdout, stderr) {
t.ok(err);
t.match(stderr, /\[Function: fooFn]/);
// TODO(jamestalmage)
// t.ok(/1 uncaught exception[^s]/.test(stdout));
t.end();
});
});
Can someone explain to me what I am doing wrong?
Sorry for the confusion, unfortunately that unit test you are looking at uses tap, not AVA. (AVA does not use itself for testing ... yet).
I am guessing that fn is async. In that case, you probably want to use test.cb.
test.cb('NonLiteral && Literal', function (t) {
fn('test.txt', '', function (res) {
console.log(res);
t.is(res, '');
t.end();
});
});
Now, it looks like maybe fn will call that callback more than once, but it is an error to call t.end() more than once. If that is so, you will need to do something like this:
test.cb('NonLiteral && Literal', function (t) {
var expected = ['foo', 'bar', 'baz'];
var i = 0;
fn('test.txt', '', function (res) {
t.is(res, expected[i]);
i++;
if (i >= expected.length) {
t.end();
}
});
});
Finally, I would encourage you to consider implementing a Promise based api so you can take advantage of async functions and the await keyword. It ends up creating much cleaner code than callbacks. In situations where you want to call a callback multiple times, consider Observables. Testing strategies for both are documented in the AVA docs. Further info on Observables is pretty easy to find by Googling.
Thanks for trying AVA. Keep those questions coming!
Related
I have a function in my project which calls a function from bootstrapper object of window. Below is the function:
export default function measurement(analObj) {
if (window.Bootsrapper._trackAnalytics === function) {
window.Bootstrapper._trackAnalytics(analObj);
}
}
I wrote below code to unit test this function in jest:
import measurement from "../helpers/measurement";
describe('Test measurement', () => {
beforeAll(() => {
const Bootstrapper = {
_trackAnalytics: function(obj) {
return obj;
},
};
window.Bootstrapper = Bootstrapper;
})
test('should send analytics object to rtrack analyitics', () => {
const testObj = {
pageName: "Leave Abasence"
}
const result = measurement(testObj);
expect(testObj).toEqual(result);
})
})
I get "undefined" for result variable that comes from measurement function call as I am unable to make window.measurement._trackAnalytics function available for measurement function at run time.
I would like to know:
Is my approach correct to unit test this scenario? If Yes, How to make the _trackAnalytics function available for measurement function while unit test run time.
Please suggest any other better approach if you know.
The window.measurement._trackAnalytics function is indeed available for measurement function when your test runs. Otherwise, you would get a TypeError for calling something that is not a function.
The problem is that in the measurement method there is nothing being returned. The _trackAnalytics method is called but its result is not returned. That's why you get undefined as a result.
In order to check that it is indeed being called I would use a jest mock function. The test would look like:
test('should send analytics object to rtrack analyitics', () => {
const testObj = {
pageName: 'Leave Abasence'
};
measurement(testObj);
expect(window.Bootstrapper._trackAnalytics).toHaveBeenCalledTimes(1);
expect(window.Bootstrapper._trackAnalytics).toHaveBeenCalledWith(testObj);
});
Note that your code has some problems (which I expect are typos). In the if condition you are checking Bootsrapper instead of Bootstrapper. And you are checking if it is equal to function instead of checking with typeof. I think the line should look:
if (typeof window.Bootstrapper._trackAnalytics === 'function') {
I am trying to write unit tests for a function that reads a jsonfile into an object. I read the file with
jsonfile.readFile(filename, function (err, obj) {
//...
});
For my unit tests, I want to mock this function so that, rather than actually reading the file, it will simply return a fixed json block and pass it into the callback.
What I'm having trouble with is how to mock the function. I've seen sinon, which says it supports mocking functions, but I can't find anything that describes how to actually define custom behavior for the function I'm mocking. Sinon looks like it allows me to define what I want the function to return, how often I expect it to be called, etc, but not actually define a mocked function.
Basically, I want something like this:
mock(jsonfile, 'readFile', function(filename, callback) {
callback(null, {attr1:"foo"});
});
How do I do this with sinon?
But actually, why don't you just replace readFile by a function with the same definition (so that it doesn't break the code using it). And just return your mock data.
jsonfile.readFile = function(filePath, callback) {
callback(null, { mockData: "foo" });
};
easy as that.
Otherwise, you can use a Proxy if you don't want to deal with the definition :
const jsonfile = {
readFile: function(filename, callback) {
callback();
}
};
// intercept every call to readFile and always return the mock data
jsonfile.readFile = new Proxy(jsonfile.readFile, {
apply: function(target, thisArg, args) {
return args[1](null, { someMocking: "" });
}
});
// call readFile as usual
jsonfile.readFile('testfile', function(err, result) {
console.log(result);
});
Proxies work as interceptors.
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Proxy
This is not straightforward in testing because it involved callbacks. You need to test wether a callback you passed to readFile was called with right arguments, which in this case is the dummyFile.
import sinon from 'sinon'
import jsonfile from './jsonfile'
const jsonFileMock = sinon.spy(jsonfile, 'readFile');
const callback = sinon.spy();
jsonfile.readFile(callback);
jsonFileMock.callsArgWith(1, 'dummyFileName');
expect(callback.calledWith('dummyFileName')).to.be.true;
jsonFileMock.restore();
If you want to abstract this into a function, than it can be something like :
function mock(module, method, ...callbacks){
const stub = sinon.stub(jsonfile, 'readFile');
callbacks.forEach((callback, index) => {
stub.callsArgWith(index, callback);
});
}
The function I was looking for is stub.callsFake():
> Thing = {
... meth : function() { console.log(1) }
... }
> Thing.meth()
1
> var stub = sinon.stub(Thing, 'meth')
> stub.callsFake(function() { console.log(2) })
> Thing.meth()
2
> stub.restore()
> Thing.meth()
1
It doesn't look like mock is capable of what I want to do.
Wondering if anyone can help me - I'm trying to test my js using Jasmine (1.3) and I can't figure out the best way to test any method calls inside a .then or a .done method.
example code to explain:
Backbone.View.extend({
myMethod: function () {
this.something.done(function () {
this.doSomethingElse();
}.bind(this));
}
})
I'd like to write a test that check that this.doSomethingElse was called.
I was looking around at jasmine.async and a waitsFor/runs set up but I'm not sure how it fits into external code i.e. I'm not going to call done() inside my actual code to get my test working. Also if I mock out the done method on this.something then I'm not longer testing the actual implementation, right?
I'm just missing how things fit together. If anyone could point me in the right direction I'd really appreciate it!
Update: based on feedback below I've now tried the following
Hey, thanks for the answer - I think maybe I don't have the last part correct - have tried 2 different ways, both initial pass but then fail after a second or 2.
it('calls doSomethingElse on done',function () {
var mockDeferred = $.Deferred();
myView.something = mockDeferred;
spyOn(myView,'doSomethingElse');
mockDeferred.resolve();
waitsFor(function () {
expect(myView.doSomethingElse).toHaveBeenCalled();
});
});
And also:
it('calls doSomethingElse on done',function () {
var mockDeferred = $.Deferred(),
someTrigger = false;
myView.something = mockDeferred;
spyOn(myView,'doSomethingElse');
runs(function () {
mockDeferred.resolve();
someTrigger = true;
});
waitsFor(function () {
someTrigger = true;
});
runs(function () {
expect(myView.doSomethingElse).toHaveBeenCalled();
});
});
In both instances the test will pass originally but then timeout to a failure after a second or 2.
Am I missing something?
To test the example function you described, I would do the following within your test:
Create a new deferred object (I'll call it mockDeferred)
Pass mockDeferred into your code under test so that it is now this.something in your example
Spy on the doSomethingElse function
Call myMethod()
Call resolve() on mockDeferred
Assert that doSomethingElse was called
Edit based on OP's Update:
I don't see anywhere in either of your examples where you are calling myView.myMethod() within your test; make sure you do that. I whipped up an example that you can reference here.
As an aside, I'm surprised the second example you tried passes initially. Maybe because you have some code outside of a runs() block?
Related problem
Spying on a method inside .then and expecting .toHaveBeenCalled fails
Solution:
run test inside fakeAsync and run tick() before the expect
Service:
getFirebaseDoc() {
this.db.firestore.doc('some-doc').get()
.then(this.getFirebaseDocThen)
.catch(this.getFirebaseDocCatch);
}
Unit testing:
it('should call getFirebaseDocThen', fakeAsync(() => { // note `fakeAsync`
spyOn(service, 'getFirebaseDocThen');
spyOn(service.db.firestore, 'doc').and.returnValue({
get: (): any => {
return new Promise((resolve: any, reject: any): any => {
return resolve({ exists: true });
});
},
});
service.getFirebaseDoc();
tick(); // note `tick()`
expect(service.getFirebaseDocThen).toHaveBeenCalled();
}));
From what I understand, the future style to write async code in JS is to use generators instead of callbacks. At least, or esp. in the V8 / Nodejs community. Is that right? (But that might be debatable and is not my main question here.)
To write async code with generators, I have found a few libraries:
gen-run (What I'm currently using.)
co
task.js
Galaxy
They all look kind of similar and I'm not that sure which of them to use (or if that even matters). (However, that might again be debatable and is also not my main question here -- but I still would be very happy about any advice.)
(I'm anyway only using pure V8 - if that matters. I'm not using Nodejs but I use pure V8 in my custom C++ app. However, I already have a few node-style elements in my code, including my custom require().)
Now I have some function X written in callback-style, which itself calls other async functions with callback arguments, e.g.:
function X(v, callback) {
return Y(onGotY);
function onGotY(err, res) {
if(err) return callback(err);
return Z(onGotZ);
}
function onGotZ(err, res, resExtended) {
if(err) return callback(err);
return callback(null, v + res + resExtended);
}
}
And I want to turn X into a generator, e.g. I guess function* X(v) { ... }. How would that look like?
I went with my very simple own lib which works quite well for my small V8 environment and also makes it easy to debug because the JS callstack stays intact. To make it work with Nodejs or on the web, it would need some modifications, though.
Rationales here:
For debugging, we don't really want async code - we want to have nice understandable call stacks in debuggers, esp. in the node-inspector debugger.
Also note that so far, all async code is completely artificial and we execute everything completely in sync, somewhat emulated via V8 Microtasks.
Callback-style async code is already hard to understand in call stacks.
Generator-style async code looses the call stack information completely in conventional debuggers - that includes the current Chrome Beta Developer Tools V8 debugger used with node-inspector. That is very much the nature of generators (coroutines in general). Later versions of the debugger might handle that, but that is not the case today. We even need some special C++ code to get the info. Example code can be found here:
https://github.com/bjouhier/galaxy-stack/blob/master/src/galaxy-stack.cc
So if we want to have useful debuggers, today, we cannot use generators -- at least not as it is usually done.
We still want to use generator-style async code because it makes the code much more readable, compared to callback-style code.
We introduce a new function async to overcome this. Imagine the following callback-style async code:
function doSthX(a, b, callback) { ... }
function doSthY(c, callback) {
doSthX(c/2, 42, function(err, res) {
if(err) return callback(err);
callback(null, c + res);
})
}
Now, the same code with the async function and generator-style code:
function* doSthX(a, b) { ... }
function* doSthY(c) {
var res = yield async(doSthX(c/2, 42));
return c + res;
}
We can provide two versions of async(iter):
Run the iterator iter on top of the stack. That will keep a sane call stack and everything is run serially.
Yield the iterator down to some lower handler and make it really async.
Note that there are a few notable libraries which can be used for the second approach:
https://github.com/visionmedia/co
http://taskjs.org/
https://github.com/creationix/gen-run
https://github.com/bjouhier/galaxy
For now, we just implement the first approach - to make debugging easier.
If we once want to have both, we can introduce a debug flag to switch via both implementations.
global.async = async;
function async(iter) {
// must be an iterator
assert(iter.next);
var gotValue;
var sendValue;
while(true) {
var next = iter.next(sendValue);
gotValue = next.value;
if(!next.done) {
// We expect gotValue as a value returned from this function `async`.
assert(gotValue.getResult);
var res = gotValue.getResult();
sendValue = res;
}
if(next.done) break;
}
return {
getResult: function() {
return gotValue;
}
};
}
// Like `async`, but wraps a callback-style function.
global.async_call_cb = async_call_cb;
function async_call_cb(f, thisArg /* , ... */) {
assert(f.apply && f.call);
var args = Array.prototype.slice.call(arguments, 2);
return async((function*() {
var gotCalled = false;
var res;
// This expects that the callback is run on top of the stack.
// We will get this if we always use the wrapped enqueueMicrotask().
// If we have to force this somehow else at some point, we could
// call runMicrotasks() here - or some other waiter function,
// to wait for our callback.
args.push(callback);
f.apply(thisArg, args);
function callback(err, _res) {
assert(!gotCalled);
if(err) throw err;
gotCalled = true;
res = _res;
}
assert(gotCalled);
return res;
})());
}
// get the result synchronously from async
global.sync_from_async = sync_from_async;
function sync_from_async(s) {
assert(s.getResult); // see async()
return s.getResult();
}
// creates a node.js callback-style function from async
global.callback_from_async = callback_from_async;
function callback_from_async(s) {
return function(callback) {
var res;
try { res = sync_from_async(s); }
catch(err) {
return callback(err);
}
return callback(null, res);
};
}
global.sync_get = sync_get;
function sync_get(iter) {
return sync_from_async(async(iter));
}
// this is like in gen-run.
// it's supposed to run the main-function which is expected to be a generator.
// f must be a generator
// returns the result.
global.run = run;
function run(f) {
return sync_get(f());
}
I assume that by "turning X into a generator" you mean "turning X into something you can yield", because that's how these libs work.
If you are using co (which I recommend), you need to make your function return thunks, that is a function, which accepts only a callback. Quite simple:
function coX (v) {
return function (cb) {
X(v, cb);
}
}
And then just:
co(function * () {
yield coX('v');
})();
I've recently used a nice library for node.js called Kue.
I wanted to get some better understanding of what's going so I started reading the code...
I stumbled on to a piece of code and my mind went "WTF!!?!#$#!$"...
This is the code:
function get(obj) {
var pending = 0
, res = {}
, callback
, done;
return function _(arg){
switch (typeof arg) {
case 'function':
callback = arg;
break;
case 'string':
++pending;
obj[arg](function(err, val){
if (done) return;
if (err) return done = true, callback(err);
res[arg] = val;
--pending || callback(null, res);
});
break;
}
return _;
};
}
which being used like this:
exports.stats = function(req, res){
get(queue)
('inactiveCount')
('completeCount')
('activeCount')
('failedCount')
('delayedCount')
('workTime')
(function(err, obj){
if (err) return res.send({ error: err.message });
res.send(obj);
});
};
.
.
.
Are those functions on functions?!
How are they aware of each other?
What is that '_'(underscore) on the 7th row of the function?
Could someone please help me understad what's goin' on over there? :)
Functions can indeed return functions. Take this function, for example:
function func(text) {
alert(text);
return func;
}
Obviously the return value of any invocation of func will be, again, func, so you can use it like this:
func("hello")("world");
…and you'll get two alerts: first "hello", and then "world".
Next, there's something called a named function expression. You might have seen anonymous function expressions before:
doSomething(thing, function(err) {
// operation completed or something
});
That, of course, is great for simple things, but sometimes you want the function to have a name so it can refer to itself. As Kolink mentioned, if you just want to recurse, there's arguments.callee, which refers to the function currently executing, but there is another way: you can give the function a name visible only within the function while still having it be a function expression:
doSomething(thing, function myself(err) {
// ^^^^^^
// now I can refer to myself as myself!
});
An underscore is a valid identifier, so they're basically just combining these techniques in a way that may be difficult to understand.