email_spec 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,5 +1,10 @@
1
1
  (In Git)
2
2
 
3
+ == 0.6.2 2010-03-21
4
+
5
+ === New features
6
+ * New reply_to matcher. (David Balatero)
7
+
3
8
  == 0.6.1 2010-03-17
4
9
 
5
10
  === New features
@@ -0,0 +1 @@
1
+ features/errors.feature:13:17:21:26:30
@@ -0,0 +1,182 @@
1
+ # Commonly used email steps
2
+ #
3
+ # To add your own steps make a custom_email_steps.rb
4
+ # The provided methods are:
5
+ #
6
+ # last_email_address
7
+ # reset_mailer
8
+ # open_last_email
9
+ # visit_in_email
10
+ # unread_emails_for
11
+ # mailbox_for
12
+ # current_email
13
+ # open_email
14
+ # read_emails_for
15
+ # find_email
16
+ #
17
+ # General form for email scenarios are:
18
+ # - clear the email queue (done automatically by email_spec)
19
+ # - execute steps that sends an email
20
+ # - check the user received an/no/[0-9] emails
21
+ # - open the email
22
+ # - inspect the email contents
23
+ # - interact with the email (e.g. click links)
24
+ #
25
+ # The Cucumber steps below are setup in this order.
26
+
27
+ module EmailHelpers
28
+ def current_email_address
29
+ # Replace with your a way to find your current email. e.g @current_user.email
30
+ # last_email_address will return the last email address used by email spec to find an email.
31
+ # Note that last_email_address will be reset after each Scenario.
32
+ last_email_address || "example@example.com"
33
+ end
34
+ end
35
+
36
+ World(EmailHelpers)
37
+
38
+ #
39
+ # Reset the e-mail queue within a scenario.
40
+ # This is done automatically before each scenario.
41
+ #
42
+
43
+ Given /^(?:a clear email queue|no emails have been sent)$/ do
44
+ reset_mailer
45
+ end
46
+
47
+ #
48
+ # Check how many emails have been sent/received
49
+ #
50
+
51
+ Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails?$/ do |address, amount|
52
+ unread_emails_for(address).size.should == parse_email_count(amount)
53
+ end
54
+
55
+ Then /^(?:I|they|"([^"]*?)") should have (an|no|\d+) emails?$/ do |address, amount|
56
+ mailbox_for(address).size.should == parse_email_count(amount)
57
+ end
58
+
59
+ Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails? with subject "([^"]*?)"$/ do |address, amount, subject|
60
+ unread_emails_for(address).select { |m| m.subject =~ Regexp.new(subject) }.size.should == parse_email_count(amount)
61
+ end
62
+
63
+ Then /^(?:I|they|"([^"]*?)") should receive an email with the following body:$/ do |address, expected_body|
64
+ open_email(address, :with_text => expected_body)
65
+ end
66
+
67
+ #
68
+ # Accessing emails
69
+ #
70
+
71
+ # Opens the most recently received email
72
+ When /^(?:I|they|"([^"]*?)") opens? the email$/ do |address|
73
+ open_email(address)
74
+ end
75
+
76
+ When /^(?:I|they|"([^"]*?)") opens? the email with subject "([^"]*?)"$/ do |address, subject|
77
+ open_email(address, :with_subject => subject)
78
+ end
79
+
80
+ When /^(?:I|they|"([^"]*?)") opens? the email with text "([^"]*?)"$/ do |address, text|
81
+ open_email(address, :with_text => text)
82
+ end
83
+
84
+ #
85
+ # Inspect the Email Contents
86
+ #
87
+
88
+ Then /^(?:I|they) should see "([^"]*?)" in the email subject$/ do |text|
89
+ current_email.should have_subject(text)
90
+ end
91
+
92
+ Then /^(?:I|they) should see \/([^"]*?)\/ in the email subject$/ do |text|
93
+ current_email.should have_subject(Regexp.new(text))
94
+ end
95
+
96
+ Then /^(?:I|they) should see "([^"]*?)" in the email body$/ do |text|
97
+ current_email.body.should include(text)
98
+ end
99
+
100
+ Then /^(?:I|they) should see \/([^"]*?)\/ in the email body$/ do |text|
101
+ current_email.body.should =~ Regexp.new(text)
102
+ end
103
+
104
+ Then /^(?:I|they) should see the email delivered from "([^"]*?)"$/ do |text|
105
+ current_email.should be_delivered_from(text)
106
+ end
107
+
108
+ Then /^(?:I|they) should see "([^\"]*)" in the email "([^"]*?)" header$/ do |text, name|
109
+ current_email.should have_header(name, text)
110
+ end
111
+
112
+ Then /^(?:I|they) should see \/([^\"]*)\/ in the email "([^"]*?)" header$/ do |text, name|
113
+ current_email.should have_header(name, Regexp.new(text))
114
+ end
115
+
116
+ #
117
+ # Inspect the Email Attachments
118
+ #
119
+
120
+ Then /^(?:I|they) should see (an|no|\d+) attachments? with the email$/ do |amount|
121
+ current_email_attachments.size.should == parse_email_count(amount)
122
+ end
123
+
124
+ Then /^there should be (an|no|\d+) attachments? named "([^"]*?)"$/ do |amount, filename|
125
+ current_email_attachments.select { |a| a.original_filename == filename }.size.should == parse_email_count(amount)
126
+ end
127
+
128
+ Then /^attachment (\d+) should be named "([^"]*?)"$/ do |index, filename|
129
+ current_email_attachments[(index.to_i - 1)].original_filename.should == filename
130
+ end
131
+
132
+ Then /^there should be (an|no|\d+) attachments? of type "([^"]*?)"$/ do |amount, content_type|
133
+ current_email_attachments.select { |a| a.content_type == content_type }.size.should == parse_email_count(amount)
134
+ end
135
+
136
+ Then /^attachment (\d+) should be of type "([^"]*?)"$/ do |index, content_type|
137
+ current_email_attachments[(index.to_i - 1)].content_type.should == content_type
138
+ end
139
+
140
+ Then /^all attachments should not be blank$/ do
141
+ current_email_attachments.each do |attachment|
142
+ attachment.size.should_not == 0
143
+ end
144
+ end
145
+
146
+ Then /^show me a list of email attachments$/ do
147
+ EmailSpec::EmailViewer::save_and_open_email_attachments_list(current_email)
148
+ end
149
+
150
+ #
151
+ # Interact with Email Contents
152
+ #
153
+
154
+ When /^(?:I|they) follow "([^"]*?)" in the email$/ do |link|
155
+ visit_in_email(link)
156
+ end
157
+
158
+ When /^(?:I|they) click the first link in the email$/ do
159
+ click_first_link_in_email
160
+ end
161
+
162
+ #
163
+ # Debugging
164
+ # These only work with Rails and OSx ATM since EmailViewer uses RAILS_ROOT and OSx's 'open' command.
165
+ # Patches accepted. ;)
166
+ #
167
+
168
+ Then /^save and open current email$/ do
169
+ EmailSpec::EmailViewer::save_and_open_email(current_email)
170
+ end
171
+
172
+ Then /^save and open all text emails$/ do
173
+ EmailSpec::EmailViewer::save_and_open_all_text_emails
174
+ end
175
+
176
+ Then /^save and open all html emails$/ do
177
+ EmailSpec::EmailViewer::save_and_open_all_html_emails
178
+ end
179
+
180
+ Then /^save and open all raw emails$/ do
181
+ EmailSpec::EmailViewer::save_and_open_all_raw_emails
182
+ end
@@ -1,9 +1,37 @@
1
1
  module EmailSpec
2
+ module Matchers
3
+ class ReplyTo
4
+ def initialize(email)
5
+ @expected_reply_to = TMail::Address.parse(email)
6
+ end
2
7
 
3
- module Matchers
8
+ def description
9
+ "have reply to as #{@expected_reply_to.address.to_s}"
10
+ end
4
11
 
5
- class DeliverTo
12
+ def matches?(email)
13
+ @email = email
14
+ @actual_reply_to = (email.reply_to || []).first
15
+ !@actual_reply_to.nil? &&
16
+ @actual_reply_to == @expected_reply_to.address
17
+ end
18
+
19
+ def failure_message
20
+ "expected #{@email.inspect} to reply to #{@expected_reply_to.address.inspect}, but it replied to #{@actual_reply_to.inspect}"
21
+ end
22
+
23
+ def negative_failure_message
24
+ "expected #{@email.inspect} not to deliver to #{@expected_reply_to.inspect}, but it did"
25
+ end
26
+ end
27
+
28
+ def reply_to(email)
29
+ ReplyTo.new(email)
30
+ end
31
+
32
+ alias :have_reply_to :reply_to
6
33
 
34
+ class DeliverTo
7
35
  def initialize(expected_email_addresses_or_objects_that_respond_to_email)
8
36
  emails = expected_email_addresses_or_objects_that_respond_to_email.map do |email_or_object|
9
37
  email_or_object.kind_of?(String) ? email_or_object : email_or_object.email
@@ -50,7 +78,7 @@ module EmailSpec
50
78
  def matches?(email)
51
79
  @email = email
52
80
  @actual_sender = (email.from_addrs || []).first
53
-
81
+
54
82
  !@actual_sender.nil? &&
55
83
  @actual_sender.address == @expected_sender.address &&
56
84
  @actual_sender.name == @expected_sender.name
@@ -122,68 +150,68 @@ module EmailSpec
122
150
  !!(given_subject =~ expected)
123
151
  end
124
152
  end
125
- end
126
-
127
- def include_email_with_subject(expected)
128
- simple_matcher do |given_emails, matcher|
129
-
130
- if expected.is_a?(String)
131
- matcher.description = "include email with subject of #{expected.inspect}"
132
- matcher.failure_message = "expected at least one email to have the subject #{expected.inspect} but none did. Subjects were #{given_emails.map(&:subject).inspect}"
133
- matcher.negative_failure_message = "expected no email with the subject #{expected.inspect} but found at least one. Subjects were #{given_emails.map(&:subject).inspect}"
134
-
135
- given_emails.map(&:subject).include?(expected)
136
- else
137
- matcher.description = "include email with subject matching #{expected.inspect}"
138
- matcher.failure_message = "expected at least one email to have a subject matching #{expected.inspect}, but none did. Subjects were #{given_emails.map(&:subject).inspect}"
139
- matcher.negative_failure_message = "expected no email to have a subject matching #{expected.inspect} but found at least one. Subjects were #{given_emails.map(&:subject).inspect}"
140
-
141
- !!(given_emails.any?{ |mail| mail.subject =~ expected })
142
- end
143
- end
144
- end
145
-
146
- def have_body_text(expected)
147
- simple_matcher do |given, matcher|
148
-
149
- if expected.is_a?(String)
150
- normalized_body = given.body.gsub(/\s+/, " ")
151
- normalized_expected = expected.gsub(/\s+/, " ")
152
- matcher.description = "have body including #{normalized_expected.inspect}"
153
- matcher.failure_message = "expected the body to contain #{normalized_expected.inspect} but was #{normalized_body.inspect}"
154
- matcher.negative_failure_message = "expected the body not to contain #{normalized_expected.inspect} but was #{normalized_body.inspect}"
155
-
156
- normalized_body.include?(normalized_expected)
157
- else
158
- given_body = given.body
159
- matcher.description = "have body matching #{expected.inspect}"
160
- matcher.failure_message = "expected the body to match #{expected.inspect}, but did not. Actual body was: #{given_body.inspect}"
161
- matcher.negative_failure_message = "expected the body not to match #{expected.inspect} but #{given_body.inspect} does match it."
162
-
163
- !!(given_body =~ expected)
164
- end
165
- end
166
- end
167
-
168
- def have_header(expected_name, expected_value)
169
- simple_matcher do |given, matcher|
170
- given_header = given.header
171
-
172
- if expected_value.is_a?(String)
173
- matcher.description = "have header #{expected_name}: #{expected_value}"
174
- matcher.failure_message = "expected the headers to include '#{expected_name}: #{expected_value}' but they were #{given_header.inspect}"
175
- matcher.negative_failure_message = "expected the headers not to include '#{expected_name}: #{expected_value}' but they were #{given_header.inspect}"
176
-
177
- given_header[expected_name].to_s == expected_value
178
- else
179
- matcher.description = "have header #{expected_name} with value matching #{expected_value.inspect}"
180
- matcher.failure_message = "expected the headers to include '#{expected_name}' with a value matching #{expected_value.inspect} but they were #{given_header.inspect}"
181
- matcher.negative_failure_message = "expected the headers not to include '#{expected_name}' with a value matching #{expected_value.inspect} but they were #{given_header.inspect}"
182
-
183
- given_header[expected_name].to_s =~ expected_value
184
- end
153
+ end
154
+
155
+ def include_email_with_subject(expected)
156
+ simple_matcher do |given_emails, matcher|
157
+
158
+ if expected.is_a?(String)
159
+ matcher.description = "include email with subject of #{expected.inspect}"
160
+ matcher.failure_message = "expected at least one email to have the subject #{expected.inspect} but none did. Subjects were #{given_emails.map(&:subject).inspect}"
161
+ matcher.negative_failure_message = "expected no email with the subject #{expected.inspect} but found at least one. Subjects were #{given_emails.map(&:subject).inspect}"
162
+
163
+ given_emails.map(&:subject).include?(expected)
164
+ else
165
+ matcher.description = "include email with subject matching #{expected.inspect}"
166
+ matcher.failure_message = "expected at least one email to have a subject matching #{expected.inspect}, but none did. Subjects were #{given_emails.map(&:subject).inspect}"
167
+ matcher.negative_failure_message = "expected no email to have a subject matching #{expected.inspect} but found at least one. Subjects were #{given_emails.map(&:subject).inspect}"
168
+
169
+ !!(given_emails.any?{ |mail| mail.subject =~ expected })
185
170
  end
186
171
  end
172
+ end
173
+
174
+ def have_body_text(expected)
175
+ simple_matcher do |given, matcher|
176
+
177
+ if expected.is_a?(String)
178
+ normalized_body = given.body.gsub(/\s+/, " ")
179
+ normalized_expected = expected.gsub(/\s+/, " ")
180
+ matcher.description = "have body including #{normalized_expected.inspect}"
181
+ matcher.failure_message = "expected the body to contain #{normalized_expected.inspect} but was #{normalized_body.inspect}"
182
+ matcher.negative_failure_message = "expected the body not to contain #{normalized_expected.inspect} but was #{normalized_body.inspect}"
183
+
184
+ normalized_body.include?(normalized_expected)
185
+ else
186
+ given_body = given.body
187
+ matcher.description = "have body matching #{expected.inspect}"
188
+ matcher.failure_message = "expected the body to match #{expected.inspect}, but did not. Actual body was: #{given_body.inspect}"
189
+ matcher.negative_failure_message = "expected the body not to match #{expected.inspect} but #{given_body.inspect} does match it."
190
+
191
+ !!(given_body =~ expected)
192
+ end
193
+ end
194
+ end
195
+
196
+ def have_header(expected_name, expected_value)
197
+ simple_matcher do |given, matcher|
198
+ given_header = given.header
199
+
200
+ if expected_value.is_a?(String)
201
+ matcher.description = "have header #{expected_name}: #{expected_value}"
202
+ matcher.failure_message = "expected the headers to include '#{expected_name}: #{expected_value}' but they were #{given_header.inspect}"
203
+ matcher.negative_failure_message = "expected the headers not to include '#{expected_name}: #{expected_value}' but they were #{given_header.inspect}"
204
+
205
+ given_header[expected_name].to_s == expected_value
206
+ else
207
+ matcher.description = "have header #{expected_name} with value matching #{expected_value.inspect}"
208
+ matcher.failure_message = "expected the headers to include '#{expected_name}' with a value matching #{expected_value.inspect} but they were #{given_header.inspect}"
209
+ matcher.negative_failure_message = "expected the headers not to include '#{expected_name}' with a value matching #{expected_value.inspect} but they were #{given_header.inspect}"
210
+
211
+ given_header[expected_name].to_s =~ expected_value
212
+ end
213
+ end
214
+ end
187
215
 
188
216
  end
189
217
  end
@@ -1,47 +1,60 @@
1
-
2
1
  require File.dirname(__FILE__) + '/../spec_helper'
3
2
 
4
-
5
-
6
3
  describe EmailSpec::Matchers do
4
+ include EmailSpec::Matchers
7
5
 
6
+ class MatcherMatch
7
+ def initialize(object_to_test_match)
8
+ @object_to_test_match = object_to_test_match
9
+ end
8
10
 
9
- class MatcherMatch
11
+ def description
12
+ "match when provided #{@object_to_test_match.inspect}"
13
+ end
10
14
 
11
- def initialize(object_to_test_match)
12
- @object_to_test_match = object_to_test_match
13
- end
15
+ def matches?(matcher)
16
+ @matcher = matcher
17
+ matcher.matches?(@object_to_test_match)
18
+ end
14
19
 
15
- def description
16
- "match when provided #{@object_to_test_match.inspect}"
17
- end
20
+ def failure_message
21
+ "expected #{@matcher.inspect} to match when provided #{@object_to_test_match.inspect}, but it did not"
22
+ end
18
23
 
19
- def matches?(matcher)
20
- @matcher = matcher
21
- matcher.matches?(@object_to_test_match)
22
- end
24
+ def negative_failure_message
25
+ "expected #{@matcher.inspect} not to match when provided #{@object_to_test_match.inspect}, but it did"
26
+ end
27
+ end
23
28
 
24
- def failure_message
25
- "expected #{@matcher.inspect} to match when provided #{@object_to_test_match.inspect}, but it did not"
26
- end
29
+ def match(object_to_test_match)
30
+ if object_to_test_match.is_a?(Regexp)
31
+ super # delegate to rspec's built in 'match' matcher
32
+ else
33
+ MatcherMatch.new(object_to_test_match)
34
+ end
35
+ end
27
36
 
28
- def negative_failure_message
29
- "expected #{@matcher.inspect} not to match when provided #{@object_to_test_match.inspect}, but it did"
30
- end
37
+ def mock_email(stubs)
38
+ mock("email", stubs)
39
+ end
40
+
41
+ describe "#reply_to" do
42
+ it "should match when the email is set to deliver to the specified address" do
43
+ email = mock_email(:reply_to => ["test@gmail.com"])
44
+ reply_to("test@gmail.com").should match(email)
31
45
  end
32
46
 
33
- def match(object_to_test_match)
34
- if object_to_test_match.is_a?(Regexp)
35
- super # delegate to rspec's built in 'match' matcher
36
- else
37
- MatcherMatch.new(object_to_test_match)
38
- end
47
+ it "should match given a name and address" do
48
+ email = mock_email(:reply_to => ["test@gmail.com"])
49
+ reply_to("David Balatero <test@gmail.com>").should match(email)
39
50
  end
40
51
 
41
- include EmailSpec::Matchers
52
+ it "should give correct failure message when the email is not set to deliver to the specified address" do
53
+ matcher = reply_to("jimmy_bean@yahoo.com")
54
+ matcher.matches?(mock_email(:inspect => 'email', :reply_to => ['freddy_noe@yahoo.com']))
55
+ matcher.failure_message.should == %{expected email to reply to "jimmy_bean@yahoo.com", but it replied to "freddy_noe@yahoo.com"}
56
+ end
42
57
 
43
- def mock_email(stubs)
44
- mock("email", stubs)
45
58
  end
46
59
 
47
60
  describe "#deliver_to" do
@@ -84,7 +97,7 @@ describe EmailSpec::Matchers do
84
97
  email = mock_email(:from_addrs => [TMail::Address.parse("jimmy_bean@yahoo.com")])
85
98
  deliver_from("jimmy_bean@yahoo.com").should match(email)
86
99
  end
87
-
100
+
88
101
  it "should match when the email is set to deliver from the specified name and address" do
89
102
  email = mock_email(:from_addrs => [TMail::Address.parse("Jimmy Bean <jimmy_bean@yahoo.com>")])
90
103
  deliver_from("Jimmy Bean <jimmy_bean@yahoo.com>").should match(email)
@@ -94,7 +107,7 @@ describe EmailSpec::Matchers do
94
107
  email = mock_email(:from_addrs => nil)
95
108
  deliver_from("jimmy_bean@yahoo.com").should_not match(email)
96
109
  end
97
-
110
+
98
111
  it "should not match when the email addresses match but the names do not" do
99
112
  email = mock_email(:from_addrs => [TMail::Address.parse("Jimmy Bean <jimmy_bean@yahoo.com>")])
100
113
  deliver_from("Freddy Noe <jimmy_bean@yahoo.com>").should_not match(email)
@@ -109,7 +122,7 @@ describe EmailSpec::Matchers do
109
122
  email = mock_email(:from_addrs => [TMail::Address.parse("freddy_noe@yahoo.com")])
110
123
  deliver_from("jimmy_bean@yahoo.com").should_not match(email)
111
124
  end
112
-
125
+
113
126
  it "should give correct failure message when the email is not set to deliver from the specified address" do
114
127
  matcher = deliver_from("jimmy_bean@yahoo.com")
115
128
  matcher.matches?(mock_email(:inspect => 'email', :from_addrs => [TMail::Address.parse("freddy_noe@yahoo.com")]))
@@ -180,11 +193,9 @@ describe EmailSpec::Matchers do
180
193
 
181
194
  matcher.negative_failure_message.should == 'expected the subject not to match /b/ but "bar" does match it.'
182
195
  end
183
-
184
196
  end
185
197
 
186
198
  describe "when strings are used" do
187
-
188
199
  it "should match when the subject equals the passed in string exactly" do
189
200
  email = mock_email(:subject => 'foo')
190
201
 
@@ -206,17 +217,13 @@ describe EmailSpec::Matchers do
206
217
  matcher.failure_message.should == 'expected the subject to be "foo" but was "bar"'
207
218
  end
208
219
 
209
-
210
220
  it "should offer helpful negative failing messages" do
211
221
  matcher = have_subject("bar")
212
222
  matcher.matches?(mock_email(:subject => "bar"))
213
223
 
214
224
  matcher.negative_failure_message.should == 'expected the subject not to be "bar" but was'
215
225
  end
216
-
217
226
  end
218
-
219
-
220
227
  end
221
228
 
222
229
  describe "#include_email_with_subject" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: email_spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Mabey
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2010-03-17 00:00:00 -06:00
14
+ date: 2010-03-21 00:00:00 -06:00
15
15
  default_executable:
16
16
  dependencies: []
17
17
 
@@ -129,6 +129,7 @@ test_files:
129
129
  - examples/rails_root/public/javascripts/prototype.js
130
130
  - examples/rails_root/public/robots.txt
131
131
  - examples/rails_root/Rakefile
132
+ - examples/rails_root/rerun.txt
132
133
  - examples/rails_root/script/about
133
134
  - examples/rails_root/script/autospec
134
135
  - examples/rails_root/script/console
@@ -158,6 +159,7 @@ test_files:
158
159
  - examples/sinatra/app.rb
159
160
  - examples/sinatra/features/errors.feature
160
161
  - examples/sinatra/features/example.feature
162
+ - examples/sinatra/features/step_definitions/email_steps.rb
161
163
  - examples/sinatra/features/step_definitions/user_steps.rb
162
164
  - examples/sinatra/features/step_definitions/web_steps.rb
163
165
  - examples/sinatra/features/support/env.rb