Search code examples
ruby-on-railsrspecmockingcapybara

Stub browser time and time zone with Capybara


I have a JavaScript component (e.g. a date picker) that heavily depends on -

  1. The current system time
  2. The current system time zone

In Ruby and Capybara it's possible to stub any time with the help of libraries such as Timecop.

Is it also possible to stub these values in the headless browser that Capybara controls?

Thanks!

Edit: Here's an example of how Ruby is stubbed but Capybara's browser still uses the system time

before do
  now = Time.zone.parse("Apr 15, 2018 12:00PM")
  Timecop.freeze(now)

  visit root_path

  binding.pry
end

> Time.zone.now
=> Sun, 15 Apr 2018 12:00:00 UTC +00:00

> page.evaluate_script("new Date();")
=> "2018-03-27T04:15:44Z"

Solution

  • As you've discovered, Timecop only affects the time in the tests and application under test. The browser is run as a separate process and completely unaffected by Timecop. Because of that you need to stub/mock the time in the browser as well using one of many JS libraries designed to do that. The one I generally use is sinon - http://sinonjs.org/ - , which I conditionally install in the pages head using something like

    - if defined?(Timecop) && Timecop.top_stack_item
      = javascript_include_tag "sinon.js" # adjust based on where you're loading sinon from
      - unix_millis = (Time.now.to_f * 1000.0).to_i
      :javascript
        sinon.useFakeTimers(#{unix_millis});
    

    That should work in a haml template (adjust if using erb) and would install and mock the browsers time whenever a page is visited while Timecop is being used to mock the apps time.