spreewald 2.5.0 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -2
  3. data/README.md +48 -41
  4. data/examples/paths.rb +36 -0
  5. data/examples/selectors.rb +28 -0
  6. data/lib/spreewald/all_steps.rb +4 -1
  7. data/lib/spreewald/email_steps.rb +87 -55
  8. data/lib/spreewald/session_steps.rb +18 -0
  9. data/lib/spreewald/time_steps.rb +102 -0
  10. data/lib/spreewald/timecop_steps.rb +6 -76
  11. data/lib/spreewald/web_steps.rb +24 -16
  12. data/lib/spreewald_support/mail_finder.rb +71 -41
  13. data/lib/spreewald_support/tolerance_for_selenium_sync_issues.rb +9 -3
  14. data/lib/spreewald_support/version.rb +1 -1
  15. data/lib/spreewald_support/web_steps_helpers.rb +17 -0
  16. data/support/step_definition_file.rb +2 -0
  17. data/tests/rails-3_capybara-1/Gemfile +2 -1
  18. data/tests/rails-3_capybara-1/Gemfile.lock +3 -1
  19. data/tests/rails-3_capybara-2/Gemfile +2 -1
  20. data/tests/rails-3_capybara-2/Gemfile.lock +3 -1
  21. data/tests/rails-4_capybara-3/Gemfile.lock +1 -1
  22. data/tests/rails-4_capybara-3/features/browser_tab_steps.feature +1 -0
  23. data/tests/rails-4_capybara-3/features/session_steps.feature +1 -0
  24. data/tests/rails-4_capybara-3/features/time_steps.feature +1 -0
  25. data/tests/rails-6_capybara-3/.ruby-version +1 -1
  26. data/tests/rails-6_capybara-3/Gemfile.lock +1 -1
  27. data/tests/rails-6_capybara-3/features/browser_tab_steps.feature +1 -0
  28. data/tests/rails-6_capybara-3/features/session_steps.feature +1 -0
  29. data/tests/rails-6_capybara-3/features/time_steps.feature +1 -0
  30. data/tests/shared/app/controllers/downloads_controller.rb +1 -1
  31. data/tests/shared/app/views/forms/disabled_elements.html.haml +18 -0
  32. data/tests/shared/app/views/mailer/html_email_with_links.haml +2 -0
  33. data/tests/shared/app/views/mailer/text_email_with_links.text.erb +1 -0
  34. data/tests/shared/app/views/static_pages/session_1.haml +1 -0
  35. data/tests/shared/app/views/static_pages/session_2.haml +1 -0
  36. data/tests/shared/app/views/static_pages/session_3.haml +1 -0
  37. data/tests/shared/app/views/static_pages/time.html.haml +2 -0
  38. data/tests/shared/config/routes.rb +4 -0
  39. data/tests/shared/features/shared/email_steps.feature +69 -5
  40. data/tests/shared/features/shared/session_steps.feature +29 -0
  41. data/tests/shared/features/shared/time_steps.feature +31 -0
  42. data/tests/shared/features/shared/web_steps.feature +8 -2
  43. metadata +29 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1168c34206078cc51317c0b55250cd4413120277f76dd08207e33ab0ad14defb
4
- data.tar.gz: 203c60be6904e5fbd56cc114a9e2b2bcc08cb50be8fa2f30159ef0a8041b4d6f
3
+ metadata.gz: 05a2f0dc08e4a044c5da09e999a488eeeab8d0ef21fd26fccf9306651e27d6ba
4
+ data.tar.gz: bc1753072141059f502b634a9a7347e63c602a072bc04f2a9aaf73a98ebd9eca
5
5
  SHA512:
6
- metadata.gz: 17930b95e19e14be451f87fc2ebf13877b1b377f57a15a29f8d7feba1bcfbbd0f35405c107db24a3955e2741070f91fba5e77c6c4ff0f66199b46aee9a9cbd9c
7
- data.tar.gz: 95584eefb31f7b90a6b9c49ec9bc9930aed8bead0fc4930075af317c9a5dd9131291d8f59b8696f30d409b77779fe8dcfdadf04dfe113344eba6374116523e8b
6
+ metadata.gz: 0b59488dcad4d0e94203fdc4b28463f69b6ccf93011f42c19dbc84582f0cca5e988a1b69c5f74520142198023dda9362e60c595d58a1bdc5abdde5b8a9e093ab
7
+ data.tar.gz: f324ae1ccd2ee7dbe97a71c4fbf614cd6888dd91846b42d2d60d900ae085413e6da55669d58ebe8275519354f10cf1a2826c5ef08323f30140d756572143dc76
@@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file.
3
3
 
4
4
  This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
5
5
 
6
+ ## 2.9.0
7
+ - The step `an email should have been sent with:` does now support wildcards (`*` at the end of a line to ignore the rest of the line, `*` as single character in a line to ignore multiple lines). The step also has better error messages if an email could not be found.
8
+ - The step `show me the emails` got an option to display only the email headers. Additionally, a new step `show me the email( header)?s with:` has been created to only show a subset of all sent emails, with a syntax similar to `an email should have been sent with:`.
9
+ - The email steps `an email should have been sent (from ...) (to ...) (cc ...) ...`, `that email should( not)? have the following lines in the body` and `that email should have the following content in the body:` have been deprecated in favor of `an email should have been sent with:`.
10
+
11
+ ## 2.8.0
12
+ - Add radio buttons to the `the "..." (field|button|checkbox|radio button) should( not)? be disabled` step.
13
+
14
+ ## 2.7.2
15
+ - Fix the step `I follow the ... link in the email` if the email contains non-HTTP(S) links
16
+
17
+ ## 2.7.1
18
+ - Support RFC-compliant encoding of filenames in `Content-Disposition` header (e.g. send_data), as provided by Rails 6.
19
+
20
+ ## 2.7.0
21
+ - Add a step modifier to control different Capybara sessions: `... in the browser session "..."`. (see issue [#66](https://github.com/makandra/spreewald/issues/66))
22
+
23
+ ## 2.6.0
24
+ - The time steps do now work with the time helpers in ActiveSupport 4.1+ if the timecop gem is not included in the bundle. Please note that the two approaches branch. While ActiveSupport will freeze the time, Timecop will keep it running.
25
+ - The steps in the file `spreewald/timecop.rb` file were moved to `spreewald/time.rb` and importing `spreewald/timecop` directly is deprecated now.
26
+
6
27
  ## 2.5.0
7
28
  - Add a set of steps to control browser tabs (Selenium only):
8
29
  * `I open ... in a new browser tab`
@@ -32,7 +53,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
32
53
 
33
54
  ## 2.2.4
34
55
  - Fix "..." field should have the error "..." test by removing old should syntax
35
- - Add single-line mail step to READNE
56
+ - Add single-line mail step to README
36
57
 
37
58
  ## 2.2.3
38
59
  - Fix 'the window should be titled' step - closes: [#102](https://github.com/makandra/spreewald/issues/102)
@@ -52,7 +73,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
52
73
 
53
74
  ## 2.2.0
54
75
  - Add a new step `I should( not)? see a link labeled "STRING"`.
55
- - Refer to Capybara 3's new flag `Capybara.default_normalize_ws = true` in the READNE,
76
+ - Refer to Capybara 3's new flag `Capybara.default_normalize_ws = true` in the README,
56
77
 
57
78
  ## 2.1.3
58
79
  The `I should(not )? see /REGEXP/` step no longer refuses slashes as part of the regular expression. You can thus match full domains and more.
data/README.md CHANGED
@@ -216,7 +216,7 @@ the step definitions.
216
216
  * **When I clear my e?mails**
217
217
 
218
218
 
219
- * **Then (an|no) e?mail should have been sent with:**
219
+ * **Then (an?|no)( HTML| plain-text|) e?mail should have been sent with:**
220
220
 
221
221
  Example:
222
222
 
@@ -225,58 +225,48 @@ the step definitions.
225
225
  From: max.mustermann@example.com
226
226
  Reply-To: mmuster@gmail.com
227
227
  To: john.doe@example.com
228
+ CC: jane.doe@example.com
229
+ BCC: johnny.doe@example.com
228
230
  Subject: The subject may contain "quotes"
229
- Attachments: ...
231
+ Attachments: image.jpg, attachment.pdf
230
232
 
231
- Message body goes here.
232
- """
233
-
234
- You may skip lines in the header, of course. Note that the mail body is only checked for
235
- _inclusion_. That means you can only test a prefix of the body. The subject may also be
236
- a prefix.
237
-
238
-
239
- * **Then (an|no) e?mail should have been sent(( |and|with|from "..."|bcc "..."|cc "..."|to "..."|the subject "..."|the body "..."|the attachments "...")+)**
240
-
241
- Example:
233
+ This is the message body. You can use * as a wildcard to omit the rest
234
+ of a line *
235
+ Or you can omit multiple lines if the asterisk is the only
236
+ character in a single line, like this:
237
+ *
242
238
 
243
- Then an email should have been sent from "max.mustermann@example.com" to "john.doe@example.com" with bcc "john.wane@example.com" and with cc "foo@bar.com" and the subject "The subject" and the body "The body" and the attachments "attachment.pdf"
239
+ """
244
240
 
245
- You may skip parts, of course.
241
+ Because of backwards-compatibility, the body currently only has to be a prefix
242
+ of the real body. However, this is deprecated and will be removed in a future
243
+ version. Use wildcards instead.
244
+ You may skip lines in the header, of course.
246
245
 
247
246
 
248
247
  * **When I follow the (first|second|third)? link in the e?mail**
249
248
 
249
+ Please note that this step will only follow HTTP and HTTPS links.
250
+ Other links (such as mailto: or ftp:// links) are ignored.
251
+
250
252
 
251
253
  * **Then no e?mail should have been sent**
252
254
 
253
255
 
254
- * **Then I should see "..." in the e?mail**
256
+ * **Then I should see "..." in the( HTML| plain-text|) e?mail**
255
257
 
256
258
  Checks that the last sent email includes some text
257
259
 
258
260
 
259
- * **Then show me the e?mails**
260
-
261
- Print all sent emails to STDOUT.
261
+ * **Then show me the e?mail( header)?s**
262
262
 
263
-
264
- * **Then that e?mail should( not)? have the following lines in the body:**
265
-
266
- Example:
267
-
268
- And that mail should have the following lines in the body:
269
- """
270
- All of these lines
271
- need to be present
272
- """
273
-
274
- You may skip lines, of course. Note that you may also omit text at the end of each line.
263
+ Print all sent emails to STDOUT (optionally only the headers).
275
264
 
276
265
 
277
- * **Then that e?mail should have the following (|content in the )body:**
266
+ * **Then show me the e?mail( header)?s with:**
278
267
 
279
- Checks that the text should be included anywhere in the retrieved email body
268
+ Print a subset of all sent emails to STDOUT
269
+ This uses the same syntax as `Then an email should have been sent with:`
280
270
 
281
271
 
282
272
  ### file_attachment_steps.rb
@@ -286,6 +276,18 @@ the step definitions.
286
276
  This step is deprecated and will be removed from spreewald. If you still want to use it, copy the code to your project's own steps.
287
277
 
288
278
 
279
+ ### session_steps.rb
280
+
281
+ * **When ... in the browser session "..."**
282
+
283
+ You can append `in the browser session "name"` to any other step to execute
284
+ the step in a different browser session.
285
+
286
+ You may need to update other steps to allow multiple sessions (e.g. your
287
+ authentication steps have to support multiple logged in users).
288
+ More details [here](https://makandracards.com/makandra/474480-how-to-make-a-cucumber-test-work-with-multiple-browser-sessions).
289
+
290
+
289
291
  ### table_steps.rb
290
292
 
291
293
  * **Then I should( not)? see a table with (exactly )?the following rows( in any order)?:?**
@@ -295,11 +297,14 @@ the step definitions.
295
297
  See [this article](https://makandracards.com/makandra/763-cucumber-step-to-match-table-rows-with-capybara) for details.
296
298
 
297
299
 
298
- ### timecop_steps.rb
300
+ ### time_steps.rb
299
301
 
300
- Steps to travel through time using [Timecop](https://github.com/jtrupiano/timecop).
302
+ Steps to travel through time
301
303
 
302
- See [this article](https://makandracards.com/makandra/1222-useful-cucumber-steps-to-travel-through-time-with-timecop) for details.
304
+ This uses [Timecop](https://github.com/jtrupiano/timecop) or Active Support 4.1+ to stub Time.now / Time.current.
305
+ The user is responsible for including one of the two gems.
306
+
307
+ Please note that the two approaches branch. While ActiveSupport will freeze the time, Timecop will keep it running.
303
308
 
304
309
 
305
310
  * **When the (date|time) is "?(\d{4}-\d{2}-\d{2}( \d{1,2}:\d{2})?)"?**
@@ -317,7 +322,7 @@ See [this article](https://makandracards.com/makandra/1222-useful-cucumber-steps
317
322
  Given the time is 13:40
318
323
 
319
324
 
320
- * **When it is (\d+|a|some|a few) (seconds?|minutes?|hours?|days?|weeks?|months?|years?) (later|earlier)**
325
+ * **When it is (\d+|an?|some|a few) (seconds?|minutes?|hours?|days?|weeks?|months?|years?) (later|earlier)**
321
326
 
322
327
  Example:
323
328
 
@@ -325,6 +330,8 @@ See [this article](https://makandracards.com/makandra/1222-useful-cucumber-steps
325
330
  When it is a few hours earlier
326
331
 
327
332
 
333
+
334
+
328
335
  ### web_steps.rb
329
336
 
330
337
  Most of cucumber-rails' original web steps plus a few of our own.
@@ -353,7 +360,7 @@ deprecation notice. Decide for yourself whether you want to use them:
353
360
 
354
361
  * **When ... within ...**
355
362
 
356
- You can append `within [selector]` to any other web step.
363
+ You can append `within [selector]` to any other web step, even multiple times.
357
364
  Be aware that within will only look at the first element that matches.
358
365
  If this is a problem for you following links, you might want to have a look
359
366
  at the 'When I follow "..." inside any "..."'-step.
@@ -663,7 +670,7 @@ deprecation notice. Decide for yourself whether you want to use them:
663
670
 
664
671
  Then "Sponsor" should link to "http://makandra.com/"
665
672
 
666
- Don't forget the trailing slash. Otherwise you'll get the error
673
+ Don't forget the trailing slash. Otherwise you'll get the error
667
674
  expected: /http:\/\/makandra.com(\?[^\/]*)?$/
668
675
  got: "http://makandra.com/" (using =~)
669
676
 
@@ -698,9 +705,9 @@ deprecation notice. Decide for yourself whether you want to use them:
698
705
  * **When I enter "..." into the browser dialog**
699
706
 
700
707
 
701
- * **Then the "..." (field|button|checkbox) should( not)? be disabled**
708
+ * **Then the "..." (field|button|checkbox|radio button) should( not)? be disabled**
702
709
 
703
- Tests that an input, button or checkbox with the given label is disabled.
710
+ Tests that an input, button, checkbox or radio button with the given label is disabled.
704
711
 
705
712
 
706
713
  * **Then the "..." field should( not)? be visible**
@@ -13,6 +13,30 @@ module NavigationHelpers
13
13
  when /^the home\s?page$/
14
14
  root_path
15
15
 
16
+ when /^the (page|form) for the (.*?) above$/
17
+ action_prose = Regexp.last_match(1)
18
+ model_prose = Regexp.last_match(2)
19
+ route = "#{(action_prose == 'form') ? 'edit_' : ''}#{model_prose_to_route_segment(model_prose)}_path"
20
+ model = model_prose_to_class(model_prose)
21
+ send(route, model.reorder(:id).last!)
22
+
23
+ when /^the (page|form) for the (.*?) "(.*?)"$/
24
+ action_prose = Regexp.last_match(1)
25
+ model_prose = Regexp.last_match(2)
26
+ identifier = Regexp.last_match(3)
27
+ path_to_show_or_edit(action_prose, model_prose, identifier)
28
+
29
+ when /^the (.*?) (page|form) for "(.*?)"$/
30
+ model_prose = Regexp.last_match(1)
31
+ action_prose = Regexp.last_match(2)
32
+ identifier = Regexp.last_match(3)
33
+ path_to_show_or_edit(action_prose, model_prose, identifier)
34
+
35
+ when /^the (.*?) form$/
36
+ model_prose = Regexp.last_match(1)
37
+ route = "new_#{model_prose_to_route_segment(model_prose)}_path"
38
+ send(route)
39
+
16
40
  else
17
41
  begin
18
42
  page_name =~ /^the (.*) page$/
@@ -24,6 +48,18 @@ module NavigationHelpers
24
48
  end
25
49
  end
26
50
  end
51
+
52
+ private
53
+
54
+ def model_prose_to_class(model_prose)
55
+ model_prose.gsub(' ', '_').classify.constantize
56
+ end
57
+
58
+ def model_prose_to_route_segment(model_prose)
59
+ model_prose = model_prose.downcase
60
+ model_prose.gsub(/[\ \/]/, '_')
61
+ end
62
+
27
63
  end
28
64
 
29
65
  World(NavigationHelpers)
@@ -12,6 +12,27 @@ module HtmlSelectorsHelpers
12
12
  when "the page"
13
13
  "html > body"
14
14
 
15
+ # Auto-mapper for BEM classes and ARIA labels
16
+ #
17
+ # Usage examples:
18
+ # the main menu -> '.main-menu, [aria-label="main menu"]'
19
+ # the item box's header -> '.item-box--header, [aria-label="item box's header"]'
20
+ # the slider's item that is current -> '.slider--item.is-current, [aria-label="slider's item that is current"]'
21
+ when /^the (.*)$/
22
+ match = Regexp.last_match(1)
23
+ match =~ /^(.+?)(?:'s (.+?))?(?: that (.+))?$/
24
+
25
+ bem_selector = '.'
26
+ bem_selector << selectorify(Regexp.last_match(1))
27
+ bem_selector << '--' << selectorify(Regexp.last_match(2)) if Regexp.last_match(2)
28
+ bem_selector << '.' << selectorify(Regexp.last_match(3)) if Regexp.last_match(3)
29
+
30
+ aria_selector = '[aria-label="'
31
+ aria_selector << match.gsub('"', '\\"')
32
+ aria_selector << '"]'
33
+
34
+ [bem_selector, aria_selector].join(', ')
35
+
15
36
  # Add more mappings here.
16
37
  # Here is an example that pulls values out of the Regexp:
17
38
  #
@@ -35,6 +56,13 @@ module HtmlSelectorsHelpers
35
56
  "Now, go and add a mapping in #{__FILE__}"
36
57
  end
37
58
  end
59
+
60
+ private
61
+
62
+ def selectorify(string)
63
+ string.gsub(/ /, '-')
64
+ end
65
+
38
66
  end
39
67
 
40
68
  World(HtmlSelectorsHelpers)
@@ -1,9 +1,12 @@
1
1
  # coding: UTF-8
2
2
  require 'rspec/matchers'
3
3
 
4
+ ALREADY_LOADED_FILES = %w[all_steps timecop_steps]
5
+
4
6
  Dir[File.join(File.dirname(__FILE__), '*_steps.rb')].each do |f|
5
7
  name = File.basename(f, '.rb')
6
- unless name == 'all_steps'
8
+
9
+ unless ALREADY_LOADED_FILES.include?(name)
7
10
  require "spreewald/#{name}"
8
11
  end
9
12
  end
@@ -17,54 +17,81 @@ end.overridable
17
17
  # From: max.mustermann@example.com
18
18
  # Reply-To: mmuster@gmail.com
19
19
  # To: john.doe@example.com
20
+ # CC: jane.doe@example.com
21
+ # BCC: johnny.doe@example.com
20
22
  # Subject: The subject may contain "quotes"
21
- # Attachments: ...
23
+ # Attachments: image.jpg, attachment.pdf
24
+ #
25
+ # This is the message body. You can use * as a wildcard to omit the rest
26
+ # of a line *
27
+ # Or you can omit multiple lines if the asterisk is the only
28
+ # character in a single line, like this:
29
+ # *
22
30
  #
23
- # Message body goes here.
24
31
  # """
25
32
  #
26
- # You may skip lines in the header, of course. Note that the mail body is only checked for
27
- # _inclusion_. That means you can only test a prefix of the body. The subject may also be
28
- # a prefix.
29
- Then /^(an|no) e?mail should have been sent with:$/ do |mode, raw_data|
33
+ # Because of backwards-compatibility, the body currently only has to be a prefix
34
+ # of the real body. However, this is deprecated and will be removed in a future
35
+ # version. Use wildcards instead.
36
+ # You may skip lines in the header, of course.
37
+ Then /^(an?|no)( HTML| plain-text|) e?mail should have been sent with:$/ do |mode, type, raw_data|
30
38
  patiently do
31
- raw_data.strip!
32
- header, body = raw_data.split(/\n\n/, 2) # 2: maximum number of fields
33
- conditions = {}
34
- header.split("\n").each do |row|
35
- if row.match(/^[a-z\-]+: /i)
36
- key, value = row.split(": ", 2)
37
- conditions[key.underscore.to_sym] = value
39
+ results = MailFinder.find(raw_data, type.strip)
40
+
41
+ if mode == 'no'
42
+ expect(results).to be_empty
43
+ else
44
+ if results.one?
45
+ @mail = results.mails[0]
46
+ elsif results.many?
47
+ warn <<-WARNING
48
+ #{results.size} emails were found with the following conditions.
49
+ You may want to make the description more precise or clear the emails in between.
50
+ #{raw_data}
51
+ WARNING
52
+ else
53
+ message = <<-ERROR
54
+ No matching mail was found. There were #{ActionMailer::Base.deliveries.size} mails in total.
55
+ #{results.matching_header.size} of those had matching headers.
56
+ ERROR
57
+ if results.matching_header.empty?
58
+ message << "Expected\n" + '-' * 80 + "\n"
59
+ message << raw_data.split(/\n\n/, 2)[0] # Show the expected header
60
+ message << "\n" + '-' * 80 + "\n\n"
61
+ message << MailFinder.show_mails(ActionMailer::Base.deliveries, true)
62
+ else
63
+ message << "\nTried to match #{results.body_regex.inspect} in the following mails:\n"
64
+ message << results.matching_header.map { |mail| MailFinder.email_text_body(mail, type.strip).strip.inspect }.join("\n")
65
+ message << "\n"
66
+ end
67
+ raise RSpec::Expectations::ExpectationNotMetError.new(message)
38
68
  end
39
69
  end
40
- conditions[:body] = body if body
41
- @mail = MailFinder.find(conditions)
42
- expectation = mode == 'no' ? 'not_to' : 'to'
43
- expect(@mail).send(expectation, be_present)
44
70
  end
45
71
  end.overridable
46
72
 
47
- # Example:
48
- #
49
- # Then an email should have been sent from "max.mustermann@example.com" to "john.doe@example.com" with bcc "john.wane@example.com" and with cc "foo@bar.com" and the subject "The subject" and the body "The body" and the attachments "attachment.pdf"
50
- #
51
- # You may skip parts, of course.
73
+ # nodoc (deprecated)
52
74
  Then /^(an|no) e?mail should have been sent((?: |and|with|from "[^"]+"|bcc "[^"]+"|cc "[^"]+"|to "[^"]+"|the subject "[^"]+"|the body "[^"]+"|the attachments "[^"]+")+)$/ do |mode, query|
75
+ warn "The step `an email should have been sent (from ...) (to ...) (cc ...) ...` has been deprecated in favor of `(an?|no)( HTML| plain-text|) e?mail should have been sent with:`"
53
76
  patiently do
54
- conditions = {}
55
- conditions[:to] = $1 if query =~ /to "([^"]+)"/
56
- conditions[:Cc] = $1 if query =~ /cc "([^"]+)"/
57
- conditions[:bcc] = $1 if query =~ /bcc "([^"]+)"/
58
- conditions[:from] = $1 if query =~ /from "([^"]+)"/
59
- conditions[:subject] = $1 if query =~ /the subject "([^"]+)"/
60
- conditions[:body] = $1 if query =~ /the body "([^"]+)"/
61
- conditions[:attachments] = $1 if query =~ /the attachments "([^"]+)"/
62
- @mail = MailFinder.find(conditions)
77
+ filename_method = Rails::VERSION::MAJOR < 3 ? 'original_filename' : 'filename'
78
+ @mail = ActionMailer::Base.deliveries.find do |mail|
79
+ [ query =~ /to "([^"]+)"/ && !mail.to.include?(MailFinder.resolve_email $1),
80
+ query =~ /cc "([^"]+)"/ && !mail.cc.include?(MailFinder.resolve_email $1),
81
+ query =~ /bcc "([^"]+)"/ && !mail.bcc.include?(MailFinder.resolve_email $1),
82
+ query =~ /from "([^"]+)"/ && !mail.from.include?(MailFinder.resolve_email $1),
83
+ query =~ /reply_to "([^"]+)"/ && !mail.reply_to.include?(MailFinder.resolve_email $1),
84
+ query =~ /subject "([^"]+)"/ && !mail.subject.include?($1),
85
+ query =~ /the attachments "([^"]+)"/ && $1.split(/\s*,\s*/).sort != Array(mail.attachments).collect(&:"#{filename_method}").sort
86
+ ].none?
87
+ end
63
88
  expectation = mode == 'no' ? 'not_to' : 'to'
64
89
  expect(@mail).send(expectation, be_present)
65
90
  end
66
91
  end.overridable
67
92
 
93
+ # Please note that this step will only follow HTTP and HTTPS links.
94
+ # Other links (such as mailto: or ftp:// links) are ignored.
68
95
  When /^I follow the (first|second|third)? ?link in the e?mail$/ do |index_in_words|
69
96
  mail = @mail || ActionMailer::Base.deliveries.last
70
97
  index = { nil => 0, 'first' => 0, 'second' => 1, 'third' => 2 }[index_in_words]
@@ -72,7 +99,7 @@ When /^I follow the (first|second|third)? ?link in the e?mail$/ do |index_in_wor
72
99
 
73
100
  paths = if mail.html_part
74
101
  dom = Nokogiri::HTML(mail.html_part.body.to_s)
75
- (dom / 'a[href]').map { |a| a['href'].match(url_pattern)[1] }
102
+ (dom / 'a[href]').map { |a| a['href'].match(url_pattern) }.compact.map { |match| match[1] }
76
103
  else
77
104
  mail_body = MailFinder.email_text_body(mail).to_s
78
105
  mail_body.scan(url_pattern).flatten(1)
@@ -86,34 +113,38 @@ Then /^no e?mail should have been sent$/ do
86
113
  end.overridable
87
114
 
88
115
  # Checks that the last sent email includes some text
89
- Then /^I should see "([^\"]*)" in the e?mail$/ do |text|
90
- expect(MailFinder.email_text_body(ActionMailer::Base.deliveries.last)).to include(text)
116
+ Then /^I should see "([^\"]*)" in the( HTML| plain-text|) e?mail$/ do |text, type|
117
+ expect(MailFinder.email_text_body(ActionMailer::Base.deliveries.last, type.strip)).to include(text)
118
+ end.overridable
119
+
120
+ # Print all sent emails to STDOUT (optionally only the headers).
121
+ Then /^show me the e?mail( header)?s$/ do |only_header|
122
+ if ActionMailer::Base.deliveries.empty?
123
+ puts MailFinder.show_mails(ActionMailer::Base.deliveries, only_header)
124
+ else
125
+ puts "No emails found" if ActionMailer::Base.deliveries.empty?
126
+ end
127
+
91
128
  end.overridable
92
129
 
93
- # Print all sent emails to STDOUT.
94
- Then /^show me the e?mails$/ do
95
- ActionMailer::Base.deliveries.each_with_index do |mail, i|
96
- puts "E-Mail ##{i}"
97
- print "-" * 80
98
- puts [ "From: #{mail.from}",
99
- "To: #{mail.to}",
100
- "Subject: #{mail.subject}",
101
- "\n" + MailFinder.email_text_body(mail)
102
- ].join("\n")
103
- print "-" * 80
130
+ # Print a subset of all sent emails to STDOUT
131
+ # This uses the same syntax as `Then an email should have been sent with:`
132
+ Then /^show me the e?mail( header)?s with:$/ do |only_header, raw_data|
133
+ results = MailFinder.find(raw_data)
134
+ if results.empty?
135
+ if results.matching_header.empty?
136
+ puts "There are no emails matching the given header."
137
+ else
138
+ puts "There are no emails matching the given header and body, but #{results.matching_header.size} matching only the header."
139
+ end
104
140
  end
141
+
142
+ print MailFinder.show_mails(results.mails, only_header)
105
143
  end.overridable
106
144
 
107
- # Example:
108
- #
109
- # And that mail should have the following lines in the body:
110
- # """
111
- # All of these lines
112
- # need to be present
113
- # """
114
- #
115
- # You may skip lines, of course. Note that you may also omit text at the end of each line.
145
+ # nodoc (deprecated)
116
146
  Then /^that e?mail should( not)? have the following lines in the body:$/ do |negate, body|
147
+ warn "The step /^that e?mail should( not)? have the following lines in the body:$/ has been deprecated in favor of the updated step /^(an?|no)( HTML| plain-text|) e?mail should have been sent with:$/."
117
148
  expectation = negate ? 'not_to' : 'to'
118
149
  mail = @mail || ActionMailer::Base.deliveries.last
119
150
  email_text_body = MailFinder.email_text_body(mail)
@@ -123,8 +154,9 @@ Then /^that e?mail should( not)? have the following lines in the body:$/ do |neg
123
154
  end
124
155
  end.overridable
125
156
 
126
- # Checks that the text should be included anywhere in the retrieved email body
157
+ # nodoc (deprecated)
127
158
  Then /^that e?mail should have the following (?:|content in the )body:$/ do |body|
159
+ warn "The step /^that e?mail should have the following( content in the)? body:$/ has been deprecated in favor of the updated step /^(an?|no)( HTML| plain-text|) e?mail should have been sent with:$/."
128
160
  mail = @mail || ActionMailer::Base.deliveries.last
129
161
  expect(MailFinder.email_text_body(mail)).to include(body.strip)
130
162
  end.overridable