Use of conditional statements in Jasmine tests - javascript

I have two functions I want to test; one that runs only in "modern browsers" the other that runs only in "older" browsers.
I am using Jasmine as my testing framework and Karma to run my tests. Karma will launch many browsers in which all the tests are run.
My problem is that testing ALL my functions in ALL browsers will lead some tests to fail. For example, testing a function that should run only in modern browsers will fail in when tested in IE8.
Code to test:
function getStuffFromSmartBrowser() {
return 'foo';
}
function getStuffFromNotSoSmartBrowser() {
return 'bar';
}
if ('intelligence' in browser) {
getStuffFromSmartBrowser();
} else {
getStuffFromNotSoSmartBrowser();
}
Original test code:
describe("A suite", function () {
it("for smart browsers", function () {
expect(getStuffFromSmartBrowser()).toEqual('foo');
});
});
describe("A suite", function () {
it("for not so smart browsers", function () {
expect(getStuffFromNotSoSmartBrowser()).toEqual('bar');
});
});
In these test cases, one test will fail in one type of browsers while the other test will fail in the other type of browsers.
Alternative test code:
describe("A suite", function () {
if ('intelligence' in browser) {
it("for smart browsers", function () {
expect(getStuffFromSmartBrowser()).toEqual('foo');
});
} else {
it("for not so smart browsers", function () {
expect(getStuffFromNotSoSmartBrowser()).toEqual('bar');
});
}
});
The alternative test code run perfectly well in all tested browsers.
Questions:
A - Is it good practice to use conditional statements in tests?
B - If not, what would be a better approach?

It's generally considered bad practice to have conditionals inside the test code. Outside of the test code is slightly more acceptable and, in the absence of a built-in mechanism to select test specs by browser, your solution is probably the simplest. However, you are coupling your unit tests to the browser-specific implementations.
A "better" approach would be to hide your browser-specific code behind a single function and use feature detection to perform multiple dispatch.
function getStuff() {
if (browserIsSmart()) {
return getStuffFromSmartBrowser();
}
else {
return getStuffFromNotSoSmartBrowser();
}
}
function browserIsSmart() {
return ('intelligence' in browser); // Or whatever
}
Here's where it gets messy. Your two functions have different return values. Ideally you'll want the same return value for all related functions, but this isn't always simple. For example, textarea selection in IE8 uses completely different objects than textarea selection in modern browsers. Sometimes you can hide the details (e.g. using the Strategy Pattern), sometimes you can't.
If you can't make it clean, make it obvious.

Related

difference on behavior when running javascript code with function and IIFE

So let's pretend that I have a index.js file with the following scenarios. The file is imported in the index.html file, and it will trigger what is inside of that file. Can I expect the following snippets to behave differently or behave the same? I see the same results, but might as well ask :)
scenario 1
(() => {
navigator.serviceWorker.register("sw.js").then(() => {
console.log('sw registered');
});
})();
scaneario 2
registerServiceWorker();
function registerServiceWorker() {
navigator.serviceWorker.register("sw.js").then(() => {
console.log('sw registered');
});
}
scenario 3
navigator.serviceWorker.register("sw.js").then(() => {
console.log('sw registered');
});
Sure - they'll behave identically. You might choose one or the other for various reasons, perhaps depending on the context of the code and how you expect the code to evolve. For example, if there might be a need to re-use the function, then you would choose the named function approach. I can't see much point in the ugly verbosity of (1) though.

Sinon alert stub: "Attempted to wrap alert which is already wrapped"

I'm using Sinon 1.14. I would like to suppress all javascript alerts using Sinon's stubs.
Using the latest Chrome version: 42.0.2311.135 m, I get an exception: "Attempted to wrap alert which is already wrapped"
The code below works fine in latest Firefox. I will update with a fiddle.
var hooks = {
beforeEach: function(assert){
this.sandbox = sinon.sandbox.create();
this.sandbox.stub(window, 'alert', function (msg) { return false; });
},
afterEach: function(){
this.sandbox.restore();
}
};
module('example', hooks);
test('example', function(assert){
ok(true, 'does not throw an exception');
});
Updating Sinon from 1.14 to 1.14.1 seems to do the trick. I assume this was a bug?
As a side note, the code runs fine in 1.12 as well.
window.alert is a global function. Every time beforeEach runs it will replace that function with a wrapped function. I guess Sinon prevents you from wrapping a function twice.
You can either make sure to have a setup function that runs only once.
Or modify your code so that you don't have global dependencies (ie. pass in a reference to alert or a delegating window object). This can impact your code architecture a lot. This also shows why it is important to think about testing when designing your architecture.

Ember Data's store promises don't work in quint tests

Update
A bit of context into some quirks of the illustrative code below. StoreProxy exists as a model, created by the ApplicationRouter, that has a reference to the store. This lets other objects access the store directly (for singletons, tests, etc). Example:
MyApp.StoreProxy = DS.Model.extend();
MyApp.ApplicationRoute = U.Route.extend({
model: function () {
return this.store.createRecord('storeProxy');
}
});
Before the route is executed, StoreProxy doesn't have a store property. After, it does. I can only assume this is because of some ember-data magic.
I very well realize your reaction to this may be "Ugh! No! You're doing it wrong!". Noted. We'll move to do it the right way from here over time. That said, this is where the code is now. So, given that, and given this method for getting a reference to the current store, why doesn't the code below call its accept or rejection handlers?
Original question
I'm writing a qUnit unit test for ember. I'm using fixture data. The findAll call on the store isn't resolving or rejecting the promise.
test('Find all in store', function() {
expect(1);
var findPromise;
findPromise = MyApp.StoreProxy.store.findAll('rule');
findPromise.then(function(result) {
console.log('yes');
ok(true);
}, function(error) {
console.log('no');
});
});
I tried using async tests mentioned in this question:
testing ember fixture data with quint but the resolve and reject are never called, so the test hangs indefinitely.
I've also tried placing Ember.run calls around my code, in case it's a weird run loop thing. But to no avail.
asyncTest('Find all in store', 1, function() {
var findPromise;
Ember.run(function() {
findPromise = MyApp.StoreProxy.store.findAll('rule');
findPromise.then(function(result) {
console.log('yes');
ok(true);
start();
}, function(error) {
console.log('no');
start();
});
});
});
The code I'm testing runs fine when I run the application normally (fixture adapter or no), so it feels like something with the test environment.
Any thoughts on what to try? I'm stumped.
The way that you're writing your asynchronous tests is incorrect. Check out QUnit's page on async testing. Your test should look something like this:
asyncTest('Find all in store', function() {
var findPromise = ...;
findPromise.then(function(result) {
start();
ok(result);
}, function() {
start();
ok(false);
});
});
Specifically:
You put an extra parameter in the asyncTest function, which likely causes the test to not run at all.
You're using Ember.Application.store, which is not how you should access your store (and probably isn't even a valid store). I'm not sure what your context is, but you should be getting your store from elsewhere.
You're putting the start() calls after your assertions when they should be before.

How can I have a beforeAll function in Jasmine ? (Not coffeeScript)

I need to know if there is a way to include or use a beforeAll function, or something similar, so I can login to my application and then start testing.
Right now I'm putting my login operations in the first test case ( it ). Which is not a good practice.
If there is a better way to store my login code other then using a beforeAll function please tell me about it.
I'm using pure Jasmine not related to any other framework like coffee-script or others.
Thank you
This is now much easier. As of Jasmine 2.1 (released 14 Nov 2014), there is a beforeAll function built into the framework.
Here are the release notes with everything that was added in 2.1. And here is the documentation explaining beforeAll and afterAll
You can nest as many describe functions as you want. So you can do something like...
describe("General Test", function () {
function login(){
//This code will run once at he beginning of your script
};
login();
beforeEach(function () {
//anything in here will apply to everything in each nested describe
});
describe("Specific Test", function () {
//Applied here
});
describe("Another Specific Test", function () {
//And here
});
});
please use below code and configure your setting in beforeAll statement.
describe("Top", function() {
beforeAll(function() {
console.log("Example 1 Setup");
});
it('xyz',function(){
console.log('Hi!')
});
});
You can add this package that adds a beforeAll() and afterAll() to Jasmine.
https://github.com/nonplus/jasmine-beforeAll

unit testing in javascript: how do you mock? - a (hard for me) example

I just rewrote backbone-mongodb to be really compatible with backbone. The original solution had nice vows for testing, and I would like my code to get tested as well, but simply have no idea how to do it.
Here is an example, I would like to test:
update: function(callback) {
var model = this.model;
this._withCollection(function(err, collection) {
if (err) callback(err);
else {
var attributes = _.clone(model.attributes);
delete attributes['_id'];
collection.update({ _id: new ObjectID(model.id) }, {$set: attributes}, {safe:true, upsert:false}, function(err) {
model.fetch();
callback(null, model.toJSON());
});
}
});
},
This code has nothing special in it. It uses the node-mongodb-native driver, and updates a record in the database. AFAIK, proper testing would mean to at least check that (1) collection.update was called with the given arguments, (2) callback is called when and how it should be, (3) model contains the new data.
With vows I can check (2), but have no idea at all how to check (1). Actually, the same holds for every unit testing framework I know about, qUnit, Jasmine. I'm sure that this can be done somehow, and I'm decided to learn at least one of them, but it's hard to make a choice when you got stuck at the beginning. :)
I know about sinon.js and think that everyting can be tested using mocking all the objects I have until I end up having the collection mocked as well, but this seems to be extremely clumsy. Could someone help me in writing the above tests please, and I'll happy to write out a tutorial of it?
I will use Jasmine for that purpose; I don't how familiar are you using that library, but they have a plugin to use jQuery for writing spec tests, you can load fixtures/templates and run tests on it.
for your particular case, assuming that function is part of MyObj "class", I will write something like:
describe("My object tests", function() {
it("Should update my obj", function () {
var noError, flag = false;
MyObj.update(function (err, model){
flag=true;
noError= err==null;
// or you can do other checks on the result
})
// we wait for 5 sec until get a response (flag==true)
waitsFor(function (){ return flag}, "Timeout on update", 5000);
// check if there are no errors
expect(noError).toBeTruthy();
});
});

Categories