You can use jasmine to test batman.js controllers by looking them up from the controller directory, then executing actions with executeAction
.
Setup
To set up,
- make sure the app is running (so that the layout view will be present)
- get the controller you want from
App.controllers
(a ControllerDirectory )
describe 'PeopleController', ->
@beforeEach ->
App.run()
@peopleController = App.get('controllers.people')
it 'is present', ->
expect(@peopleController.constructor).toBe(App.PeopleController)
In our tests, we’ll use Batman.Controller::executeAction
to fire controller actions. This way, before-actions and after-actions will be run, too.
Functions Are Called on Records
Use Jasmine spyOn(...).andCallThrough()
to make sure functions have been called
describe 'edit', ->
# This action is invoked from a view binding, not a route
# so it takes `person`, not `params`....
it 'calls transaction on the person', ->
person = new App.Person(id: 1)
spyOn(person, 'transaction').andCallThrough()
@peopleController.executeAction('edit', person)
expect(person.transaction).toHaveBeenCalled()
Options Passed to Render
Get the most recent render arguments from jasmine’s mostRecentCall
. It will be the options passed to @render
.
it 'renders into the dialog', ->
person = new App.Person(id: 1)
spyOn(@peopleController, 'render').andCallThrough()
@peopleController.executeAction('edit', person)
lastRenderArgs = @peopleController.render.mostRecentCall.args[0]
lastYield = lastRenderArgs["into"]
expect(lastYield).toEqual("modal")
Functions Called on Model Classes
Checking class to get
is tough becuase there are a lot of them! I just iterate through and make sure nothing jumps out as wrong:
describe 'index', ->
it 'gets loaded people, not all people', ->
spyOn(App.Person, 'get').andCallThrough()
@peopleController.executeAction('index')
# there are a lot of calls to App.Person.get, just make sure
# that "all" wasn't requested!
loadedCalls = 0
for call in App.Person.get.calls
getArg = call.args[0]
expect(getArg).not.toMatch(/all/)
if getArg.match(/loaded/)
loadedCalls += 1
expect(loadedCalls).toBeGreaterThan(0)
Renders a Specific View
Rendering into the default yield is easy enough – just check layout.subviews
for an instance of the desired view.
it 'renders the PeopleIndexView', ->
@peopleController.executeAction('index')
hasPeopleIndexView = App.get('layout.subviews').some (view) -> view instanceof App.PeopleIndexView
expect(hasPeopleIndexView).toBe(true)