Last Updated: February 25, 2016
·
2.262K
· abe33

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)