diff --git a/spec/features/subscribing_to_emails_spec.rb b/spec/features/subscribing_to_emails_spec.rb index 044fbab3b..7d99f35ed 100644 --- a/spec/features/subscribing_to_emails_spec.rb +++ b/spec/features/subscribing_to_emails_spec.rb @@ -24,62 +24,76 @@ end context 'a member receives a welcome email' do + before do + ActionMailer::Base.deliveries.clear + end + scenario 'Subscribing to a coach mailing list for the first time sends a coach email to the user' do coach_group = Fabricate(:coaches) - expect_any_instance_of(MemberMailer).to receive(:welcome_coach) - expect_any_instance_of(MemberMailer).not_to receive(:welcome_students) visit subscriptions_path click_on "#{coach_group.chapter.name}-coaches" + + welcome_emails = ActionMailer::Base.deliveries.select { |e| e.to.include?(member.email) } + expect(welcome_emails.count).to eq(1) + expect(welcome_emails.first.body.encoded).to include('coach') end scenario 'Subscribing to a student mailing list for the first time sends a student email to the user' do - expect_any_instance_of(MemberMailer).to receive(:welcome_student) - expect_any_instance_of(MemberMailer).not_to receive(:welcome_coach) - visit subscriptions_path click_on "#{group.chapter.name}-students" + + welcome_emails = ActionMailer::Base.deliveries.select { |e| e.to.include?(member.email) } + expect(welcome_emails.count).to eq(1) + expect(welcome_emails.first.body.encoded).to include('student') end scenario "Subscribing to a second coach mailing list doesn't send another mail" do coach_groups = Fabricate.times(2, :coaches) - expect_any_instance_of(MemberMailer).to receive(:welcome_coach).once - expect_any_instance_of(MemberMailer).not_to receive(:welcome_students) visit subscriptions_path click_on "#{coach_groups[0].chapter.name}-coaches" + ActionMailer::Base.deliveries.clear click_on "#{coach_groups[1].chapter.name}-coaches" + + welcome_emails = ActionMailer::Base.deliveries.select { |e| e.to.include?(member.email) } + expect(welcome_emails.count).to eq(0) end scenario "Subscribing to a second student mailing list doesn't send another mail" do - expect_any_instance_of(MemberMailer).to receive(:welcome_student).once - expect_any_instance_of(MemberMailer).not_to receive(:welcome_coach) extra_student_group = Fabricate(:students) visit subscriptions_path click_on "#{group.chapter.name}-students" + ActionMailer::Base.deliveries.clear click_on "#{extra_student_group.chapter.name}-students" + + welcome_emails = ActionMailer::Base.deliveries.select { |e| e.to.include?(member.email) } + expect(welcome_emails.count).to eq(0) end scenario "Unsubscribing and re-subscribing doesn't send a second mail to a coach" do coach_group = Fabricate(:coaches) - expect_any_instance_of(MemberMailer).to receive(:welcome_coach).once - expect_any_instance_of(MemberMailer).not_to receive(:welcome_students) visit subscriptions_path click_on "#{coach_group.chapter.name}-coaches" + ActionMailer::Base.deliveries.clear click_on "#{coach_group.chapter.name}-coaches" click_on "#{coach_group.chapter.name}-coaches" + + welcome_emails = ActionMailer::Base.deliveries.select { |e| e.to.include?(member.email) } + expect(welcome_emails.count).to eq(0) end scenario "Unsubscribing and re-subscribing doesn't send a second mail to a student" do - expect_any_instance_of(MemberMailer).to receive(:welcome_student).once - expect_any_instance_of(MemberMailer).not_to receive(:welcome_coach) - visit subscriptions_path click_on "#{group.chapter.name}-students" + ActionMailer::Base.deliveries.clear click_on "#{group.chapter.name}-students" click_on "#{group.chapter.name}-students" + + welcome_emails = ActionMailer::Base.deliveries.select { |e| e.to.include?(member.email) } + expect(welcome_emails.count).to eq(0) end end end diff --git a/spec/mailers/member_mailer_spec.rb b/spec/mailers/member_mailer_spec.rb index b09ed32f6..9539ae1d8 100644 --- a/spec/mailers/member_mailer_spec.rb +++ b/spec/mailers/member_mailer_spec.rb @@ -81,24 +81,27 @@ it 'sends the coach welcome email to coaches' do member = Fabricate(:coach) - expect_any_instance_of(MemberMailer).to receive(:welcome_coach) - expect_any_instance_of(MemberMailer).not_to receive(:welcome_student) - MemberMailer.welcome(member).deliver_now + mail = MemberMailer.welcome(member).deliver_now + + expect(mail.body.encoded).to match('depends on coaches attending') end it 'sends the student welcome email to students' do member = Fabricate(:student) - expect_any_instance_of(MemberMailer).not_to receive(:welcome_coach) - expect_any_instance_of(MemberMailer).to receive(:welcome_student) - MemberMailer.welcome(member).deliver_now + + mail = MemberMailer.welcome(member).deliver_now + + expect(mail.body.encoded).to match('Spots are limited') end it 'sends a ban email to a member' do member = Fabricate(:member) ban = Fabricate(:ban) - expect_any_instance_of(MemberMailer).to receive(:ban).with(member, ban) - MemberMailer.ban(member, ban).deliver_now + mail = MemberMailer.ban(member, ban).deliver_now + + expect(mail.to).to eq([member.email]) + expect(mail.body.encoded).to match('your account has been suspended') end it 'actually sends a coach email' do diff --git a/spec/models/attendance_warning_spec.rb b/spec/models/attendance_warning_spec.rb index e3e4e6623..402ec7684 100644 --- a/spec/models/attendance_warning_spec.rb +++ b/spec/models/attendance_warning_spec.rb @@ -10,11 +10,10 @@ end it 'sends an attendance warning email' do - allow(MemberMailer).to receive(:attendance_warning).with(member, member.email).and_call_original - described_class.create(member: member, issued_by: admin) - expect(MemberMailer).to have_received(:attendance_warning).with(member, member.email) + email = ActionMailer::Base.deliveries.find { |e| e.to.include?(member.email) && e.subject.include?('Attendance') } + expect(email).not_to be_nil end describe '.scopes' do diff --git a/spec/models/eligibility_inquiry_spec.rb b/spec/models/eligibility_inquiry_spec.rb index 60f9cb656..b6e67db02 100644 --- a/spec/models/eligibility_inquiry_spec.rb +++ b/spec/models/eligibility_inquiry_spec.rb @@ -9,12 +9,14 @@ expect(eligibility_inquiry.issued_by).to eq(admin) end - it 'sends an attendance warning email' do - allow(MemberMailer).to receive(:eligibility_check).with(member, member.email).and_call_original + it 'sends an eligibility check email' do + expect { + described_class.create(member: member, issued_by: admin) + }.to change { ActionMailer::Base.deliveries.count }.by(1) - described_class.create(member: member, issued_by: admin) - - expect(MemberMailer).to have_received(:eligibility_check).with(member, member.email) + email = ActionMailer::Base.deliveries.last + expect(email.to).to include(member.email) + expect(email.subject).to include('Eligibility') end end end diff --git a/spec/models/feedback_request_spec.rb b/spec/models/feedback_request_spec.rb index c14805e7e..68be3fc31 100644 --- a/spec/models/feedback_request_spec.rb +++ b/spec/models/feedback_request_spec.rb @@ -25,18 +25,13 @@ end context 'after create hook' do - it '#email' do - feedback_request = Fabricate.build(:feedback_request) - allow(feedback_request).to receive(:email) - allow(feedback_request).to receive(:member_id).and_return(:member_id) - feedback_request.save - expect(feedback_request).to have_received(:email) - end - it 'sends request feedback email' do - allow(FeedbackRequestMailer).to receive(:request_feedback) { double('feedback_request_mailer').as_null_object } - Fabricate(:feedback_request) - expect(FeedbackRequestMailer).to have_received(:request_feedback) + expect { + Fabricate(:feedback_request) + }.to change { ActionMailer::Base.deliveries.count }.by(1) + + email = ActionMailer::Base.deliveries.last + expect(email.subject).to include('Feedback') end end end diff --git a/spec/models/invitation_manager_spec.rb b/spec/models/invitation_manager_spec.rb index 516464159..651c8e94f 100644 --- a/spec/models/invitation_manager_spec.rb +++ b/spec/models/invitation_manager_spec.rb @@ -113,15 +113,19 @@ end describe '#send_monthly_attendance_reminder_emails', :wip do + # Note: This test is WIP because the method is async and doesn't currently + # call .deliver_now or .deliver_later on the mailer it 'emails all attending members' do meeting = Fabricate(:meeting) attendees = Fabricate.times(2, :attending_meeting_invitation, meeting: meeting).map(&:member) - attendees.each do |attendee| - expect(MeetingInvitationMailer).to receive(:attendance_reminder).with(meeting, attendee) - end + expect { + manager.send_monthly_attendance_reminder_emails_without_delay(meeting) + }.to change { ActionMailer::Base.deliveries.count }.by(attendees.count) - manager.send_monthly_attendance_reminder_emails(meeting) + emails = ActionMailer::Base.deliveries.last(attendees.count) + attendee_emails = attendees.map(&:email) + expect(emails.map(&:to).flatten).to match_array(attendee_emails) end end @@ -130,36 +134,35 @@ workshop = Fabricate(:workshop) invitations = Fabricate.times(2, :attending_workshop_invitation, workshop: workshop) - invitations.each do |invitation| - expect(WorkshopInvitationMailer).to receive(:attending_reminder) - .with(workshop, invitation.member, invitation) - .and_call_original - end + expect { + manager.send_workshop_attendance_reminders_without_delay(workshop) + }.to change { ActionMailer::Base.deliveries.count }.by(invitations.count) - manager.send_workshop_attendance_reminders(workshop) invitations.each { |invitation| expect(invitation.reload.reminded_at).not_to be_nil } + + emails = ActionMailer::Base.deliveries.last(invitations.count) + invitation_emails = invitations.map { |i| i.member.email } + expect(emails.map(&:to).flatten).to match_array(invitation_emails) end end describe '#send_workshop_waiting_list_reminders', :wip do + # Note: This test is WIP because the method is async it 'emails everyone that hasn\'t already been reminded from the workshop\'s waitinglist' do workshop = Fabricate(:workshop) invitations = Fabricate.times(2, :waitinglist_invitation, workshop: workshop) reminded_invitations = Fabricate.times(2, :waitinglist_invitation_reminded, workshop: workshop) - invitations.each do |invitation| - expect(WorkshopInvitationMailer).to receive(:waiting_list_reminder) - .with(workshop, invitation.member, invitation) - .and_call_original - end - - reminded_invitations.each do |invitation| - expect(WorkshopInvitationMailer).not_to receive(:waiting_list_reminder) - .with(workshop, invitation.member, invitation) - end + expect { + manager.send_workshop_waiting_list_reminders_without_delay(workshop) + }.to change { ActionMailer::Base.deliveries.count }.by(invitations.count) - manager.send_workshop_waiting_list_reminders(workshop) invitations.each { |invitation| expect(invitation.reload.reminded_at).not_to be_nil } + reminded_invitations.each { |invitation| expect(invitation.reload.reminded_at).to be_nil } + + emails = ActionMailer::Base.deliveries.last(invitations.count) + invitation_emails = invitations.map { |i| i.member.email } + expect(emails.map(&:to).flatten).to match_array(invitation_emails) end end @@ -167,43 +170,41 @@ it 'emails coaches when there are free coach spots' do waitinglist_invitation = Fabricate(:waitinglist_invitation, workshop: workshop, role: 'Coach') - expect(WorkshopInvitationMailer).to receive(:notify_waiting_list).once - .with(waitinglist_invitation) - .and_call_original + expect { + manager.send_waiting_list_emails(workshop) + }.to change { ActionMailer::Base.deliveries.count }.by(1) - manager.send_waiting_list_emails(workshop) + email = ActionMailer::Base.deliveries.last + expect(email.to).to include(waitinglist_invitation.member.email) end it 'does not email coaches when no coach spots are available' do workshop = Fabricate(:workshop, coach_count: 0) - waitinglist_invitation = Fabricate(:waitinglist_invitation, workshop: workshop, role: 'Coach') + Fabricate(:waitinglist_invitation, workshop: workshop, role: 'Coach') - expect(WorkshopInvitationMailer).not_to receive(:notify_waiting_list) - .with(waitinglist_invitation) - .and_call_original - - manager.send_waiting_list_emails(workshop) + expect { + manager.send_waiting_list_emails(workshop) + }.not_to(change { ActionMailer::Base.deliveries.count }) end it 'emails students when there are free student spots' do waitinglist_invitation = Fabricate(:waitinglist_invitation, workshop: workshop, role: 'Student') - expect(WorkshopInvitationMailer).to receive(:notify_waiting_list).once - .with(waitinglist_invitation) - .and_call_original + expect { + manager.send_waiting_list_emails(workshop) + }.to change { ActionMailer::Base.deliveries.count }.by(1) - manager.send_waiting_list_emails(workshop) + email = ActionMailer::Base.deliveries.last + expect(email.to).to include(waitinglist_invitation.member.email) end it 'does not email students when no student spots are available' do workshop = Fabricate(:workshop, student_count: 0) - waitinglist_invitation = Fabricate(:waitinglist_invitation, workshop: workshop, role: 'Student') - - expect(WorkshopInvitationMailer).not_to receive(:notify_waiting_list) - .with(waitinglist_invitation) - .and_call_original + Fabricate(:waitinglist_invitation, workshop: workshop, role: 'Student') - manager.send_waiting_list_emails(workshop) + expect { + manager.send_waiting_list_emails(workshop) + }.not_to(change { ActionMailer::Base.deliveries.count }) end end @@ -216,12 +217,9 @@ Fabricate(:ban, member: students.last) expected_student_count = students.count - 1 - expect(MeetingInvitationMailer).to receive(:invite) - .exactly(expected_student_count).times - .with(meeting, instance_of(Member), instance_of(MeetingInvitation)) - .and_call_original - - manager.send_meeting_emails(meeting) + expect { + manager.send_meeting_emails_without_delay(meeting) + }.to change { ActionMailer::Base.deliveries.count }.by(expected_student_count) end it 'emails valid invitees only once' do @@ -232,12 +230,9 @@ MeetingInvitation.create(meeting: meeting, member: students.last, role: 'Participant') expected_student_count = students.count - 1 - expect(MeetingInvitationMailer).to receive(:invite) - .exactly(expected_student_count).times - .with(meeting, instance_of(Member), instance_of(MeetingInvitation)) - .and_call_original - - manager.send_meeting_emails(meeting) + expect { + manager.send_meeting_emails_without_delay(meeting) + }.to change { ActionMailer::Base.deliveries.count }.by(expected_student_count) end end @@ -375,10 +370,9 @@ Fabricate(:students, chapter: chapter, members: students) Fabricate(:coaches, chapter: chapter, members: coaches) - expect(WorkshopInvitationMailer).to receive(:invite_student).at_least(:once).and_call_original - expect(WorkshopInvitationMailer).to receive(:invite_coach).at_least(:once).and_call_original - - manager.send_workshop_emails(workshop, 'everyone') + expect { + manager.send_workshop_emails_without_delay(workshop, 'everyone') + }.to change { ActionMailer::Base.deliveries.count }.by(students.count + coaches.count) end end @@ -422,9 +416,11 @@ it 'sends attendance reminder emails' do invitation = Fabricate(:attending_workshop_invitation, workshop: workshop) - expect(WorkshopInvitationMailer).to receive(:attending_reminder).at_least(:once).and_call_original + expect { + manager.send_workshop_attendance_reminders_without_delay(workshop) + }.to change { ActionMailer::Base.deliveries.count }.by(1) - manager.send_workshop_attendance_reminders(workshop) + expect(invitation.reload.reminded_at).not_to be_nil end end diff --git a/spec/support/shared_examples/behaves_like_sending_workshop_emails.rb b/spec/support/shared_examples/behaves_like_sending_workshop_emails.rb index 925e169dc..33f9fbf62 100644 --- a/spec/support/shared_examples/behaves_like_sending_workshop_emails.rb +++ b/spec/support/shared_examples/behaves_like_sending_workshop_emails.rb @@ -1,24 +1,38 @@ RSpec.shared_examples 'sending workshop emails' do - it 'creates an invitation for each student' do + it 'creates an invitation for each student and sends emails' do Fabricate(:students, chapter: chapter, members: students) students.each do |student| expect(WorkshopInvitation).to receive(:find_or_initialize_by).with(workshop: workshop, member: student, role: 'Student').and_call_original - expect(mailer).to receive(:invite_student).and_call_original end - manager.send(send_email, workshop, 'students') + expect { + manager.send(send_email, workshop, 'students') + }.to change { ActionMailer::Base.deliveries.count }.by(students.count) + .and change { WorkshopInvitation.where(workshop: workshop, role: 'Student').count }.by(students.count) + + # Verify emails were sent to the right recipients + emails = ActionMailer::Base.deliveries.last(students.count) + student_emails = students.map(&:email) + expect(emails.map(&:to).flatten).to match_array(student_emails) end - it 'creates an invitation for each coach' do + it 'creates an invitation for each coach and sends emails' do Fabricate(:coaches, chapter: chapter, members: coaches) coaches.each do |coach| expect(WorkshopInvitation).to receive(:find_or_initialize_by).with(workshop: workshop, member: coach, role: 'Coach').and_call_original - expect(mailer).to receive(:invite_coach).and_call_original end - manager.send(send_email, workshop, 'coaches') + expect { + manager.send(send_email, workshop, 'coaches') + }.to change { ActionMailer::Base.deliveries.count }.by(coaches.count) + .and change { WorkshopInvitation.where(workshop: workshop, role: 'Coach').count }.by(coaches.count) + + # Verify emails were sent to the right recipients + emails = ActionMailer::Base.deliveries.last(coaches.count) + coach_emails = coaches.map(&:email) + expect(emails.map(&:to).flatten).to match_array(coach_emails) end it 'does not invite banned coaches' do