Skip to content

Instantly share code, notes, and snippets.

@ka8725
Last active October 24, 2022 18:41
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ka8725/6053d55be74f15b53cabfc3ac4dc99df to your computer and use it in GitHub Desktop.
Save ka8725/6053d55be74f15b53cabfc3ac4dc99df to your computer and use it in GitHub Desktop.
Send mail matcher
# 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: 'test@example.com', 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