Skip to content

Commit 66bfb2f

Browse files
test(course_duplication_service): add tests for duplicating timelines
1 parent db00190 commit 66bfb2f

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

spec/services/course/duplication/course_duplication_service_spec.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,34 @@
145145
end
146146
end
147147

148+
context 'when has multiple reference timelines' do
149+
let(:old_default_timeline) { course.default_reference_timeline }
150+
let(:empty_timeline) { create(:course_reference_timeline, course: course) }
151+
let(:nonempty_timeline) { create(:course_reference_timeline, course: course) }
152+
let(:time) do
153+
create(
154+
:course_reference_time,
155+
reference_timeline: nonempty_timeline,
156+
lesson_plan_item: course.lesson_plan_items.sample
157+
)
158+
end
159+
160+
it 'duplicates all the reference timelines' do
161+
new_default_timeline = new_course.default_reference_timeline
162+
163+
expect(new_default_timeline).to be_similar_to_timeline(old_default_timeline, time_shift)
164+
165+
old_timelines = course.reference_timelines
166+
new_timelines = new_course.reference_timelines
167+
expect(new_timelines.size).to eq(course.reference_timelines.size)
168+
169+
new_timelines.each_with_index do |new_timeline, index|
170+
old_timeline = old_timelines[index]
171+
expect(new_timeline).to be_similar_to_timeline(old_timeline, time_shift)
172+
end
173+
end
174+
end
175+
148176
context 'when assessment has no children' do
149177
it 'duplicates assessment attributes' do
150178
new_assessment = new_course.assessments.first
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# frozen_string_literal: true
2+
require 'rspec/expectations'
3+
4+
module ReferenceTimelinesTestHelper
5+
# Checks whether two `Course::ReferenceTimeline`s are similar to each other.
6+
#
7+
# Note that this is not a check for equality or equivalency, but similarity. This method is meant to compare
8+
# two timelines that were duplicated when duplicating a course. As such, it checks for the equivalency of the
9+
# attributes in both `Course::ReferenceTimeline` records.
10+
#
11+
# @param timeline1 [Course::ReferenceTimeline] a timeline
12+
# @param timeline2 [Course::ReferenceTimeline] the timeline to compare against `timeline1`
13+
# @param time_shift [ActiveSupport::Duration] number of days expected to be between the times in both timelines
14+
# @return [Boolean] `true` if both timelines are similar to each other
15+
#
16+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
17+
def similar_timelines?(timeline1, timeline2, time_shift = 0.day)
18+
return false unless timeline1.title == timeline2.title
19+
20+
times1 = timeline1.reference_times
21+
times2 = timeline2.reference_times
22+
return false unless times1.size == times2.size
23+
24+
times1.each_with_index do |time1, index|
25+
time2 = times2[index]
26+
return false unless time1.lesson_plan_item.actable_type == time2.lesson_plan_item.actable_type
27+
return false unless time1.lesson_plan_item.title == time2.lesson_plan_item.title
28+
return false unless days_equal_or_offset_by(time1.start_at, time2.start_at, time_shift)
29+
return false unless days_equal_or_offset_by(time1.bonus_end_at, time2.bonus_end_at, time_shift)
30+
return false unless days_equal_or_offset_by(time1.end_at, time2.end_at, time_shift)
31+
end
32+
33+
true
34+
end
35+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
36+
37+
private
38+
39+
# Checks whether two times are equal or differ by some given number of days.
40+
#
41+
# @param time1 [ActiveSupport::TimeWithZone, nil] a time
42+
# @param time2 [ActiveSupport::TimeWithZone, nil] the time to compare against `time1`
43+
# @param offset [ActiveSupport::Duration] number of days expected to be between `time1` and `time2`
44+
# @return [Boolean] `true` if `time1` and `time2` are equal, or differ by `offset` days
45+
def days_equal_or_offset_by(time1, time2, offset)
46+
return true if time1 == time2
47+
48+
days_between(time1, time2) == offset
49+
end
50+
51+
# Returns the number of days between two `ActiveSupport::TimeWithZone` times.
52+
# It returns `0.days` if either time is `nil`.
53+
#
54+
# @param time1 [ActiveSupport::TimeWithZone, nil] a time
55+
# @param time2 [ActiveSupport::TimeWithZone, nil] the time to differ against `time1`
56+
# @return [ActiveSupport::Duration] the number of days between `time1` and `time2`
57+
def days_between(time1, time2)
58+
return 0.days if time1.blank? || time2.blank?
59+
60+
date1 = time1.to_date
61+
date2 = time2.to_date
62+
(date1 - date2).to_i.days
63+
end
64+
end
65+
66+
RSpec::Matchers.define :be_similar_to_timeline do |expected, time_shift|
67+
include ReferenceTimelinesTestHelper
68+
69+
match do |actual|
70+
expect(similar_timelines?(actual, expected, time_shift)).to be_truthy
71+
end
72+
end
73+
74+
RSpec.configure do |config|
75+
config.include ReferenceTimelinesTestHelper
76+
end

0 commit comments

Comments
 (0)