Mocha: Data-driven testing breaks before, beforeEach, after, and afterEach

Created on 26 Dec 2017  Â·  6Comments  Â·  Source: mochajs/mocha

Prerequisites

  • [x] Checked that your issue isn't already filed by cross referencing issues with the common mistake label
  • [x] Checked next-gen ES issues and syntax problems by using the same environment and/or transpiler configuration without Mocha to ensure it isn't just a feature that actually isn't supported in the environment in question or a bug in your code.
  • [x] 'Smoke tested' the code to be tested by running it outside the real test suite to get a better sense of whether the problem is in the code under test, your usage of Mocha, or Mocha itself
  • [x] Ensured that there is no discrepancy between the locally and globally installed versions of Mocha. You can find them with:
    node node_modules/.bin/mocha --version(Local) and mocha --version(Global). We recommend avoiding the use of globally installed Mocha.

Description

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)

Steps to Reproduce

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%

Versions

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.

All 6 comments

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DinisCruz picture DinisCruz  Â·  38Comments

moll picture moll  Â·  46Comments

enobufs picture enobufs  Â·  38Comments

jbnicolai picture jbnicolai  Â·  37Comments

domenic picture domenic  Â·  43Comments