jbk
jbk

Reputation: 2200

How to stub Time.now.hour

I have a helper method which outputs a greeting #{greet(Time.now.hour)} in the view pending the time of day:

users_helper.rb:

def greet(hour_of_clock)
 if hour_of_clock >= 1 && hour_of_clock <= 11
  "Morning"
 elsif hour_of_clock >= 12 && hour_of_clock <= 16
  "Afternoon"
 else
  "Evening"
 end
end

And I am trying to test this unsuccessfully as below:

users_feature_spec.rb

describe 'greeting a newly registered user' do
  before do 
    @fake_time = Time.parse("11:00")
    Time.stub(:now) { @fake_time }
  end
  it 'tailors the greeting to the time of day' do
    visit '/'
    fill_in 'Name here...', with: 'test name'
    fill_in 'Your email here...', with: '[email protected]'
    click_button 'Notify me'

    expect(page).to have_content 'Morning'
  end
end

The test fails as the Time.now.hour is not being stubbed as intended above.

I've now tried all sorts of variations thanks to various advice, the two main reformats which it at least seemed were syntactically correct were:

describe 'greeting a newly registered user' do
  before do 
    @fake_time =  Time.parse("11:00")
    allow(Time).to receive(:now).and_return(@fake_time)  
  end
  it 'tailors the greeting to the time of day' do
      visit '/'
      fill_in 'Name here...', with: 'test name'
      fill_in 'Your email here...', with: '[email protected]'
      click_button 'Notify me'

      expect(page).to have_content 'Morning'
    end
  end

and using the new ActiveSupport::Testing::TimeHelpers method #travel_to:

describe 'greeting a newly registered user' do
  it 'tailors the greeting to the time of day' do
    travel_to Time.new(2013, 11, 24, 01, 04, 44) do
      visit '/'
      fill_in 'Name here...', with: 'test name'
      fill_in 'Your email here...', with: '[email protected]'
      click_button 'Notify me'

      expect(page).to have_content 'Morning'
    end
  end

But still I'm doing something wrong which means that #greet is still taking the live output of Time.now.hour and not using my stubbed or travel_to Time value. Any help please?

Upvotes: 2

Views: 2936

Answers (3)

jbk
jbk

Reputation: 2200

I gave up trying to either stub out myself or use the ::TimeHelpers method #travel_to :( and used the Timecop gem, worked first time as below:

before do 
    Timecop.freeze(Time.now.beginning_of_day + 11.hours)
end

it 'tailors the greeting to the time of day' do
    visit '/'
    fill_in 'Name here...', with: 'test name'
    fill_in 'Your email here...', with: '[email protected]'
    click_button 'Notify me'

    expect(page).to have_content 'Morning'
end

I would really like to understand what was failing with my original approach though, does anyone see what was going wrong?

Upvotes: 0

Sharvy Ahmed
Sharvy Ahmed

Reputation: 7405

You can try this :

let!(:fake_hour) { '11' }
before do 
  allow(Time).to receive_message_chain(:now, :hour).and_return(fake_hour)
end

Upvotes: 2

Topher Hunt
Topher Hunt

Reputation: 4813

Another approach would be to use Timecop (or the new Rails replacement travel_to) to stub out your time for you. With Timecop you can have super readable specs with no need for manual stubbing:

# spec setup

Timecop.freeze(Time.now.beginning_of_day + 11.hours) do
  visit root_path
  do_other_stuff!
end

Upvotes: 1

Related Questions