email_spec-2.3.0/ 0000755 0000041 0000041 00000000000 14671407415 013656 5 ustar www-data www-data email_spec-2.3.0/lib/ 0000755 0000041 0000041 00000000000 14671407415 014424 5 ustar www-data www-data email_spec-2.3.0/lib/generators/ 0000755 0000041 0000041 00000000000 14671407415 016575 5 ustar www-data www-data email_spec-2.3.0/lib/generators/email_spec/ 0000755 0000041 0000041 00000000000 14671407415 020676 5 ustar www-data www-data email_spec-2.3.0/lib/generators/email_spec/steps/ 0000755 0000041 0000041 00000000000 14671407415 022034 5 ustar www-data www-data email_spec-2.3.0/lib/generators/email_spec/steps/steps_generator.rb 0000644 0000041 0000041 00000000550 14671407415 025565 0 ustar www-data www-data # This generator adds email steps to the step definitions directory
require 'rails/generators'
module EmailSpec
class StepsGenerator < Rails::Generators::Base
def generate
copy_file 'email_steps.rb', 'features/step_definitions/email_steps.rb'
end
def self.source_root
File.join(File.dirname(__FILE__), 'templates')
end
end
end email_spec-2.3.0/lib/generators/email_spec/steps/templates/ 0000755 0000041 0000041 00000000000 14671407415 024032 5 ustar www-data www-data email_spec-2.3.0/lib/generators/email_spec/steps/templates/email_steps.rb 0000644 0000041 0000041 00000015772 14671407415 026700 0 ustar www-data www-data # Commonly used email steps
#
# To add your own steps make a custom_email_steps.rb
# The provided methods are:
#
# last_email_address
# reset_mailer
# open_last_email
# visit_in_email
# unread_emails_for
# mailbox_for
# current_email
# open_email
# read_emails_for
# find_email
#
# General form for email scenarios are:
# - clear the email queue (done automatically by email_spec)
# - execute steps that sends an email
# - check the user received an/no/[0-9] emails
# - open the email
# - inspect the email contents
# - interact with the email (e.g. click links)
#
# The Cucumber steps below are setup in this order.
module EmailHelpers
def current_email_address
# Replace with your a way to find your current email. e.g @current_user.email
# last_email_address will return the last email address used by email spec to find an email.
# Note that last_email_address will be reset after each Scenario.
last_email_address || "example@example.com"
end
end
World(EmailHelpers)
#
# Reset the e-mail queue within a scenario.
# This is done automatically before each scenario.
#
Given /^(?:a clear email queue|no emails have been sent)$/ do
reset_mailer
end
#
# Check how many emails have been sent/received
#
Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails?$/ do |address, amount|
expect(unread_emails_for(address).size).to eql parse_email_count(amount)
end
Then /^(?:I|they|"([^"]*?)") should have (an|no|\d+) emails?$/ do |address, amount|
expect(mailbox_for(address).size).to eql parse_email_count(amount)
end
Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails? with subject "([^"]*?)"$/ do |address, amount, subject|
expect(unread_emails_for(address).select { |m| m.subject =~ Regexp.new(Regexp.escape(subject)) }.size).to eql parse_email_count(amount)
end
Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails? with subject \/([^"]*?)\/$/ do |address, amount, subject|
expect(unread_emails_for(address).select { |m| m.subject =~ Regexp.new(subject) }.size).to eql parse_email_count(amount)
end
Then /^(?:I|they|"([^"]*?)") should receive an email with the following body:$/ do |address, expected_body|
open_email(address, :with_text => expected_body)
end
#
# Accessing emails
#
# Opens the most recently received email
When /^(?:I|they|"([^"]*?)") opens? the email$/ do |address|
open_email(address)
end
When /^(?:I|they|"([^"]*?)") opens? the email with subject "([^"]*?)"$/ do |address, subject|
open_email(address, :with_subject => subject)
end
When /^(?:I|they|"([^"]*?)") opens? the email with subject \/([^"]*?)\/$/ do |address, subject|
open_email(address, :with_subject => Regexp.new(subject))
end
When /^(?:I|they|"([^"]*?)") opens? the email with text "([^"]*?)"$/ do |address, text|
open_email(address, :with_text => text)
end
When /^(?:I|they|"([^"]*?)") opens? the email with text \/([^"]*?)\/$/ do |address, text|
open_email(address, :with_text => Regexp.new(text))
end
#
# Inspect the Email Contents
#
Then /^(?:I|they) should see "([^"]*?)" in the email subject$/ do |text|
expect(current_email).to have_subject(text)
end
Then /^(?:I|they) should see \/([^"]*?)\/ in the email subject$/ do |text|
expect(current_email).to have_subject(Regexp.new(text))
end
Then /^(?:I|they) should not see "([^"]*?)" in the email subject$/ do |text|
expect(current_email).not_to have_subject(text)
end
Then /^(?:I|they) should not see \/([^"]*?)\/ in the email subject$/ do |text|
expect(current_email).not_to have_subject(Regexp.new(text))
end
Then /^(?:I|they) should see "([^"]*?)" in the email body$/ do |text|
expect(current_email.default_part_body.to_s).to include(text)
end
Then /^(?:I|they) should not see "([^"]*?)" in the email body$/ do |text|
expect(current_email.default_part_body.to_s).not_to include(text)
end
Then /^(?:I|they) should see \/([^"]*?)\/ in the email body$/ do |text|
expect(current_email.default_part_body.to_s).to match Regexp.new(text)
end
Then /^(?:I|they) should not see \/([^"]*?)\/ in the email body$/ do |text|
expect(current_email.default_part_body.to_s).not_to match Regexp.new(text)
end
Then /^(?:I|they) should see the email delivered from "([^"]*?)"$/ do |text|
expect(current_email).to be_delivered_from(text)
end
Then /^(?:I|they) should see the email reply to "([^"]*?)"$/ do |text|
expect(current_email).to have_reply_to(text)
end
Then /^(?:I|they) should see "([^\"]*)" in the email "([^"]*?)" header$/ do |text, name|
expect(current_email).to have_header(name, text)
end
Then /^(?:I|they) should see \/([^\"]*)\/ in the email "([^"]*?)" header$/ do |text, name|
expect(current_email).to have_header(name, Regexp.new(text))
end
Then /^I should see it is a multi\-part email$/ do
expect(current_email).to be_multipart
end
Then /^(?:I|they) should see "([^"]*?)" in the email html part body$/ do |text|
expect(current_email.html_part.body.to_s).to include(text)
end
Then /^(?:I|they) should see "([^"]*?)" in the email text part body$/ do |text|
expect(current_email.text_part.body.to_s).to include(text)
end
#
# Inspect the Email Attachments
#
Then /^(?:I|they) should see (an|no|\d+) attachments? with the email$/ do |amount|
expect(current_email_attachments.size).to eql parse_email_count(amount)
end
Then /^there should be (an|no|\d+) attachments? named "([^"]*?)"$/ do |amount, filename|
expect(current_email_attachments.select { |a| a.filename == filename }.size).to eql parse_email_count(amount)
end
Then /^attachment (\d+) should be named "([^"]*?)"$/ do |index, filename|
expect(current_email_attachments[(index.to_i - 1)].filename).to eql filename
end
Then /^there should be (an|no|\d+) attachments? of type "([^"]*?)"$/ do |amount, content_type|
expect(current_email_attachments.select { |a| a.content_type.include?(content_type) }.size).to eql parse_email_count(amount)
end
Then /^attachment (\d+) should be of type "([^"]*?)"$/ do |index, content_type|
expect(current_email_attachments[(index.to_i - 1)].content_type).to include(content_type)
end
Then /^all attachments should not be blank$/ do
current_email_attachments.each do |attachment|
expect(attachment.read.size).to_not eql 0
end
end
Then /^show me a list of email attachments$/ do
EmailSpec::EmailViewer::save_and_open_email_attachments_list(current_email)
end
#
# Interact with Email Contents
#
When /^(?:I|they|"([^"]*?)") follows? "([^"]*?)" in the email$/ do |address, link|
visit_in_email(link, address)
end
When /^(?:I|they) click the first link in the email$/ do
click_first_link_in_email
end
#
# Debugging
# These only work with Rails and OSx ATM since EmailViewer uses RAILS_ROOT and OSx's 'open' command.
# Patches accepted. ;)
#
Then /^save and open current email$/ do
EmailSpec::EmailViewer::save_and_open_email(current_email)
end
Then /^save and open all text emails$/ do
EmailSpec::EmailViewer::save_and_open_all_text_emails
end
Then /^save and open all html emails$/ do
EmailSpec::EmailViewer::save_and_open_all_html_emails
end
Then /^save and open all raw emails$/ do
EmailSpec::EmailViewer::save_and_open_all_raw_emails
end
email_spec-2.3.0/lib/email-spec.rb 0000644 0000041 0000041 00000000112 14671407415 016762 0 ustar www-data www-data require File.expand_path(File.join(File.dirname(__FILE__), 'email_spec'))
email_spec-2.3.0/lib/email_spec/ 0000755 0000041 0000041 00000000000 14671407415 016525 5 ustar www-data www-data email_spec-2.3.0/lib/email_spec/address_converter.rb 0000644 0000041 0000041 00000001137 14671407415 022570 0 ustar www-data www-data require 'singleton'
module EmailSpec
class AddressConverter
include Singleton
attr_accessor :converter
# The block provided to conversion should convert to an email
# address string or return the input untouched. For example:
#
# EmailSpec::AddressConverter.instance.conversion do |input|
# if input.is_a?(User)
# input.email
# else
# input
# end
# end
#
def conversion(&block)
self.converter = block
end
def convert(input)
return input unless converter
converter.call(input)
end
end
end email_spec-2.3.0/lib/email_spec/test_observer.rb 0000644 0000041 0000041 00000000214 14671407415 021735 0 ustar www-data www-data module EmailSpec
class TestObserver
def self.delivered_email(message)
ActionMailer::Base.deliveries << message
end
end
end email_spec-2.3.0/lib/email_spec/cucumber.rb 0000644 0000041 0000041 00000001513 14671407415 020657 0 ustar www-data www-data # require this in your env.rb file after you require cucumber/rails/world
# Global Setup
if defined?(ActionMailer)
unless [:test, :activerecord, :cache, :file].include?(ActionMailer::Base.delivery_method)
ActionMailer::Base.register_observer(EmailSpec::TestObserver)
end
ActionMailer::Base.perform_deliveries = true
Before do
# Scenario setup
case ActionMailer::Base.delivery_method
when :test then ActionMailer::Base.deliveries.clear
when :cache then ActionMailer::Base.clear_cache
end
end
end
After do
EmailSpec::EmailViewer.save_and_open_all_raw_emails if ENV['SHOW_EMAILS']
EmailSpec::EmailViewer.save_and_open_all_html_emails if ENV['SHOW_HTML_EMAILS']
EmailSpec::EmailViewer.save_and_open_all_text_emails if ENV['SHOW_TEXT_EMAILS']
end
World(EmailSpec::Helpers)
World(EmailSpec::Matchers)
email_spec-2.3.0/lib/email_spec/matchers.rb 0000644 0000041 0000041 00000031100 14671407415 020653 0 ustar www-data www-data require_relative 'extractors'
module EmailSpec
module Matchers
class EmailMatcher
def address_array
if @email.perform_deliveries
Array(yield)
else
[]
end
end
end
class ReplyTo
def initialize(email)
@expected_reply_to = Mail::ReplyToField.new(email).addrs.first
end
def description
"have reply to as #{@expected_reply_to.address}"
end
def matches?(email)
@email = email
@actual_reply_to = (email.reply_to || []).first
!@actual_reply_to.nil? &&
@actual_reply_to == @expected_reply_to.address
end
def failure_message
"expected #{@email.inspect} to reply to #{@expected_reply_to.address.inspect}, but it replied to #{@actual_reply_to.inspect}"
end
def failure_message_when_negated
"expected #{@email.inspect} not to deliver to #{@expected_reply_to.address.inspect}, but it did"
end
alias negative_failure_message failure_message_when_negated
end
def reply_to(email)
ReplyTo.new(email)
end
alias :have_reply_to :reply_to
class DeliverTo < EmailMatcher
def initialize(expected_email_addresses_or_objects_that_respond_to_email)
emails = expected_email_addresses_or_objects_that_respond_to_email.map do |email_or_object|
email_or_object.kind_of?(String) ? email_or_object : email_or_object.email
end
@expected_recipients = Mail::ToField.new(emails).addrs.map(&:to_s).sort
end
def description
"be delivered to #{@expected_recipients.inspect}"
end
def matches?(email)
@email = email
recipients = email.header[:to] || email.header[:bcc]
@actual_recipients = address_array{ recipients && recipients.addrs }.map(&:to_s).sort
@actual_recipients == @expected_recipients
end
def failure_message
"expected #{@email.inspect} to deliver to #{@expected_recipients.inspect}, but it delivered to #{@actual_recipients.inspect}"
end
def failure_message_when_negated
"expected #{@email.inspect} not to deliver to #{@expected_recipients.inspect}, but it did"
end
alias negative_failure_message failure_message_when_negated
end
def deliver_to(*expected_email_addresses_or_objects_that_respond_to_email)
DeliverTo.new(expected_email_addresses_or_objects_that_respond_to_email.flatten)
end
alias :be_delivered_to :deliver_to
class DeliverFrom < EmailMatcher
def initialize(email)
@expected_sender = Mail::FromField.new(email).addrs.first
end
def description
"be delivered from #{@expected_sender}"
end
def matches?(email)
@email = email
@actual_sender = address_array{ email.header[:from].addrs }.first
!@actual_sender.nil? &&
@actual_sender.to_s == @expected_sender.to_s
end
def failure_message
%(expected #{@email.inspect} to deliver from "#{@expected_sender.to_s}", but it delivered from "#{@actual_sender.to_s}")
end
def failure_message_when_negated
%(expected #{@email.inspect} not to deliver from "#{@expected_sender.to_s}", but it did)
end
alias negative_failure_message failure_message_when_negated
end
def deliver_from(email)
DeliverFrom.new(email)
end
alias :be_delivered_from :deliver_from
class BccTo < EmailMatcher
def initialize(expected_email_addresses_or_objects_that_respond_to_email)
emails = expected_email_addresses_or_objects_that_respond_to_email.map do |email_or_object|
email_or_object.kind_of?(String) ? email_or_object : email_or_object.email
end
@expected_email_addresses = emails.sort
end
def description
"be bcc'd to #{@expected_email_addresses.inspect}"
end
def matches?(email)
@email = email
@actual_recipients = address_array { email[:bcc].formatted }.sort
@actual_recipients == @expected_email_addresses
end
def failure_message
"expected #{@email.inspect} to bcc to #{@expected_email_addresses.inspect}, but it was bcc'd to #{@actual_recipients.inspect}"
end
def failure_message_when_negated
"expected #{@email.inspect} not to bcc to #{@expected_email_addresses.inspect}, but it did"
end
alias negative_failure_message failure_message_when_negated
end
def bcc_to(*expected_email_addresses_or_objects_that_respond_to_email)
BccTo.new(expected_email_addresses_or_objects_that_respond_to_email.flatten)
end
class CcTo < EmailMatcher
def initialize(expected_email_addresses_or_objects_that_respond_to_email)
emails = expected_email_addresses_or_objects_that_respond_to_email.map do |email_or_object|
email_or_object.kind_of?(String) ? email_or_object : email_or_object.email
end
@expected_email_addresses = emails.sort
end
def description
"be cc'd to #{@expected_email_addresses.inspect}"
end
def matches?(email)
@email = email
@actual_recipients = address_array { email[:cc].formatted }.sort
@actual_recipients == @expected_email_addresses
end
def failure_message
"expected #{@email.inspect} to cc to #{@expected_email_addresses.inspect}, but it was cc'd to #{@actual_recipients.inspect}"
end
def failure_message_when_negated
"expected #{@email.inspect} not to cc to #{@expected_email_addresses.inspect}, but it did"
end
alias negative_failure_message failure_message_when_negated
end
def cc_to(*expected_email_addresses_or_objects_that_respond_to_email)
CcTo.new(expected_email_addresses_or_objects_that_respond_to_email.flatten)
end
class HaveSubject
def initialize(subject)
@expected_subject = subject
end
def description
if @expected_subject.is_a?(String)
"have subject of #{@expected_subject.inspect}"
else
"have subject matching #{@expected_subject.inspect}"
end
end
def matches?(email)
@given_subject = email.subject
if @expected_subject.is_a?(String)
@given_subject == @expected_subject
else
!!(@given_subject =~ @expected_subject)
end
end
def failure_message
if @expected_subject.is_a?(String)
"expected the subject to be #{@expected_subject.inspect} but was #{@given_subject.inspect}"
else
"expected the subject to match #{@expected_subject.inspect}, but did not. Actual subject was: #{@given_subject.inspect}"
end
end
def failure_message_when_negated
if @expected_subject.is_a?(String)
"expected the subject not to be #{@expected_subject.inspect} but was"
else
"expected the subject not to match #{@expected_subject.inspect} but #{@given_subject.inspect} does match it."
end
end
alias negative_failure_message failure_message_when_negated
end
def have_subject(subject)
HaveSubject.new(subject)
end
class IncludeEmailWithSubject
def initialize(subject)
@expected_subject = subject
end
def description
if @expected_subject.is_a?(String)
"include email with subject of #{@expected_subject.inspect}"
else
"include email with subject matching #{@expected_subject.inspect}"
end
end
def matches?(emails)
@given_emails = emails
if @expected_subject.is_a?(String)
@given_emails.map(&:subject).include?(@expected_subject)
else
!!(@given_emails.any?{ |mail| mail.subject =~ @expected_subject })
end
end
def failure_message
if @expected_subject.is_a?(String)
"expected at least one email to have the subject #{@expected_subject.inspect} but none did. Subjects were #{@given_emails.map(&:subject).inspect}"
else
"expected at least one email to have a subject matching #{@expected_subject.inspect}, but none did. Subjects were #{@given_emails.map(&:subject).inspect}"
end
end
def failure_message_when_negated
if @expected_subject.is_a?(String)
"expected no email with the subject #{@expected_subject.inspect} but found at least one. Subjects were #{@given_emails.map(&:subject).inspect}"
else
"expected no email to have a subject matching #{@expected_subject.inspect} but found at least one. Subjects were #{@given_emails.map(&:subject).inspect}"
end
end
alias negative_failure_message failure_message_when_negated
end
def include_email_with_subject(*emails)
IncludeEmailWithSubject.new(emails.flatten.first)
end
class HaveBodyText
def initialize(text)
@expected_text = text
@extractor = EmailSpec::Extractors::DefaultPartBody
end
def description
if @expected_text.is_a?(String)
"have body including #{@expected_text.inspect}"
else
"have body matching #{@expected_text.inspect}"
end
end
def in_html_part
@extractor = EmailSpec::Extractors::HtmlPartBody
self
end
def in_text_part
@extractor = EmailSpec::Extractors::TextPartBody
self
end
def matches?(email)
if @expected_text.is_a?(String)
@given_text = @extractor.new(email).call.to_s.gsub(/\s+/, " ")
@expected_text = @expected_text.gsub(/\s+/, " ")
@given_text.include?(@expected_text)
else
@given_text = @extractor.new(email).call.to_s
!!(@given_text =~ @expected_text)
end
end
def failure_message
if @expected_text.is_a?(String)
"expected the body to contain #{@expected_text.inspect} but was #{@given_text.inspect}"
else
"expected the body to match #{@expected_text.inspect}, but did not. Actual body was: #{@given_text.inspect}"
end
end
def failure_message_when_negated
if @expected_text.is_a?(String)
"expected the body not to contain #{@expected_text.inspect} but was #{@given_text.inspect}"
else
"expected the body not to match #{@expected_text.inspect} but #{@given_text.inspect} does match it."
end
end
alias negative_failure_message failure_message_when_negated
end
def have_body_text(text)
HaveBodyText.new(text)
end
class HaveHeader
def initialize(name, value)
@expected_name, @expected_value = name, value
end
def description
if @expected_value.is_a?(String)
"have header #{@expected_name}: #{@expected_value}"
else
"have header #{@expected_name} with value matching #{@expected_value.inspect}"
end
end
def matches?(email)
@given_header = email.header
if @expected_value.is_a?(String)
@given_header[@expected_name].to_s == @expected_value
else
@given_header[@expected_name].to_s =~ @expected_value
end end
def failure_message
if @expected_value.is_a?(String)
"expected the headers to include '#{@expected_name}: #{@expected_value}' but they were #{mail_headers_hash(@given_header).inspect}"
else
"expected the headers to include '#{@expected_name}' with a value matching #{@expected_value.inspect} but they were #{mail_headers_hash(@given_header).inspect}"
end
end
def failure_message_when_negated
if @expected_value.is_a?(String)
"expected the headers not to include '#{@expected_name}: #{@expected_value}' but they were #{mail_headers_hash(@given_header).inspect}"
else
"expected the headers not to include '#{@expected_name}' with a value matching #{@expected_value.inspect} but they were #{mail_headers_hash(@given_header).inspect}"
end
end
alias negative_failure_message failure_message_when_negated
def mail_headers_hash(email_headers)
email_headers.fields.inject({}) do |hash, field|
if field.field.class.const_defined?('FIELD_NAME')
hash[field.field.class::FIELD_NAME] = field.to_s
else
hash[field.field.class::NAME.downcase] = field.to_s
end
hash
end
end
end
def have_header(name, value)
HaveHeader.new(name, value)
end
def self.included base
if base.respond_to? :register_matcher
instance_methods.each do |name|
base.register_matcher name, name
end
end
end
end
end
email_spec-2.3.0/lib/email_spec/helpers.rb 0000644 0000041 0000041 00000014362 14671407415 020522 0 ustar www-data www-data require 'uri'
require 'email_spec/deliveries'
module EmailSpec
module Helpers
include Deliveries
A_TAG_BEGIN_REGEX = %r{]*href=['"]?([^'"]*)['"]?[^>]*>\s*(?:(?!).)*?\s*}
A_TAG_END_REGEX = %r{\s*(?:(?!).)*?\s*}
def visit_in_email(link_text, address = '')
if address.nil? || address.empty?
email = current_email
else
email = find_email!(address)
end
visit(parse_email_for_link(email, link_text))
end
def click_email_link_matching(regex, email = current_email)
url = links_in_email(email).detect { |link| link =~ regex }
raise "No link found matching #{regex.inspect} in #{email.default_part_body}" unless url
visit request_uri(url)
end
def click_first_link_in_email(email = current_email)
link = links_in_email(email).first
visit request_uri(link)
end
def open_email(address, opts={})
set_current_email(find_email!(address, opts))
end
alias_method :open_email_for, :open_email
def open_last_email
set_current_email(last_email_sent)
end
def open_last_email_for(address)
set_current_email(mailbox_for(address).last)
end
def current_email(address=nil)
address = convert_address(address)
email = address ? email_spec_hash[:current_emails][address] : email_spec_hash[:current_email]
exception_class = if defined?(RSpec)
RSpec::Expectations::ExpectationNotMetError
else
StandardError
end
raise exception_class, "Expected an open email but none was found. Did you forget to call open_email?" unless email
email
end
def current_email_attachments(address=nil)
current_email(address).attachments || Array.new
end
def unread_emails_for(address)
read_message_ids = read_emails_for(address).map(&:message_id)
mailbox_for(address).reject { |m| read_message_ids.include?(m.message_id) }
end
def read_emails_for(address)
email_spec_hash[:read_emails][convert_address(address)] ||= []
end
# Should be able to accept String or Regexp options.
def find_email(address, opts={})
address = convert_address(address)
if opts[:with_subject]
expected_subject = (opts[:with_subject].is_a?(String) ? Regexp.escape(opts[:with_subject]) : opts[:with_subject])
mailbox_for(address).find { |m| m.subject =~ Regexp.new(expected_subject) }
elsif opts[:with_text]
expected_text = (opts[:with_text].is_a?(String) ? Regexp.escape(opts[:with_text]) : opts[:with_text])
mailbox_for(address).find { |m| m.default_part_body =~ Regexp.new(expected_text) }
elsif opts[:from]
mailbox_for(address).find { |m| m.from.include? opts[:from] }
else
mailbox_for(address).first
end
end
def links_in_email(email)
links = URI::Parser.new.extract(email.default_part_body.to_s, ['http', 'https'])
links.map{|url| HTMLEntities.new.decode(url) }.uniq
end
private
def email_spec_hash
@email_spec_hash ||= {:read_emails => {}, :unread_emails => {}, :current_emails => {}, :current_email => nil}
end
def find_email!(address, opts={})
email = find_email(address, opts)
if current_email_address.nil?
raise EmailSpec::NoEmailAddressProvided, "No email address has been provided. Make sure current_email_address is returning something."
elsif email.nil?
error = "#{opts.keys.first.to_s.gsub("_", " ").downcase unless opts.empty?} #{('"' + opts.values.first.to_s + '"') unless opts.empty?}"
raise EmailSpec::CouldNotFindEmailError, "Could not find email #{error} in the mailbox for #{current_email_address}. \n Found the following emails:\n\n #{all_emails.to_s}"
end
email
end
def set_current_email(email)
return unless email
[email.to, email.cc, email.bcc].compact.flatten.each do |to|
read_emails_for(to) << email
email_spec_hash[:current_emails][to] = email
end
email_spec_hash[:current_email] = email
end
def parse_email_for_link(email, text_or_regex)
matcher = EmailSpec::Matchers::HaveBodyText.new(text_or_regex)
if defined?(RSpec)
RSpec::Expectations::PositiveExpectationHandler.handle_matcher(email, matcher)
else
assert_must matcher, email
end
url = parse_email_for_explicit_link(email, text_or_regex)
url ||= parse_email_for_anchor_text_link(email, text_or_regex)
raise "No link found matching #{text_or_regex.inspect} in #{email}" unless url
url
end
def request_uri(link)
return unless link
url = URI::parse(link)
url.fragment ? (url.request_uri + "#" + url.fragment) : url.request_uri
end
# e.g. confirm in http://confirm
def parse_email_for_explicit_link(email, regex)
regex = /#{Regexp.escape(regex)}/ unless regex.is_a?(Regexp)
url = links_in_email(email).detect { |link| link =~ regex }
request_uri(url)
end
# e.g. Click here in Click here
def parse_email_for_anchor_text_link(email, link_text)
if textify_images(email.default_part_body) =~ %r{#{A_TAG_BEGIN_REGEX}#{link_text}#{A_TAG_END_REGEX}}
URI.split($1)[5..-1].compact!.join("?").gsub("&", "&")
# sub correct ampersand after rails switches it (http://dev.rubyonrails.org/ticket/4002)
else
return nil
end
end
def textify_images(email_body)
email_body.to_s.gsub(%r{
]*alt=['"]?([^'"]*)['"]?[^>]*?/>}) { $1 }
end
def parse_email_count(amount)
case amount
when "no"
0
when "an"
1
else
amount.to_i
end
end
attr_reader :last_email_address
def convert_address(address)
@last_email_address = (address || current_email_address)
AddressConverter.instance.convert(@last_email_address)
end
# Overwrite this method to set default email address, for example:
# last_email_address || @current_user.email
def current_email_address
last_email_address
end
def mailbox_for(address)
super(convert_address(address)) # super resides in Deliveries
end
def email_spec_deprecate(text)
puts ""
puts "DEPRECATION: #{text.split.join(' ')}"
puts ""
end
end
end
email_spec-2.3.0/lib/email_spec/rspec.rb 0000644 0000041 0000041 00000000245 14671407415 020167 0 ustar www-data www-data RSpec.configure do |config|
config.include(EmailSpec::Helpers)
config.include(EmailSpec::Matchers)
config.before(:each) do |group|
reset_mailer
end
end
email_spec-2.3.0/lib/email_spec/mail_ext.rb 0000644 0000041 0000041 00000000556 14671407415 020662 0 ustar www-data www-data module EmailSpec::MailExt
def default_part
@default_part ||= html_part || text_part || self
end
def default_part_body
# Calling to_str as we want the actual String object
HTMLEntities.new.decode(default_part.decoded.to_s.to_str)
end
def html
html_part ? html_part.decoded : nil
end
end
Mail::Message.send(:include, EmailSpec::MailExt)
email_spec-2.3.0/lib/email_spec/extractors.rb 0000644 0000041 0000041 00000001336 14671407415 021253 0 ustar www-data www-data module EmailSpec
module Extractors
class Base
attr_accessor :mail
def initialize(mail)
@mail = mail
end
def call
part_body ? HTMLEntities.new.decode(part_body) : ''
end
private
def part_body
raise NotImplementedError
end
end
class DefaultPartBody < Base
private
def part_body
(mail.html_part || mail.text_part || mail).body
end
end
class HtmlPartBody < Base
private
def part_body
mail.html_part ? mail.html_part.body : nil
end
end
class TextPartBody < Base
private
def part_body
mail.text_part ? mail.text_part.body : nil
end
end
end
end
email_spec-2.3.0/lib/email_spec/deliveries.rb 0000644 0000041 0000041 00000002351 14671407415 021206 0 ustar www-data www-data module EmailSpec
module Deliveries
def all_emails
deliveries
end
def last_email_sent
deliveries.last || raise("No email has been sent!")
end
def reset_mailer
if defined?(ActionMailer) && ActionMailer::Base.delivery_method == :activerecord
Email.delete_all
elsif defined?(ActionMailer) && ActionMailer::Base.delivery_method == :cache
mailer.clear_cache
else
deliveries.clear
end
end
def mailbox_for(address)
deliveries.select { |email| email.destinations.include?(address) }
end
protected
def deliveries
if defined?(Pony)
Pony.deliveries
elsif ActionMailer::Base.delivery_method == :activerecord
Email.all.map { |email| parse_ar_to_mail(email) }
elsif ActionMailer::Base.delivery_method == :cache
mailer.cached_deliveries
else
mailer.deliveries
end
end
def mailer
ActionMailer::Base
end
def parse_ar_to_mail(email)
Mail.read(email.mail)
end
end
if defined?(Pony)
module ::Pony
def self.deliveries
@deliveries ||= []
end
def self.mail(options)
deliveries << build_mail(options)
end
end
end
end
email_spec-2.3.0/lib/email_spec/spinach.rb 0000644 0000041 0000041 00000001675 14671407415 020510 0 ustar www-data www-data # Require this in your spinach features/support/env.rb file to get access
# to the helpers and matchers in your steps.
if defined?(ActionMailer)
unless [:test, :activerecord, :cache, :file].include?(ActionMailer::Base.delivery_method)
ActionMailer::Base.register_observer(EmailSpec::TestObserver)
end
ActionMailer::Base.perform_deliveries = true
Spinach.hooks.before_scenario do
# Scenario setup
case ActionMailer::Base.delivery_method
when :test then ActionMailer::Base.deliveries.clear
when :cache then ActionMailer::Base.clear_cache
end
end
end
Spinach.hooks.after_scenario do
EmailSpec::EmailViewer.save_and_open_all_raw_emails if ENV['SHOW_EMAILS']
EmailSpec::EmailViewer.save_and_open_all_html_emails if ENV['SHOW_HTML_EMAILS']
EmailSpec::EmailViewer.save_and_open_all_text_emails if ENV['SHOW_TEXT_EMAILS']
end
class Spinach::FeatureSteps
include EmailSpec::Helpers
include EmailSpec::Matchers
end
email_spec-2.3.0/lib/email_spec/version.rb 0000644 0000041 0000041 00000000110 14671407415 020527 0 ustar www-data www-data # frozen_string_literal: true
module EmailSpec
VERSION = "2.3.0"
end
email_spec-2.3.0/lib/email_spec/email_viewer.rb 0000644 0000041 0000041 00000004710 14671407415 021524 0 ustar www-data www-data module EmailSpec
class EmailViewer
extend Deliveries
def self.save_and_open_all_raw_emails
filename = tmp_email_filename
File.open(filename, "w") do |f|
all_emails.each do |m|
f.write m.to_s
f.write "\n" + '='*80 + "\n"
end
end
open_in_text_editor(filename)
end
def self.save_and_open_all_html_emails
all_emails.each_with_index do |m, index|
if m.multipart? && m.parts.detect{ |p| p.content_type.include?('text/html') }
filename = tmp_email_filename("-#{index}.html")
File.open(filename, "w") do |f|
f.write m.parts[1].body
end
open_in_browser(filename)
end
end
end
def self.save_and_open_all_text_emails
filename = tmp_email_filename
File.open(filename, "w") do |f|
all_emails.each do |m|
if m.multipart? && text_part = m.parts.detect{ |p| p.content_type.include?('text/plain') }
if m.respond_to?(:ordered_each) # Rails 2 / TMail
m.ordered_each{|k,v| f.write "#{k}: #{v}\n" }
else # Rails 4 / Mail
f.write(text_part.header.to_s + "\n")
end
f.write text_part.body
else
f.write m.to_s
end
f.write "\n" + '='*80 + "\n"
end
end
open_in_text_editor(filename)
end
def self.save_and_open_email(mail)
filename = tmp_email_filename
File.open(filename, "w") do |f|
f.write mail.to_s
end
open_in_text_editor(filename)
end
def self.save_and_open_email_attachments_list(mail)
filename = tmp_email_filename
File.open(filename, "w") do |f|
mail.attachments.each_with_index do |attachment, index|
info = "#{index + 1}:"
info += "\n\tfilename: #{attachment.original_filename}"
info += "\n\tcontent type: #{attachment.content_type}"
info += "\n\tsize: #{attachment.size}"
f.write info + "\n"
end
end
open_in_text_editor(filename)
end
def self.open_in_text_editor(filename)
Launchy.open(URI.parse("file://#{File.expand_path(filename)}"), :application => :editor)
end
def self.open_in_browser(filename)
Launchy.open(URI.parse("file://#{File.expand_path(filename)}"))
end
def self.tmp_email_filename(extension = '.txt')
"#{Rails.root}/tmp/email-#{Time.now.to_i}#{extension}"
end
end
end
email_spec-2.3.0/lib/email_spec/errors.rb 0000644 0000041 0000041 00000000200 14671407415 020356 0 ustar www-data www-data module EmailSpec
class CouldNotFindEmailError < StandardError
end
class NoEmailAddressProvided < StandardError
end
end
email_spec-2.3.0/lib/email_spec.rb 0000644 0000041 0000041 00000001145 14671407415 017053 0 ustar www-data www-data unless defined?(Pony) or defined?(ActionMailer)
Kernel.warn("Neither Pony nor ActionMailer appear to be loaded so email-spec is requiring ActionMailer.")
require 'action_mailer'
end
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
require 'htmlentities'
require 'mail'
require 'email_spec/deliveries'
require 'email_spec/address_converter'
require 'email_spec/email_viewer'
require 'email_spec/helpers'
require 'email_spec/matchers'
require 'email_spec/mail_ext'
require 'email_spec/test_observer'
require 'email_spec/errors'
email_spec-2.3.0/spec/ 0000755 0000041 0000041 00000000000 14671407415 014610 5 ustar www-data www-data email_spec-2.3.0/spec/spec_helper.rb 0000644 0000041 0000041 00000001264 14671407415 017431 0 ustar www-data www-data require 'rubygems'
require 'action_mailer'
require 'mail'
require File.expand_path(File.dirname(__FILE__) + '/../lib/email_spec.rb')
RSpec.configure do |config|
config.include EmailSpec::Helpers
config.include EmailSpec::Matchers
config.mock_with :rspec
config.raise_errors_for_deprecations!
def matcher_failure_message(matcher)
matcher.respond_to?(:failure_message_for_should) ?
matcher.failure_message_for_should :
matcher.failure_message
end
def matcher_failure_message_when_negated(matcher)
matcher.respond_to?(:failure_message_for_should_not) ?
matcher.failure_message_for_should_not :
matcher.negative_failure_message
end
end
email_spec-2.3.0/spec/email_spec/ 0000755 0000041 0000041 00000000000 14671407415 016711 5 ustar www-data www-data email_spec-2.3.0/spec/email_spec/mail_ext_spec.rb 0000644 0000041 0000041 00000003602 14671407415 022053 0 ustar www-data www-data require 'spec_helper'
describe EmailSpec::MailExt do
describe "#default_part" do
it "prefers html_part over text_part" do
email = Mail.new do
text_part { body "This is text" }
html_part { body "This is html" }
end
expect(email.default_part.body.to_s).to eq("This is html")
end
it "returns text_part if html_part not available" do
email = Mail.new do
text_part { body "This is text" }
end
expect(email.default_part.body.to_s).to eq("This is text")
end
it "returns the email if not multi-part" do
email = Mail.new { body "This is the body" }
expect(email.default_part.body.to_s).to eq("This is the body")
end
end
describe "#default_part_body" do
it "returns default_part.body" do
email = Mail.new(:body => "hi")
expect(email.default_part.body).to eq(email.default_part_body)
end
it "compatible with ActiveSupport::SafeBuffer" do
email = Mail.new(:body => ActiveSupport::SafeBuffer.new("bacon & pancake"))
expect(email.default_part_body).to eq ("bacon & pancake")
end
it "decodes parts before return" do
email = Mail.new(:body => "hello\r\nquoted-printable")
email.content_transfer_encoding = 'quoted-printable'
expect(email.encoded).to include("hello\r\nquoted-printable=")
expect(email.default_part_body).to eq("hello\nquoted-printable")
end
end
describe "#html" do
it "returns the html part body" do
email = Mail.new do
html_part { body "This is html" }
end
expect(email.html).to eq("This is html")
end
it "returns a String" do
email = Mail.new do
html_part { body "This is html" }
end
expect(email.html).to be_a(String)
end
it "returns nil for mail with no html part" do
email = Mail.new
expect(email.html).to be_nil
end
end
end
email_spec-2.3.0/spec/email_spec/email_viewer_spec.rb 0000644 0000041 0000041 00000001177 14671407415 022726 0 ustar www-data www-data require 'spec_helper'
require 'launchy'
describe EmailSpec::EmailViewer do
describe ".open_in_browser" do
it "should open with launchy" do
expected_uri = URI("file://#{File.expand_path("a_file")}")
expect(Launchy).to receive(:open).with(expected_uri)
EmailSpec::EmailViewer.open_in_browser("a_file")
end
end
describe ".open_in_text_editor" do
it "should open with launchy" do
expected_uri = URI("file://#{File.expand_path("a_file")}")
expect(Launchy).to receive(:open).with(expected_uri, {application: :editor})
EmailSpec::EmailViewer.open_in_text_editor("a_file")
end
end
end
email_spec-2.3.0/spec/email_spec/helpers_spec.rb 0000644 0000041 0000041 00000026501 14671407415 021716 0 ustar www-data www-data require File.dirname(__FILE__) + '/../spec_helper'
describe EmailSpec::Helpers do
include EmailSpec::Helpers
describe "#visit_in_email" do
it "visits the link in the email" do
@to = "jimmy_bean@yahoo.com"
@body = "Hello!"
@email = Mail::Message.new(:to => @to, :from => "foo@bar.com", :body => @body)
allow(self).to receive(:mailbox_for).with(@to).and_return([@email])
expect(open_email(@to, :from => "foo@bar.com")).to eq(@email)
expect do
expect(self).to(receive(:visit).with('/hello'))
visit_in_email("Hello!")
end.not_to raise_error
end
it "raises an exception when an email is not found" do
expect do
visit_in_email("Hello!", 'jon@example.com')
end.to raise_error(EmailSpec::CouldNotFindEmailError)
end
end
describe "#parse_email_for_link" do
it "properly finds links with text" do
email = Mail.new(:body => %(Click Here))
expect(parse_email_for_link(email, "Click Here")).to eq("/path/to/page")
end
it "properly finds links with text surrounded by tags" do
email = Mail.new(:body => %(
WelcomeClick Here))
expect(parse_email_for_link(email, "Click Here")).to eq("/path/to/page")
end
it "properly finds links with tags and text in new lines" do
email = Mail.new(:body => <<-HTML
Welcome
Click Here
HTML
)
expect(parse_email_for_link(email, "Click Here")).to eq("/path/to/page")
end
it "recognizes img alt properties as text" do
email = Mail.new(:body => %(
))
expect(parse_email_for_link(email, "an image")).to eq("/path/to/page")
end
it "causes a spec to fail if the body doesn't contain the text specified to click" do
email = Mail.new(:body => "")
expect { parse_email_for_link(email, "non-existent text") }.to raise_error( RSpec::Expectations::ExpectationNotMetError)
end
end
describe "#set_current_email" do
it "should cope with a nil email" do
expect do
out = set_current_email(nil)
expect(out).to be_nil
expect(email_spec_hash[:current_email]).to be_nil
end.not_to raise_error
end
it "should cope with a real email" do
email = Mail.new
expect do
out = set_current_email(email)
expect(out).to eq(email)
expect(email_spec_hash[:current_email]).to eq(email)
end.not_to raise_error
end
shared_examples_for 'something that sets the current email for recipients' do
before do
@email = Mail.new(@recipient_type => 'dave@example.com')
end
it "should record that the email has been read for that recipient" do
set_current_email(@email)
expect(email_spec_hash[:read_emails]['dave@example.com']).to include(@email)
end
it "should record that the email has been read for all the recipient of that type" do
@email.send(@recipient_type) << 'dave_2@example.com'
set_current_email(@email)
expect(email_spec_hash[:read_emails]['dave@example.com']).to include(@email)
expect(email_spec_hash[:read_emails]['dave_2@example.com']).to include(@email)
end
it "should record that the email is the current email for the recipient" do
set_current_email(@email)
expect(email_spec_hash[:current_emails]['dave@example.com']).to eq(@email)
end
it "should record that the email is the current email for all the recipients of that type" do
@email.send(@recipient_type) << 'dave_2@example.com'
set_current_email(@email)
expect(email_spec_hash[:current_emails]['dave@example.com']).to eq(@email)
expect(email_spec_hash[:current_emails]['dave_2@example.com']).to eq(@email)
end
it "should overwrite current email for the recipient with this one" do
other_mail = Mail.new
email_spec_hash[:current_emails]['dave@example.com'] = other_mail
set_current_email(@email)
expect(email_spec_hash[:current_emails]['dave@example.com']).to eq(@email)
end
it "should overwrite the current email for all the recipients of that type" do
other_mail = Mail.new
email_spec_hash[:current_emails]['dave@example.com'] = other_mail
email_spec_hash[:current_emails]['dave_2@example.com'] = other_mail
@email.send(@recipient_type) << 'dave_2@example.com'
set_current_email(@email)
expect(email_spec_hash[:current_emails]['dave@example.com']).to eq(@email)
expect(email_spec_hash[:current_emails]['dave_2@example.com']).to eq(@email)
end
it "should not complain when the email has recipients of that type" do
@email.send(:"#{@recipient_type}=", nil)
expect { set_current_email(@email) }.not_to raise_error
end
end
describe "#request_uri(link)" do
context "without query and anchor" do
it "returns the path" do
expect(request_uri('http://www.path.se/to/page')).to eq('/to/page')
end
end
context "with query and anchor" do
it "returns the path and query and the anchor" do
expect(request_uri('http://www.path.se/to/page?q=adam#task')).to eq('/to/page?q=adam#task')
end
end
context "with anchor" do
it "returns the path and query and the anchor" do
expect(request_uri('http://www.path.se/to/page#task')).to eq('/to/page#task')
end
end
end
describe 'for mails with recipients in the to address' do
before do
@recipient_type = :to
end
it_should_behave_like 'something that sets the current email for recipients'
end
describe 'for mails with recipients in the cc address' do
before do
@recipient_type = :cc
end
it_should_behave_like 'something that sets the current email for recipients'
end
describe 'for mails with recipients in the bcc address' do
before do
@recipient_type = :bcc
end
it_should_behave_like 'something that sets the current email for recipients'
end
end
describe '#open_email' do
describe 'from' do
before do
@to = "jimmy_bean@yahoo.com"
@email = Mail::Message.new(:to => @to, :from => "foo@bar.com")
allow(self).to receive(:mailbox_for).with(@to).and_return([@email])
end
it "should open the email from someone" do
expect(open_email(@to, :from => "foo@bar.com")).to eq(@email)
end
end
describe 'with subject' do
shared_examples_for 'something that opens the email with subject' do
before do
@to = "jimmy_bean@yahoo.com"
@email = Mail::Message.new(:to => @to, :subject => @subject)
allow(self).to receive(:mailbox_for).with(@to).and_return([@email])
end
it "should open the email with subject" do
expect(open_email(@to, :with_subject => @expected)).to eq(@email)
end
end
describe 'simple string subject' do
before do
@subject = 'This is a simple subject'
@expected = 'a simple'
end
it_should_behave_like 'something that opens the email with subject'
end
describe 'string with regex sensitive characters' do
before do
@subject = '[app name] Contains regex characters?'
@expected = 'regex characters?'
end
it_should_behave_like 'something that opens the email with subject'
end
describe 'regular expression' do
before do
@subject = "This is a simple subject"
@expected = /a simple/
end
it_should_behave_like 'something that opens the email with subject'
end
end
describe 'with text' do
shared_examples_for 'something that opens the email with text' do
before do
@to = "jimmy_bean@yahoo.com"
@email = Mail::Message.new(:to => @to, :body => @body)
allow(self).to receive(:mailbox_for).with(@to).and_return([@email])
end
it "should open the email with text" do
expect(open_email(@to, :with_text => @text)).to eq(@email)
end
end
describe 'simple string text' do
before do
@body = 'This is an email body that is very simple'
@text = 'email body'
end
it_should_behave_like 'something that opens the email with text'
end
describe 'string with regex sensitive characters' do
before do
@body = 'This is an email body. It contains some [regex] characters?'
@text = '[regex] characters?'
end
it_should_behave_like 'something that opens the email with text'
end
describe 'regular expression' do
before do
@body = 'This is an email body.'
@text = /an\ email/
end
it_should_behave_like 'something that opens the email with text'
end
end
describe "when the email isn't found" do
it "includes the mailbox that was looked in when an address was provided" do
@email_address = "foo@bar.com"
expect { open_email(@email_address, :with_subject => "baz") }.to raise_error(EmailSpec::CouldNotFindEmailError) { |error| expect(error.message).to include(@email_address) }
end
it "includes a warning that no mailboxes were searched when no address was provided" do
allow(subject).to receive(:last_email_address).and_return nil
expect { open_email(nil, :with_subject => "baz") }.to raise_error(EmailSpec::NoEmailAddressProvided) { |error| expect(error.message).to eq("No email address has been provided. Make sure current_email_address is returning something.") }
end
describe "search by with_subject" do
before do
@email_subject = "Subject of 'Nonexistent Email'"
begin
open_email("foo@bar.com", :with_subject => @email_subject)
rescue EmailSpec::CouldNotFindEmailError => e
@error = e
end
expect(@error).not_to be_nil, "expected an error to get thrown so we could test against it, but didn't catch one"
end
it "includes the subject that wasn't found in the error message" do
expect(@error.message).to include(@email_subject)
end
it "includes 'with subject' in the error message" do
expect(@error.message).to include('with subject')
end
end
describe "search by with_text" do
before do
@email_text = "This is a line of text from a 'Nonexistent Email'."
begin
open_email("foo@bar.com", :with_text => @email_text)
rescue EmailSpec::CouldNotFindEmailError => e
@error = e
end
expect(@error).not_to be_nil, "expected an error to get thrown so we could test against it, but didn't catch one"
end
it "includes the text that wasn't found in the error message" do
expect(@error.message).to include(@email_text)
end
it "includes 'with text' in the error message" do
expect(@error.message).to include('with text')
end
end
end
end
end
email_spec-2.3.0/spec/email_spec/matchers_spec.rb 0000644 0000041 0000041 00000056423 14671407415 022070 0 ustar www-data www-data require File.dirname(__FILE__) + '/../spec_helper'
describe EmailSpec::Matchers do
include EmailSpec::Matchers
class MatcherMatch
def initialize(object_to_test_match)
@object_to_test_match = object_to_test_match
end
def description
"match when provided #{@object_to_test_match.inspect}"
end
def matches?(matcher)
@matcher = matcher
matcher.matches?(@object_to_test_match)
end
def failure_message
"expected #{@matcher.inspect} to match when provided #{@object_to_test_match.inspect}, but it did not"
end
def failure_message_when_negated
"expected #{@matcher.inspect} not to match when provided #{@object_to_test_match.inspect}, but it did"
end
alias negative_failure_message failure_message_when_negated
end
def match(object_to_test_match)
if object_to_test_match.is_a?(Regexp)
super # delegate to rspec's built in 'match' matcher
else
MatcherMatch.new(object_to_test_match)
end
end
describe "#reply_to" do
it "should match when the email is set to deliver to the specified address" do
email = Mail::Message.new(:reply_to => ["test@gmail.com"])
expect(reply_to("test@gmail.com")).to match(email)
end
it "should match given a name and address" do
email = Mail::Message.new(:reply_to => ["test@gmail.com"])
expect(reply_to("David Balatero ")).to match(email)
end
it "should give correct failure message when the email is not set to deliver to the specified address" do
matcher = reply_to("jimmy_bean@yahoo.com")
message = Mail::Message.new(:reply_to => ['freddy_noe@yahoo.com'])
allow(message).to receive(:inspect).and_return("email")
matcher.matches?(message)
expect(matcher_failure_message(matcher)).to eq(%{expected email to reply to "jimmy_bean@yahoo.com", but it replied to "freddy_noe@yahoo.com"})
end
end
describe "#deliver_to" do
it "should match when the email is set to deliver to the specified address" do
email = Mail::Message.new(:to => "jimmy_bean@yahoo.com")
expect(deliver_to("jimmy_bean@yahoo.com")).to match(email)
end
it "should match when the email is set to deliver to the specified name and address" do
email = Mail::Message.new(:to => "Jimmy Bean ")
expect(deliver_to("Jimmy Bean ")).to match(email)
end
it "should match when a list of emails is exact same as all of the email's recipients" do
email = Mail::Message.new(:to => ["james@yahoo.com", "karen@yahoo.com"])
expect(deliver_to("karen@yahoo.com", "james@yahoo.com")).to match(email)
expect(deliver_to("karen@yahoo.com")).not_to match(email)
end
it "should match when an array of emails is exact same as all of the email's recipients" do
addresses = ["james@yahoo.com", "karen@yahoo.com"]
email = Mail::Message.new(:to => addresses)
expect(deliver_to(addresses)).to match(email)
end
it "should match when the names and email addresses match in any order" do
addresses = ["James ", "Karen "]
email = Mail::Message.new(:to => addresses.reverse)
expect(deliver_to(addresses)).to match(email)
end
it "should use the passed in objects :email method if not a string" do
email = Mail::Message.new(:to => "jimmy_bean@yahoo.com")
user = double("user", :email => "jimmy_bean@yahoo.com")
expect(deliver_to(user)).to match(email)
end
it "should not match when the email does not have a recipient" do
email = Mail::Message.new(:to => nil)
expect(deliver_to("jimmy_bean@yahoo.com")).not_to match(email)
end
it "should not match when the email addresses match but the names do not" do
email = Mail::Message.new(:to => "Jimmy Bean ")
expect(deliver_to("Freddy Noe ")).not_to match(email)
end
it "should not match when the names match but the email addresses do not" do
email = Mail::Message.new(:to => "Jimmy Bean ")
expect(deliver_to("Jimmy Bean ")).not_to match(email)
end
it "should give correct failure message when the email is not set to deliver to the specified address" do
matcher = deliver_to("jimmy_bean@yahoo.com")
message = Mail::Message.new(:to => 'freddy_noe@yahoo.com')
allow(message).to receive(:inspect).and_return("email")
matcher.matches?(message)
expect(matcher_failure_message(matcher)).to eq(%{expected email to deliver to ["jimmy_bean@yahoo.com"], but it delivered to ["freddy_noe@yahoo.com"]})
end
it "should deliver to nobody when the email does not perform deliveries" do
email = Mail::Message.new(:to => "jimmy_bean@yahoo.com")
email.perform_deliveries = false
expect(deliver_to("jimmy_bean@yahoo.com")).not_to match(email)
end
end
describe "#deliver_from" do
it "should match when the email is set to deliver from the specified address" do
email = Mail::Message.new(:from => "jimmy_bean@yahoo.com")
expect(deliver_from("jimmy_bean@yahoo.com")).to match(email)
end
it "should match when the email is set to deliver from the specified name and address" do
email = Mail::Message.new(:from => "Jimmy Bean ")
expect(deliver_from("Jimmy Bean ")).to match(email)
end
it "should not match when the email does not have a sender" do
email = Mail::Message.new(:from => "johnshow@yahoo.com")
expect(deliver_from("jimmy_bean@yahoo.com")).not_to match(email)
end
it "should not match when the email addresses match but the names do not" do
email = Mail::Message.new(:from => "Jimmy Bean ")
expect(deliver_from("Freddy Noe ")).not_to match(email)
end
it "should not match when the names match but the email addresses do not" do
email = Mail::Message.new(:from => "Jimmy Bean ")
expect(deliver_from("Jimmy Bean ")).not_to match(email)
end
it "should not match when the email is not set to deliver from the specified address" do
email = Mail::Message.new(:from => "freddy_noe@yahoo.com")
expect(deliver_from("jimmy_bean@yahoo.com")).not_to match(email)
end
it "should give correct failure message when the email is not set to deliver from the specified address" do
matcher = deliver_from("jimmy_bean@yahoo.com")
matcher.matches?(Mail::Message.new(:from => "freddy_noe@yahoo.com"))
expect(matcher_failure_message(matcher)).to match(/expected .+ to deliver from "jimmy_bean@yahoo\.com", but it delivered from "freddy_noe@yahoo\.com"/)
end
it "should not deliver from anybody when perform_deliveries is false" do
email = Mail::Message.new(:from => "freddy_noe@yahoo.com")
email.perform_deliveries = false
expect(deliver_from("freddy_noe@yahoo.com")).not_to match(email)
end
end
describe "#bcc_to" do
it "should match when the email is set to deliver to the specidied address" do
email = Mail::Message.new(:bcc => "jimmy_bean@yahoo.com")
expect(bcc_to("jimmy_bean@yahoo.com")).to match(email)
end
it "should match when the email is set to deliver to the specified name and address" do
email = Mail::Message.new(:bcc => "Jimmy Bean ")
expect(bcc_to("Jimmy Bean ")).to match(email)
end
it "should match when a list of emails is exact same as all of the email's recipients" do
email = Mail::Message.new(:bcc => ["james@yahoo.com", "karen@yahoo.com"])
expect(bcc_to("karen@yahoo.com", "james@yahoo.com")).to match(email)
expect(bcc_to("karen@yahoo.com")).not_to match(email)
end
it "should match when an array of emails is exact same as all of the email's recipients" do
addresses = ["james@yahoo.com", "karen@yahoo.com"]
email = Mail::Message.new(:bcc => addresses)
expect(bcc_to(addresses)).to match(email)
end
it "should use the passed in objects :email method if not a string" do
email = Mail::Message.new(:bcc => "jimmy_bean@yahoo.com")
user = double("user", :email => "jimmy_bean@yahoo.com")
expect(bcc_to(user)).to match(email)
end
it "should bcc to nobody when the email does not perform deliveries" do
email = Mail::Message.new(:bcc => "jimmy_bean@yahoo.com")
email.perform_deliveries = false
expect(bcc_to("jimmy_bean@yahoo.com")).not_to match(email)
end
end
describe "#cc_to" do
it "should match when the email is set to deliver to the specified address" do
email = Mail::Message.new(:cc => "jimmy_bean@yahoo.com")
expect(cc_to("jimmy_bean@yahoo.com")).to match(email)
end
it "should match when the email is set to deliver to the specified name and address" do
email = Mail::Message.new(:cc => "Jimmy Bean ")
expect(cc_to("Jimmy Bean ")).to match(email)
end
it "should match when a list of emails is exact same as all of the email's recipients" do
email = Mail::Message.new(:cc => ["james@yahoo.com", "karen@yahoo.com"])
expect(cc_to("karen@yahoo.com", "james@yahoo.com")).to match(email)
expect(cc_to("karen@yahoo.com")).not_to match(email)
end
it "should match when an array of emails is exact same as all of the email's recipients" do
addresses = ["james@yahoo.com", "karen@yahoo.com"]
email = Mail::Message.new(:cc => addresses)
expect(cc_to(addresses)).to match(email)
end
it "should use the passed in objects :email method if not a string" do
email = Mail::Message.new(:cc => "jimmy_bean@yahoo.com")
user = double("user", :email => "jimmy_bean@yahoo.com")
expect(cc_to(user)).to match(email)
end
it "should cc to nobody when the email does not perform deliveries" do
email = Mail::Message.new(to: "jimmy_bean@yahoo.com")
email.perform_deliveries = false
expect(cc_to("jimmy_bean@yahoo.com")).not_to match(email)
end
end
describe "#have_subject" do
describe "when regexps are used" do
it "should match when the subject matches regexp" do
email = Mail::Message.new(:subject => ' -- The Subject --')
expect(have_subject(/The Subject/)).to match(email)
expect(have_subject(/foo/)).not_to match(email)
end
it "should have a helpful description" do
matcher = have_subject(/foo/)
matcher.matches?(Mail::Message.new(:subject => "bar"))
expect(matcher.description).to eq("have subject matching /foo/")
end
it "should offer helpful failing messages" do
matcher = have_subject(/foo/)
matcher.matches?(Mail::Message.new(:subject => "bar"))
expect(matcher_failure_message(matcher)).to eq('expected the subject to match /foo/, but did not. Actual subject was: "bar"')
end
it "should offer helpful negative failing messages" do
matcher = have_subject(/b/)
matcher.matches?(Mail::Message.new(:subject => "bar"))
expect(matcher_failure_message_when_negated(matcher)).to eq('expected the subject not to match /b/ but "bar" does match it.')
end
end
describe "when strings are used" do
it "should match when the subject equals the passed in string exactly" do
email = Mail::Message.new(:subject => 'foo')
expect(have_subject("foo")).to match(email)
expect(have_subject(" - foo -")).not_to match(email)
end
it "should have a helpful description" do
matcher = have_subject("foo")
matcher.matches?(Mail::Message.new(:subject => "bar"))
expect(matcher.description).to eq('have subject of "foo"')
end
it "should offer helpful failing messages" do
matcher = have_subject("foo")
matcher.matches?(Mail::Message.new(:subject => "bar"))
expect(matcher_failure_message(matcher)).to eq('expected the subject to be "foo" but was "bar"')
end
it "should offer helpful negative failing messages" do
matcher = have_subject("bar")
matcher.matches?(Mail::Message.new(:subject => "bar"))
expect(matcher_failure_message_when_negated(matcher)).to eq('expected the subject not to be "bar" but was')
end
end
end
describe "#include_email_with_subject" do
describe "when regexps are used" do
it "should match when any email's subject matches passed in regexp" do
emails = [Mail::Message.new(:subject => "foobar"), Mail::Message.new(:subject => "bazqux")]
expect(include_email_with_subject(/foo/)).to match(emails)
expect(include_email_with_subject(/quux/)).not_to match(emails)
end
it "should have a helpful description" do
matcher = include_email_with_subject(/foo/)
matcher.matches?([])
expect(matcher.description).to eq('include email with subject matching /foo/')
end
it "should offer helpful failing messages" do
matcher = include_email_with_subject(/foo/)
matcher.matches?([Mail::Message.new(:subject => "bar")])
expect(matcher_failure_message(matcher)).to eq('expected at least one email to have a subject matching /foo/, but none did. Subjects were ["bar"]')
end
it "should offer helpful negative failing messages" do
matcher = include_email_with_subject(/foo/)
matcher.matches?([Mail::Message.new(:subject => "foo")])
expect(matcher_failure_message_when_negated(matcher)).to eq('expected no email to have a subject matching /foo/ but found at least one. Subjects were ["foo"]')
end
end
describe "when strings are used" do
it "should match when any email's subject equals passed in subject exactly" do
emails = [Mail::Message.new(:subject => "foobar"), Mail::Message.new(:subject => "bazqux")]
expect(include_email_with_subject("foobar")).to match(emails)
expect(include_email_with_subject("foo")).not_to match(emails)
end
it "should have a helpful description" do
matcher = include_email_with_subject("foo")
matcher.matches?([])
expect(matcher.description).to eq('include email with subject of "foo"')
end
it "should offer helpful failing messages" do
matcher = include_email_with_subject("foo")
matcher.matches?([Mail::Message.new(:subject => "bar")])
expect(matcher_failure_message(matcher)).to eq('expected at least one email to have the subject "foo" but none did. Subjects were ["bar"]')
end
it "should offer helpful negative failing messages" do
matcher = include_email_with_subject("foo")
matcher.matches?([Mail::Message.new(:subject => "foo")])
expect(matcher_failure_message_when_negated(matcher)).to eq('expected no email with the subject "foo" but found at least one. Subjects were ["foo"]')
end
end
end
describe "#have_body_text" do
describe "when regexps are used" do
it "should match when the body matches regexp" do
email = Mail::Message.new(:body => 'foo bar baz')
expect(have_body_text(/bar/)).to match(email)
expect(have_body_text(/qux/)).not_to match(email)
end
it "should have a helpful description" do
matcher = have_body_text(/qux/)
matcher.matches?(Mail::Message.new(:body => 'foo bar baz'))
expect(matcher.description).to eq('have body matching /qux/')
end
it "should offer helpful failing messages" do
matcher = have_body_text(/qux/)
matcher.matches?(Mail::Message.new(:body => 'foo bar baz'))
expect(matcher_failure_message(matcher)).to eq('expected the body to match /qux/, but did not. Actual body was: "foo bar baz"')
end
it "should offer helpful negative failing messages" do
matcher = have_body_text(/bar/)
matcher.matches?(Mail::Message.new(:body => 'foo bar baz'))
expect(matcher_failure_message_when_negated(matcher)).to eq('expected the body not to match /bar/ but "foo bar baz" does match it.')
end
end
describe "when strings are used" do
it "should match when the body includes text with symbols" do
full_name = "Jermain O'Keefe"
email = Mail::Message.new(body: full_name)
expect(have_body_text(full_name)).to match(email)
end
it "should match when the body includes the text" do
email = Mail::Message.new(:body => 'foo bar baz')
expect(have_body_text('bar')).to match(email)
expect(have_body_text('qux')).not_to match(email)
end
it "should have a helpful description" do
matcher = have_body_text('qux')
matcher.matches?(Mail::Message.new(:body => 'foo bar baz'))
expect(matcher.description).to eq('have body including "qux"')
end
it "should offer helpful failing messages" do
matcher = have_body_text('qux')
matcher.matches?(Mail::Message.new(:body => 'foo bar baz'))
expect(matcher_failure_message(matcher)).to eq('expected the body to contain "qux" but was "foo bar baz"')
end
it "should offer helpful negative failing messages" do
matcher = have_body_text('bar')
matcher.matches?(Mail::Message.new(:body => 'foo bar baz'))
expect(matcher_failure_message_when_negated(matcher)).to eq('expected the body not to contain "bar" but was "foo bar baz"')
end
end
describe "when dealing with multipart messages" do
it "should look at the html part" do
email = Mail.new do
text_part do
body "This is text"
end
html_part do
body "This is html"
end
end
expect(have_body_text(/This is html/)).to match(email)
expect(have_body_text(/This is text/)).not_to match(email)
end
end
end
describe "#have_body_text", ".in_html_part" do
describe 'when html part is definded in mulitpart' do
it 'should match when the body matches regexp' do
email = Mail.new do
html_part do
body 'This is html'
end
end
expect(have_body_text(/This is html/).in_html_part).to match(email)
end
end
describe 'when text part is definded in mulitpart' do
it 'should not look at text part' do
email = Mail.new do
text_part do
body 'This is text'
end
end
expect(have_body_text(/This is text/).in_html_part).not_to match(email)
end
end
describe 'when html and text parts are definded in mulitpart' do
it 'should look at html part' do
email = Mail.new do
html_part do
body 'This is html'
end
text_part do
body 'This is text'
end
end
expect(have_body_text(/This is html/).in_html_part).to match(email)
expect(have_body_text(/This is text/).in_html_part).not_to match(email)
end
end
describe 'when nothing is defined in mulitpart' do
it 'should not look at any parts' do
email = Mail.new(body: 'This is body')
expect(have_body_text(/This is body/).in_html_part).not_to match(email)
end
end
end
describe "#have_body_text", ".in_text_part" do
describe 'when text part is definded in mulitpart' do
it 'should match when the body matches regexp' do
email = Mail.new do
text_part do
body 'This is text'
end
end
expect(have_body_text(/This is text/).in_text_part).to match(email)
end
end
describe 'when text and html parts are definded in mulitpart' do
it 'should look at text part' do
email = Mail.new do
text_part do
body 'This is text'
end
html_part do
body 'This is html'
end
end
expect(have_body_text(/This is text/).in_text_part).to match(email)
expect(have_body_text(/This is html/).in_text_part).not_to match(email)
end
end
describe 'when html part is definded in mulitpart' do
it 'should not look at html part' do
email = Mail.new do
html_part do
body "This is html"
end
end
expect(have_body_text(/This is html/).in_text_part).not_to match(email)
end
end
describe 'when nothing is defined in mulitpart' do
it 'should not look at any parts' do
email = Mail.new(body: 'This is body')
expect(have_body_text(/This is body/).in_text_part).not_to match(email)
end
end
end
describe "#have_header" do
describe "when regexps are used" do
it "should match when header matches passed in regexp" do
email = Mail::Message.new(:content_type => "text/html")
expect(have_header(:content_type, /text/)).to match(email)
expect(have_header(:foo, /text/)).not_to match(email)
expect(have_header(:content_type, /bar/)).not_to match(email)
end
it "should have a helpful description" do
matcher = have_header(:content_type, /bar/)
matcher.matches?(Mail::Message.new(:content_type => "text/html"))
expect(matcher.description).to eq('have header content_type with value matching /bar/')
end
it "should offer helpful failing messages" do
matcher = have_header(:content_type, /bar/)
matcher.matches?(Mail::Message.new(:content_type => "text/html"))
expect(matcher_failure_message(matcher)).to eq('expected the headers to include \'content_type\' with a value matching /bar/ but they were {"content-type"=>"text/html"}')
end
it "should offer helpful negative failing messages" do
matcher = have_header(:content_type, /text/)
matcher.matches?(Mail::Message.new(:content_type => "text/html"))
expect(matcher_failure_message_when_negated(matcher)).to eq('expected the headers not to include \'content_type\' with a value matching /text/ but they were {"content-type"=>"text/html"}')
end
end
describe "when strings are used" do
it "should match when header equals passed in value exactly" do
email = Mail::Message.new(:content_type => "text/html")
expect(have_header(:content_type, 'text/html')).to match(email)
expect(have_header(:foo, 'text/html')).not_to match(email)
expect(have_header(:content_type, 'text')).not_to match(email)
end
it "should have a helpful description" do
matcher = have_header(:content_type, 'text')
matcher.matches?(Mail::Message.new(:content_type => "text/html"))
expect(matcher.description).to eq('have header content_type: text')
end
it "should offer helpful failing messages" do
matcher = have_header(:content_type, 'text')
matcher.matches?(Mail::Message.new(:content_type => "text/html"))
expect(matcher_failure_message(matcher)).to eq('expected the headers to include \'content_type: text\' but they were {"content-type"=>"text/html"}')
end
it "should offer helpful negative failing messages" do
matcher = have_header(:content_type, 'text/html')
matcher.matches?(Mail::Message.new(:content_type => "text/html"))
matcher_failure_message_when_negated(matcher) == 'expected the headers not to include \'content_type: text/html\' but they were {:content_type=>"text/html"}'
end
end
end
end
email_spec-2.3.0/Rakefile 0000644 0000041 0000041 00000000605 14671407415 015324 0 ustar www-data www-data require 'rubygems'
require 'bundler'
Bundler::GemHelper.install_tasks
begin
require 'cucumber/rake/task'
Cucumber::Rake::Task.new(:features)
rescue LoadError
task :features do
abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
end
end
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new
task :default => [:features, :spec]
email_spec-2.3.0/features/ 0000755 0000041 0000041 00000000000 14671407415 015474 5 ustar www-data www-data email_spec-2.3.0/features/step_definitions/ 0000755 0000041 0000041 00000000000 14671407415 021042 5 ustar www-data www-data email_spec-2.3.0/features/step_definitions/app_steps.rb 0000644 0000041 0000041 00000004321 14671407415 023365 0 ustar www-data www-data require 'fileutils'
Given /^the (\w+) app is setup with the latest email steps$/ do |app_name|
app_dir = File.join(root_dir, 'examples',"#{app_name}_root")
email_specs_path = File.join(app_dir, 'features', 'step_definitions',
'email_steps.rb')
latest_specs_path = File.join(root_dir, 'lib', 'generators', 'email_spec',
'steps', 'templates','email_steps.rb')
FileUtils.rm(email_specs_path) if File.exist?(email_specs_path)
FileUtils.cp_r(latest_specs_path, email_specs_path)
end
Then /^the (\w+) app should have the email steps in place$/ do |app_name|
email_specs_path = "#{root_dir}/examples/#{app_name}_root/features/step_definitions/email_steps.rb"
expect(File.exist?(email_specs_path)).to be true
end
Then /^I should see the following summary report:$/ do |expected_report|
expect(@output).to include(expected_report)
end
Given /^the (\w+) app is setup with the latest generators$/ do |app_name|
app_dir= File.join(root_dir,'examples',"#{app_name}_root")
email_specs_path = File.join(app_dir,'features','step_definitions','email_steps.rb')
FileUtils.rm(email_specs_path) if File.exist?(email_specs_path)
if app_name == 'rails4'
#Testing using the gem
#make sure we are listed in the bundle
Dir.chdir(app_dir) do
output =`bundle list`
expect(output).to include('email_spec')
end
else
FileUtils.mkdir_p("#{app_dir}/vendor/plugins/email_spec")
FileUtils.cp_r("#{root_dir}/rails_generators","#{app_dir}/vendor/plugins/email_spec/")
Dir.chdir(app_dir) do
system "ruby ./script/generate email_spec"
end
end
end
When /^I run "([^\"]*)" in the (\w+) app$/ do |cmd, app_name|
#cmd.gsub!('cucumber', "#{Cucumber::RUBY_BINARY} #{Cucumber::BINARY}")
app_path = File.join(root_dir, 'examples', "#{app_name}_root")
app_specific_gemfile = File.join(app_path,'Gemfile')
Dir.chdir(app_path) do
#hack to fight competing bundles (email specs vs rails4_root's
if File.exist? app_specific_gemfile
orig_gemfile = ENV['BUNDLE_GEMFILE']
ENV['BUNDLE_GEMFILE'] = app_specific_gemfile
@output = `#{cmd}`
ENV['BUNDLE_GEMFILE'] = orig_gemfile
else
@output = `#{cmd}`
end
end
end
email_spec-2.3.0/features/sinatra_app.feature 0000644 0000041 0000041 00000001022 14671407415 021345 0 ustar www-data www-data Feature: Email Spec in Sinatra App
In order to prevent me from shipping a defective email_spec gem
As a email_spec dev
I want to verify that the example sinatra app runs all of it's features as expected
Scenario: regression test
Given the sinatra app is setup with the latest email steps
When I run "bundle exec cucumber features -q --no-color" in the sinatra app
Then I should see the following summary report:
"""
12 scenarios (7 failed, 5 passed)
110 steps (7 failed, 1 skipped, 102 passed)
"""
email_spec-2.3.0/features/support/ 0000755 0000041 0000041 00000000000 14671407415 017210 5 ustar www-data www-data email_spec-2.3.0/features/support/env.rb 0000644 0000041 0000041 00000000413 14671407415 020323 0 ustar www-data www-data require 'rubygems'
#require 'spec/expectations'
class EmailSpecWorld
def self.root_dir
@root_dir ||= File.join(File.expand_path(File.dirname(__FILE__)), "..", "..")
end
def root_dir
EmailSpecWorld.root_dir
end
end
World do
EmailSpecWorld.new
end
email_spec-2.3.0/features/rails4_app.feature 0000644 0000041 0000041 00000002240 14671407415 021105 0 ustar www-data www-data Feature: Email Spec in Rails 4 App
In order to prevent me from shipping a defective email_spec gem
As a email_spec dev
I want to verify that the example rails 4 app runs all of it's features as expected
Scenario: generators test
Given the rails4 app is setup with the latest generators
When I run "bundle exec rails g email_spec:steps" in the rails4 app
Then the rails4 app should have the email steps in place
Scenario: regression test
Given the rails4 app is setup with the latest email steps
When I run "bundle exec rake db:migrate RAILS_ENV=test" in the rails4 app
And I run "bundle exec cucumber features -q --no-color" in the rails4 app
Then I should see the following summary report:
"""
15 scenarios (7 failed, 8 passed)
136 steps (7 failed, 1 skipped, 128 passed)
"""
When I run "bundle exec rake spec RAILS_ENV=test" in the rails4 app
Then I should see the following summary report:
"""
11 examples, 0 failures
"""
When I run "bundle exec rake test RAILS_ENV=test" in the rails4 app
Then I should see the following summary report:
"""
8 runs, 8 assertions, 0 failures, 0 errors, 0 skips
"""
email_spec-2.3.0/MIT-LICENSE.txt 0000644 0000041 0000041 00000002042 14671407415 016126 0 ustar www-data www-data Copyright (c) 2008-2009 Ben Mabey
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
email_spec-2.3.0/README.md 0000644 0000041 0000041 00000025243 14671407415 015143 0 ustar www-data www-data [](http://travis-ci.org/email-spec/email-spec)
## Email Spec
A collection of matchers for `RSpec`, `MiniTest` and `Cucumber` steps to make testing emails go smoothly.
This library works with `ActionMailer` and `Pony`. When using it with ActionMailer it works with ActiveRecord Mailer, and [action_mailer_cache_delivery](https://rubygems.org/gems/action_mailer_cache_delivery).
If you are testing emails in conjunction with an automated browser solution, like Selenium,
you will want to use [action_mailer_cache_delivery](http://rubygems.org/gems/action_mailer_cache_delivery) in your test environment. (This is
because your test process and server processes are distinct and therefore need an
intermediate store for the emails.) ActiveRecord Mailer will also work but
you generally don't want to include those projects unless you need them in production.
### Gem Setup
```ruby
# Gemfile
group :test do
gem 'email_spec'
end
```
### Cucumber
To use the steps in features put the following in your env.rb:
```ruby
# Make sure this require is after you require cucumber/rails/world.
require 'email_spec' # add this line if you use spork
require 'email_spec/cucumber'
```
This will load all the helpers that the steps rely on. It will also add a `Before` hook for `Cucumber` so that emails are cleared at the start of each scenario.
Then:
```bash
rails generate email_spec:steps
```
This will give you a bunch of steps to get started with in `step_definitions/email_steps.rb`
By default, the generated file will look for email to example@example.com. You can either change this by editing the `current_email_address` method in `email_steps.rb`, or by simply specifying the target email in your features:
```gherkin
Scenario: A new person signs up
Given I am at "/"
When I fill in "Email" with "quentin@example.com"
And I press "Sign up"
Then "quentin@example.com" should receive an email # Specify who should receive the email
```
### Spinach
To use the helpers and matchers in your Spinach steps, add this to your env.rb:
```ruby
require 'email_spec/spinach'
```
Creating shared steps (as for Cucumber above) doesn't fit so well with the Spinach ethos of very compartmentalized steps, so there is no generator for Spinach. It's easy to use the helpers/matchers in your steps. For example:
```ruby
step 'the last email sent should welcome the user' do
expect(last_email_sent).to have_subject('Welcome')
end
```
### RSpec (3.1+)
First you need to require `email_spec` in your `spec_helper.rb`:
```ruby
require "email_spec"
require "email_spec/rspec"
```
This will load all the helpers that the scenarios can count on. It will also add a `before(:each)` hook so that emails are cleared at the start of each scenario.
If you are upgrading to Rails 5, make sure your `rails_helper.rb` requires `spec_helper` **after** loading the environment. For example:
```ruby
require File.expand_path('../../config/environment', __FILE__)
require 'spec_helper'
```
### MiniTest
First you need to require minitest-matchers and email_spec in your test_helper.rb:
```ruby
require "minitest-matchers"
require "email_spec"
```
You will then need to include EmailSpec::Helpers and EmailSpec::Matchers in your test classes.
If you want to have access to the helpers and matchers in all of your tests you can do the following in your test_helper.rb:
```ruby
class MiniTest::Unit::TestCase
include EmailSpec::Helpers
include EmailSpec::Matchers
end
```
Otherwise, you will need to include them in the tests where you use them:
```ruby
class SignupMailerTest < MiniTest::Unit::TestCase
include EmailSpec::Helpers
include EmailSpec::Matchers
...
end
```
Or, if you are using the MiniTest spec DSL, it would look like this:
```ruby
describe SignupMailer do
include EmailSpec::Helpers
include EmailSpec::Matchers
...
end
```
### Turnip
If you're using [Turnip](https://github.com/jnicklas/turnip), you might be interested in this [conversion of the Cucumber steps into Turnip steps](https://github.com/jmuheim/base/blob/7708873e77165993c2c962894c756621be1b15cc/spec/steps/email_steps.rb).
## Background Jobs
If you are using a background job, you might need to use a step to process the jobs. Another alternative is to use an inline statement for your scenario.
For example, for DelayedJob:
```ruby
Delayed::Worker.delay_jobs = false
```
## Usage
### Cucumber
```gherkin
Scenario: A new person signs up
Given I am at "/"
When I fill in "Email" with "quentin@example.com"
And I press "Sign up"
And I should receive an email
When I open the email
Then I should see "confirm" in the email body
When I follow "confirm" in the email
Then I should see "Confirm your new account"
```
For more examples, check out examples/rails_root in the source for a small example app that implements these steps.
### Cucumber Matchers (Ruby)
See RSpec Matchers (they are the same)
### RSpec
#### Testing In Isolation
It is often useful to test your mailers in isolation. You can accomplish this by using mocks to verify that the mailer is being called in the correct place and then write focused examples for the actual mailer. This is a simple example from the sample app found in the gem:
Verify that the mailer is used correctly in the controller (this would apply to a model as well):
```ruby
describe "POST /signup (#signup)" do
it "should deliver the signup email" do
# expect
expect(UserMailer).to(receive(:deliver_signup).with("email@example.com", "Jimmy Bean"))
# when
post :signup, "Email" => "email@example.com", "Name" => "Jimmy Bean"
end
end
```
Examples for the #signup method in UserMailer:
```ruby
describe "Signup Email" do
include EmailSpec::Helpers
include EmailSpec::Matchers
# include ActionController::UrlWriter - old rails
include Rails.application.routes.url_helpers
before(:all) do
@email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
end
it "should be set to be delivered to the email passed in" do
expect(@email).to deliver_to("jojo@yahoo.com")
end
it "should contain the user's message in the mail body" do
expect(@email).to have_body_text(/Jojo Binks/)
end
it "should contain a link to the confirmation link" do
expect(@email).to have_body_text(/#{confirm_account_url}/)
end
it "should have the correct subject" do
expect(@email).to have_subject(/Account confirmation/)
end
end
```
#### RSpec Matchers
##### reply_to(email)
alias: `have_reply_to`
This checks that the Reply-To header's email address (the bob@example.com of
"Bob Saget ") is set to the given string.
```ruby
email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
expect(email).to reply_to("support@myapp.com")
```
##### deliver_to(\*email_addresses)
alias: `be_delivered_to`
This checks that the To header's email addresses (the bob@example.com of
"Bob Saget ") are set to the addresses.
```ruby
email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
expect(email).to deliver_to("jojo@yahoo.com")
```
##### deliver_from(email)
alias: `be_delivered_from`
This checks that the From header's email address (the bob@example.com of
"Bob Saget ") is set to the given string.
```ruby
email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
expect(email).to deliver_from("sally@yahoo.com")
```
##### bcc_to(\*email_addresses)
This checks that the BCC header's email addresses (the bob@example.com of
"Bob Saget ") are set to the addresses.
```ruby
email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
expect(email).to bcc_to("sue@yahoo.com", "bill@yahoo.com")
```
##### cc_to(\*email_addresses)
This checks that the CC header's email addresses (the bob@example.com of
"Bob Saget ") are set to the addresses.
```ruby
email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
expect(email).to cc_to("sue@yahoo.com", "bill@yahoo.com")
```
##### have_subject(subject)
This checks that the Subject header's value is set to the given subject.
```ruby
email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
expect(email).to have_subject("Welcome!")
```
##### include_email_with_subject(subject)
Note: subject can be either a String or a Regexp
This checks that one of the given emails' subjects includes the subject.
```ruby
email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
email2 = UserMailer.forgot_password("jojo@yahoo.com", "Jojo Binks")
expect([email, email2]).to include_email_with_subject("Welcome!")
```
##### have_body_text(text)
Note: text can be either a String or a Regexp
This checks that the text of the body has the given body.
```ruby
email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
expect(email).to have_body_text(/Hi Jojo Binks,/)
```
You can specify which part in multipart to check with `in_html_part` or
`in_text_part`.
```ruby
email = UserMailer.("jojo@yahoo.com", "Jojo Binks")
expect(email).to have_body_text(/This is html/).in_html_part
expect(email).to have_body_text(/This is text/).in_text_part
```
##### have_header(key, value)
This checks that the expected key/value pair is in the headers of the email.
```ruby
email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
expect(email).to have_header("X-Campaign", "1234abc")
```
#### Using the helpers when not testing in isolation
Don't. :) Seriously, if you do just take a look at the helpers and use them as you wish.
### MiniTest
You will use EmailSpec in your tests the same way you use it in your specs. The only difference is the use of MiniTest's `must` instead of Rspec's `should`:
```ruby
email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
email.must deliver_to("jojo@yahoo.com")
```
Or, you can use the matcher as an expectation:
```ruby
email = UserMailer.create_signup "jojo@yahoo.com", "Jojo Binks"
email.must_deliver_to "jojo@yahoo.com"
```
And of course you can use the matcher as an assertion:
```ruby
email = UserMailer.create_signup "jojo@yahoo.com", "Jojo Binks"
assert_must deliver_to("jojo@yahoo.com"), email
```
## Issue triage [](https://www.codetriage.com/email-spec/email-spec)
You can contribute by triaging issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to email-spec on CodeTriage](https://www.codetriage.com/email-spec/email-spec).
## Original Authors
Ben Mabey, Aaron Gibralter, Mischa Fierer
Please see [Changelog.md](Changelog.md) for upcoming changes and other contributors.
email_spec-2.3.0/examples/ 0000755 0000041 0000041 00000000000 14671407415 015474 5 ustar www-data www-data email_spec-2.3.0/examples/rails4_root/ 0000755 0000041 0000041 00000000000 14671407415 017735 5 ustar www-data www-data email_spec-2.3.0/examples/rails4_root/doc/ 0000755 0000041 0000041 00000000000 14671407415 020502 5 ustar www-data www-data email_spec-2.3.0/examples/rails4_root/doc/README_FOR_APP 0000644 0000041 0000041 00000000323 14671407415 022566 0 ustar www-data www-data Use this README file to introduce your application and point to useful places in the API for learning more.
Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
email_spec-2.3.0/examples/rails4_root/db/ 0000755 0000041 0000041 00000000000 14671407415 020322 5 ustar www-data www-data email_spec-2.3.0/examples/rails4_root/db/schema.rb 0000644 0000041 0000041 00000002373 14671407415 022114 0 ustar www-data www-data # encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20141119224309) do
create_table "delayed_jobs", force: :cascade do |t|
t.integer "priority", default: 0
t.integer "attempts", default: 0
t.text "handler"
t.text "last_error"
t.datetime "run_at"
t.datetime "locked_at"
t.datetime "failed_at"
t.string "locked_by"
t.datetime "created_at"
t.datetime "updated_at"
t.string "queue"
end
create_table "users", force: :cascade do |t|
t.string "email"
t.string "name"
end
end
email_spec-2.3.0/examples/rails4_root/db/migrate/ 0000755 0000041 0000041 00000000000 14671407415 021752 5 ustar www-data www-data email_spec-2.3.0/examples/rails4_root/db/migrate/20090125013728_create_users.rb 0000644 0000041 0000041 00000000265 14671407415 026435 0 ustar www-data www-data class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :email, :name
end
end
def self.down
drop_table :users
end
end
email_spec-2.3.0/examples/rails4_root/db/migrate/20090908054656_create_delayed_jobs.rb 0000644 0000041 0000041 00000002105 14671407415 027731 0 ustar www-data www-data class CreateDelayedJobs < ActiveRecord::Migration
def self.up
create_table :delayed_jobs, :force => true do |table|
table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
table.text :handler # YAML-encoded string of the object that will do work
table.text :last_error # reason for last failure (See Note below)
table.datetime :run_at # When to run. Could be Time.now for immediately, or sometime in the future.
table.datetime :locked_at # Set when a client is working on this object
table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
table.string :locked_by # Who is working on this object (if locked)
table.timestamps null: false
end
end
def self.down
drop_table :delayed_jobs
end
end
email_spec-2.3.0/examples/rails4_root/db/migrate/20141119224309_add_queue_to_delayed_jobs.rb 0000644 0000041 0000041 00000000273 14671407415 031111 0 ustar www-data www-data class AddQueueToDelayedJobs < ActiveRecord::Migration
def self.up
add_column :delayed_jobs, :queue, :string
end
def self.down
remove_column :delayed_jobs, :queue
end
end
email_spec-2.3.0/examples/rails4_root/db/seeds.rb 0000644 0000041 0000041 00000000541 14671407415 021752 0 ustar www-data www-data # This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#
# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
# Mayor.create(:name => 'Daley', :city => cities.first)
email_spec-2.3.0/examples/rails4_root/public/ 0000755 0000041 0000041 00000000000 14671407415 021213 5 ustar www-data www-data email_spec-2.3.0/examples/rails4_root/public/robots.txt 0000644 0000041 0000041 00000000314 14671407415 023262 0 ustar www-data www-data # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
#
# To ban all spiders from the entire site uncomment the next two lines:
# User-Agent: *
# Disallow: /
email_spec-2.3.0/examples/rails4_root/public/javascripts/ 0000755 0000041 0000041 00000000000 14671407415 023544 5 ustar www-data www-data email_spec-2.3.0/examples/rails4_root/public/javascripts/application.js 0000644 0000041 0000041 00000000224 14671407415 026403 0 ustar www-data www-data // Place your application-specific JavaScript functions and classes here
// This file is automatically included by javascript_include_tag :defaults
email_spec-2.3.0/examples/rails4_root/public/javascripts/prototype.js 0000644 0000041 0000041 00000421116 14671407415 026154 0 ustar www-data www-data /* Prototype JavaScript framework, version 1.6.1
* (c) 2005-2009 Sam Stephenson
*
* Prototype is freely distributable under the terms of an MIT-style license.
* For details, see the Prototype web site: http://www.prototypejs.org/
*
*--------------------------------------------------------------------------*/
var Prototype = {
Version: '1.6.1',
Browser: (function(){
var ua = navigator.userAgent;
var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
return {
IE: !!window.attachEvent && !isOpera,
Opera: isOpera,
WebKit: ua.indexOf('AppleWebKit/') > -1,
Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
MobileSafari: /Apple.*Mobile.*Safari/.test(ua)
}
})(),
BrowserFeatures: {
XPath: !!document.evaluate,
SelectorsAPI: !!document.querySelector,
ElementExtensions: (function() {
var constructor = window.Element || window.HTMLElement;
return !!(constructor && constructor.prototype);
})(),
SpecificElementExtensions: (function() {
if (typeof window.HTMLDivElement !== 'undefined')
return true;
var div = document.createElement('div');
var form = document.createElement('form');
var isSupported = false;
if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
isSupported = true;
}
div = form = null;
return isSupported;
})()
},
ScriptFragment: '