Testing a $interval with Jasmine in PhantomJS - javascript

It appears that my interval is never triggered.
I have a directive which contains a $interval and I want to test it. I've removed all the directive-related code and added this piece instead in its controller:
window.called = 0;
window.interval = $interval(function () {
window.called++;
console.log('interval ' + window.called); // 4
}, 10);
console.log('initialized'); // 1
The test looks like this:
describe('myDirective', function () {
beforeEach(module('myModule'));
beforeEach(function($compile, $rootScope) {
/* ... compile element in its own scope ... */
});
it('should run the interval', function () {
console.log(window.interval); // 2
waitsFor(function () {
console.log('tick'); // 3
return false;
}, 1000);
});
});
This is a dumb test. The waitsFor method actually returns false all the time, for debugging purposes. But this is all I see in the console:
initialized // 1
Object: {then: ..} // 2
tick // 3
tick // 3
tick // 3
tick // 3
..
and eventually the test failure. I never see a single interval in the logs. Is there something wrong with my code in general or is there something particular to Jasmine/PhantomJS that I'm missing?

$interval has a mock implementation in angular-mocks.
Make sure you are using a version of angular-mocks that matches your angular version.
The mock version of $interval has a flush method for controlling ticks.
See ngMock.$interval
See this fiddle with a demonstration:
//--- CODE --------------------------
angular.module('myModule', []).service('myModuleService', ['$interval', function ($interval) {
var called = 0;
$interval(function () {
called++;
}, 10);
this.getCalled = function () {
return called;
}
}]);
// --- SPECS -------------------------
describe('test $interval', function () {
it('calls the interval callback', function () {
var service, $interval;
angular.mock.module('myModule');
angular.mock.inject(function (myModuleService, _$interval_) {
// Initialize the service under test instance
service = myModuleService;
$interval = _$interval_;
});
expect(service.getCalled()).toEqual(0);
$interval.flush(11);
expect(service.getCalled()).toEqual(1);
$interval.flush(10);
expect(service.getCalled()).toEqual(2);
});
});

Related

How to define a sub method using "prototype"?

When I define a javascript class with methodes and submethodes this way it works:
function Controller () {
this.OrdersSyncFreq = 3000; //ms
this.syncOrders = function () {};
this.syncOrders.start = function () { console.log("start was called"); };
this.syncOrders.stop = function () { console.log("stop was called"); };
}
But how can I define the function Controller.syncOrders.start() later using "prototype"? Something like this does not work:
Controller.prototype.syncOrders.stop = function () {
console.log("The NEW stop was called");
}
Looking a bit more around, i found out it can be written like this:
function Controller () {
this.OrdersSyncFreq = 3000; //ms
this.syncOrders(); // have to be called at init to make sure the definitions of start and stop will be active.
}
Controller.prototype.syncOrders = function () {
this.syncOrders.start = function () {
console.log("Start was called, frequence is: ",this.OrdersSyncFreq);
}.bind(this); // .bind(this) is needed to have access this of your controller instance
this.syncOrders.stop = function () {
console.log("Stop was called, frequence is: ",this.OrdersSyncFreq);
};
}
// run the code
var app = new Controller();
app.syncOrders.start(); // console: Start was called, frequence is: 3000
app.syncOrders.stop(); // console: Stop was called, frequence is: undefined
The methodes of syncOrders - Start() and Stop() do not need to be prototyped, because syncOrders will not instantiated.
Anyhow I'm not sure if it really make sense to do it like this. I did it only because of the namespacing. may be it is better to use something more simple like syncOrdersStart() and syncOrdersStop() instead.

How can you avoid prevent a beforeEach from running before one particular it block?

describe('1', function () {
beforeEach(function () {
// do this before each it EXCEPT 1.5
});
it('1.1', function () {
});
it('1.2', function () {
});
it('1.3', function () {
});
it('1.4', function () {
});
it('1.5', function () {
// beforeEach shouldn't run before this
});
});
I'd like to prevent a beforeEach from running before it block 1.5. How can I do that?
Option 1
I would suggest using nesting your describes, e.g.:
describe('1', function () {
describe('1 to 4', function () {
beforeEach(function () {
// do this before each it EXCEPT 1.5
});
it('1.1', function () {
});
it('1.2', function () {
});
it('1.3', function () {
});
it('1.4', function () {
});
});
describe('only 5', function () {
it('1.5', function () {
// beforeEach shouldn't run before this
});
});
Behind the scenes describe will register the beforeEach function which will get called for all itFunctions if it exists.
Option 2
The it functions will be called sequentially so you could also use a closure to control when beforeEach gets run - but it's a bit hacky - e.g.:
describe('1', function () {
var runBefore = true
beforeEach(function () {
// do this before each it EXCEPT 1.5
if (runBefore) {
// actual code
}
});
// functions removed for brevity
it('1.4', function () {
runBefore = false;
});
it('1.5', function () {
// beforeEach shouldn't run before this
// turn it back on for 1.6
runBefore = true;
});
});
You can achieve that by avoiding nesting when you're testing. The idea is to avoid unnecessary abstraction and instead extract some function(s) that will set up your test case, and then call this function(s) wherever it's necessary.
This leads to code that is more readable and easier to maintain. Instead of figuring out what is happening in a test case by following all the nested beforeEach calls, you can simply read it line-by-line. And it makes your problem trivial to solve:
const setupTestCase = () => {
// put the code here, instead of in beforeEach
// if you're doing multiple actions, put them in separate functions and call them one by one
// this makes your test more readable and easier to maintain
};
describe('1', function () {
it('1.1', function () {
setupTestCase();
// do test stuff
});
it('1.2', function () {
setupTestCase();
// do test stuff
});
it('1.3', function () {
setupTestCase();
// do test stuff
});
it('1.4', function () {
setupTestCase();
// do test stuff
});
it('1.5', function () {
// here we simply don't call setupTestCase()
// do test stuff
});
});
PS. also in many cases you don't need that top-level describe block and can make your code more readable and save yourself one level of nesting by simply moving each top-level describe into a separate file.

Reset module in unit tests

I have a requirejs module created with the following pattern:
// foo.js
define(function(){
var x = 0;
function doStuff(){
return ++x;
}
return { doStuff: doStuff };
});
And a QUnit test which looks something like this:
// testfoo.js
define(['QUnit, foo'], function(QUnit, foo){
function setup(){
//...?
}
function teardown(){
//...?
}
function runTests(){
QUnit.test('foo counter remains at 1 on multiple tests', function(assert){
assert.equal(foo.doStuff(), 1); // this will work
});
QUnit.test('foo counter remains at 1 on multiple tests', function(assert){
assert.equal(foo.doStuff(), 1); // this obviously won't
});
}
return runTests;
});
How can I reset foo for each test?
I would like to keep foo a revealing module, i.e. not converting it to a constructor function with an altered prototype.
I tried var foo = require('foo');, but since requirejs is AMD based, it will complain about things getting loaded in the wrong order.
I suggest checking out SquireJS to create an isolated context for your tests. Squire is designed to inject mock dependencies by creating an isolated RequireJS context. A side effect of this is that the 'foo' library will be reload each time you call injector.require(), resetting the state of your library. The only downside is that your tests will need to be asynchronous.
// testfoo.js
define(['Squire', 'foo'], function (Squire, foo) {
'use strict';
QUnit.start();
QUnit.module('foo', {
setup: function () {
},
teardown: function () {
}
});
QUnit.test('Testing foo counter in main context.', 2, function (assert) {
assert.equal(foo.doStuff(), 1); // this will work
assert.equal(foo.doStuff(), 2); // this should work also.
});
QUnit.test('Testing foo counter in context created by Squire.', 1, function (assert) {
var done = assert.async(),
injector = new Squire();
injector.require([
'foo'
], function (foo) {
assert.equal(foo.doStuff(), 1); // this will work.
done();
});
});
});
I've posted a sample project here: qunit-squirejs
While this certainly isn't the cleanest way about it, by saving the function as a string, and recreating the function before each test, you can accomplish the same effect.
var fooString = foo.toString();
QUnit.testStart(function() { eval('foo = ' + fooString});

Delay gulp-watch execution

I am using gulp-watch to monitor file changes and I have code that look something like this:
watch('public/**/*.js',function(){
runSequence('compressjs','browser-sync','jshint');
});
It works fine. But because it run the task every-time as soon as there is changes to the file, it causes repeat task execution when there is more than 1 file changed.
How can I make the delay to task execution so that when there is more than 1 file changes in a extreme short period of time, it only execute the task once and only execute after the last file changes done?
Taken from: https://remysharp.com/2010/07/21/throttling-function-calls#comment-216435
Try this:
function debounce(fn, delay) {
var timer = null;
return function () {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
};
}
watch('public/**/*.js',function(){
debounce(runSequence('compressjs','browser-sync','jshint'), 500);
});
In Gulp 4, gulp.watch supports setting a delay. See my answer here for the full low-down.
After much searching and many failures using debounce, debounce watch, I came up with a simple solution where my function 'buildAngularApp' is the equivalent of 'runSequence'. Here is the code example:
//the files to watch
var backendModules = ['**/*.min.js']
var delay = 2000;
/*
The watched build task
*/
gulp.task('watchBuild', function () {
console.log('Watching: ' + backendModules);
gulp.watch(backendModules,
function () {
setTimeout(function () {
console.log('Timer ' + delay + ' Reached');
return buildAngularApp();
}, delay);
});
});
/*
The non watched task to build. calls the same build function
*/
gulp.task('build', function () {
return buildAngularApp();
})
/*
The gulp task wrapped in a function
*/
function buildAngularApp() {
return gulp.src(backendModules)
.pipe($.useref())
.pipe($.sourcemaps.init())
.pipe($.concat('app.js'))
.pipe($.sourcemaps.write('.'))
.pipe(gulp.dest('lib/js'))
.pipe($.size({
title: path.join('lib/js'),
showFiles: true
}));
}

mocha nesting/replicating tests

Given a data structure that satisfies some invariants, I would like to test the state of an instance of the data structure after various operations. What is the best way to do this?
describe('data-structure', function() {
var x;
beforeEach(function() {
x = getDataStructure();
});
describe('satisfies invariants', function() {
// run tests on 'fresh' x
it('should ...', function() {
// ...
});
// ...
});
describe('operation 1', function() {
it('should preserve invariants', function() {
x.doSomething();
// run 'satisfies invariants' tests on modified x
});
});
});
I thought about using an afterEach hook, but I do not think x is preserved there?
afterEach(function() {
// somehow run 'satisfies invariants' test
});
It maybe be that I can refactor 'satisfies invariants' into a method, but it would be nice if mocha could report which invariant-tests failed for each operation, e.g.
data-structure
satisfies invariants
should satisfy invariant 1 ...
...
operation 1
should satisfy invariant 1 ...
...
operation 2
should satisfy invariant 1 ...
...
Edit
Using the structure
describe('data-structure', function() {
var x;
describe('satisfies invariants', function() {
afterEach(function() {
it('should satisfy invariant 1', function() {
// x.value === a again
// ...
});
// ...
});
it('should work after operation 1', function() {
x = getDataStructure(); // x.value === a
x.operation1(); // x.value === b
});
it('should work after operation 2', function() {
x = getDataStructure();
x.operation2();
});
// ...
});
});
does not seem to preserve the changes to x.
It follows an example, let me know if I forget something of what we have discussed:
var assert = require('assert');
describe('data-structure', function() {
var x;
beforeEach(function() {
// freshly created data structure for each describe block below
x = getDataStructure;
});
describe('satisfies invariants', function() {
after(function() {
// it executes those tests only once after all the it block below
assert(x); // put your tests here
});
it('op 1.1', function() {
do_something_on(x);
});
it('op 1.2', function() {
// keep in mind that x is the same instance of the previous test
do_something_else_on(x);
});
// so on
});
describe('satisfies something else', function() {
// here you have a new instance of x, because of the outer beforeeach
after(function() {
// it executes those tests only once after all the it block within this describe block
assert(x); // put your tests here
});
it('op 2.1', function() {
do_something_on(x);
});
it('op 2.2', function() {
// keep in mind that x is the same instance of the previous test, but not the one used in 1.2
do_something_else_on(x);
});
// so on
});
// so on
});
This piece of code should give you an idea of which instance is accessible and where.
If it lacks something, let me know and I'll have a go to fix it.
The Problem
Mocha does not support putting it inside a hook like you do in your last snippet. (afterEach is a hook). In some trivial cases you may get the desired behavior but that's just luck. Once you move on to more complicated test suites, you won't get the behavior your expect.
Moreover, I suggest that afterEach is the wrong place for that kind of test. You should use the hooks only to setup and tear down your test environment and not for performing assertions on the state of your code. Mocha treats any failure in a hook as "the test suite is broken, abort!!" rather than as a test failure. Look at this example, for instance:
var assert = require('assert');
describe("test", function () {
var x;
beforeEach(function () {
x = { foo: 'something' };
});
afterEach(function () {
assert(x.foo === 'something');
});
it("one", function () {});
it("two", function () {
x.foo = 'something else';
});
it("three", function () {});
});
In theory there's no reason test three should not run but when the failure occurs in the afterEach hook after test two is run, Mocha will just stop running tests there. The output (omitting the final stack trace) is:
test
✓ one
✓ two
1) "after each" hook
2 passing (14ms)
1 failing
Note how two is marked as passing but the hook failed. And note how three is never even attempted. As soon as there is a failure in a hook, Mocha stops right there.
The Solution
You should just create a function that you call from each test to test your invariants. For instance:
var assert = require('assert');
describe("test", function () {
var x;
beforeEach(function () {
x = { foo: 'something' };
});
function testInvariant() {
assert(x.foo === 'something');
}
it("one", function () {
testInvariant();
});
it("two", function () {
x.foo = 'something else';
testInvariant();
});
it("three", function () {
testInvariant();
});
});
If you run Mocha on the code above, you'll get (again, omitting the final stack trace):
test
✓ one
1) two
✓ three
2 passing (10ms)
1 failing
two was marked as failed and Mocha moved on to run three, which was successful.
If you don't want to write testInvariant() in each test you could create a function that adds it for you. For instance:
var assert = require('assert');
describe("test", function () {
var x;
beforeEach(function () {
x = { foo: 'something' };
});
function makeTest(name, fn) {
it(name, function () {
fn();
assert(x.foo === 'something');
});
}
makeTest("one", function () {
});
makeTest("two", function () {
x.foo = 'something else';
});
makeTest("three", function () {
});
});
This produces the same output as the previous code snippet.

Categories