From d468d3b79d138fbd2fa68c4704dda70fa4c0fb5f Mon Sep 17 00:00:00 2001 From: Marcello Barnaba Date: Mon, 23 May 2011 23:57:16 +0200 Subject: [PATCH] Added a matcher that matches a RE or String on parts matching a given content type --- .../matchers/action_mailer/have_sent_email.rb | 33 ++++++++++++++++++- .../action_mailer/have_sent_email_spec.rb | 28 +++++++++++++--- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/lib/shoulda/matchers/action_mailer/have_sent_email.rb b/lib/shoulda/matchers/action_mailer/have_sent_email.rb index 2eab3ff5..56fbcf9f 100644 --- a/lib/shoulda/matchers/action_mailer/have_sent_email.rb +++ b/lib/shoulda/matchers/action_mailer/have_sent_email.rb @@ -36,6 +36,12 @@ module Shoulda # :nodoc: self end + def with_part(content_type, body) + @parts ||= [] + @parts << [/#{Regexp.escape(content_type)}/, body, content_type] + self + end + def to(recipient) @recipient = recipient self @@ -49,6 +55,7 @@ module Shoulda # :nodoc: def matches?(subject) ::ActionMailer::Base.deliveries.each do |mail| @subject_failed = !regexp_or_string_match(mail.subject, @email_subject) if @email_subject + @parts_failed = !parts_match(mail, @parts) if @parts @body_failed = !body_match(mail, @body) if @body @sender_failed = !regexp_or_string_match_in_array(mail.from, @sender) if @sender @recipient_failed = !regexp_or_string_match_in_array(mail.to, @recipient) if @recipient @@ -71,6 +78,9 @@ module Shoulda # :nodoc: description = "send an email" description << " with a subject of #{@email_subject.inspect}" if @email_subject description << " containing #{@body.inspect}" if @body + @parts.each do |_, body, content_type| + description << " having a #{content_type} part containing #{body.inspect}" + end if @parts description << " from #{@sender.inspect}" if @sender description << " to #{@recipient.inspect}" if @recipient description @@ -82,6 +92,9 @@ module Shoulda # :nodoc: expectation = "sent email" expectation << " with subject #{@email_subject.inspect}" if @subject_failed expectation << " with body #{@body.inspect}" if @body_failed + @parts.each do |_, body, content_type| + expectation << " with a #{content_type} part containing #{body}" + end if @parts && @parts_failed expectation << " from #{@sender.inspect}" if @sender_failed expectation << " to #{@recipient.inspect}" if @recipient_failed expectation << " #{!@multipart && 'not '}being multipart" if @multipart_failed @@ -95,7 +108,8 @@ module Shoulda # :nodoc: end def anything_failed? - @subject_failed || @body_failed || @sender_failed || @recipient_failed || @multipart_failed + @subject_failed || @body_failed || @parts_failed || @sender_failed || + @recipient_failed || @multipart_failed end def regexp_or_string_match(a_string, a_regexp_or_string) @@ -129,6 +143,23 @@ module Shoulda # :nodoc: end end + def parts_match(mail, parts) + return false if mail.parts.empty? + + parts.all? do |content_type, match, _| + part_match(mail, content_type, match) + end + end + + def part_match(mail, content_type, a_regexp_or_string) + matching = mail.parts.select {|p| p.content_type =~ content_type} + return false if matching.empty? + + matching.all? do |part| + regexp_or_string_match(part.body, a_regexp_or_string) + end + end + end end end diff --git a/spec/shoulda/action_mailer/have_sent_email_spec.rb b/spec/shoulda/action_mailer/have_sent_email_spec.rb index 43d58ed8..20815715 100644 --- a/spec/shoulda/action_mailer/have_sent_email_spec.rb +++ b/spec/shoulda/action_mailer/have_sent_email_spec.rb @@ -51,6 +51,20 @@ describe Shoulda::Matchers::ActionMailer::HaveSentEmailMatcher do matcher.failure_message.should =~ /Expected sent email with body/ end + it "accepts sent e-mail based on a text/plain part" do + should have_sent_email.with_part('text/plain', /is spam\./) + matcher = have_sent_email.with_part('text/plain', /HTML is spam/) + matcher.matches?(nil) + matcher.failure_message.should =~ /Expected sent email with a text\/plain part containing/ + end + + it "accepts sent e-mail based on a text/html part" do + should have_sent_email.with_part('text/html', /HTML is spam/) + matcher = have_sent_email.with_part('text/html', /HTML is not spam\./) + matcher.matches?(nil) + matcher.failure_message.should =~ /Expected sent email with a text\/html part containing/ + end + it "accept sent e-mail based on the recipient" do should have_sent_email.to('myself@me.com') matcher = have_sent_email.to('you@example.com') @@ -74,8 +88,10 @@ describe Shoulda::Matchers::ActionMailer::HaveSentEmailMatcher do end it "allows chaining" do - should have_sent_email.with_subject(/spam/).from('do-not-reply@example.com').with_body(/spam/).to('myself@me.com') - should_not have_sent_email.with_subject(/ham/).from('you@example.com').with_body(/ham/).to('them@example.com') + should have_sent_email.with_subject(/spam/).from('do-not-reply@example.com').with_body(/spam/). + with_part('text/plain', /is spam\./).with_part('text/html', /HTML is spam/).to('myself@me.com') + should_not have_sent_email.with_subject(/ham/).from('you@example.com').with_body(/ham/). + with_part('text/plain', /is ham/).with_part('text/html', /HTML is ham/).to('them@example.com') end end @@ -86,9 +102,13 @@ describe Shoulda::Matchers::ActionMailer::HaveSentEmailMatcher do matcher.description.should == 'send an email with a subject of "Welcome!"' matcher = matcher.with_body("Welcome, human!") matcher.description.should == 'send an email with a subject of "Welcome!" containing "Welcome, human!"' + matcher = matcher.with_part('text/plain', 'plain') + matcher.description.should == 'send an email with a subject of "Welcome!" containing "Welcome, human!" having a text/plain part containing "plain"' + matcher = matcher.with_part('text/html', 'html') + matcher.description.should == 'send an email with a subject of "Welcome!" containing "Welcome, human!" having a text/plain part containing "plain" having a text/html part containing "html"' matcher = matcher.from("alien@example.com") - matcher.description.should == 'send an email with a subject of "Welcome!" containing "Welcome, human!" from "alien@example.com"' + matcher.description.should == 'send an email with a subject of "Welcome!" containing "Welcome, human!" having a text/plain part containing "plain" having a text/html part containing "html" from "alien@example.com"' matcher = matcher.to("human@example.com") - matcher.description.should == 'send an email with a subject of "Welcome!" containing "Welcome, human!" from "alien@example.com" to "human@example.com"' + matcher.description.should == 'send an email with a subject of "Welcome!" containing "Welcome, human!" having a text/plain part containing "plain" having a text/html part containing "html" from "alien@example.com" to "human@example.com"' end end