Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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"
like image 929
user2490003 Avatar asked Mar 27 '18 04:03

user2490003


2 Answers

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.

like image 133
Thomas Walpole Avatar answered Sep 21 '22 04:09

Thomas Walpole


I know that the question is a bit old, but we had the same request and found the following solution to work with rails 6:

context 'different timezones between back-end and front-end' do
        it 'shows the event timestamp according to front-end timezone' do
          # Arrange
          previous_timezone = Time.zone
          previous_timezone_env = ENV['TZ']

          server_timezone = "Europe/Copenhagen"
          browser_timezone = "America/Godthab"

          Time.zone = server_timezone
          ENV['TZ'] = browser_timezone

          Capybara.using_session(browser_timezone) do
            freeze_time do
              # Act
              # ... Code here

              # Assert
              server_clock = Time.zone.now.strftime('%H:%M')
              client_clock = Time.zone.now.in_time_zone(browser_timezone).strftime('%H:%M')
              expect(page).not_to have_content(server_clock)
              expect(page).to have_content(client_clock)
            end
          end
          # (restore)
          Time.zone = previous_timezone
          ENV['TZ'] = previous_timezone_env
        end
end
like image 45
Norfeldt Avatar answered Sep 19 '22 04:09

Norfeldt