Last active
October 24, 2022 18:41
-
-
Save ka8725/6053d55be74f15b53cabfc3ac4dc99df to your computer and use it in GitHub Desktop.
Send mail matcher
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
# Source: https://gist.github.com/ka8725/6053d55be74f15b53cabfc3ac4dc99df | |
# Installation: put this file into spec/support/matchers/ folder. | |
# Simple matcher that allows checking of an email was sent during an example run. | |
# | |
# @example Positive expectation | |
# expect { action }.to send_email | |
# | |
# @example Negative expectations | |
# expect { action }.not_to send_email | |
# expect { action }.to not_send_email | |
# | |
# @example More precise expectation with attributes to match | |
# expect { action }.to send_email(to: '[email protected]', subject: 'Confirm email') | |
# | |
RSpec::Matchers.define :send_email do |criteria = {}| | |
match do |block| | |
@init_criteria = criteria | |
define_matched_emails(block) | |
@matched_emails.size == 1 | |
end | |
failure_message do | |
if multiple_match? | |
'More than 1 matching emails were sent.' | |
else | |
super() | |
end | |
end | |
match_when_negated do |block| | |
define_matched_emails(block) | |
@matched_emails.size.zero? | |
end | |
diffable | |
supports_block_expectations | |
private | |
def define_matched_emails(block) | |
before = deliveries | |
block.call | |
after = deliveries | |
@diff = after - before | |
@matched_emails = select_matching(@diff) | |
end | |
def deliveries | |
ActionMailer::Base.deliveries.clone | |
end | |
def select_matching(emails) | |
criteria.empty? ? emails : emails.select(&method(:matched_email?)) | |
end | |
def matched_email?(email) | |
# `values_match?` is RSpec's comparison API, supporting value matchers like | |
# `hash_including`, `ends_with` and so on. | |
criteria.all? do |attr, expected| | |
values_match?(expected, email.public_send(attr)) | |
end | |
end | |
def criteria | |
@criteria ||= | |
if init_criteria.key?(:to) | |
{ **init_criteria, to: Array(init_criteria[:to]) } | |
else | |
init_criteria | |
end | |
end | |
def init_criteria | |
@init_criteria ||= {} | |
end | |
def multiple_match? | |
@matched_emails.many? | |
end | |
end | |
RSpec::Matchers.define_negated_matcher :not_send_email, :send_email |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment