From b67db3710e6d2841c80f554c7dabe8440378b998 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Fri, 10 Jul 2026 08:39:30 +0200 Subject: [PATCH 1/2] refactor: move WorkshopCalendar from app/models to app/serializers WorkshopCalendar is a serialization class that builds iCalendar output from a workshop model. It has no domain identity, no persistence, and no business invariants. Place it in the correct architectural layer. Rails 8 autoloads all app/ subdirectories, so no require path updates are needed. --- app/{models => serializers}/workshop_calendar.rb | 0 spec/{models => serializers}/workshop_calendar_spec.rb | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename app/{models => serializers}/workshop_calendar.rb (100%) rename spec/{models => serializers}/workshop_calendar_spec.rb (100%) diff --git a/app/models/workshop_calendar.rb b/app/serializers/workshop_calendar.rb similarity index 100% rename from app/models/workshop_calendar.rb rename to app/serializers/workshop_calendar.rb diff --git a/spec/models/workshop_calendar_spec.rb b/spec/serializers/workshop_calendar_spec.rb similarity index 100% rename from spec/models/workshop_calendar_spec.rb rename to spec/serializers/workshop_calendar_spec.rb From 4c4146af49d01b89ab0d9536218603bb507db808 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Fri, 10 Jul 2026 08:39:55 +0200 Subject: [PATCH 2/2] test: add #ical contract tests and explicit setup test The existing tests verified calendar event structure through the internal .calendar accessor. Add tests for the public #ical method (the actual interface used by mailers) that assert on the raw iCalendar output format and verify the invitation URL appears in the event description. Also add an explicit setup test that confirms #setup runs during initialization, making that side effect visible. --- spec/serializers/workshop_calendar_spec.rb | 33 +++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/spec/serializers/workshop_calendar_spec.rb b/spec/serializers/workshop_calendar_spec.rb index 74008c38c..804eef745 100644 --- a/spec/serializers/workshop_calendar_spec.rb +++ b/spec/serializers/workshop_calendar_spec.rb @@ -1,9 +1,40 @@ RSpec.describe WorkshopCalendar do let(:invitation_url) { Faker::Internet.url } - let(:calendar) { WorkshopCalendar.new(workshop, invitation_url).calendar } + + describe '.new' do + it 'calls setup during initialization' do + workshop = Fabricate(:workshop) + calendar = described_class.new(workshop, invitation_url) + + expect(calendar.calendar.events.count).to eq(1) + end + end + + describe '#ical' do + it 'returns an iCalendar string' do + workshop = Fabricate(:workshop) + cal = described_class.new(workshop, invitation_url) + + result = cal.ical + + expect(result).to start_with("BEGIN:VCALENDAR\r\n") + expect(result).to include("BEGIN:VEVENT\r\n") + expect(result).to include("END:VEVENT\r\n") + expect(result).to include("END:VCALENDAR\r\n") + end + + it 'includes the invitation URL in the event description' do + workshop = Fabricate(:workshop) + cal = described_class.new(workshop, invitation_url) + + expect(cal.ical).to include(invitation_url) + end + end describe 'workshop calendar entry' do let(:workshop) { Fabricate(:workshop) } + let(:calendar) { described_class.new(workshop, invitation_url).calendar } + it 'has an event associated with it' do expect(calendar.events.count).to eq(1) end