RSpec-like subject/let helpers for Jasmine
First let see how to implement the let
helper. As you may have already guessed, we can't use let
as a name as let is already a javascript keyword. Let call it given
instead.
Given Helper
Basically the given helper will register a beforeEach and a afterEach hook that will create a get accessor in the current spec with the given name. We'll use an accessor rather than a simple property to allow lazy evaluation of the passed-in block. Note that if you need to run your specs on browsers that doesn't support Object.defineProperty you can use a property but you'll lose the lazy evaluation.
# With Object.defineProperty
global.given = (name, block) ->
beforeEach ->
# The resulting value is cached after the first evaluation
cache = null
Object.defineProperty this, name, configurable: true, get: ->
cache ||= block.call(this)
afterEach ->
# To avoid conflict accross tests the
delete @[name]
Here's the version with property :
# Without Object.defineProperty
global.given = (name, block) ->
beforeEach -> @[name] = block.call(this)
afterEach -> delete @[name]
Now we can use it in our specs:
describe 'a spec', ->
given 'value', -> 10
it 'should do something with value' ->
# ...
Subject Helper
Now let's follow with the subject
helper. In that context, the subject is just a proxy to the given
helper that can be invoked with or without a name:
global.subject = (name=null, block) ->
[name, block] = [block, name] if typeof name is 'function'
given 'subject', block
given name, block if name?
And we can use it in our spec like this:
describe 'a spec', ->
given 'value', -> 10
given 'result', -> 20
subject -> new MyObject
it 'should do something with value' ->
expect(@subject.doSomething(@value)).toBe(@result)
Or:
describe 'a spec', ->
given 'value', -> 10
given 'result', -> 20
subject 'myObject', -> new MyObject
it 'should do something with value' ->
expect(@myObject.doSomething(@value)).toBe(@result)