describe("/test" , ()=> {
// separate class 2
class2 = {
// function that i wanna stub
hi: function () {
return "hi";
}
}
// separate class 1
class1 = {
// function that i have stubbed and tested
method1: function() {
return new Promise((resolve, reject) => {
resolve(num);
})
}
}
// method that i will execute
var parent= function (){
class1.method1().then(()=>{
class2.hi();
})
}
// the test
it("should stub hi method",()=>{
var hiTest = sinon.stub(class2, 'hi').resolves(5);
var method1Test = sinon.stub(class1 , 'method1').resolves(5);
// this start the execution of the promise with then call
parent();
// this works fine and test pass
expect(method1Test.calledOnce.should.be.true);
// this doesn't work although i executed the function
expect(hiTest.calledOnce.should.be.true);
})
})
what i wanna do is test the hi method correctly .. because when i test if the method is executed once or not
although i executed it in the then call of the promise it doesn't show that and it make the calledOnce test fail
The problem here is that you are testing the code as if it is synchronous, when it is not (as you are using Promise).
To be able to test this properly we need to be able to hook onto the promise chain that is started with parentcalling class1.method1.
We can do this by returning the promise that calling class1.method1 returns.
In terms of the test itself, we need to make sure Mocha doesnt end the test while we are waiting for the promises, so we use the done callback parameter to tell Mocha when we think the test is finished.
describe("/test", ()=> {
class2 = {
hi: function () {
return "hi";
}
}
class1 = {
method1: function() {
return new Promise((resolve, reject) => {
resolve(num);
})
}
}
var parent = function (){
return class1.method1().then(()=>{
class2.hi();
})
}
it("should stub hi method", (done)=> {
var hiTest = sinon.stub(class2, 'hi').returns(5);
var method1Test = sinon.stub(class1 , 'method1').resolves(5);
parent().then(() => {
expect(method1Test.calledOnce.should.be.true);
expect(hiTest.calledOnce.should.be.true);
done();
});
})
})
Related
I am trying to unit test the following code using jasmine but I can't seem to mock the checkStatus function. What am I seem to get wrong? It seems like when i actually call the Booking.saveBooking method it is not using the mocked version of the checkStatus. Please help.
Booking.js
const checkStatus = (id) => {
.. // some code here
return new Promise((resolve, reject)=>{
resolve(value);
});
}
const saveBooking =(req) => {
checkStatus(req.id).then(()=>{
//save booking here ..
}).catch((error)=>{
throw new Error();
});
}
module.exports ={saveBooking, checkStatus}
booking.Spec.js
const Booking = require('Booking');
describe('Booking',()=>{
const req = {
id: 2133,
customer_name: 'John Smith',
contact_number: '888-8888',
contact_email: 'cam888#example.com'
};
it('Should check the status', async ()=>{
spyOn(Booking, "checkStatus").and.callFake(function() {
var deferred = $q.defer();
deferred.resolve(true);
return deferred.promise;
});
await Booking.saveBooking(req);
expect(Booking.checkStatus).toHaveBeenCalled()
});
});
I am getting an error Error: Expected spy checkStatus to have been called.
It seems like saveBooking method it is not using the mocked version of the checkStatus.
I'm trying to mock function that has a stream return type and callback as arg. I get timeout because the call back function never get called.
This is the function I'm trying to test:
public setServerUrls(): Observable<void> {
const obs: Observable<void> = new Observable((observer: Observer<void>) => {
const stream: ClientWritableStream<Util.Server> = this.fileTransferClient.setURLs((error: ServiceError, response) => {
if (error) {
observer.error(`TransferManager Electron: unable to set server urls error: ${error.message}.`);
}
observer.next();
observer.complete();
logger.info(`TransferManager Electron: setting URLs completed.`);
});
const transferRequest = new Util.Server();
transferRequest
.setIp('localhost')
.setTransferport('9092')
.setUuid('4020a522-81fe-4996-b637-0620ae656d29');
stream.write(transferRequest);
stream.end();
});
return obs;
}
My jasmine setup:
const settingStream = {
write: () => { },
end: () => { }
};
const callBack = () => {
return;
};
const f = function (callback: Function): any {
return settingStream;
};
mockFileTransferClient = jasmine.createSpyObj('FileTransferClient', {
subscribe: () => mockFileTransferStream,
uploadFile: () => duplexStream,
setURLs: f(callBack)
});
mockFileTransferClientWrapper.createNewFileTransferClient.and.returnValue(mockFileTransferClient as any);
// Question here... does not work!
mockFileTransferClient.setURLs.and.returnValue(settingStream);
test:
it('should set urls', done => {
transferManager.setServerUrls()
.subscribe(
x => {
expect(x).toBeDefined();
done();
}
);
});
This is Elctron + grpc functionality test.
Test timeout because it never gets into the callback and observable never completes.
I'm not sure how to mock setURLs with return value AND callback.
You have to first mock your setUrls to return a resolved observable.
I think what you need here is to use fakeAsync() functionality as you are dealing with async test. Using Tick with fakeAsync ensures that all pending asynchronous activities will finish. In your case it will wait for setTimeout.
Note that you should also inject the setServerUrls using TestBed.inject...
So I think your tests should look like this
it("should .....", fakeAsync(() => {
// Arrange - mock functions
// Act - Make a call to the function
// Use tick() after making call to the function which will flush your setTimeouts
// Assert
}));
For more information, see the fakeAsync documentation
Is there a way to show why tested function can pass?
When I follow Jest test Async Code section
It says:
Be sure to return the promise - if you omit this return statement,
your test will complete before fetchData completes.
And my code is:
function add1(n) {
return new Promise((res, rej)=>{
res(n+1)
})
}
test('should add 1', function() {
expect.assertions(1)
//////////////////////////// I did not use RETURN here
add1(10).then((n11)=>{
expect(n11).toBe(11)
})
});
This still passed, I want to know how this can pass?
The Promise resolves immediately and synchronously so the then gets called immediately and the expect has run before the test finishes. (then callbacks run immediately if the Promise has already resolved)
If you use setTimeout to keep the Promise from resolving immediately and synchronously then the test fails unless you return the Promise:
function add1(n) {
return new Promise((res, rej) => {
setTimeout(() => { res(n + 1) }, 0); // use setTimeout
})
}
test('should add 1', function () {
expect.assertions(1)
// PASSES only if Promise is returned
return add1(10).then((n11) => {
expect(n11).toBe(11);
})
});
I have the following function that uses bind to bind a context to the then chains. When i try and test it, it throws
TypeError: redisClient.hgetallAsync(...).bind is not a function
myFunc() {
let self = this;
return redisClient.hgetallAsync('abcde')
.bind({ api: self })
.then(doStuff)
.catch(err => {
// error
});
}
Test
let redisClient = { hgetallAsync: sinon.stub() };
describe('myFunc', () => {
beforeEach(() => {
redisCLient.hgetallAsync.resolves('content!');
});
it('should do stuff', () => {
return myFunc()
.should.eventually.be.rejectedWith('Internal Server Error')
.and.be.an.instanceOf(Error)
.and.have.property('statusCode', 500);
});
});
The hgetallAsync stub is returning a plain JS Promise rather than a Bluebird promise.
To use a Bluebird promise, you need to tell Sinon to do so using .usingPromise().
let redisClient = { hgetallAsync: sinon.stub().usingPromise(bluebird.Promise) };
Documentation Link:
http://sinonjs.org/releases/v4.1.2/stubs/#stubusingpromisepromiselibrary
How can I unit test this knockoutjs binding where I call a certain function 'myValueAccessor' when the element is swiped on my touchpad?
I am also unsure what the unit should or is able to test at all here.
It would be ok for the first time to assert wether myValueAccessor is called.
But how can I trigger/imitate or should I say mock... the swiperight event?
ko.bindingHandlers.tap = {
'init': function (element, valueAccessor) {
var value = valueAccessor();
var hammertime1 = Hammer(element).on("swiperight", function (event) {
$(element).fadeOut('fast', function () {
value();
});
});
}
};
self.myValueAccessor = function () {
location.href = 'set a new url'
};
UPDATE
I have put here my unit test with mocha.js
I can outcomment the 'value()' in the binding but still the test succeeded thats odd.
Is it not correct to put this (as a test):
function (element,args) {
alert('assertion here');
}
as a 3rd parameter into the ko.test function?
ko.bindingHandlers.tap = {
'init': function (element, valueAccessor) {
var value = valueAccessor();
var hammertime1 = $(element).on("swiperight", function (event) {
$(element).fadeOut('fast', function () {
//value();
});
});
}
};
// Subscribe the swiperight event to the jquery on function
$.fn.on = function (event, callback) {
if (event === "swiperight") {
callback();
}
};
// Subscribe the fadeOut event to the jquery fadeOut function
$.fn.fadeOut = function (speed, callback) {
callback();
};
ko.test("div", {
tap: function () {
assert.ok(true, "It should call the accessor");
}
}, function () {
});
UPDATE:
custom.bindings.js:
define(['knockout','hammer'], function (ko,Hammer) {
return function Bindings() {
ko.bindingHandlers.tap = {
'init': function (element, valueAccessor) {
var value = valueAccessor();
var hammertime1 = Hammer(element).on("swiperight", function (event) {
$(element).fadeOut('fast', function () {
value();
});
});
}
};
};
});
unittest.js:
how can I connect this code to knockout in my test?
UPDATE
The Bindings is injected via require.js from my bindings.js file:
describe("When swiping left or right", function () {
it("then the accessor function should be called", function () {
ko.bindingHandlers.tap = new Bindings();
Hammer.Instance.prototype.on = function (event, callback) {
if (event === "swiperight") {
callback();
}
};
$.fn.fadeOut = function (speed, callback) {
callback();
};
var accessorCalled = false;
ko.test("div", {
tap: function () {
accessorCalled = true;
}
}, function () {
assert.ok(accessorCalled, "It should call the accessor");
});
});
});
bindings.js
define(['knockout','hammer'], function (ko,Hammer) {
return function () {
return {
'init': function (element, valueAccessor) {
var value = valueAccessor();
var hammertime1 = Hammer(element).on("swiperight", function (event) {
$(element).fadeOut('fast', function () {
value();
});
});
}
};
};
});
myviewmodel.js
...
ko.bindingHandlers.tap = new Bindings();
...
You can check my binding collection for how to test
https://github.com/AndersMalmgren/Knockout.Bindings/tree/master/test
This is my function that all my tests using
ko.test = function (tag, binding, test) {
var element = $("<" + tag + "/>");
element.appendTo("body");
ko.applyBindingsToNode(element[0], binding);
var args = {
clean: function () {
element.remove();
}
};
test(element, args);
if (!args.async) {
args.clean();
}
};
edit: Sorry forgot mocking, you just do
$.fn.on = function() {
}
I do not know what exact logic you want to test in that code since there hardly is any, but something like this
http://jsfiddle.net/Akqur/
edit:
May you get confused where i hook up your binding? Its done here
{
tap: function() {
ok(true, "It should call the accessor");
}
}
I tell ko to hook up a "tap" binding and instead of hooking in up to a observable I use a mocking function, when your custom bindnig calls value() from the fadeout function the test assert will fire
edit:
Maybe this approuch makes more sense to you?
http://jsfiddle.net/Akqur/5/
Note that it only works if your code is executed synchronous
edit:
Here i use the third argument of ko.test
http://jsfiddle.net/Akqur/8/