Tape: before/beforeEach/after/afterEach

Created on 21 Jan 2014  Â·  15Comments  Â·  Source: substack/tape

Hello :-)

I'm considering using tape for a project requiring IE8 testing, in order to replace chai/mocha.

Is there any way to achieve doing before/beforeEach/after/afterEach to setup fixtures and stubs before running assertions?

Thanks very much :-)

Most helpful comment

For before()/after() you can just use ordinary tests to do setup and teardown:

var test = require('tape');

test('setup', function (t) {
    // setup goes here, call t.end() when finished
});

// your other tests go here...

test('teardown', function (t) {
    // teardown goes here, call t.end() when finished
});

to perform some setup around each test, you can just write a function inline that takes a callback.

All 15 comments

var test = require("tape")

var before = test
var after = test

var test = beforeEach(test, function before(assert) {
    // called before each thing

    // when done call
    assert.end()
})
test = afterEach(test, function after(assert) {
    // called after each thing

    // when done call
    assert.end()
})

before("before all tests", function (assert) {
    // before logic

    // when done call
    assert.end()
})

test("name of test", function (assert) {
    // before logic & beforeEach has run

    // when done with test call
    assert.end()
    // afterEach logic will run
})

after("after all tests", function (assert) {
    // after logic

    // when done call
    assert.end()
})

function beforeEach(test, handler) {
    return function tapish(name, listener) {
        test(name, function (assert) {
            var _end = assert.end
            assert.end = function () {
                assert.end = _end
                listener(assert)
            }

            handler(assert)
        })
    }
}
function afterEach(test, handler) {
    return function tapish(name, listener) {
        test(name, function (assert) {
            var _end = assert.end
            assert.end = function () {
                assert.end = _end
                handler(assert)
            }

            listener(assert)
        })
    }
}

We should put afterEach and beforeEach in a module like tape-before-after

For before()/after() you can just use ordinary tests to do setup and teardown:

var test = require('tape');

test('setup', function (t) {
    // setup goes here, call t.end() when finished
});

// your other tests go here...

test('teardown', function (t) {
    // teardown goes here, call t.end() when finished
});

to perform some setup around each test, you can just write a function inline that takes a callback.

Thanks guys for this very quick follow up. I'll give a try this way.

:cake:

@substack
What do you mean exactly by "write a function inline that takes a callback"?

I'm having trouble setting up asynchronous beforeEach/afterEach.

edit: nvm figured it out

@MayhemYDG
could you post your solution? thx

For others that are interested, there is a package called redtape that extends tape to give you beforeEach and afterEach functionality.

For before()/after() you can just use ordinary tests to do setup and teardown:

So simple… :heart:

@Raynos I just wanna say that, that is some clever piece of code there. My mind was figuratively blown when I finally understood what was going on. :clap:

@oncletom @Raynos @sinkingshriek you can also listen to the end event on assert. Benefit: it also works with assert.plan.

Any ideas about merging this functionality? From tapes, for instance...

Also ran into this. Thanks for the excellent idea @Raynos. I'm still not 100% satisfied with this, as it prevents accessing the Test object to set eg. tape.onFinished(), so that has to be done before you ever call beforeEach (afaik?), f.ex.

I ended up re-implementing it slightly, so that the beforeEach/afterEach methods can take either a function, or an array of functions, as follows (beware, ES6):

export const beforeEach = (_test, handlers) => {
  if (typeof handlers === 'function') return _beforeEach(_test, handlers)

  return handlers.reduce((prev, cur, curIdx, arr) => {
    if (curIdx === 0) return prev
    return _beforeEach(prev, cur)
  }, _beforeEach(_test, handlers[0]))
}

export const afterEach = (_test, handlers) => {
  if (typeof handlers === 'function') return _afterEach(_test, handlers)

  return handlers.reduce((prev, cur, curIdx, arr) => {
    if (curIdx === 0) return prev
    return _afterEach(prev, cur)
  }, _afterEach(_test, handlers[0]))
}

const _beforeEach = (_test, handler) => {
  return function tapish (name, listener) {
    _test(name, function (assert) {
      let _end = assert.end

      assert.end = function () {
        assert.end = _end
        listener(assert)
      }

      handler(assert)
    })
  }
}

const _afterEach = (_test, handler) => {
  return function tapish (name, listener) {
    _test(name, function (assert) {
      let _end = assert.end

      assert.end = function () {
        assert.end = _end
        handler(assert)
      }

      listener(assert)
    })
  }
}

Use is f.ex:

import tapeLib from 'tape'
import { beforeEach, someMethodA, someMethodB, someMethodC } from './helpers/hooks'

let tape = beforeEach(tapeLib, dropTables) // dropTables will run before each test.
tape = beforeEach(tape, [someMethodB, someMethodC]) // dropTables -> someMethodB -> someMethodC will run before each test

This allows you to separate the functionality into smaller methods that each do a certain thing, such as resetting your DB, or whatever else you need to do before tests.

@alathon I've since written tape-cluster ( https://github.com/Raynos/tape-cluster ).

This allows you to build a generic class for your test suite, useful if your testing an app and want to setup & teardown the app before every test.

Bonus feature is that MyTest.test.only(); and MyTest.test.skip() work.
Bonus feature, you can pass options into your test class so that you can different configurations before every test.

@substack your code is clear, but not fit with only case, if one test case is describe with test.only, then all the setup and teardown are skiped

The above solutions looks can only be used for the whole testing. It couldn't set beforeEach/afterEach or before/after for every single file because these solutions would modify the test object which is a single instance.

Set alias from test function for implementing before and after might work around for calling order, but it would make side effects like we will see it on the result list. That might make the report looks not the same with the test case writers' expection.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mkermani144 picture mkermani144  Â·  6Comments

timbuckley picture timbuckley  Â·  5Comments

justingosan picture justingosan  Â·  8Comments

dcousens picture dcousens  Â·  8Comments

jimkang picture jimkang  Â·  3Comments