aboutsummaryrefslogtreecommitdiffstats
path: root/spec/models/calendar_spec.rb
blob: 09ac0e416fc26535c337eed793cd0da6aa4d4392 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
RSpec.describe Calendar, :type => :model do

  it { should belong_to(:organisation) }

  it { is_expected.to validate_presence_of(:organisation) }
  it { is_expected.to validate_presence_of(:name) }
  it { is_expected.to be_versioned }

  describe '#to_time_table' do
    let(:calendar) { create(:calendar, int_day_types: Calendar::MONDAY | Calendar::SUNDAY, date_ranges: [Date.today...(Date.today + 1.month)]) }

    it 'should convert calendar to an instance of Chouette::TimeTable' do
      time_table = calendar.convert_to_time_table
      expect(time_table).to be_an_instance_of(Chouette::TimeTable)
      expect(time_table.int_day_types).to eq calendar.int_day_types
      expect(time_table.periods[0].period_start).to eq(calendar.periods[0].begin)
      expect(time_table.periods[0].period_end).to eq(calendar.periods[0].end)
      expect(time_table.dates.map(&:date)).to match_array(calendar.dates)
    end
  end

  describe 'application days' do
    let(:calendar) { create(:calendar) }
    it "should default to all days" do
      %w(monday tuesday wednesday thursday friday saturday sunday).each do |day|
        expect(calendar.send(day)).to be_truthy
      end
    end
  end

  describe 'validations' do
    it 'validates that dates and date_ranges do not overlap' do
      expect(build(:calendar, dates: [Date.today.beginning_of_week], date_ranges: [Date.today.beginning_of_week..Date.today])).to_not be_valid
    end

    it 'validates that dates and date_ranges do not overlap but allow for days not in the list' do
      expect(build(:calendar, dates: [Date.today.beginning_of_week - 1.week], date_ranges: [(Date.today.beginning_of_week - 1.week)..Date.today], int_day_types: Calendar::THURSDAY)).to be_valid
    end

    it 'validates that there are no duplicates in dates' do
      expect(build(:calendar, dates: [Date.yesterday, Date.yesterday], date_ranges: [Date.today..Date.tomorrow])).to_not be_valid
    end
  end

  describe 'before_validation' do
    let(:calendar) { create(:calendar, date_ranges: []) }

    it 'shoud fill date_ranges with date ranges' do
      expected_range = Date.today..Date.tomorrow
      calendar.date_ranges << expected_range
      calendar.valid?

      expect(calendar.date_ranges.map { |period| period.begin..period.end }).to eq([expected_range])
    end
  end

  describe "Update state" do
    def calendar_to_state calendar
      calendar.slice('id').tap do |item|
        item['comment'] = calendar.name
        item['day_types'] = "Di,Lu,Ma,Me,Je,Ve,Sa"
        item['current_month'] = calendar.month_inspect(Date.today.beginning_of_month)
        item['current_periode_range'] = Date.today.beginning_of_month.to_s
        item['time_table_periods'] = calendar.periods.map{|p| {'id': p.id, 'period_start': p.period_start.to_s, 'period_end': p.period_end.to_s}}
      end
    end

    subject(:calendar){ create :calendar }
    let(:state) { calendar_to_state subject }

    it 'should update time table periods association' do
      period = state['time_table_periods'].first
      period['period_start'] = (Date.today - 1.month).to_s
      period['period_end']   = (Date.today + 1.month).to_s

      subject.state_update_periods state['time_table_periods']
      ['period_end', 'period_start'].each do |prop|
        expect(subject.reload.periods.first.send(prop).to_s).to eq(period[prop])
      end
    end

    it 'should create time table periods association' do
      state['time_table_periods'] << {
        'id' => false,
        'period_start' => (Date.today + 1.year).to_s,
        'period_end' => (Date.today + 2.year).to_s
      }

      expect {
        subject.state_update_periods state['time_table_periods']
      }.to change {subject.periods.count}.by(1)
      expect(state['time_table_periods'].last['id']).to eq subject.reload.periods.last.id
    end

    it 'should delete time table periods association' do
      state['time_table_periods'].first['deleted'] = true
      expect {
        subject.state_update_periods state['time_table_periods']
      }.to change {subject.periods.count}.by(-1)
    end

    it 'should update name' do
      state['comment'] = "Edited timetable name"
      subject.state_update state
      expect(subject.reload.name).to eq state['comment']
    end

    it 'should update day_types' do
      state['day_types'] = "Di,Lu,Je,Ma"
      subject.state_update state
      expect(subject.reload.valid_days).to include(7, 1, 4, 2)
      expect(subject.reload.valid_days).not_to include(3, 5, 6)
    end

    it 'should delete date if date is set to neither include or excluded date' do
      updated = state['current_month'].map do |day|
        day['include_date'] = false if day['include_date']
      end

      expect {
        subject.state_update state
      }.to change {subject.dates.count}.by(-updated.compact.count)
    end

    it 'should update date if date is set to excluded date' do
        updated = state['current_month'].map do |day|
          next unless day['include_date']
          day['include_date']  = false
          day['excluded_date'] = true
        end

        subject.state_update state
        expect(subject.reload.excluded_days.count).to eq (updated.compact.count)
    end

    it 'should create new include date' do
      day  = state['current_month'].find{|d| !d['excluded_date'] && !d['include_date'] }
      date = Date.parse(day['date'])
      day['include_date'] = true
      expect(subject.included_days).not_to include(date)

      expect {
        subject.state_update state
      }.to change {subject.dates.count}.by(1)
      expect(subject.reload.included_days).to include(date)
    end

    it 'should create new exclude date' do
      day  = state['current_month'].find{|d| !d['excluded_date'] && !d['include_date']}
      date = Date.parse(day['date'])
      day['excluded_date'] = true
      expect(subject.excluded_days).not_to include(date)

      expect {
        subject.state_update state
      }.to change {subject.all_dates.count}.by(1)
      expect(subject.reload.excluded_days).to include(date)
    end
  end

end