Mocking Window

Recently I have been working on a project with other apprentices. The project is using Backbone.js with Rails and for some reason one of the features was created with React. The feature that was created with React did not have its own route. So when loading the view for this feature it did not route to anywhere. Meaning loading the view and pressing back in the browser would take the user back to the last URL and not the last view the user was on.

To fix this we used history.pushState, a function which lies within the window. This allowed us to attach a new part to the URL when opening the view. Then we listened (with onpopstate) for when users pressed the back button and when they did we removed the view.

The project used Jasmine with PhantomJS for the tests. Initially our test looked like:

beforeEach ->
view = new Artisan.Stories.StoryView({ story : story }, browser)
it "browser back button removes the form from the DOM", ->
view.show()
window.onpopstate("fake event")
expect(container.children(".story-container")).not.toExist()

The problem with this test is that we access the global window object. So if we ran this test in our browser it would trigger onpopstate for the current window and make the page go backwards. This is wrong because our tests should not interact with the actual window. So we created a Browser object which takes in a window and history object. We then pass this into the constructor of the react class. The Browser object wraps the functions we need from window and history.

With the new Browser object we could mock out the window and history object which is exactly what we done. Now our test looked like:

class FakeWindow
onpopstate = null
beforeEach ->
fakeWindow = new FakeWindow()
fakeHistory = new FakeHistory()
browser = new Artisan.Browser(fakeWindow, fakeHistory)
view = new Artisan.Stories.StoryView({ story : story }, browser)
class FakeHistory
goBack: ->
pushState: (stateObject, title, url) ->
it "browser back button removes the form from the DOM", ->
view.show()
fakeWindow.onpopstate("fake event")
expect(container.children(".story-container")).not.toExist()

Now our tests do not interact with the public window or history object.