skalb.com

Using Sinon Spys With Meteor Collections

Following my testing described here, I wanted to verify that Meteor interacts with my Routers correctly.

The Meteor.Collection object exposes methods for querying the MongoDB collection as described in the docs. I want to test if my index callback will retrieve all the items it should.

Add the new module we need:

1
npm install sinon

Here’s how to use the spy:

lib/sample_router_factory.coffee
1
2
items =
  find: sinon.spy()

Now, let’s write our test:

tests/sample_router_factory_test.coffee
1
2
3
it "should retrieve all items", ->
  router.navigate('', true)
  items.find.called.should.equal true

This will fail, since we need to first modify our Router to accept a collection as an argument and then call find on it.

lib/sample_router_factory.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
root = exports ? this

class SampleRouterFactory
  constructor: (@Backbone, @Items) ->

  getRouter: () ->
    SampleRouter = @Backbone.Router.extend(
      routes:
        "": "index"

      index: =>
        items = @Items.find()
    )
    new SampleRouter

root.SampleRouterFactory = SampleRouterFactory

This should pass, but yet doesn’t. Why? Thinking about the assumption our test is making when using the a Backbone router, it likely depends on Backbone initialization. We can try this in our test, also:

1
2
3
Backbone.history.start
  silent: true
  pushState: true

This doesn’t work either because Backbone assumes we are in the browser when accessing window. I’m pretty sure this is not the approach I want. We don’t need to add a dependency on Backbone’s internal behavior to test a method of my Router. My previous test verifies that the root path will call an index method, so now I only need to call that index method and validate that behavior. This has the added benefit of simplifying the test.

Here’s the final version of my tests:

tests/sample_router_factory_test.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
util = require('util')
should = require('should')
Backbone = require('backbone')
sinon = require('sinon')
SampleRouterFactory = require('../client/lib/sample_router_factory').SampleRouterFactory

describe "SampleRouter", ->
  items =
    find: sinon.spy()

  factory = new SampleRouterFactory(Backbone, items)
  router = factory.getRouter(Backbone)

  it "should have an index route", ->
    router.routes[''].should.equal('index')

  it "should retrieve all items when navigating to index", ->
    router.index()
    items.find.called.should.equal true

A bit roundabout, but in the end what I was trying to accomplish. Source here.

Comments