I’ve been playing a bit with Cucumber lately. I needed a way to test whether my site was sending emails in certain situations. So far, I’ve found Cucumber to be a highly flexible tool for behavior-driven development. Paired up with Watir WebDriver, it controls your browser and makes sure your site functions as it should based on the test definitions you provide. Overall, it’s pretty easy to pick up, partly because Ruby is pretty elegant. Cucumber reads from “features” files. The format of these files is similar to scrum story definitions and acceptance criteria. Here’s what I used:
Scenario: As a user, I visit service site and subscribe to the newsletter Given I am on the service site When I subscribe to the newsletter with my test email address Then I should receive an email with the subject """ Thank you for subscribing """
So, that was great. I could have WebDriver go to the site and fill out the subscription form. Pretty close. But I didn’t have a way to check whether the confirmation email arrived. Ruby made that part pretty easy. Ruby comes with an IMAP class in its stdlib, and I found a Gmail library that I could borrow code from to create a class that would connect to Gmail and poll for new emails. Here’s my class:
require 'net/imap.rb' class TestEmail def init_email(username, password, folder = 'inbox') @imap = Net::IMAP.new('imap.gmail.com', 993, true, nil, false) res = @imap.login(username, password) if res.name == 'OK' @logged_in = true @folder = folder @imap.select(@folder) @imap.search(["NOT", "SEEN"]).each do |message_id| @imap.store(message_id, "+FLAGS", [:Seen]) end at_exit { if @logged_in @imap.logout end } end end def poll(retries, timeout = 5) while retries > 0 do retries -= 1 # it does seem to be necessary to reselect this @imap.select(@folder) @imap.search(["UNSEEN"]).each do |message_id| @imap.store(message_id, "+FLAGS", [:Seen]) envelope = @imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"] return envelope end sleep timeout end end end
I call TestEmail.new and init_email() and assign the object to @mail when I setup the webdriver browser. The last step was to write the step definition to verify that we found the right email:
Then /I should receive an email with the subject/ do |text| email = @mail.poll(5) email.subject.should =~ /#{text}/m end