npm install given-when-thenitsettap() instead of result.setgwt.combine(…)Behaviour driven development for nodejs.
The available dictionary of steps has to be created before
the order of execution of these steps is declared:
assert = require 'assert'
gwt = require 'gwt'
steps = gwt.steps
GIVEN:
'an elevator with open doors and ${n} buttons': ({n}) ->
@buttons = new Array(n)
@lights = new Array(n)
WHEN:
'button ${i} is pressed': ({i}) ->
@button[i].press()
THEN:
'the button light ${i} goes on': ->
assert @lights[i].pressed
See how \this\ is bound to a context object that is passed between
each given/when/then step. Store shared data against \this\.
The order of execution is declared using the dictionary of
steps. Steps can be used multiple times and in any order.
\${…}\ strings are placeholders for values passed into steps. They
are used to generate descriptions for \it\ blocks.
myTest = steps
.given 'elevator with open doors and ${n} buttons', {n: 10}
.when 'button ${i} is pressed', {i: 4}
.then 'the button light ${i} goes on', {i: 4}
1. Using a callback
myTest.run (err) -> ...
2. Returning a promise
myTest.run()
.then -> ...
.fail (err) -> ...
# done() registers with it
myTest.done()
# done() registers with it
myTest.done(it: (description, testFn) -> ...)
Each step has access to a context object, via \this\, which is shared
between all steps attached to a runner.
steps = gwt.steps
GIVEN: 'a given': ->
@bar = 'x'
WHEN: 'an action is taken': ->
assert.equal @bar, 'x', 'Context not shared' # -> PASS
steps
.given 'a given'
.when 'an action is taken'
.run (err) -> ...
If the return value of a step is a promise, it will
be used to chain onto the following steps.
Q = require 'q'
steps = gwt.steps
GIVEN: 'a precondition': ->
deferred = Q.defer()
setTimeout (-> deferred.resolve()), 1000
return deferred.promise
steps.run()
If the return value of a step is a function, it is assumed
to be an asynchronous function and called with a callback which
will resume execution of following steps when it is called.
steps = gwt.steps
GIVEN: 'a precondition': -> (cb) ->
setTimeout (-> cb()), 1000
steps.run()
\gwt.result()\ produces a placeholder that carries information via
the context across steps, but provides us with an external reference.
baz = gwt.result()
steps = gwt.steps
WHEN: 'baz is created': ->
return baz: 'xyz'
THEN: 'baz can be used': ({baz}) ->
assert.deepEqual baz, baz: 'xyz'
steps
.when('baz is created').resultTo(baz)
.then('baz can be used', {baz})
.run (err) ->
baz = gwt.result()
foo = gwt.result()
steps = gwt.steps
WHEN:
'baz is created': ->
return 'xyz'
'foo is created': -> (cb) ->
cb null, 'foo'
THEN: 'results can be used': ({baz, foo}) ->
assert.equal baz, 'xyz'
assert.equal foo, 'foo'
steps
.when('baz is created').resultTo(baz)
.then('results can be used', {baz, foo})
.run (err) -> ...
baz = gwt.result()
foo = gwt.result()
steps = gwt.steps
WHEN:
'foo and baz are created': ->
return foo: 'foo', baz: 'xyz'
THEN: 'results can be used': ({baz, foo}) ->
assert.equal baz, 'xyz'
assert.equal foo, 'foo'
steps
.when('foo and baz are created').resultTo({baz, foo})
.then('results can be used', {baz, foo})
.run (err) -> ...
If you call \result.set\ with a value, any time it is passed
to a step, it will be substituted with the given value.
You can call \set\ inside or outside a step.
value = gwt.result()
value.set 'xyz'
steps = gwt.steps
THEN: 'result can be used': ({value}) ->
assert.equal baz, 'xyz'
steps
.then('result can be used', {value})
.run (err) -> ...
Using \tap()\ provides a less permanent way of setting a result
placeholder value.
baz = gwt.result()
steps = gwt.steps
THEN:
'baz has been set': ({baz}) ->
assert.equal baz, 'xyz'
steps
.tap(({baz} -> return 'xyz'), {baz})
.then 'baz has been set', {baz}
.run (err) -> ...
gwt.combine(…)\Calls to \gwt.steps(…).given().when().then()\ produce a runner,
which
can be combined with other runners using \gwt.combine(runner1, to produce another runner, so that any level of nesting
runner2, …)\
is possible.
NOTE: Context does not get copied between combined runners. However,
result placeholders do carry values across combined runners.
steps1 = gwt.steps
GIVEN: 'one': ->
THEN: 'two': ->
steps2 = gwt.steps
GIVEN: 'three': ->
WHEN: 'four': ->
THEN: 'five': ->
gwt.combine(
steps1
.given 'one'
.then 'two'
steps2
.given 'three'
.when 'four'
.then 'five'
).run (err) -> ...
You can access context and result values by providing a function
instead of a description to the \steps.tap()\ function
baz = gwt.result()
steps = gwt.steps
WHEN:
'baz is created': ->
return 'xyz'
steps
.when('baz is created').resultTo(baz)
.tap(({baz} -> console.log baz), {baz})
.run (err) -> ...