Why can't nested describe() blocks see vars defined in outer blocks?
Solution 1:
The body of a describe
block is executed before the beforeEach
blocks.
This is exactly as expected. The problem is that your var trees
variable is trying to access orchard
before it has been initialized. The body of a describe
block is executed before the beforeEach
blocks. To solve this problem, the third code snippet is the only way to go.
Jasmine will first execute the describe blocks, and then execute the beforeEach blocks before running each test.
Solution 2:
Well you could still initialize variables outside the beforeEach block. I generally do it for constants and still remain DRY without introducing beforeEach blocks.
describe('simple object', function () {
const orchard = {
trees: {
apple: 10,
orange: 20
},
bushes: {
boysenberry: 40,
blueberry: 35
}
};
describe('trees', function () {
const trees = orchard.trees;
it('should have apples and oranges', function () {
expect(trees.apple).toBeDefined();
expect(trees.orange).toBeDefined();
expect(trees.apple).toEqual(10);
expect(trees.orange).toEqual(20);
});
it('should NOT have pears or cherries', function () {
var trees = orchard.trees;
expect(trees.pear).toBeUndefined();
expect(trees.cherry).toBeUndefined();
});
});
});
Solution 3:
Lets take the third code snippet. Further, it can be refactored as below:
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
it ('should have apples and oranges', function() {
expect (orchard.trees.apple).toBeDefined();
expect (orchard.trees.orange).toBeDefined();
expect (orchard.trees.apple).toEqual(10);
expect (orchard.trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
expect (orchard.trees.pear).toBeUndefined();
expect (orchard.trees.cherry).toBeUndefined();
});
});
});
For the new comers to Jasmine, this is how you intrepret the above code :\
-
describe
defines atest suite
. Thetest suite
name here is a user defined simple string, say "simple object". - A
test suite
can itself contain othertest suites
, meaningdescribe
can contain nested suites. - Just like other programming languages,
orchid
is global to all the functions & suites defined withinsimple object
test suite. -
It
block is called aspecification
or aSPEC
.It
blocks contain individual tests. - Just when
Jasmine
executes the test cases, it will first visit theit
blocks meaning it will traverse all theit
block declarations. - When
Jasmine
actually executes test cases, it will check forbeforeEach
function and henceorchard
getstrees
value assigned to it. -
And hence you need not write a beforeEach function, inside a
sub suite
. You can simply ignorebeforeEach (function() { trees = orchard.trees; });
Now compare the latest snippet below with the third snippet above.