- Notifications
You must be signed in to change notification settings - Fork171
Collection of RSpec/MiniTest matchers and Cucumber steps for testing email in a ruby app using ActionMailer or Pony
License
email-spec/email-spec
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A collection of matchers forRSpec
,MiniTest
andCucumber
steps to make testing emails go smoothly.
This library works withActionMailer
andPony
. When using it with ActionMailer it works with ActiveRecord Mailer, andaction_mailer_cache_delivery.
If you are testing emails in conjunction with an automated browser solution, like Selenium,you will want to useaction_mailer_cache_delivery in your test environment. (This isbecause your test process and server processes are distinct and therefore need anintermediate store for the emails.) ActiveRecord Mailer will also work butyou generally don't want to include those projects unless you need them in production.
# Gemfilegroup:testdogem'email_spec'end
To use the steps in features put the following in your env.rb:
# Make sure this require is after you require cucumber/rails/world.require'email_spec'# add this line if you use sporkrequire'email_spec/cucumber'
This will load all the helpers that the steps rely on. It will also add aBefore
hook forCucumber
so that emails are cleared at the start of each scenario.
Then:
rails generate email_spec:steps
This will give you a bunch of steps to get started with instep_definitions/email_steps.rb
By default, the generated file will look for email toexample@example.com. You can either change this by editing thecurrent_email_address
method inemail_steps.rb
, or by simply specifying the target email in your features:
Scenario: A new person signs upGivenI am at"/"WhenI fill in"Email" with"quentin@example.com"AndI press"Sign up"Then"quentin@example.com" should receive an email # Specify who should receive the email
To use the helpers and matchers in your Spinach steps, add this to your env.rb:
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:
step'the last email sent should welcome the user'doexpect(last_email_sent).tohave_subject('Welcome')end
First you need to requireemail_spec
in yourspec_helper.rb
:
require"email_spec"require"email_spec/rspec"
This will load all the helpers that the scenarios can count on. It will also add abefore(:each)
hook so that emails are cleared at the start of each scenario.
If you are upgrading to Rails 5, make sure yourrails_helper.rb
requiresspec_helper
after loading the environment. For example:
requireFile.expand_path('../../config/environment',__FILE__)require'spec_helper'
First you need to require minitest-matchers and email_spec in your test_helper.rb:
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:
classMiniTest::Unit::TestCaseincludeEmailSpec::HelpersincludeEmailSpec::Matchersend
Otherwise, you will need to include them in the tests where you use them:
classSignupMailerTest <MiniTest::Unit::TestCaseincludeEmailSpec::HelpersincludeEmailSpec::Matchers ...end
Or, if you are using the MiniTest spec DSL, it would look like this:
describeSignupMailerdoincludeEmailSpec::HelpersincludeEmailSpec::Matchers ...end
If you're usingTurnip, you might be interested in thisconversion of the Cucumber steps into Turnip steps.
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:
Delayed::Worker.delay_jobs=false
Scenario: A new person signs upGivenI am at"/"WhenI fill in"Email" with"quentin@example.com"AndI press"Sign up"AndI should receive an emailWhenI open the emailThenI should see"confirm" in the email bodyWhenI follow"confirm" in the emailThenI 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.
See RSpec Matchers (they are the same)
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):
describe"POST /signup (#signup)"doit"should deliver the signup email"do# expectexpect(UserMailer).to(receive(:deliver_signup).with("email@example.com","Jimmy Bean"))# whenpost:signup,"Email"=>"email@example.com","Name"=>"Jimmy Bean"endend
Examples for the #signup method in UserMailer:
describe"Signup Email"doincludeEmailSpec::HelpersincludeEmailSpec::Matchers# include ActionController::UrlWriter - old railsincludeRails.application.routes.url_helpersbefore(:all)do@email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")endit"should be set to be delivered to the email passed in"doexpect(@email).todeliver_to("jojo@yahoo.com")endit"should contain the user's message in the mail body"doexpect(@email).tohave_body_text(/Jojo Binks/)endit"should contain a link to the confirmation link"doexpect(@email).tohave_body_text(/#{confirm_account_url}/)endit"should have the correct subject"doexpect(@email).tohave_subject(/Account confirmation/)endend
alias:have_reply_to
This checks that the Reply-To header's email address (thebob@example.com of"Bob Sagetbob@example.com") is set to the given string.
email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")expect(email).toreply_to("support@myapp.com")
alias:be_delivered_to
This checks that the To header's email addresses (thebob@example.com of"Bob Sagetbob@example.com") are set to the addresses.
email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")expect(email).todeliver_to("jojo@yahoo.com")
alias:be_delivered_from
This checks that the From header's email address (thebob@example.com of"Bob Sagetbob@example.com") is set to the given string.
email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")expect(email).todeliver_from("sally@yahoo.com")
This checks that the BCC header's email addresses (thebob@example.com of"Bob Sagetbob@example.com") are set to the addresses.
email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")expect(email).tobcc_to("sue@yahoo.com","bill@yahoo.com")
This checks that the CC header's email addresses (thebob@example.com of"Bob Sagetbob@example.com") are set to the addresses.
email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")expect(email).tocc_to("sue@yahoo.com","bill@yahoo.com")
This checks that the Subject header's value is set to the given subject.
email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")expect(email).tohave_subject("Welcome!")
Note: subject can be either a String or a Regexp
This checks that one of the given emails' subjects includes the subject.
email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")email2=UserMailer.forgot_password("jojo@yahoo.com","Jojo Binks")expect([email,email2]).toinclude_email_with_subject("Welcome!")
Note: text can be either a String or a Regexp
This checks that the text of the body has the given body.
email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")expect(email).tohave_body_text(/Hi Jojo Binks,/)
You can specify which part in multipart to check within_html_part
orin_text_part
.
email=UserMailer.("jojo@yahoo.com","Jojo Binks")expect(email).tohave_body_text(/This is html/).in_html_partexpect(email).tohave_body_text(/This is text/).in_text_part
This checks that the expected key/value pair is in the headers of the email.
email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")expect(email).tohave_header("X-Campaign","1234abc")
Don't. :) Seriously, if you do just take a look at the helpers and use them as you wish.
You will use EmailSpec in your tests the same way you use it in your specs. The only difference is the use of MiniTest'smust
instead of Rspec'sshould
:
email=UserMailer.create_signup("jojo@yahoo.com","Jojo Binks")email.mustdeliver_to("jojo@yahoo.com")
Or, you can use the matcher as an expectation:
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:
email=UserMailer.create_signup"jojo@yahoo.com","Jojo Binks"assert_mustdeliver_to("jojo@yahoo.com"),email
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 tosubscribe to email-spec on CodeTriage.
Ben Mabey, Aaron Gibralter, Mischa Fierer
Please seeChangelog.md for upcoming changes and other contributors.
About
Collection of RSpec/MiniTest matchers and Cucumber steps for testing email in a ruby app using ActionMailer or Pony