Jasmine 2 Spec has no expectations - javascript

I have the following test:
describe('when invoked', function() {
it('should check something', function() {
_.each(someData, function(obj, index) {
expect(obj[index].lable).toBe('foo');
});
});
});
When I run Jasmine 2.2.0 it get the following error:
Spec 'SpecLabel function when invoked return value should check something' has no expectations.
Am I missing something? In Jasmin 1.x we could do this. Have expect inside a for each, or even a for loop.
How can I fix these type of tests? And what are the docs for these situations? The Jasmine website is not really helpful.

A quick workaround can be refactoring your tests to:
describe('when invoked', function () {
it('should check something', function () {
var success = true;
_.each(someData, function (obj, index) {
success &= obj[index].lable === 'foo';
});
expect(success).toBeTruthy();
});
});

Related

In javascript, how do I copy all properties of an object into a block's variable scope?

Is there a way to add to a function or a block's variable scope in javascript in an automated manner? If so, how?
For instance, let's say I had some unit test code like this:
describe('something something', function () {
// tested module
let myTestedModule;
before(function () {
myTestedModule = rewire('../../path/to/my-tested-module');
});
// tested module dependencies
let someRandomLib;
let myDBAdapter;
let util;
let common;
const restoreFunctions = [];
beforeEach(function () {
restoreFunctions.push(myTestedModule.__set__('someRandomLib', new Mock()));
restoreFunctions.push(myTestedModule.__set__('myDBAdapter', new Mock()));
restoreFunctions.push(myTestedModule.__set__('util', new Mock()));
restoreFunctions.push(myTestedModule.__set__('common', new Mock()));
});
afterEach(function () {
lodash.forEach(restoreFunctions, function (restore) {
restore();
});
});
// tests
it('should do some amazing things', function (done) {
// tested call
myTestedModule.doStuff('foo', 'bar');
// assertions
someRandomLib.asdf.should.be.calledWithExactly('foo');
// done
done();
});
});
Most of this actual code would be repeated in multiple tests, and it's trivial to simplify it to something like this:
describe('something something', function () {
const testEnv = new TestEnvironment({
module: 'myTestedModule',
path: '../../path/to/my-tested-module',
dependencies: ['someRandomLib', 'myDBAdapter', 'util', 'common'],
});
it('should do some amazing things', function (done) {
// tested call
testEnv.myTestedModule.doStuff('foo', 'bar');
// assertions
testEnv.someRandomLib.asdf.should.be.calledWithExactly('foo');
// done
done();
});
});
However, the test would be better in terms of readability if I could omit most of the testEnv indexing. It's just plumbing, not part of the actual test.
So, to get the best of both worlds, what I really wanted to write was something like this:
describe('something something', function () {
setupTestEnvironment({
module: 'myTestedModule',
path: '../../path/to/my-tested-module',
dependencies: ['someRandomLib', 'myDBAdapter', 'util', 'common'],
});
it('should do some amazing things', function (done) {
// tested call
myTestedModule.doStuff('foo', 'bar');
// assertions
someRandomLib.asdf.should.be.calledWithExactly('foo');
// done
done();
});
});
To do this, I need a way to import an object's own properties into a variable scope (i.e. this function's variable scope).
In Python you can achieve this with decorators. In Lua you can do this with _M or setfenv. Is it possible at all in Javascript?
I think this would be a good case for destructuring.
it('should do some amazing things', function (done) {
const {myTestedModule, someRandomLib} = testEnv;
// tested call
myTestedModule.doStuff('foo', 'bar');
// assertions
someRandomLib.asdf.should.be.calledWithExactly('foo');
// done
done();
});

Testing JS callback with timeout using Jasmine

I need to test some code in Angular with Jasmine, but the thing is that I can't do this because of $timeout call. So the code looks like this:
$scope.add = function() {
SomeService.add(id, function() {
$timeout(function() {
$scope.showSuccessMessage();
}, 1000)
}, function() {})
};
So the test code is:
describe('method add', function() {
it('should add', function() {
spyOn(SomeService, 'add').and.callFake(function(id, successCallback, errorCallback) {
spyOn(scope, 'showSuccessMessage');
successCallback();
expect(scope.showSuccessMessage).toHaveBeenCalled();
});
scope.add();
expect(SomeService.add).toHaveBeenCalled();
});
});
And the problem is that because of the timeout call I can't check that showSuccessMessage() has been called. I know about Jasmine's ability to work with timeouts but in that case I can't find a working way because of calling it in the callback.
You can flush your timeout by using $timeout.flush() after calling the original function. That should allow you to access the successCallback.
Also, I would put the spy and expect of the showSuccessMessage outside the other spy
describe('method add', function() {
it('should add', function() {
spyOn(SomeService, 'add').and.callFake(function(id, successCallback, errorCallback) {
successCallback();
});
spyOn(scope, 'showSuccessMessage');
scope.add();
$timeout.flush();
expect(SomeService.add).toHaveBeenCalled();
expect(scope.showSuccessMessage).toHaveBeenCalled();
});
});
Im not very familiar with the workings of angular, I hope this helps:
You can use the done function for asynchronous code:
it('should add', function (done) {
$scope.successCallback = function () {
// successCallback was called
done();
}
$scope.add();
});

Resetting ajax mock calls count in Jest tests

I have test structure represented below, my code uses ajax calls so I'm mocking as represented in the Jest tutorial:
describe('it behavior', function() {
it('is as it is', function() {
jQuery.ajax.mock.calls[0][0].success({
data: []
});
...
});
it('is is not as it was', function() {
jQuery.ajax.mock.calls[1][0].success({
data: [1, 2, 3]
});
...
});
});
What bothers me most is this jQuery.ajax.mock.calls[X][0] in every case, mostly because I made typos or forget to increment call number in mock.
Is it possible to reset mock call count in afterEach callback or some pattern for test organisation in that case? Preferably without any extra test dependencies.
Try this:
describe('something', function() {
beforeEach(function() {
jQuery.ajax = jest.genMockFunction()
})
it('does something', function() {
// do something
})
}

Node Mocha Chai Async - Everything Passing even when it should fail

I was attempting to teach myself to use a Testing framework for automating tests instead of having to do them by hand. After a bit of trial and error, I finally got the unit tests to start passing ... but now, my problem is everything is passing regardless of if it should or not.
Currently I have the following code:
describe('create {authName, authPW}', function() {
it('no name', function() {
init({
path: ':memory:',
callback: function() {
var arg;
arg = {};
//arg['authName'] = 'Name';
arg['authPW'] = 'Pass';
arg['callback'] = function(r) {
// r.should.equal('create error');
r.should.equal('foobar');
done();
};
create(arg);
}
});
});
});
as you can guess ... r should NOT equal 'foobar'
What am I doing wrong here?
When creating async tests with mocha you need to let him know when it is done
describe('an asynch piece of code', function() {
var foo = new bar();
it('should call the callback with a result', function( done ) {
foo.doAsynchStuff( function( result ) {
result.should.be.ok;
done();
});
});
});
If done is present as an argument on the it then mocha will wait for the done to be called. It has a timeout of 2 seconds, that if exceeded fails the test. You can increase this timeout:
it('should resolve in less than 10 seconds', function( done ) {
this.timeout( 10000 );
foo.doAsynchStuff( function( result ) {
result.should.be.ok;
done();
});
}
it('no name', function(done) {
done has to be an argument of the function passed to it()

Why is Jasmine not resetting a spy when spying on $.ajax?

I am trying to spy on $.ajax in Jasmine 2.0 tests. Here is a simplified example (TypeScript) showing my scenario:
describe("first test", () => {
var deferred = jQuery.Deferred();
spyOn($, "ajax").and.callFake((uri: string, settings: JQueryAjaxSettings) => {
return deferred.resolve("ThisIsADummyResult");
});
it("should return dummy result", done => {
$.ajax("http://somedummyserver.net").then(result => {
expect(result).toBe("ThisIsADummyResult");
done();
});
});
});
describe("second test", () => {
var deferred = jQuery.Deferred();
spyOn($, "ajax").and.callFake((uri: string, settings: JQueryAjaxSettings) => {
return deferred.resolve("ThisIsAnotherResult");
});
it("should return another result", done => {
$.ajax("http://somedummyserver.net").then(result => {
expect(result).toBe("ThisIsAnotherResult");
done();
});
});
});
firstTest as well as second test work if I run them alone. However, if I run both tests as shown above, I get the following error message: ajax has already been spied upon.
So my questions are:
Shouldn't the spies be reset by Jasmine after each test automatically? Why doesn't that work in my case?
Is there another way of using spyOn which makes Jasmine reset the spies?
How can I manually reset the spies?
Update: I continued experimenting and found a possible solution myself. If I set up the spies inside of the it spec, both tests run fine. Here is the code for first test showing what I mean:
describe("first test", () => {
it("should return dummy result", done => {
var deferred = jQuery.Deferred();
spyOn($, "ajax").and.callFake((uri: string, settings: JQueryAjaxSettings) => {
return deferred.resolve("ThisIsADummyResult");
});
$.ajax("http://somedummyserver.net").then(result => {
expect(result).toBe("ThisIsADummyResult");
done();
});
});
});
Still, it would be very interesting why the first version does not work. Why does Jasmine not reset the spies in the first version whereas it does in the second one?
For stuff that is used across all tests but you need it reset for each test use 'beforeEach' : http://jasmine.github.io/2.0/introduction.html#section-Setup_and_Teardown
Jasmine does not magically know which lines of your describe body you want reevaluated for each 'it' block.

Categories