Jasmine spyOn not working - unit-testing

I am fairly new to Jasmine, and I have to test a few function calls:
JS CODE
object1 = {
function1: function() {
// object1.function2 is a callback
object2.someFunction("called", object1.function2)
},
function2: function() {
// code to do stuff
}
}
TEST CODE
describe("test suite", function(){
it("test1", function(){
spyOn(object1, "function2");
object1.function1();
expect(object1.function2).toHaveBeenCalled();
});
});
I've tried the above but it fails, and says "Expected spy function2 to have been called". Can somebody help me out with this ? Thanks

You can rewrite the test as follows
describe("test suite", function(){
it("test1", function(done){
spyOn(object1, "function2");
object1.function1();
setTimeout(function() {
expect(object1.function2).toHaveBeenCalled();
done();
});
});
});
Your test code needs to have asynchronous testing since the callback will never be called immediately. You can add another async call which will be placed after your object1.function2 in the call stack and by the time the function inside setTimeout is executed it would have already called the object1.function2 and once assertion is made you can end the async test by calling done().

Related

Jest coverage testing global objects and inverse condition

I've got a global object on window that has a function. In my code I'm writing this:
if (window.foo) {
window.foo.bar();
}
In the tests, when window.foo has a value I assert that window.foo.bar has been called. Easy enough.
Jest coverage is complaining that I'm not testing the negative value, i.e. when window.foo is undefined. But I've been struggling to work out what to assert on.
What I'd like to do - is mock window.foo and assert that it is only called once, when we check whether it has a value or is undefined (i.e. the call to window.foo.bar is never made.
I'm trying to mock the global window object and return an object but I'm getting confused as to how to mock and spyOn a value when it isn't a function, and then check it has been accessed.
Any help appreciated!
You could use a getter so whenever a property in the object is being accessed inside the getter we could run multiple actions, in our case we just trigger our spy manually.
describe('window.foo', () => {
afterEach(() => {
delete global.foo // make sure you clean your global object after each test
})
it('should be called twice', () => {
const fooSpy = jest.fn();
const barSpy = jest.fn();
Object.defineProperty(global, 'foo', {
configurable: true, // very important or else you can't delete
get() {
fooSpy(); //we manually call our spy so we can assert later
// and we return an object with another spy for our bar function
return { bar: barSpy};
}
});
if (global.foo) {
global.foo.bar()
}
expect(fooSpy).toHaveBeenCalledTimes(2);
expect(barSpy).toHaveBeenCalledTimes(1);
});
it('should be called once', () => {
const fooSpy = jest.fn();
Object.defineProperty(global, 'foo', {
writconfigurableable: true,
get() {
fooSpy(); // we trigger the spy manually
// we return undefined
return undefined;
}
});
if (global.foo) {
global.foo.bar()
}
expect(fooSpy).toHaveBeenCalledTimes(1);
});
});
You can see it working in here

Test when eventEmitter subscription has finished

I have a function like:
public openCamera = (obj) => {
this._nativeCamera.getPicture()
.subscribe((selectedImage) => {
obj.avatar = selectedImage;
});
};
Now I want to test this function.
it('should pass', function(){
let e = new EventEmitter();
let obj = {};
spyOn(mockNativeCamera,'getPicture').and.callFake(()=>e);
sut.openCamera(obj);
e.emit('Hello Dolly');
expect(obj.avatar).toBe('Hello Dolly'); // This should be checked after subscription has finished, but happens synchronously and thus fails
});
Problem is that although this test should be async, I do not know how to hook to the execution of the asynchronous execution.
I thought of subscribing to the event emitter inside the test, but there is no guarantee which subscription callback will be called first, so this sounds like a bad idea.
Any thoughts?

Mocha test will not resolve promise using Sinon stub

I'm using Mocha to test a method that has an asynchronous method inside of it. I'm stubbing that dependency with Sinon, and returning a resolved promise. But the promise is never resolved, or at least when the assertion is run it hasn't resolved yet.
Here is the method under test
function identify(traits) {
//THIS GETS CALLED SUCCESSFULLY
userService.get().then(function(user){
//CODE NEVER REACHES HERE
userService.set(user).then(function(){
//do something
}, function(){
//handle error
});
});
}
And here is the test
it('should identify a valid email address', function(){
var user = { email: 'test#example.com' };
var getUserStub = sinon.stub(userService, "get");
var setUserStub = sinon.stub(userService, "set");
var userReturn = { email: 'test#example.com', urls: ['http://some.url.com'] };
getUserStub.returns(Promise.resolve(userReturn));
//THE METHOD UNDER TEST
identifyController.identify(user);
sinon.assert.calledOnce(userService.get); //WORKS FINE
sinon.assert.calledOnce(userService.set); //FAILS
getUserStub.restore();
});
The assertion on userService.set fails, it says it was called 0 times. What am I doing wrong?
I've finally found the problem.
Promises are essentially asynchronous, but sinon calls are synchronous.
See this code pen.
What happens:
You call identifyController.identify(user);
It will call get, which returns a promise, which is asyncrhonous.
The main thread of the program will still be running, so your both sinon.assert.calledOnce calls will happen in sequence, synchronously
By the time get resolves itself and calls set, because promises are non-blocking, the assertion will already have been executed, so it will fail.
So, you can do like this:
function identify(traits) {
return userService.get().then(function(user){
console.log('get');
userService.set(user).then(function(){
console.log('set');
//do something
});
});
}
And change this:
identify(user).then(function(){
sinon.assert.calledOnce(myObj.get); //WORKS FINE
sinon.assert.calledOnce(myObj.set); //WORKS FINE NOW
});

Injection in the setUp() method causes the framework not to wait for the Future to complete

I am testing an AngularDart component. I am trying to fetch the template and put it in TemplateCache in the setUp() method. For this I need to inject the template cache. However the inject in the setUp() makes the framework continue to the test method and not waiting for the Future to complete. Here is a simplified example.
import 'dart:async';
import 'package:angular/angular.dart';
import 'package:mock/mock.dart';
import 'package:unittest/unittest.dart';
import 'package:angular/mock/test_injection.dart';
import 'package:angular/mock/module.dart';
import 'package:di/di.dart';
class MyTest {
static main() {
group("SetUp with future that waits", () {
setUp(() {
return new Future.value("First").then((_) => print(_));
});
test("Welcome to the world of tomorrow!", () {
print("Second");
});
});
group("SetUp with future that doesn't wait", () {
setUp(inject((Injector inject) { // injection causes the test to not wait
return new Future.value("First").then((_) => print(_));
}));
test("Welcome to the world of tomorrow!", () {
print("Second");
});
});
}
}
In the console you can see the printed messages: First, Second, Second, First.
I think it must be that the inject is not returning the Future. What else can I do to both have the framework injecting objects that I need and waiting for the Future in the setUp()?
This is what I needed. The mistake was trying to return something from the inject itself. It is actually as simple as this:
setUp(() {
// ...
inject((Injectable injectable) {
// inject the objects here and save them in variables
});
// work with the variables
return new Future.value("First").then((_) => print(_));
});

Qooxdoo: How to call MMock.verify() in an asynchronous test

I'm trying to use qx.dev.unit.MMock.verify() in an asynchronous situation effectively the same as this:
, test_no_output_from_verify: function () {
var mocker = this.mock({ callMeOnce: function () { } });
mocker.expects('callMeOnce').once();
qx.event.Timer.once(function () {
mocker.verify();
this.resume();
}, this, 100);
this.wait(1000);
}
I find that, when the verify() call throws an exception (because the callMeOnce function was not called), that exception is swallowed by the Test Runner. It carries on waiting for the 1000ms timeout to elapse, and then throws the standard timeout exception: 'Asynchronous Test Error: Timeout reached before resume() was called.'.
Is there any way that I can make Test Runner halt immediately and display the exception thrown from mocker.verify() instead?
==============================
EDIT: Reading the manual one more time after posting the question shows my mistake. The correct technique is to put the verify() call inside the resume(), thus:
, test_no_output_from_verify: function () {
var mocker = this.mock({ callMeOnce: function () { } });
mocker.expects('callMeOnce').once();
qx.event.Timer.once(function () {
this.resume(function () {
mocker.verify();
});
}, this, 100);
this.wait(1000);
}
This works as expected and I get the ExpectationError: Expected callMeOnce([...]) once (never called) message inside the Test Runner.