Avoid confusing JavaScript Mocha test bugs
Posted: 2016-07-13
The Problem
- You have a global
this.fixture
that you use as the default DOM for testing - You have nested describe blocks that redefine
this.fixture
in their ownbeforeEach
blocks for specific cases - Your component attaches events to the DOM in the fixture (important!)
- You consistently tear down the test fixture in a global
afterEach
. - Most of your tests pass except one which behaves unexplainably weird
- When you add a
console.log
to debug the problem you notice it gets called multiple times
Why?
Your global afterEach
is only tearing down the default fixture as this
in the describe blocks is a completely different object and so the nested this.fixture
blocks don’t get torn down. Events attached to the DOM for these orphaned fixture prevent them from being garbage collected.
What’s the solution?
Always use a single global (highest containing scope) context variable so that all afterEach blocks can see and tear down the same fixture.
Examples
BAD:
describe('Whatever', function() {
'use strict';
beforeEach(function() {
this.fixture = someDOMthing();
});
afterEach(function() {
this.fixture.cleanupProperly();
this.fixture = null;
});
describe('Test the thing', function() {
beforeEach(function() {
// !!!!!!!!!!!!!!! `this` is an entirely different object to
// parent scope `this`
this.fixture = someTestSpecificDOMthing();
});
// ...
}
GOOD:
describe('Whatever', function() {
'use strict';
// Use the context from this scope throughout so all nested blocks
// see the same objects
var context = this;
beforeEach(function() {
context.fixture = someDOMthing();
});
afterEach(function() {
context.fixture.cleanupProperly();
context.fixture = null;
});
describe('Test the thing', function() {
beforeEach(function() {
context.fixture = someTestSpecificDOMthing();
});
// ...
}
For background info see: http://stackoverflow.com/a/27575978/369171