Skip to content

Commit bda56a6

Browse files
Spoof browser time (#5431)
* Added sinon library to spoof browser time during tests * Updated deadline_day_controller to force RRule to calculate the next occurrence after today * Updated reminder schedule form tests to run on specific dates and times * Fixed deadline and reminder form shared example assuming the form always used the same path * Swapped explicit path names for refresh, fixed the partner page not being handled correctly, applied linter * Forgot sinon
1 parent 1314d7a commit bda56a6

File tree

7 files changed

+1631
-11
lines changed

7 files changed

+1631
-11
lines changed

app/javascript/controllers/deadline_day_controller.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,14 @@ export default class extends Controller {
4444
let today = new Date();
4545
let untilDate = new Date( today );
4646
untilDate.setMonth( untilDate.getMonth() + monthlyInterval + 1 )
47-
47+
4848
if (this.byDayOfMonthTarget.checked && this.dayOfMonthTarget.value) {
4949
const rule = new RRule({
5050
dtstart: new Date(Date.UTC(today.getFullYear(), today.getMonth(), today.getDate(), 12)),
5151
freq: RRule.MONTHLY,
5252
interval: monthlyInterval,
5353
bymonthday: parseInt(this.dayOfMonthTarget.value),
54+
byhour: 11, // Force RRule to calculate an occurrance after today
5455
until: untilDate
5556
})
5657
reminder_date = this.getFirstOccurrenceAfterToday( rule.all(), today )
@@ -61,6 +62,7 @@ export default class extends Controller {
6162
freq: RRule.MONTHLY,
6263
interval: monthlyInterval,
6364
byweekday: WEEKDAY_NUM_TO_OBJ[ parseInt(this.dayOfWeekTarget.value) ].nth( parseInt(this.everyNthDayTarget.value) ),
65+
byhour: 11, // Force RRule to calculate an occurrance after today
6466
wkst: RRule.SU,
6567
until: untilDate
6668
})

app/views/layouts/application.html.erb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,23 @@
1616
# DO NOT LOAD ANY JAVASCRIPT BEFORE THIS!!!
1717
javascript_importmap_tags
1818
%>
19+
20+
<!-- Use sinon to make sure the browser's time matches Rails' potentially spoofed time.
21+
Be sure to navigate to the page under test AFTER spoofing Rails' time or there will be a
22+
mismatch. -->
23+
<% if Rails.env.test? %>
24+
<script type="module">
25+
import sinon from "sinon"
26+
if( window.fakeTimerClock ){
27+
window.fakeTimerClock.restore();
28+
}
29+
window.fakeTimerClock = sinon.useFakeTimers({
30+
now: <%= Time.now.to_i * 1000 %>,
31+
shouldAdvanceTime: true
32+
})
33+
</script>
34+
<% end %>
35+
1936
<%= raw fullstory_script(current_user: current_user) if Rails.env.production? %>
2037
<script type="esms-options">
2138
{

config/importmap.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@
3636
pin "@rails/activestorage", to: "@rails--activestorage.js" # @8.0.100
3737
pin "rrule", to: "https://ga.jspm.io/npm:[email protected]/dist/esm/index.js" # @2.8.1
3838
pin "tslib", to: "https://ga.jspm.io/npm:[email protected]/tslib.es6.mjs" # @2.8.1
39+
pin "sinon" # @21.0.0

spec/support/deadline_day_fields_shared_example.rb

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def safe_subtract_days(date, num)
2222
result
2323
end
2424

25-
RSpec.shared_examples_for "deadline and reminder form" do |form_prefix, save_button, post_form_submit|
25+
RSpec.shared_examples_for "deadline and reminder form" do |form_prefix, save_button, post_form_submit, post_refresh|
2626
it "can set a reminder on a day of the month" do
2727
choose "Day of Month"
2828
fill_in "#{form_prefix}_reminder_schedule_service_day_of_month", with: 1
@@ -74,12 +74,17 @@ def safe_subtract_days(date, num)
7474
expect(page).to have_content("Deadline day must be between 1 and 28")
7575
end
7676

77-
# These tests make assertions about the dates calculated by the javascript in deadline_day_controller.js
78-
# Because we currently don't have a great way of spoofing the date the headless browser sees during tests, they
79-
# cannot effectively set the date for the tests (like with travel_to) and have to make due with the actual datetime
80-
# of whenever the test is run. To the best of my knowledge, the tests are sound but be aware that they could
81-
# pass or fail based on when they are run!
82-
describe "reported reminder and deadline dates" do
77+
RSpec.shared_examples_for "reported reminder and deadline dates" do |datetime|
78+
before do
79+
if datetime
80+
travel_to datetime
81+
end
82+
refresh
83+
if post_refresh
84+
send(post_refresh)
85+
end
86+
end
87+
8388
context "when the reminder is a day of the month" do
8489
before do
8590
choose "Day of Month"
@@ -169,4 +174,16 @@ def calc_every_nth_day(target_date)
169174
end
170175
end
171176
end
177+
178+
context "at the end of the month" do
179+
it_behaves_like "reported reminder and deadline dates", Time.zone.local(2025, 9, 30)
180+
end
181+
182+
context "in the middle of the month" do
183+
it_behaves_like "reported reminder and deadline dates", Time.zone.local(2025, 9, 14)
184+
end
185+
186+
context "at the start of the month" do
187+
it_behaves_like "reported reminder and deadline dates", Time.zone.local(2025, 9, 1)
188+
end
172189
end

spec/system/organization_system_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ def post_form_submit
7474
it_behaves_like "deadline and reminder form", "organization", "Save", :post_form_submit
7575

7676
it "the deadline day form's reminder and deadline dates are consistent with the dates calculated by the FetchPartnersToRemindNowService and DeadlineService" do
77+
travel_to Time.zone.local(2025, 9, 30)
78+
refresh
7779
choose "Day of Month"
7880
fill_in "organization_reminder_schedule_service_day_of_month", with: safe_add_days(Time.zone.now, 1).day
7981
fill_in "Deadline day in reminder email", with: safe_add_days(Time.zone.now, 2).day

spec/system/partner_system_spec.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,11 @@
758758
end
759759

760760
describe "editing a custom reminder schedule" do
761+
def post_refresh
762+
# Opt in to sending deadline reminders
763+
check 'Yes'
764+
end
765+
761766
before do
762767
partner.update!(partner_group: existing_partner_group)
763768
visit partners_path
@@ -766,13 +771,15 @@
766771
assert page.has_content? existing_partner_group.name, wait: page_content_wait
767772

768773
click_on 'Edit'
769-
# Opt in to sending deadline reminders
770-
check 'Yes'
774+
post_refresh
771775
end
772776

773-
it_behaves_like "deadline and reminder form", "partner_group", "Update Partner Group"
777+
it_behaves_like "deadline and reminder form", "partner_group", "Update Partner Group", nil, :post_refresh
774778

775779
it "the deadline day form's reminder and deadline dates are consistent with the dates calculated by the FetchPartnersToRemindNowService and DeadlineService" do
780+
travel_to Time.zone.local(2025, 9, 30)
781+
refresh
782+
post_refresh
776783
choose "Day of Month"
777784
fill_in "partner_group_reminder_schedule_service_day_of_month", with: safe_add_days(Time.zone.now, 1).day
778785
fill_in "Deadline day in reminder email", with: safe_add_days(Time.zone.now, 2).day

vendor/javascript/sinon.js

Lines changed: 1574 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)