common mistake labelnode node_modules/.bin/mocha --version(Local) and mocha --version(Global). We recommend avoiding the use of globally installed Mocha.It looks like mocha's before, beforeEach, after, and afterEach hooks do not play nicely with data-driven testing. Mocha offers hooks for executing code before a test or section of tests. Due to its structure as plain JavaScript functions taking callbacks, it also supports data-driven tests, where test cases can be generated dynamically based on expected inputs and outputs.
However, it looks like the two features don't work well together: if I attempt to combine them, I get an opaque error (see below)
Here is a minimal test case: I can run it directly via node_modules/.bin/mocha test/before_after_ddt_test.js:
describe('before/after with data-driven tests', () => {
before(() => console.log('before worked'))
beforeEach(() => console.log('beforeEach worked'))
afterEach(() => console.log('afterEach worked'))
after(() => console.log('after worked'))
[ 'foo' ].forEach((item) => {
it(`works for item ${item}`, () => {
console.log('item is', item)
})
})
})
This works correctly if I "unroll" the forEach loop or drop all the hooks.
Expected behavior: [What you expect to happen]
Expect the following output:
before/after with data-driven tests
before worked
beforeEach worked
item is foo
✓ works for item foo
afterEach worked
after worked
1 passing (6ms)
Actual behavior: [What actually happens]
I get the following error:
maciek@mothra:~/code/herokudata$ node_modules/.bin/mocha test/before_after_ddt_test.js
/home/maciek/code/herokudata/test/before_after_ddt_test.js:16
[ 'foo' ].forEach((item) => {
^
TypeError: Cannot read property 'foo' of undefined
at Suite.describe (/home/maciek/code/herokudata/test/before_after_ddt_test.js:16:3)
at Object.create (/home/maciek/code/herokudata/node_modules/mocha/lib/interfaces/common.js:114:19)
at context.describe.context.context (/home/maciek/code/herokudata/node_modules/mocha/lib/interfaces/bdd.js:44:27)
at Object.<anonymous> (/home/maciek/code/herokudata/test/before_after_ddt_test.js:11:1)
at Module._compile (module.js:635:30)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Module.require (module.js:579:17)
at require (internal/module.js:11:18)
at /home/maciek/code/herokudata/node_modules/mocha/lib/mocha.js:231:27
at Array.forEach (<anonymous>)
at Mocha.loadFiles (/home/maciek/code/herokudata/node_modules/mocha/lib/mocha.js:228:14)
at Mocha.run (/home/maciek/code/herokudata/node_modules/mocha/lib/mocha.js:514:10)
at Object.<anonymous> (/home/maciek/code/herokudata/node_modules/mocha/bin/_mocha:480:18)
at Module._compile (module.js:635:30)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Function.Module.runMain (module.js:676:10)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:608:3
Reproduces how often: [What percentage of the time does it reproduce?]
100%
maciek@mothra:~/code/herokudata$ node_modules/.bin/mocha --version
3.5.3
maciek@mothra:~/code/herokudata$ mocha --version
2.4.5
Reproducible without a transpiler.
I think this is actually due to my lack of understanding of scope in JavaScript. The following code does work:
describe('before/after with data-driven tests', () => {
before(() => console.log('before worked'))
beforeEach(() => console.log('beforeEach worked'))
afterEach(() => console.log('afterEach worked'))
after(() => console.log('after worked'))
const tests = [ 'foo' ]
tests.forEach((item) => {
it(`works for item ${item}`, () => {
console.log('item is', item)
})
})
})
apologies for the noise.
I still don't really understand the behavior though; if someone can explain it I'd appreciate it.
I don't see the difference between the problematic code and the code that works?
I have never seen that before, but if you eliminate the space, and change your original code to this, it works:
describe('before/after with data-driven tests', () => {
before(() => console.log('before worked'));
beforeEach(() => console.log('beforeEach worked'));
afterEach(() => console.log('afterEach worked'));
after(() => console.log('after worked'));
['foo'].forEach((item) => {
it(`works for item ${item}`, () => {
console.log('item is', item)
})
})
})
it's not a scope problem. JS is for some reason interpreting [ 'foo' ] as reading a property off of a variable, instead of declaring an array. JS is surprisingly robust, this is one of the first weird things I have seen in a long time.
Thanks!
yeah if you are transpiling / minifying the code, I assume even more risk that omitting semi-colons will cause problems
Most helpful comment
USE SEMI-COLONS!
https://stackoverflow.com/questions/47984041/why-is-js-interpreting-foo-as-reading-a-property-instead-of-an-array-decla/47984076#47984076