I'm testing an angular.js app using karma with sinon-chai. I need to test a code like this:
var sync = function() {
async.then(function() {
// success
}, function() {
throw Error('foo');
});
}
sync is the function I want to test. async is a function returning a $q promise I want to test it fails throwing an error.
My ideal test suit:
describe('unit', function() {
it('should throw an error', function() {
expect(function() {
return sync();
}).to.throw(Error, 'foo');
})
});
But, it fails at afterEach() because the error is thrown on $digest.
How can I achieve this test?
Thank you very much!
Related
I have the following code that needs to be tested in Jasmine
sampleMethod() {
if (this.sampleObject) {
// business logic
} else {
console.error('sampleObject not initialized');
}
}
I had referred to Spying on console.error() with Jasmine to add jasmine test to monitor console.error.
it('should check for console.error', () => {
spyOn(console, 'error');
component.sampleMethod();
expect(console.error).toHaveBeenCalled();
});
However, I'm getting the following error:
Error: Expected spy error to have been called.
SampleObject is undefined. I've also tried adding spyOn to beforeEach. Still, I'm getting the error.
Can you try this to ensure that sampleObject is undefined and try assigning the spy to a variable?
it('should check for console.error', () => {
const errorSpy = spyOn(console, 'error');
component.sampleObject = undefined;
component.sampleMethod();
expect(errorSpy).toHaveBeenCalled();
});
In our mocha tests, sometimes we have bugs and throw exceptions, and when those exceptions are thrown, the subsequent asserts are not called and our tests might pass even though there was something wrong.
// this would pass
it('adsf', async () => {
assert.equal(1,1)
var foo = undefined;
foo.hi(); // throw exception
assert.equal(1,2) // assert not called
});
We tried wrapping this in a try catch, like the following
// this would fail, but not say why
it('adsf', async () => {
try {
assert.equal(1,1)
// var foo = undefined;
// foo.hi();
assert.equal(1,2)
} catch (err) {
assert.fail(err) // if fail, such as the 1,2 case above, the line number of the error is not shown
}
});
but the catch case hides some of the failed assert info. If anyone has any suggestions, it would be appreciated.
The test in your example will not pass. In mocha, the test would fail if the function that is called in a test throws an exception. Example:
const assert = require('assert');
function foo() {
throw new Error('err');
}
describe('test', () => {
it('works', async () => {
foo();
console.log('came here');
});
});
$ npx mocha test.js
test
1) works
0 passing (6ms)
1 failing
1) test
works:
Error: err
at foo (test.js:8:9)
at Context.<anonymous> (test.js:13:11)
at processImmediate (internal/timers.js:439:21)
So, in your example, since foo.hi throws TypeError, it would be caught by mocha and shown as a test failure (the execution won't reach asserts indeed but the test will be shown as failed anyway).
What I suspect happens in your case is throwing in a promise or rejecting a promise, like in one of these examples:
function throwing() {
return new Promise((resolve, reject) => { throw new Error('err'); });
}
function rejecting() {
return new Promise((resolve, reject) => { reject(new Error('err')); });
}
describe('test', () => {
it('works', async () => {
throwing();
rejecting();
console.log('came here');
});
});
$ npx mocha test.js
test
came here
✓ works
[some UnhandledPromiseRejectionWarnings here]
1 passing (6ms)
Both will not be caught by a test because the function executes successfully returning a promise and the test block completes, but the failure occurs later. If your function returns a promise, just await for it in your test to make sure you get the promise result:
describe('test', () => {
it('works', async () => {
await throwing();
await rejecting();
console.log('came here');
});
});
$ npx mocha test.js
test
1) works
0 passing (6ms)
1 failing
1) test
works:
Error: err
at test.js:4:51
at new Promise (<anonymous>)
at throwing (test.js:4:10)
at Context.<anonymous> (test.js:13:11)
at processImmediate (internal/timers.js:439:21)
I have the following async function:
async $onInit() {
try {
this.settings = await this.Service.getSettings(this.companyId);
} catch (error) {
this.uiFeedback.showSystemError('There was an error processing the request.', error);
}
}
I am trying to test if the function displays an error if the async function catches an error. At the moment the only spec which successfully managed to do this was the following:
it('should show error if api call to get availability settings fails', () => {
Company.getSettings = () => {
throw new Error();
};
try {
cmp.$onInit().catch(() => {});
}
catch (error) {
expect(uiFeedback.showSystemError).toHaveBeenCalled();
}
});
So basically i need to add two extra catch blocks within my test to get this test to work. Otherwise i get the following error:
ERROR: 'Unhandled promise rejection', 'error'
Is there a better way to do this?
So it turns out the issue is simply how karma handles errors for async functions. this.uiFeedback was undefined in the $onInit function. However karma did not show the uiFeedback is undefined error until i ran the tests in Chrome and checked the console there. Something for everyone to watch out for when testing async functions with karma jasmine.
I have the following code in an angularjs controller:
async updateGrid() {
const paging = angular.copy(this.gridData.getServerCallObj());
try {
const model = await this.service.get(paging);
this._setGridData(model, true);
this._$rootScope.$apply();
} catch (e){
this._notification.error(this._$rootScope.lang.notifications.unexpectedError);
}
}
I am trying to test this code through jasmin. The following test is run:
it('updateGrid() should should call broadcast when fail', async () => {
spyOn(service, 'get').and.callFake(() => {
return Promise.reject();
});
spyOn($rootScope, '$broadcast').and.callThrough();
await ctrl.updateGrid();
expect(service.get).toHaveBeenCalled();
expect($rootScope.$broadcast).toHaveBeenCalled();
});
My issue is that jasmine return a result for the test with the message "spec... has not expectations." before the function completes! I can continue debugging, after jasmin says the test is done, at his end! Of course, after its done, the line expect(service.get).toHaveBeenCalled(); throws and error with the message: "expect' was used when there was no current spec, this could be because an asynchronous test timed out".
Does anyone knows what am I doing wrong here?
I have a db.js set up to do all my database calls. This is an example of one of the functions that query the database.
db.getUserCount = function () {
return new Promise (function (resolve, reject) {
db.users.count().then(function (result) {
resolve (result);
}, function(e) {
reject (e);
});
});
};
I am pretty new to JavaScript and testing. I have used mocha and chai to test that it resolves like this:
describe('getUserCount', function() {
it('should be fulfilled when called', function() {
return db.getUserCount().should.be.fulfilled;
});
});
How can I test the reject part of the promises. Do I have to use something like sinon or is there some simple way to make the promise fail?
Make db.users.count() call to fail by either causing some change in database entry or in your api.
I ended up using sinon stubs so the other test would still pass.
describe('db.getUserCount rejection test', function() {
sinon.stub(db, 'getUserCount').returns(Q.reject(new Error(errorMessage)));
it('should be rejected when called', function() {
return db.getUserCount().should.be.rejected;
});
it.only('getUserCount responds with correct error message', function() {
return db.getUserCount().catch(function(err) {
expect(err.message).to.equal('Error could not connect to database');
});
});
});