Недавно я работал над проектом с другими учениками. В проекте используется Backbone.js с Rails, и по какой-то причине одна из функций была создана с помощью React. Функция, созданная с помощью React, не имела собственного маршрута. Поэтому при загрузке представления для этой функции оно никуда не направлялось. Это означает, что загрузка представления и нажатие назад в браузере вернет пользователя к последнему URL-адресу, а не к последнему представлению, в котором он был.

Чтобы исправить это, мы использовали history.pushState, функцию, которая находится внутри окна. Это позволило нам прикрепить новую часть к URL-адресу при открытии представления. Затем мы слушали (с помощью onpopstate), когда пользователи нажимали кнопку «Назад», и когда они это делали, мы удаляли представление.

В проекте для тестов использовался Jasmine с PhantomJS. Изначально наш тест выглядел так:

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()

Проблема с этим тестом в том, что мы обращаемся к глобальному объекту окна. Поэтому, если мы запустим этот тест в нашем браузере, он вызовет onpopstate для текущего окна и заставит страницу вернуться назад. Это неправильно, потому что наши тесты не должны взаимодействовать с реальным окном. Итак, мы создали объект Browser, который принимает окно и объект истории. Затем мы передаем это в конструктор класса реакции. Объект Browser оборачивает нужные нам функции из окна и истории.

С новым объектом Browser мы могли смоделировать окно и объект истории, что мы и сделали. Теперь наш тест выглядел так:

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()

Теперь наши тесты не взаимодействуют с публичным окном или объектом истории.