Bee
Bee

Reputation: 14427

How to control time for capybara / phantomjs tests

I want to test that some deadlines are getting displayed to users correctly in different timezones and at different times of day. My tests are using capybara+rspec+phantomjs.

I am passing a block to Timecop.travel(datetime) and the code in the test within that block is getting the mocked datetime correctly, but it looks like PhantomJS / the mocked browser are not getting the mocked time.

Is there any known way to get PhantomJS to work with Timecop? Or other ways to mock out or manipulate time for testing purposes?

Here's a simple example to illustrate what I mean.

time_spec.rb:

it "should show the Time travel date" do
  # current date is 2017-01-24
  Date.today.should == Date.parse("2017-01-24")
  Timecop.travel( Time.parse("2001-01-01 01:01") ) {
    sign_in(user)
    visit "/#{user.username}"

    Date.today.should == Date.parse("2001-01-01")
    page.should have_text("Today is 2001-01-01")
    page.should have_text("Javascript says 2001-01-01")
  }
end

user.html.erb:

<p>Today is <%= Time.now.iso8601 %></p>
<script>
  var now = moment().format()
  $('p').append("<p>Javascript says "+now+"</p>")
</script>

output of running the test:

Failures:

  1) Dashboard should show the time travel date
     Failure/Error: page.should have_text("Javascript says 2001-01-01")
       expected to find text "Javascript says 2001-01-01" in 
       "Today is 2001-01-01T01:01:00-08:00 Javascript says 2017-01-24T12:36:02-08:00"
     # ./spec/features/time_spec.rb:67:in `block (3 levels) in <top (required)>'
     # /gems/ruby-2.2.0/gems/timecop-0.8.0/lib/timecop/timecop.rb:147:in `travel'
     # /gems/ruby-2.2.0/gems/timecop-0.8.0/lib/timecop/timecop.rb:121:in `send_travel'
     # /gems/ruby-2.2.0/gems/timecop-0.8.0/lib/timecop/timecop.rb:62:in `travel'
     # ./spec/features/time_spec.rb:59:in `block (2 levels) in <top (required)>'

Upvotes: 4

Views: 1610

Answers (1)

Thomas Walpole
Thomas Walpole

Reputation: 49910

As you've discovered TimeCop only adjusts the servers time, but the browser uses system time. There are a number of JS libraries to allow for time faking, that all work by mocking the JS Date Class. One I have used successfully is Sinon.JS which I implemented in my _head.html.haml file by doing

- if defined?(Timecop) && Timecop.top_stack_item
  = javascript_include_tag "testing/sinon-1.17.3.js"
  - unix_millis = (Time.now.to_f * 1000.0).to_i
  :javascript
    sinon.useFakeTimers(#{unix_millis});

before requiring any other JS. This will set the browser time in any page rendered to whatever Timecop is set to.

Upvotes: 5

Related Questions