Skip to content

Commit 07c5322

Browse files
authored
Merge pull request #2568 from mroderick/fix/time-dependent-flaky-tests
fix(test): freeze time in tests to prevent flaky failures
2 parents 88fc3db + 3f44835 commit 07c5322

15 files changed

Lines changed: 278 additions & 220 deletions

Gemfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ group :test do
114114
gem 'shoulda-matchers', '~> 7.0'
115115
gem 'simplecov', require: false
116116
gem 'simplecov-lcov', require: false
117-
gem 'timecop', '~> 0.9.10'
118117
gem 'webmock'
119118
end
120119

Gemfile.lock

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,6 @@ GEM
567567
execjs (>= 0.3.0, < 3)
568568
thor (1.5.0)
569569
tilt (2.7.0)
570-
timecop (0.9.10)
571570
timeout (0.6.0)
572571
tsort (0.2.0)
573572
turbo-rails (2.0.23)
@@ -694,7 +693,6 @@ DEPENDENCIES
694693
stimulus-rails
695694
stripe
696695
terser
697-
timecop (~> 0.9.10)
698696
turbo-rails
699697
tzinfo-data
700698
view_component

config/environments/test.rb

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
require "active_support/core_ext/integer/time"
2-
require "timecop"
1+
require 'active_support/core_ext/integer/time'
32

43
# The test environment is used exclusively to run your application's
54
# test suite. You never need to work with it otherwise. Remember that
@@ -16,10 +15,10 @@
1615
# this is usually not necessary, and can slow down your test suite. However, it's
1716
# recommended that you enable it in continuous integration systems to ensure eager
1817
# loading is working properly before deploying your code.
19-
config.eager_load = ENV["CI"].present?
18+
config.eager_load = ENV['CI'].present?
2019

2120
# Configure public file server for tests with cache-control for performance.
22-
config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.hour.to_i}" }
21+
config.public_file_server.headers = { 'cache-control' => "public, max-age=#{1.hour.to_i}" }
2322

2423
# Show full error reports.
2524
config.consider_all_requests_local = true
@@ -41,7 +40,7 @@
4140
config.action_mailer.delivery_method = :test
4241

4342
# Set host to be used by links generated in mailer templates.
44-
config.action_mailer.default_url_options = { host: "localhost:3000" }
43+
config.action_mailer.default_url_options = { host: 'localhost:3000' }
4544

4645
# Print deprecation notices to the stderr.
4746
config.active_support.deprecation = :stderr
@@ -63,7 +62,4 @@
6362
Bullet.bullet_logger = true
6463
Bullet.raise = false # raise an error if n+1 query occurs
6564
end
66-
67-
# https://github.com/travisjeffery/timecop#timecopsafe_mode
68-
Timecop.safe_mode = true
6965
end

spec/features/admin/announcements_spec.rb

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
click_on 'announcement[create]'
1616

1717
expect(page).to have_content('Announcement successfully created')
18-
expect(page.current_path).to eq(admin_announcements_path)
18+
expect(page).to have_current_path(admin_announcements_path, ignore_query: true)
1919
end
2020
end
2121

@@ -37,18 +37,20 @@
3737

3838
expect(page).to have_content('Announcement successfully updated')
3939
expect(page).to have_content('New event coming up soon! Stay tuned.')
40-
expect(page.current_path).to eq(admin_announcements_path)
40+
expect(page).to have_current_path(admin_announcements_path, ignore_query: true)
4141
end
4242
end
4343

4444
scenario 'can view all announcements' do
45-
announcement = Fabricate(:announcement)
46-
old_announcement = Fabricate(:announcement, expires_at: Time.zone.now - 1.week)
45+
travel_to(Time.current) do
46+
announcement = Fabricate(:announcement)
47+
old_announcement = Fabricate(:announcement, expires_at: 1.week.ago)
4748

48-
visit admin_announcements_path
49+
visit admin_announcements_path
4950

50-
expect(page).to have_content(announcement.message)
51-
expect(page).to have_content(old_announcement.message)
51+
expect(page).to have_content(announcement.message)
52+
expect(page).to have_content(old_announcement.message)
53+
end
5254
end
5355

5456
scenario 'can successfully send a new announcement to every group' do
@@ -60,7 +62,7 @@
6062
expect(page).to have_content('An announcement to every group')
6163
expect(page).to have_content("Coaches #{chapter.name}")
6264
expect(page).to have_content("Students #{chapter.name}")
63-
expect(page.current_path).to eq(admin_announcements_path)
65+
expect(page).to have_current_path(admin_announcements_path, ignore_query: true)
6466
end
6567

6668
scenario 'can successfully send a new announcement to selected groups' do
@@ -71,8 +73,8 @@
7173

7274
expect(page).to have_content('An announcement to selected groups')
7375
expect(page).to have_content("Coaches #{chapter.name}")
74-
expect(page).to_not have_content("Students #{chapter.name}")
75-
expect(page.current_path).to eq(admin_announcements_path)
76+
expect(page).not_to have_content("Students #{chapter.name}")
77+
expect(page).to have_current_path(admin_announcements_path, ignore_query: true)
7678
end
7779
end
7880
end

spec/features/chapter_spec.rb

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
end
1010

1111
it 'a visitor to the website can access inactive chapter events' do
12-
past_workshop = Fabricate(:workshop, chapter: inactive_chapter, date_and_time: Time.zone.today - 2.weeks)
12+
travel_to(Time.current) do
13+
past_workshop = Fabricate(:workshop, chapter: inactive_chapter, date_and_time: 2.weeks.ago)
1314

14-
visit workshop_path(past_workshop)
15+
visit workshop_path(past_workshop)
1516

16-
expect(page).to have_content "Workshop at #{past_workshop.host.name}"
17+
expect(page).to have_content "Workshop at #{past_workshop.host.name}"
18+
end
1719
end
1820
end
1921

@@ -25,59 +27,67 @@
2527
end
2628

2729
it 'renders chapter without organisers' do
28-
chapter = Fabricate(:chapter_without_organisers, name: "Empty Chapter")
30+
chapter = Fabricate(:chapter_without_organisers, name: 'Empty Chapter')
2931
expect(chapter.organisers.size).to eq 0
3032

3133
visit chapter_path(chapter.slug)
3234

33-
expect(page).to have_content "Empty Chapter"
34-
expect(page).not_to have_content "Team"
35+
expect(page).to have_content 'Empty Chapter'
36+
expect(page).not_to have_content 'Team'
3537
end
3638

3739
it 'renders any upcoming workshops for the chapter' do
38-
chapter = Fabricate(:chapter)
39-
workshops = 2.times.map do |n|
40-
Fabricate(:workshop, chapter: chapter, date_and_time: Time.zone.now + 9.days - n.weeks)
41-
end
42-
43-
visit chapter_path(chapter.slug)
44-
workshops.each do |workshop|
45-
expect(page).to have_content "Workshop at #{workshop.host.name}"
40+
travel_to(Time.current) do
41+
chapter = Fabricate(:chapter)
42+
workshops = 2.times.map do |n|
43+
Fabricate(:workshop, chapter: chapter, date_and_time: 9.days.from_now - n.weeks)
44+
end
45+
46+
visit chapter_path(chapter.slug)
47+
workshops.each do |workshop|
48+
expect(page).to have_content "Workshop at #{workshop.host.name}"
49+
end
4650
end
4751
end
4852

4953
it 'renders any upcoming events for the chapter' do
50-
chapter = Fabricate(:chapter)
51-
2.times.map do |n|
52-
Fabricate(:event, name: "Event #{n + 1}",
53-
chapters: [chapter],
54-
date_and_time: Time.zone.now + 2.months - n.months)
54+
travel_to(Time.current) do
55+
chapter = Fabricate(:chapter)
56+
2.times.map do |n|
57+
Fabricate(:event, name: "Event #{n + 1}",
58+
chapters: [chapter],
59+
date_and_time: 2.months.from_now - n.months)
60+
end
61+
62+
visit chapter_path(chapter.slug)
63+
expect(page).to have_content 'Event 1'
64+
expect(page).to have_content 'Event 2'
5565
end
56-
57-
visit chapter_path(chapter.slug)
58-
expect(page).to have_content 'Event 1'
59-
expect(page).to have_content 'Event 2'
6066
end
6167

6268
it 'renders the most recent past workshop for the chapter' do
63-
chapter = Fabricate(:chapter)
64-
past_workshop = Fabricate(:workshop, chapter: chapter, date_and_time: Time.zone.today - 2.weeks)
65-
recent_past_workshop = Fabricate(:workshop, chapter: chapter, date_and_time: Time.zone.today - 1.week)
66-
67-
visit chapter_path(chapter.slug)
68-
expect(page).to have_content "Workshop at #{recent_past_workshop.host.name}"
69-
expect(page).to_not have_content "Workshop at #{past_workshop.host.name}"
69+
travel_to(Time.current) do
70+
chapter = Fabricate(:chapter)
71+
past_workshop = Fabricate(:workshop, chapter: chapter, date_and_time: 2.weeks.ago)
72+
recent_past_workshop = Fabricate(:workshop, chapter: chapter, date_and_time: 1.week.ago)
73+
74+
visit chapter_path(chapter.slug)
75+
expect(page).to have_content "Workshop at #{recent_past_workshop.host.name}"
76+
expect(page).not_to have_content "Workshop at #{past_workshop.host.name}"
77+
end
7078
end
7179

7280
it 'renders the 6 most recent sponsors for the chapter' do
73-
chapter = Fabricate(:chapter)
74-
workshops = 2.times.map do |n|
75-
Fabricate(:workshop, chapter: chapter, date_and_time: Time.zone.now - n.weeks)
76-
end
77-
78-
visit chapter_path(chapter.slug)
79-
workshops.each do |workshop|
80-
expect(page).to have_link(workshop.sponsors.name)
81+
travel_to(Time.current) do
82+
chapter = Fabricate(:chapter)
83+
workshops = 2.times.map do |n|
84+
Fabricate(:workshop, chapter: chapter, date_and_time: n.weeks.ago)
85+
end
86+
87+
visit chapter_path(chapter.slug)
88+
workshops.each do |workshop|
89+
expect(page).to have_link(workshop.sponsors.name)
90+
end
8191
end
8292
end
8393
end

spec/features/listing_coaches_spec.rb

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,37 @@
66
end
77

88
scenario 'I can see the top coaches by year' do
9-
latest_workshop = Fabricate(:workshop, date_and_time: Time.zone.now - 1.year)
10-
old_workshop = Fabricate(:workshop, date_and_time: Time.zone.now - 3.years)
11-
invitations = 2.times { Fabricate(:attended_coach, workshop: latest_workshop) }
12-
older_invitations = 4.times { Fabricate(:attended_coach, workshop: old_workshop) }
9+
travel_to(Time.current) do
10+
latest_workshop = Fabricate(:workshop, date_and_time: 1.year.ago)
11+
old_workshop = Fabricate(:workshop, date_and_time: 3.years.ago)
12+
2.times { Fabricate(:attended_coach, workshop: latest_workshop) }
13+
4.times { Fabricate(:attended_coach, workshop: old_workshop) }
1314

14-
visit coaches_path(year: latest_workshop.date_and_time.year)
15-
expect(page).to have_css(".coach", count: 2)
15+
visit coaches_path(year: latest_workshop.date_and_time.year)
16+
expect(page).to have_css('.coach', count: 2)
1617

17-
visit coaches_path(year: old_workshop.date_and_time.year)
18-
expect(page).to have_css(".coach", count: 4)
18+
visit coaches_path(year: old_workshop.date_and_time.year)
19+
expect(page).to have_css('.coach', count: 4)
20+
end
1921
end
2022

2123
scenario 'I can navigate the top coaches by year' do
22-
current_workshop = Fabricate(:workshop, date_and_time: Time.zone.now)
23-
latest_workshop = Fabricate(:workshop, date_and_time: Time.zone.now - 1.year)
24-
old_workshop = Fabricate(:workshop, date_and_time: Time.zone.now - 3.years)
25-
current_invitations = 1.times { Fabricate(:attended_coach, workshop: current_workshop) }
26-
invitations = 3.times { Fabricate(:attended_coach, workshop: latest_workshop) }
27-
older_invitations = 2.times { Fabricate(:attended_coach, workshop: old_workshop) }
24+
travel_to(Time.current) do
25+
current_workshop = Fabricate(:workshop, date_and_time: Time.current)
26+
latest_workshop = Fabricate(:workshop, date_and_time: 1.year.ago)
27+
old_workshop = Fabricate(:workshop, date_and_time: 3.years.ago)
28+
1.times { Fabricate(:attended_coach, workshop: current_workshop) }
29+
3.times { Fabricate(:attended_coach, workshop: latest_workshop) }
30+
2.times { Fabricate(:attended_coach, workshop: old_workshop) }
2831

29-
visit coaches_path
30-
expect(page).to have_css(".coach", count: 1)
32+
visit coaches_path
33+
expect(page).to have_css('.coach', count: 1)
3134

32-
click_on latest_workshop.date_and_time.year.to_s
33-
expect(page).to have_css(".coach", count: 3)
35+
click_on latest_workshop.date_and_time.year.to_s
36+
expect(page).to have_css('.coach', count: 3)
3437

35-
click_on old_workshop.date_and_time.year.to_s
36-
expect(page).to have_css(".coach", count: 2)
38+
click_on old_workshop.date_and_time.year.to_s
39+
expect(page).to have_css('.coach', count: 2)
40+
end
3741
end
3842
end

spec/features/listing_events_spec.rb

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,25 @@
55
let!(:event) { Fabricate(:event) }
66

77
scenario 'displays upcoming events page' do
8-
visit upcoming_events_path
9-
expect(page).to have_content 'Upcoming Events'
10-
expect(page).to have_content event.name
8+
travel_to(Time.current) do
9+
visit upcoming_events_path
10+
expect(page).to have_content 'Upcoming Events'
11+
expect(page).to have_content event.name
12+
end
1113
end
1214
end
1315

1416
describe 'I can see past events' do
1517
let!(:chapter) { Fabricate(:chapter, active: true) }
16-
let!(:past_event) { Fabricate(:event, date_and_time: Time.zone.now - 2.weeks) }
17-
let!(:past_workshop) { Fabricate(:workshop, date_and_time: Time.zone.now - 1.week, chapter: chapter) }
18+
let!(:past_event) { Fabricate(:event, date_and_time: 2.weeks.ago) }
19+
let!(:past_workshop) { Fabricate(:workshop, date_and_time: 1.week.ago, chapter: chapter) }
1820

1921
scenario 'displays past events page' do
20-
visit past_events_path
21-
expect(page).to have_content 'Past Events'
22-
expect(page).to have_content past_event.name
22+
travel_to(Time.current) do
23+
visit past_events_path
24+
expect(page).to have_content 'Past Events'
25+
expect(page).to have_content past_event.name
26+
end
2327
end
2428
end
2529

@@ -33,26 +37,32 @@
3337

3438
context 'pagination' do
3539
scenario 'past events paginates at 20 per page' do
36-
chapter = Fabricate(:chapter, active: true)
37-
Fabricate.times(22, :event, date_and_time: 2.weeks.ago)
38-
Fabricate(:workshop, date_and_time: 3.weeks.ago, chapter: chapter)
40+
travel_to(Time.current) do
41+
chapter = Fabricate(:chapter, active: true)
42+
Fabricate.times(22, :event, date_and_time: 2.weeks.ago)
43+
Fabricate(:workshop, date_and_time: 3.weeks.ago, chapter: chapter)
3944

40-
visit past_events_path
41-
expect(page).to have_selector('.card', count: 20)
45+
visit past_events_path
46+
expect(page).to have_selector('.card', count: 20)
47+
end
4248
end
4349

4450
scenario 'past meetings paginate at 20 per page' do
45-
Fabricate.times(22, :meeting, date_and_time: 2.weeks.ago)
51+
travel_to(Time.current) do
52+
Fabricate.times(22, :meeting, date_and_time: 2.weeks.ago)
4653

47-
visit past_events_path
48-
expect(page).to have_selector('.card', count: 20)
54+
visit past_events_path
55+
expect(page).to have_selector('.card', count: 20)
56+
end
4957
end
5058

5159
scenario 'upcoming meetings paginate at 20 per page' do
52-
Fabricate.times(22, :meeting, date_and_time: 2.weeks.from_now)
60+
travel_to(Time.current) do
61+
Fabricate.times(22, :meeting, date_and_time: 2.weeks.from_now)
5362

54-
visit upcoming_events_path
55-
expect(page).to have_selector('.card', count: 20)
63+
visit upcoming_events_path
64+
expect(page).to have_selector('.card', count: 20)
65+
end
5666
end
5767
end
5868
end

0 commit comments

Comments
 (0)