Set last_ping_at
to something definitely not now, then check if it's close to now with be_within
.
it 'successfully updates last_ping_at' do
obj.update!(last_ping_at: 1.day.ago)
patch url(obj)
expect(response).to have_http_status(:ok)
expect(obj.reload.last_ping_at).to be_within(1.second).of(DateTime.now)
end
Note: DateTime.now
will be the time zone on your machine, not the application's time zone. Use DateTime.current
instead.
[4] pry(main)> Time.zone = "Fiji"
=> "Fiji"
[5] pry(main)> DateTime.now
=> Thu, 21 Jan 2021 12:13:14 -0800
[6] pry(main)> DateTime.current
=> Fri, 22 Jan 2021 08:13:16 +1200
[7] pry(main)>
See It's About Time (Zones).
Sometimes you can't use be_within
. In that case you can freeze time. For general Ruby use timecop as @max says. Rails has that built in with travel_to
.
it 'successfully updates last_ping_at' do
travel_to Time.current do
patch url(obj)
expect(response).to have_http_status(:ok)
expect(obj.reload.last_ping_at).to eq Time.current
end
end
I go a step further and bake this into rspec metadata.
# spec/support/config/travel_to.rb
RSpec.configure do |config|
config.around do |example|
if example.metadata[:travel_to]
travel_to example.metadata[:travel_to] do
example.run
end
else
example.run
end
end
end
Now you can travel_to: Time.current
in any RSpec block.
it 'successfully updates last_ping_at', travel_to: Time.current do
patch url(obj)
expect(response).to have_http_status(:ok)
expect(obj.reload.last_ping_at).to eq Time.current
end
YMMV whether you prefer the explicit block or the implicit metadata.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…