Skip to content

Commit

Permalink
Fix several email step bugs
Browse files Browse the repository at this point in the history
Fixes #171
Fixes #172
Fixes #173
  • Loading branch information
NiklasHae committed Jul 28, 2021
1 parent 1304312 commit 0d3af62
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 21 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file.

This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## 4.2.2
- Fixes the "Show me the email" step (#171)
- Fixes the "I follow the link in the email" step. (#172, #173)
- It works for emails with and without explicit html parts
- There's a better error message if no links are found

## 4.1.2
- Multiple invocations of console don't raise anymore

Expand Down
22 changes: 4 additions & 18 deletions lib/spreewald/email_steps.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# coding: UTF-8

require 'spreewald_support/mail_finder'
require 'steps/show_me_the_mails'
require 'steps/follow_the_link'

Before do
ActionMailer::Base.deliveries.clear
Expand Down Expand Up @@ -73,18 +75,7 @@
# Other links (such as mailto: or ftp:// links) are ignored.
When /^I follow the (first|second|third)? ?link in the e?mail$/ do |index_in_words|
mail = @mail || ActionMailer::Base.deliveries.last
index = { nil => 0, 'first' => 0, 'second' => 1, 'third' => 2 }[index_in_words]
url_pattern = %r((?:https?://[^/]+)([^"'\s]+))

paths = if mail.html_part
dom = Nokogiri::HTML(mail.html_part.body.to_s)
(dom / 'a[href]').map { |a| a['href'].match(url_pattern) }.compact.map { |match| match[1] }
else
mail_body = MailFinder.email_text_body(mail).to_s
mail_body.scan(url_pattern).flatten(1)
end

visit paths[index]
Spreewald::Steps::FollowTheLink.new(mail, index_in_words).run
end.overridable

Then /^no e?mail should have been sent$/ do
Expand All @@ -98,12 +89,7 @@

# Print all sent emails to STDOUT (optionally only the headers).
Then /^show me the e?mail( header)?s$/ do |only_header|
if ActionMailer::Base.deliveries.empty?
puts MailFinder.show_mails(ActionMailer::Base.deliveries, only_header)
else
puts "No emails found" if ActionMailer::Base.deliveries.empty?
end

Spreewald::Steps::ShowMeTheMails.new(ActionMailer::Base.deliveries, only_header).run
end.overridable

# Print a subset of all sent emails to STDOUT
Expand Down
2 changes: 1 addition & 1 deletion lib/spreewald_support/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Spreewald
VERSION = '4.1.2'
VERSION = '4.2.2'
end
63 changes: 63 additions & 0 deletions lib/steps/follow_the_link.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
module Spreewald
module Steps
class FollowTheLink
class NoVisitableLinkFound < StandardError
def initialize(paths, index)
error_message = <<~MESSAGE
Could not follow the #{index} link in the email.
MESSAGE
if paths&.empty?
error_message << "Found no link paths in the email."
else
error_message << "Found these link paths in the email: #{paths.join(', ')}"
end
super(error_message)
end
end

URL_PATTERN = %r((?:https?://[^/]+)([^"'\s]+))

def initialize(mail, index_in_words)
@mail = mail
@index_in_words = index_in_words
end

def run
index = { nil => 0, 'first' => 0, 'second' => 1, 'third' => 2 }[@index_in_words]

paths = if @mail.html_part || body_text_html?
search_for_links_in_html
else
search_for_links_in_plaintext
end

if paths[index]
visit_path paths[index]
else
raise NoVisitableLinkFound.new(paths, @index_in_words) unless paths[index]
end
end

private

def visit_path(path)
Capybara.visit(path)
end

def body_text_html?
@mail.body.to_s.include? "<html>"
end

def search_for_links_in_html
body = @mail.html_part ? @mail.html_part.body : @mail.body
dom = Nokogiri::HTML(body.to_s)
(dom / 'a[href]').map { |a| a['href'].match(URL_PATTERN) }.compact.map { |match| match[1] }
end

def search_for_links_in_plaintext
mail_body = MailFinder.email_text_body(@mail).to_s
mail_body.scan(URL_PATTERN).flatten(1)
end
end
end
end
20 changes: 20 additions & 0 deletions lib/steps/show_me_the_mails.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'spreewald_support/mail_finder'

module Spreewald
module Steps
class ShowMeTheMails
def initialize(mails, only_header = false)
@mails = mails
@only_header = only_header
end

def run
if @mails.empty?
puts "No emails found"
else
puts MailFinder.show_mails(@mails, @only_header)
end
end
end
end
end
81 changes: 81 additions & 0 deletions spec/steps/follow_the_link_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
require "steps/follow_the_link"

describe Spreewald::Steps::FollowTheLink do
it "raises helpful error message if no link is found" do
mail_without_links = Mail.new do
html_part do
body "<html><body>no link</body></html>"
end

text_part do
body "no link either"
end
end

step = ->() { Spreewald::Steps::FollowTheLink.new(mail_without_links, "first").run }
expect(step).to raise_error Spreewald::Steps::FollowTheLink::NoVisitableLinkFound
end

it "finds links in multipart html email" do
mail = Mail.new do
html_part do
body "<html><body><a href='https://www.example.com/abc'>a link</a><a href='https://www.example.com/def'>second link</a></body></html>"
end

text_part do
body "no link here"
end
end

step = Spreewald::Steps::FollowTheLink.new(mail, "first")
expect(step).to receive(:visit_path).with("/abc")
step.run
end

it "finds the second link in a multipart html email" do
mail = Mail.new do
html_part do
body "<html><body><a href='https://www.example.com/abc'>a link</a><a href='https://www.example.com/def'>second link</a></body></html>"
end

text_part do
body "no link here"
end
end

step = Spreewald::Steps::FollowTheLink.new(mail, "second")
expect(step).to receive(:visit_path).with("/def")
step.run
end

it "finds links in html email" do
mail = Mail.new do
text_part do
body "my link: https://www.example.com/abc"
end
end

step = Spreewald::Steps::FollowTheLink.new(mail, "first")
expect(step).to receive(:visit_path).with("/abc")
step.run
end

it "finds links in non multipart text emails" do
plaintext_email = Mail.new(body: 'a link: https://www.example.com/abc')
step = Spreewald::Steps::FollowTheLink.new(plaintext_email, "first")

expect(step).to receive(:visit_path).with("/abc")
step.run
end

it "finds links in non multipart html emails" do
html_mail = Mail.new(body: <<-HTML)
<html><body><a href="https://www.example.com/abc">this is a link!</a></body></html>
HTML
step = Spreewald::Steps::FollowTheLink.new(html_mail, "first")

expect(step).to receive(:visit_path).with("/abc")
step.run
end
end

96 changes: 96 additions & 0 deletions spec/steps/show_me_the_mails_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
require "steps/show_me_the_mails"

describe Spreewald::Steps::ShowMeTheMails do
context "without deliveries" do
it "logs 'no emails found'" do
step = Spreewald::Steps::ShowMeTheMails.new([])

expect { step.run }.to output("No emails found\n").to_stdout
end

it "logs 'no emails found' with only headers enabled" do
step = Spreewald::Steps::ShowMeTheMails.new([], true)

expect { step.run }.to output("No emails found\n").to_stdout
end
end

context "with deliveries" do
it "logs the email" do
mail = Mail.new do
html_part do
body "<html><body>html part</body></html>"
end
end

expected_output = <<~TXT
E-Mail #0
--------------------------------------------------------------------------------
From:
Subject:
html part
--------------------------------------------------------------------------------
TXT
step = Spreewald::Steps::ShowMeTheMails.new([mail])
expect { step.run }.to output(expected_output).to_stdout
end

it "logs only headers with only headers enabled" do
mail = Mail.new do
html_part do
body "<html><body>html part</body></html>"
end
end

expected_output = <<~TXT
E-Mail #0
--------------------------------------------------------------------------------
From:
Subject:
--------------------------------------------------------------------------------
TXT
step = Spreewald::Steps::ShowMeTheMails.new([mail], true)
expect { step.run }.to output(expected_output).to_stdout
end
end

context "with multiple deliveries" do
it "logs the emails" do
mail_one = Mail.new do
html_part do
body "<html><body>html part</body></html>"
end
end

mail_two = Mail.new do
html_part do
body "<html><body>html2 part</body></html>"
end
end

expected_output = <<~TXT
E-Mail #0
--------------------------------------------------------------------------------
From:
Subject:
html part
--------------------------------------------------------------------------------
E-Mail #1
--------------------------------------------------------------------------------
From:
Subject:
html2 part
--------------------------------------------------------------------------------
TXT
step = Spreewald::Steps::ShowMeTheMails.new([mail_one, mail_two])
expect { step.run }.to output(expected_output).to_stdout
end
end
end
2 changes: 1 addition & 1 deletion tests/rails-4_capybara-2/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: ../..
specs:
spreewald (4.1.2)
spreewald (4.2.2)
cucumber
cucumber_priority (>= 0.3.0)
rspec (>= 2.13.0)
Expand Down
2 changes: 1 addition & 1 deletion tests/rails-6_capybara-3/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: ../..
specs:
spreewald (4.1.2)
spreewald (4.2.2)
cucumber
cucumber_priority (>= 0.3.0)
rspec (>= 2.13.0)
Expand Down

0 comments on commit 0d3af62

Please sign in to comment.