nowk
2/23/2012 - 8:12 PM

Simple custom matcher for emails against a "user" model

Simple custom matcher for emails against a "user" model

RSpec::Matchers.define :have_received_an_email do |expected|
  def last_email
    @last_email ||= ActionMailer::Base.deliveries.last
  end

  def inbox_size
    ActionMailer::Base.deliveries.size
  end

  def to
    last_email.to[0]
  end

  def subjects_match?
    return true if @expected_subject.nil?

    @subject_message = " with subject '#{@expected_subject}'"

    if last_email.subject == @expected_subject
      true
    else
      @subject_message << " not '#{last_email.subject}'"
      false
    end
  end

  def received_an_email?(email)
    inbox_size == 1 && to == email
  end



  def with_subject(expected_subject)
    @expected_subject = expected_subject
    self
  end

  match do |actual|
    received_an_email?(actual.email) && subjects_match?
  end

  failure_message_for_should do |actual|
    "expected #{actual.email} to receive an email#{@subject_message}"
  end

  failure_message_for_should_not do |actual|
    "expected #{actual.email} to not receive an email#{@subject_message}, but did"
  end

  description do
    "#{actual.email} should have received an email#{@subject_message}"
  end
end
describe "an email" do
  let(:user) { Factory(:user) }

  before do
    SomeMailer.email_user(user).deliver
  end

  it "should have received an email with subject" do
    user.should have_received_an_email.with_subject "Rspec my authoritah!"
  end
end