2026-02-08 11:15:51 +01:00
|
|
|
require 'rails_helper'
|
|
|
|
|
|
|
|
|
|
RSpec.describe MoodCalendarService do
|
2026-03-21 20:23:34 +01:00
|
|
|
let(:user) { create(:user) }
|
|
|
|
|
let(:mode) { create(:mode, user: user) }
|
2026-02-08 11:15:51 +01:00
|
|
|
|
2026-03-21 20:23:34 +01:00
|
|
|
describe '.generate_calendar' do
|
2026-02-08 11:15:51 +01:00
|
|
|
context 'avec des jours manquants' do
|
|
|
|
|
it 'remplit les jours manquants avec mode: nil et guess égal au dernier mode' do
|
2026-03-21 20:23:34 +01:00
|
|
|
mode2 = create(:mode, user: user)
|
|
|
|
|
mode3 = create(:mode, user: user)
|
|
|
|
|
create(:mood, user: user, mode: mode2, recorded_at: Time.zone.parse("2025-02-12 14:20:00"))
|
|
|
|
|
create(:mood, user: user, mode: mode3, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
|
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-18 16:45:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
end_date: Date.parse("2025-02-28")
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(result.length).to be >= 1
|
|
|
|
|
expect(result.any? { |m| m[:month] == Date.parse("2025-02-01") }).to be true
|
|
|
|
|
|
|
|
|
|
all_days = result.find { |m| m[:month] == Date.parse("2025-02-01") }[:weeks].flatten
|
|
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
mood_12 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-12") }
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(mood_12[:mode]).to eq(mode2)
|
2026-02-08 11:15:51 +01:00
|
|
|
expect(mood_12[:recorded_at].to_i).to eq(Time.zone.parse("2025-02-12 14:20:00").to_i)
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
mood_13 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-13") }
|
|
|
|
|
expect(mood_13[:mode]).to be_nil
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(mood_13[:guess]).to eq(mode2)
|
|
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
mood_14 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-14") }
|
|
|
|
|
expect(mood_14[:mode]).to be_nil
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(mood_14[:guess]).to eq(mode2)
|
|
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
mood_15 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-15") }
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(mood_15[:mode]).to eq(mode3)
|
|
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
mood_16 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-16") }
|
|
|
|
|
expect(mood_16[:mode]).to be_nil
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(mood_16[:guess]).to eq(mode3)
|
|
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
mood_3 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-03") }
|
|
|
|
|
expect(mood_3[:mode]).to be_nil
|
|
|
|
|
expect(mood_3[:guess]).to be_nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'gère correctement plusieurs mois avec des jours manquants' do
|
2026-03-21 20:23:34 +01:00
|
|
|
mode2 = create(:mode, user: user)
|
|
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
|
|
|
|
create(:mood, user: user, mode: mode2, recorded_at: Time.zone.parse("2025-04-20 11:30:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
end_date: Date.parse("2025-04-30")
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(result.length).to be >= 3
|
|
|
|
|
expect(result.any? { |m| m[:month] == Date.parse("2025-02-01") }).to be true
|
|
|
|
|
expect(result.any? { |m| m[:month] == Date.parse("2025-03-01") }).to be true
|
|
|
|
|
expect(result.any? { |m| m[:month] == Date.parse("2025-04-01") }).to be true
|
|
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
march = result.find { |m| m[:month] == Date.parse("2025-03-01") }
|
|
|
|
|
all_march_days = march[:weeks].flatten
|
|
|
|
|
expect(all_march_days.all? { |d| d[:mode].nil? }).to be true
|
|
|
|
|
all_march_days.each do |day|
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(day[:guess]).to be_present,
|
|
|
|
|
"Le jour #{day[:recorded_at].to_date} devrait avoir un guess"
|
2026-02-08 11:15:51 +01:00
|
|
|
end
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
april = result.find { |m| m[:month] == Date.parse("2025-04-01") }
|
|
|
|
|
all_april_days = april[:weeks].flatten
|
|
|
|
|
mood_20_april = all_april_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-04-20") }
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(mood_20_april[:mode]).to eq(mode2)
|
|
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
mood_10_april = all_april_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-04-10") }
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(mood_10_april[:guess]).to eq(mode)
|
|
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
mood_21_april = all_april_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-04-21") }
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(mood_21_april[:guess]).to eq(mode2)
|
2026-02-08 11:15:51 +01:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'sans aucun recorded_at' do
|
2026-03-21 20:23:34 +01:00
|
|
|
it 'retourne un calendrier à partir de la date courante' do
|
|
|
|
|
result = MoodCalendarService.generate_calendar(Mood.where(user: user))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(result).not_to be_empty
|
|
|
|
|
expect(result.first[:month]).to eq(Date.current.beginning_of_month)
|
2026-02-08 11:15:51 +01:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'structure du calendrier' do
|
|
|
|
|
it 'commence chaque mois par le premier lundi' do
|
2026-03-21 20:23:34 +01:00
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
end_date: Date.parse("2025-02-28")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
february = result[0]
|
|
|
|
|
first_day = february[:weeks][0][0]
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
expect(first_day[:recorded_at].to_date).to eq(Date.parse("2025-02-03"))
|
|
|
|
|
expect(first_day[:recorded_at].to_date.monday?).to be true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'va du premier lundi du mois au dimanche avant le premier lundi du mois suivant' do
|
2026-03-21 20:23:34 +01:00
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
end_date: Date.parse("2025-03-31")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
february = result[0]
|
|
|
|
|
all_days = february[:weeks].flatten
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
first_day = all_days.first
|
|
|
|
|
expect(first_day[:recorded_at].to_date).to eq(Date.parse("2025-02-03"))
|
|
|
|
|
expect(first_day[:recorded_at].to_date.monday?).to be true
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
last_day = all_days.last
|
|
|
|
|
expect(last_day[:recorded_at].to_date).to eq(Date.parse("2025-03-02"))
|
|
|
|
|
expect(last_day[:recorded_at].to_date.sunday?).to be true
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
expect(all_days.any? { |d| d[:recorded_at].to_date == Date.parse("2025-03-03") }).to be false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'toutes les semaines ont exactement 7 jours' do
|
2026-03-21 20:23:34 +01:00
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
end_date: Date.parse("2025-02-28")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
february = result[0]
|
|
|
|
|
february[:weeks].each do |week|
|
|
|
|
|
expect(week.length).to eq(7)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'retourne month comme Date (le premier du mois)' do
|
2026-03-21 20:23:34 +01:00
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
end_date: Date.parse("2025-02-28")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
february = result[0]
|
|
|
|
|
expect(february[:month]).to be_a(Date)
|
|
|
|
|
expect(february[:month]).to eq(Date.parse("2025-02-01"))
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(february[:month].day).to eq(1)
|
2026-02-08 11:15:51 +01:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'avec paramètres par défaut' do
|
2026-03-21 20:23:34 +01:00
|
|
|
it "utilise le premier mood comme start_date et aujourd'hui comme end_date" do
|
|
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
2026-03-21 20:23:34 +01:00
|
|
|
result = MoodCalendarService.generate_calendar(Mood.where(user: user))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
expect(result).not_to be_empty
|
|
|
|
|
expect(result.first[:month]).to eq(Date.parse("2025-02-01"))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'avec start_date spécifié' do
|
|
|
|
|
it 'commence à la date spécifiée' do
|
2026-03-21 20:23:34 +01:00
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
start_date: Date.parse("2025-03-01"),
|
|
|
|
|
end_date: Date.parse("2025-03-31")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expect(result.first[:month]).to eq(Date.parse("2025-03-01"))
|
|
|
|
|
expect(result.any? { |m| m[:month] == Date.parse("2025-02-01") }).to be false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'avec end_date spécifié' do
|
2026-03-21 20:23:34 +01:00
|
|
|
it 'se termine à end_date' do
|
|
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
|
|
|
|
end_date: Date.parse("2025-09-30")
|
2026-02-08 11:15:51 +01:00
|
|
|
)
|
|
|
|
|
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(result.last[:month]).to eq(Date.parse("2025-09-01"))
|
2026-02-08 11:15:51 +01:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'avec start_date et end_date spécifiés' do
|
|
|
|
|
it 'génère le calendrier pour la plage spécifiée' do
|
2026-03-21 20:23:34 +01:00
|
|
|
mode2 = create(:mode, user: user)
|
|
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
|
|
|
|
create(:mood, user: user, mode: mode2, recorded_at: Time.zone.parse("2025-04-20 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
start_date: Date.parse("2025-03-01"),
|
|
|
|
|
end_date: Date.parse("2025-03-31")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expect(result.length).to eq(1)
|
|
|
|
|
expect(result.first[:month]).to eq(Date.parse("2025-03-01"))
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
all_days = result.first[:weeks].flatten
|
|
|
|
|
expect(all_days.all? { |d| d[:mode].nil? }).to be true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'gère une plage de plusieurs mois' do
|
2026-03-21 20:23:34 +01:00
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
start_date: Date.parse("2025-02-01"),
|
|
|
|
|
end_date: Date.parse("2025-04-30")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
months = result.map { |m| m[:month] }
|
|
|
|
|
expect(months).to include(
|
|
|
|
|
Date.parse("2025-02-01"),
|
|
|
|
|
Date.parse("2025-03-01"),
|
|
|
|
|
Date.parse("2025-04-01")
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'fonctionne avec DateTime en paramètres' do
|
2026-03-21 20:23:34 +01:00
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
start_date: Time.zone.parse("2025-02-01 00:00:00"),
|
|
|
|
|
end_date: Time.zone.parse("2025-02-28 23:59:59")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expect(result).not_to be_empty
|
|
|
|
|
expect(result.first[:month]).to eq(Date.parse("2025-02-01"))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'avec une plage ne contenant aucun mood' do
|
|
|
|
|
it 'génère un calendrier avec tous les jours à nil et guess du dernier mood avant la plage' do
|
2026-03-21 20:23:34 +01:00
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
start_date: Date.parse("2025-04-01"),
|
|
|
|
|
end_date: Date.parse("2025-04-30")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expect(result.first[:month]).to eq(Date.parse("2025-04-01"))
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
all_days = result.first[:weeks].flatten
|
|
|
|
|
expect(all_days.all? { |d| d[:mode].nil? }).to be true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'avec plusieurs mois' do
|
|
|
|
|
it 'chaque mois commence et finit correctement' do
|
2026-03-21 20:23:34 +01:00
|
|
|
mode2 = create(:mode, user: user)
|
|
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
|
|
|
|
create(:mood, user: user, mode: mode2, recorded_at: Time.zone.parse("2025-03-20 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
end_date: Date.parse("2025-03-31")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
february = result.find { |m| m[:month] == Date.parse("2025-02-01") }
|
|
|
|
|
march = result.find { |m| m[:month] == Date.parse("2025-03-01") }
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
last_day_february = february[:weeks].flatten.last
|
|
|
|
|
expect(last_day_february[:recorded_at].to_date).to eq(Date.parse("2025-03-02"))
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
first_day_march = march[:weeks].flatten.first
|
|
|
|
|
expect(first_day_march[:recorded_at].to_date).to eq(Date.parse("2025-03-03"))
|
2026-03-21 20:23:34 +01:00
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
expect(last_day_february[:recorded_at].to_date + 1.day).to eq(first_day_march[:recorded_at].to_date)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'avec un scope spécifique' do
|
|
|
|
|
it 'fonctionne avec des moods filtrés par user' do
|
|
|
|
|
user2 = create(:user)
|
2026-03-21 20:23:34 +01:00
|
|
|
mode2 = create(:mode, user: user2)
|
|
|
|
|
create(:mood, user: user, mode: mode, recorded_at: Time.zone.parse("2025-02-15 10:00:00"))
|
|
|
|
|
create(:mood, user: user2, mode: mode2, recorded_at: Time.zone.parse("2025-02-16 10:00:00"))
|
2026-02-08 11:15:51 +01:00
|
|
|
|
|
|
|
|
result = MoodCalendarService.generate_calendar(
|
2026-03-21 20:23:34 +01:00
|
|
|
Mood.where(user: user),
|
2026-02-08 11:15:51 +01:00
|
|
|
end_date: Date.parse("2025-02-28")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
all_days = result[0][:weeks].flatten
|
|
|
|
|
mood_15 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-15") }
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(mood_15[:mode]).to eq(mode)
|
|
|
|
|
|
2026-02-08 11:15:51 +01:00
|
|
|
mood_16 = all_days.find { |m| m[:recorded_at].to_date == Date.parse("2025-02-16") }
|
|
|
|
|
expect(mood_16[:mode]).to be_nil
|
2026-03-21 20:23:34 +01:00
|
|
|
expect(mood_16[:guess]).to eq(mode)
|
2026-02-08 11:15:51 +01:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|