email_spec 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
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