Mocha 'this' in before and beforeEach hooks - javascript

The following test code, written using Mocha.js fails. I expect the someVal to be increased 3 times and equal 3 in the last test. The issue came up in more complex scenario where I used value set in outer before block to set up another in inner beforeEach block. Simplified case:
describe('increasing 3 times', function() {
before(function() {
this.instanceThis = this;
return this.someVal = 0;
});
beforeEach(function() {
return this.someVal += 1;
});
return describe('going deeper', function() {
before(function() {
return this.someVal += 1;
});
beforeEach(function() {
return this.someVal += 1;
});
return it('has increased someVal to 3', function() {
return this.someVal.should.equal(3);
});
});
});

Explanation
I don't know of any version of Mocha that would run the code you show in your question without error. For your code to work, it would have to be written like this:
require("chai").should();
describe('increasing 3 times', function() {
before(function() {
this.someVal = 0;
});
beforeEach(function() {
this.someVal += 1;
});
describe('going deeper', function() {
var parent_ctx = this.parent.ctx;
before(function() {
parent_ctx.someVal += 1;
// The line above is equivalent to this:
// this.test.parent.ctx.someVal += 1;
});
beforeEach(function() {
parent_ctx.someVal += 1;
});
it('has increased someVal to 3', function() {
parent_ctx.someVal.should.equal(3);
// The above line is equivalent to this:
// this.test.parent.parent.ctx.someVal.should.equal(3);
});
});
});
Inside the function passed to describe and the functions passed to the hooks of a describe block (before, beforeAll, etc.) the value of this is a "context" object which is the same for the describe and all of its own hooks (not the hooks of other describe calls nested in it). So when you assign to this, it assigns to the context. If you want to access this context inside nested calls to describe or in tests you have to walk up the tree of describe and test objects.
Solution
I would do it exactly the same way Second Rikudo suggested: use a variable scoped to your uppermost describe call. For the sake of completeness:
require("chai").should();
describe('increasing 3 times', function() {
var someVal;
before(function() {
someVal = 0;
});
beforeEach(function() {
someVal += 1;
});
describe('going deeper', function() {
before(function() {
someVal += 1;
});
beforeEach(function() {
someVal += 1;
});
it('has increased someVal to 3', function() {
someVal.should.equal(3);
});
});
});

this is not what you think it is. this gets redefined in every function() {} block (unless Mocha calls them in some specific way I'm not familiar with).
What you want is to use scope in your advantage:
describe('increasing 3 times', function() {
var someVal; // Initialization.
before(function() {
someVal = 0; //No need to return from before()
});
beforeEach(function() {
someVal += 1;
});
describe('going deeper', function() {
before(function() {
someVal += 1;
});
beforeEach(function() {
someVal += 1;
});
return it('has increased someVal to 3', function() {
someVal.should.equal(3);
});
});
});
Also, you don't need to return so much. In fact, you almost never have to return in test code.

Related

Avoiding a global variable

The purpose of the example code below is to be able to restrict a function from printing something via console.log (a loop in this case) if the function is executed twice.
However, the function uses the global variable "condition" and I want to find a way to avoid this. I've been playing around with workarounds, but to no avail. Also, I have checked sources online, but relate to other more complex examples which are beyond my level. This is a simpler example, but haven't been able to crack this.
Grateful for some guidance. Thanks.
let condition = false;
const testFunc = function (value) {
for (let i = 0; i < 10; i++) {
if (!condition) {
console.log(value + i);
}
}
condition = true;
};
testFunc(5);
testFunc(5);
The usual answer is to create yet another scope to hold the state:
function once(fn) {
let called = false
return function(...args) {
if (!called) {
fn(...args)
called = true
}
}
}
const test = once(function() {
console.log('hello')
})
test() // hello
test() // nothing
Thanks for your feedback - I considered the use of using closure by way of returning a function within another.
Would this be a viable option in order to avoid a global variable? Note that "func" needs to be declared globally -
const testFuncEncaps = function (value) {
let trueOrFalse = false;
return function () {
for (let i = 0; i < 10; i++) {
if (!trueOrFalse) {
console.log(value + i);
}
}
trueOrFalse = true;
};
};
let func = testFuncEncaps(5);
func();
func();

What's the reason of the following JavaScript syntax when using closures?

Studying about closures, I looked at the Developer's Mozilla article about it and saw the code below:
var counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
};
})();
console.log(counter.value()); // 0.
counter.increment();
counter.increment();
console.log(counter.value()); // 2.
counter.decrement();
console.log(counter.value()); // 1.
I'm confused about how the function is attributed to the variable counter, because the function is initially envolved by those parentheses, and after all, there are also two unreaseble parentheses together... I just wondered, what's the reason of that syntax? I certainly would do:
var counter = function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
};
};
But then I got the error
Uncaught TypeError: counter.value is not a function
When I do console.log(counter.value());
Can someone please explain it to me?
What you're looking at is an Immediately Invoked Function Expression or IIFE. This code is creating a function, then immediately calling that function, then assigning the return value of the function to counter. So counter isn't a function, it's an object with three properties: increment, decrement, and value.
The reason that they used an IIFE was to make what's essentially a private variable. privateCounter is only in scope to other code inside that function, which means only increment, decrement, and value can access it.
If they didn't care about making the variable private, the equivalent code would be:
var publicCounter = 0;
function changeBy(val) {
publicCounter += val;
}
var counter = {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return publicCounter;
}
}

Jasmine mock value in if statement test

I have an if-else statement in a function. I want to test both cases. When the instance is initiated, self.count is set to 1. When I run my test, it goes to the false statement. How can I make self.count = 2 to go into the else statement?
Test:
it('verify change', function () {
spyOn(this.instance, 'change').and.callThrough();
this.instance.change('messageBoard');
expect(this.instance.change).toHaveBeenCalled();
});
Javascript:
self.count = 1;
self.change = function change() {
if(self.count <= 1) {
// do stuff
} else {
// do stuff
}
};
I know I can use this.object.method.and.returnValue() to make a method return a value, but I don't know how to do it with variables.
So it seems i do not need to mock the variables. I can just assign it within the test like:
it('verify change', function () {
this.instance.count = 2; // this would nake it go to the else block
spyOn(this.instance, 'change').and.callThrough();
this.instance.change('messageBoard');
expect(this.instance.change).toHaveBeenCalled();
});

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.

jasmine test method is being called as asynchronously

I am trying to test a code snippet using jasmine but its always passing due to Jasmine's it method is being called as asynchronously. Here is my test code
function outer() {
it("| --- BEFORE OUTER ---|", function() {
expect("yes").toEqual("yes");
});
it("outer() is in scope", function() {
expect(typeof outer).toEqual('function');
});
it("inner() is in scope", function() {
expect(typeof inner).toEqual('function');
});
it("a is in scope", function() {
console.log('Why this is running after');
expect(typeof a).toEqual('number');
});
it("b is in scope", function() {
expect(typeof b).toEqual('number');
});
it("c is in scope", function() {
expect(typeof c).toEqual('number');
});
console.log("This is running first");
var a = 1;
function inner() {}
var b = 2;
if (a == 1) {
var c = 3;
}
}
outer();
how to fix this? I want to run it's callback method immediately before running the declaration statements like var a = 1;

Categories