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

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()

Related

Nightwatch correct way to get api result to populate variable then run tests that use that variable

I am new to node and the async way of doing things.
I want to create and run a test suite using nightwatch.js, I have read all the docs and I'm baffled at how to do what I want (been working on it for 3 days already).
Am I thinking about this the wrong way?
module.exports = {
before: function(browser) {
/*
Here I just want to make a web call to an api and get a result and then
store that result in a variable which we will use later in test1 and other test cases
*/
browser.globals.myVariable = resultofsomeapicalll;
//wait here until proceeding
},
after: function(browser) {
browser.end();
},
beforeEach: function(browser) {
},
afterEach: function() {
},
'test1': function(browser) {
browser.url(browser.launchUrl + browser.globals.myVariable, function(result) {
browser.waitForElementPresent('body', 1000);
browser.expect.element("#something").to.be.present;
browser.saveScreenshot('./screenshots/' + browser.currentTest.module + '/' + browser.currentTest.name + '.png');
});
},
};
To perform asynchronous task in the Nightwatch.JS before[Each] or after[Each] hooks, you need to pass an callback argument to the function, which you trigger once the job is done.
In below example, it would be an API Call using Axios library;
module.exports = {
before: function(browser, done) {
axios.get('https://example.com/api?ID=12345')
.then(function (response) {
browser.globals.myVariable = response;
done();
})
.catch(function (error) {
done(error);
});
},
after: function(browser) {
browser.end();
},
beforeEach: function(browser) {
},
afterEach: function() {
},
'test1': function(browser) {
console.log()
},
};
Controlling the done invocation timeout
By default the done invocation timeout is set to 10 seconds (2 seconds
for unit tests). In some cases this might not be sufficient and to
avoid a timeout error, you can increase this timeout by defining an
asyncHookTimeout property (in milliseconds) in your external globals
file (see below for details on external globals).
http://nightwatchjs.org/guide/#asynchronous-before-each-and-after-each-
Best regards,
Riku

Jasmine 2 Spec has no expectations

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();
});
});

How can I reuse mocha tests so I don't have to repeat myself?

I'm trying to write some tests in mocha that I'm going to automate in several browsers via BrowserStack. Rather than repeat the test.it code for each browser, I want to keep my code DRY and wrap a few test.it blocks in a function and just call that function inside of test.describe, like this (the actual test details are unimportant);
function runTests(driver) {
test.it('form works', function() {
var result = testForm(driver, '#formId', 'test#test.com');
return 'Expected Result' === result;
});
}
test.describe('Tests for IE 9', function() {
var driver;
test.before(function() {
var capabilities = {
'browser' : 'IE',
'browser_version' : '9.0'
};
driver = setupDriver(capabilities);
});
runTests(driver);
test.after(function() { driver.quit(); });
});
test.describe('Tests for IE 10', function() {
var driver;
test.before(function() {
var capabilities = {
'browser' : 'IE',
'browser_version' : '10.0'
};
driver = setupDriver(capabilities);
});
runTests(driver);
test.after(function() { driver.quit(); });
});
But since this code is async, driver is not defined when runTests() is called, so it fails. How can I structure this so that I don't have to repeat the test.it blocks for each browser?
I would structure it like this:
function makeTests(kind, version) {
describe("Tests for " + kind + " " + version, function () {
var driver;
before(function() {
var capabilities = {
'browser' : kind,
'browser_version' : version
};
driver = setupDriver(capabilities);
});
it('form works', function() {
var result = testForm(driver, '#formId', 'test#test.com');
if ('Expected Result' !== result)
throw new Error("failed!");
});
// Add more tests here...
after(function() { driver.quit(); });
});
}
makeTests('IE', '9');
makeTests('IE', '10');
I've used describe and it directly in the code above rather than test.describe, etc. I suppose your test environment wraps Mocha calls or that you are using an interface I'm not familiar with.
Mocha also uses concept of injecting "done" callback for async tests. So if you specify this callback in "beforeEach", "it" and "afterEach", Mocha will inject it and don't execute next method until this callback is called. So I would change your code this way:
function runTests(driver, done) {
test.it('form works', function(done) {
var result = testForm(driver, '#formId', 'test#test.com');
return 'Expected Result' === result;
done();
});
}
test.describe('Tests for IE 9', function() {
var driver;
test.before(function(done) {
var capabilities = {
'browser' : 'IE',
'browser_version' : '9.0'
};
driver = setupDriver(capabilities);
done();
});
runTests(driver, done);
test.after(function(done) {
driver.quit();
done();
});
});
You can find more information about asynchronous testing with mocha here.

Unit testing actions in ember controller that return promises

I have a controller that performs an asynchronous operation, which I would like to test:
/*globals Ember, momnent*/
import { raw as icAjaxRaw } from 'ic-ajax';
//...
actions: {
foo: function() {
var req = icAjaxRaw({
type: 'POST',
url: ApiUtils.apiUrl+'/dofoo',
processData: false,
});
return req.then(
function resolve(result) {
console.log(result.response);
this.set('fooLastDoneAt', moment());
}.bind(this)
);
},
... and in the tests:
test('actions.foo', function() {
expect(2);
var ctrl = this.subject();
var model = {
fooLastDoneAt: moment().add(-10, 'days'),
};
ctrl.set('model', model);
ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), true, 'initial');
ctrl.send('foo');
ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), false, 'updated date');
});
However, this inevitably results in an error being thrown, in another, unrelated, test case:
"Uncaught Error: Assertion Failed: calling set on destroyed object"[
which must be occurring because this.set('fooLastDoneAt', moment()); is executed after this test case has finished, and the test runner has done a teardown for this module, and gone on to the next one; while the action is still executing.
Is there a way for me to wait for an action to complete, asynchronously, before moving on to the next step the unit test?
#kingpin2k suggests this solution,
where you pass in a promise deferred object into the action.
However, in my app, the app itself would never do this,
and it seems like a fundamental problem if I need to modify my app source
just so that it can be tested -
especially since it adds added complexity.
Are there any other ways to make the test execution wait for the action to complete?
I would go for QUnit start() stop() functions.
Here is example of using taken from QUnit documentation:
QUnit.test( "a test", function( assert ) {
QUnit.stop();
asyncOp();
setTimeout(function() {
assert.equals( asyncOp.result, "someExpectedValue" );
QUnit.start();
}, 150 );
});
Also ember-qunit library covers this with then.
Here is example for ember-qunit
test('actions.foo', function() {
expect(2);
var ctrl = this.subject();
var model = {
fooLastDoneAt: moment().add(-10, 'days'),
};
ctrl.set('model', model);
ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), true, 'initial');
ctrl.send('foo').then(function(){
ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), false, 'updated date');
});
});
I didn't test the code so I hope it solves your problem

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