spreewald 4.1.1 → 4.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +0 -5
  3. data/CHANGELOG.md +16 -0
  4. data/Gemfile.lock +3 -3
  5. data/Gemfile.ruby266.lock +59 -42
  6. data/Gemfile.ruby300.lock +37 -53
  7. data/README.md +10 -19
  8. data/Rakefile +5 -11
  9. data/examples/paths.rb +7 -0
  10. data/features/binary.feature +12 -8
  11. data/lib/spreewald/development_steps.rb +5 -5
  12. data/lib/spreewald/email_steps.rb +4 -18
  13. data/lib/spreewald/web_steps.rb +53 -50
  14. data/lib/spreewald.rb +1 -0
  15. data/lib/spreewald_support/field_errors.rb +56 -0
  16. data/lib/spreewald_support/version.rb +1 -1
  17. data/lib/steps/follow_the_link.rb +63 -0
  18. data/lib/steps/show_me_the_mails.rb +20 -0
  19. data/spec/steps/follow_the_link_spec.rb +81 -0
  20. data/spec/steps/show_me_the_mails_spec.rb +96 -0
  21. data/support/step_definition.rb +11 -0
  22. data/support/step_manager.rb +1 -1
  23. data/tests/rails-6_capybara-3/Gemfile.lock +1 -1
  24. data/tests/shared/app/controllers/forms_controller.rb +8 -2
  25. data/tests/shared/app/controllers/static_pages_controller.rb +3 -0
  26. data/tests/shared/app/views/forms/invalid_bootstrap3_form.html.haml +16 -0
  27. data/tests/shared/app/views/forms/invalid_bootstrap4_form.html.haml +18 -0
  28. data/tests/shared/app/views/forms/{invalid_form.html.haml → invalid_rails_form.html.haml} +0 -0
  29. data/tests/shared/app/views/static_pages/should_see.haml +7 -0
  30. data/tests/shared/config/routes.rb +4 -1
  31. data/tests/shared/features/shared/iframe_steps.feature +1 -2
  32. data/tests/shared/features/shared/web_steps.feature +47 -15
  33. metadata +15 -112
  34. data/Gemfile.ruby245 +0 -10
  35. data/Gemfile.ruby245.lock +0 -73
  36. data/tests/rails-4_capybara-2/Gemfile +0 -24
  37. data/tests/rails-4_capybara-2/Gemfile.lock +0 -230
  38. data/tests/rails-4_capybara-2/README.rdoc +0 -28
  39. data/tests/rails-4_capybara-2/Rakefile +0 -6
  40. data/tests/rails-4_capybara-2/app +0 -1
  41. data/tests/rails-4_capybara-2/bin/bundle +0 -3
  42. data/tests/rails-4_capybara-2/bin/rails +0 -4
  43. data/tests/rails-4_capybara-2/bin/rake +0 -4
  44. data/tests/rails-4_capybara-2/bin/setup +0 -29
  45. data/tests/rails-4_capybara-2/config/application.rb +0 -35
  46. data/tests/rails-4_capybara-2/config/boot.rb +0 -3
  47. data/tests/rails-4_capybara-2/config/cucumber.yml +0 -8
  48. data/tests/rails-4_capybara-2/config/database.yml +0 -18
  49. data/tests/rails-4_capybara-2/config/environment.rb +0 -5
  50. data/tests/rails-4_capybara-2/config/environments/development.rb +0 -28
  51. data/tests/rails-4_capybara-2/config/environments/test.rb +0 -42
  52. data/tests/rails-4_capybara-2/config/initializers/backtrace_silencers.rb +0 -7
  53. data/tests/rails-4_capybara-2/config/initializers/cookies_serializer.rb +0 -3
  54. data/tests/rails-4_capybara-2/config/initializers/filter_parameter_logging.rb +0 -4
  55. data/tests/rails-4_capybara-2/config/initializers/inflections.rb +0 -16
  56. data/tests/rails-4_capybara-2/config/initializers/mime_types.rb +0 -4
  57. data/tests/rails-4_capybara-2/config/initializers/session_store.rb +0 -3
  58. data/tests/rails-4_capybara-2/config/initializers/silence_deprecation_warnings.rb +0 -11
  59. data/tests/rails-4_capybara-2/config/initializers/to_time_preserves_timezone.rb +0 -10
  60. data/tests/rails-4_capybara-2/config/initializers/wrap_parameters.rb +0 -14
  61. data/tests/rails-4_capybara-2/config/locales/en.yml +0 -23
  62. data/tests/rails-4_capybara-2/config/routes.rb +0 -1
  63. data/tests/rails-4_capybara-2/config/secrets.yml +0 -22
  64. data/tests/rails-4_capybara-2/config.ru +0 -4
  65. data/tests/rails-4_capybara-2/db +0 -1
  66. data/tests/rails-4_capybara-2/features/browser_tab_steps.feature +0 -1
  67. data/tests/rails-4_capybara-2/features/development_steps.feature +0 -1
  68. data/tests/rails-4_capybara-2/features/email_steps.feature +0 -1
  69. data/tests/rails-4_capybara-2/features/iframe_steps.feature +0 -1
  70. data/tests/rails-4_capybara-2/features/overriding.feature +0 -1
  71. data/tests/rails-4_capybara-2/features/session_steps.feature +0 -1
  72. data/tests/rails-4_capybara-2/features/step_definitions/overriding_steps.rb +0 -1
  73. data/tests/rails-4_capybara-2/features/step_definitions/test_steps.rb +0 -1
  74. data/tests/rails-4_capybara-2/features/support/env.rb +0 -66
  75. data/tests/rails-4_capybara-2/features/support/paths.rb +0 -1
  76. data/tests/rails-4_capybara-2/features/support/selectors.rb +0 -1
  77. data/tests/rails-4_capybara-2/features/support/selenium.rb +0 -1
  78. data/tests/rails-4_capybara-2/features/table_steps.feature +0 -1
  79. data/tests/rails-4_capybara-2/features/time_steps.feature +0 -1
  80. data/tests/rails-4_capybara-2/features/web_steps.feature +0 -1
  81. data/tests/rails-4_capybara-2/lib/tasks/cucumber.rake +0 -65
  82. data/tests/rails-4_capybara-2/log/.keep +0 -0
  83. data/tests/rails-4_capybara-2/public/404.html +0 -67
  84. data/tests/rails-4_capybara-2/public/422.html +0 -67
  85. data/tests/rails-4_capybara-2/public/500.html +0 -66
  86. data/tests/rails-4_capybara-2/public/favicon.ico +0 -0
  87. data/tests/rails-4_capybara-2/public/fixture_files +0 -1
  88. data/tests/rails-4_capybara-2/script/cucumber +0 -10
@@ -31,6 +31,7 @@ require 'spreewald_support/custom_matchers'
31
31
  require 'spreewald_support/web_steps_helpers'
32
32
  require 'spreewald_support/driver_info'
33
33
  require 'spreewald_support/comparison'
34
+ require 'spreewald_support/field_errors'
34
35
  require 'uri'
35
36
  require 'cgi'
36
37
 
@@ -167,32 +168,23 @@ end.overridable
167
168
  # Checks that some text appears on the page
168
169
  #
169
170
  # Note that this does not detect if the text might be hidden via CSS
170
- Then /^(?:|I )should see "([^"]*)"$/ do |text|
171
+ Then /^(?:|I )should( not)? see "([^"]*)"$/ do |negate, text|
172
+ expectation = negate ? :not_to : :to
173
+
171
174
  patiently do
172
- expect(page).to have_content(text)
175
+ expect(page).send(expectation, have_content(text))
173
176
  end
174
177
  end.overridable
175
178
 
176
179
  # Checks that a regexp appears on the page
177
180
  #
178
181
  # Note that this does not detect if the text might be hidden via CSS
179
- Then /^(?:|I )should see \/(.*)\/$/ do |regexp|
182
+ Then /^(?:|I )should( not)? see \/(.*)\/$/ do |negate, regexp|
183
+ expectation = negate ? :not_to : :to
180
184
  regexp = Regexp.new(regexp)
181
- patiently do
182
- expect(page).to have_xpath('.//descendant-or-self::*', :text => regexp)
183
- end
184
- end.overridable
185
185
 
186
- Then /^(?:|I )should not see "([^"]*)"$/ do |text|
187
186
  patiently do
188
- expect(page).to have_no_content(text)
189
- end
190
- end.overridable
191
-
192
- Then /^(?:|I )should not see \/(.*)\/$/ do |regexp|
193
- patiently do
194
- regexp = Regexp.new(regexp)
195
- expect(page).to have_no_xpath('.//descendant-or-self::*', :text => regexp)
187
+ expect(page).send(expectation, have_xpath('.//descendant-or-self::*', text: regexp))
196
188
  end
197
189
  end.overridable
198
190
 
@@ -239,22 +231,20 @@ end.overridable(priority: -5) # priority lower than within
239
231
 
240
232
  # Like `Then I should see`, but with single instead of double quotes. In case
241
233
  # the expected string contains quotes as well.
242
- Then /^(?:|I )should see '([^']*)'$/ do |text|
234
+ Then /^(?:|I )should( not)? see '([^']*)'$/ do |negate, text|
235
+ expectation = negate ? :not_to : :to
236
+
243
237
  patiently do
244
- expect(page).to have_content(text)
238
+ expect(page).send(expectation, have_content(text))
245
239
  end
246
240
  end.overridable
247
241
 
248
242
  # Check that the raw HTML contains a string
249
- Then /^I should see "([^\"]*)" in the HTML$/ do |text|
250
- patiently do
251
- expect(page.body).to include(text)
252
- end
253
- end.overridable
243
+ Then /^I should( not)? see "([^\"]*)" in the HTML$/ do |negate, text|
244
+ expectation = negate ? :not_to : :to
254
245
 
255
- Then /^I should not see "([^\"]*)" in the HTML$/ do |text|
256
246
  patiently do
257
- expect(page.body).not_to include(text)
247
+ expect(page.body).send(expectation, include(text))
258
248
  end
259
249
  end.overridable
260
250
 
@@ -271,7 +261,7 @@ end.overridable
271
261
  # Then I should see the element ".panel"
272
262
  # Then I should not see an element ".sidebar"
273
263
  # Then I should not see the element ".sidebar"
274
- Then /^I should (not )?see (?:an|the) element "([^"]+)"$/ do |negate, selector|
264
+ Then /^I should( not)? see (?:an|the) element "([^"]+)"$/ do |negate, selector|
275
265
  expectation = negate ? :not_to : :to
276
266
  patiently do
277
267
  expect(page).send(expectation, have_css(selector))
@@ -286,7 +276,7 @@ end.overridable
286
276
  # Then I should see the element for the panel
287
277
  # Then I should not see an element for the sidebar
288
278
  # Then I should not see the element for the sidebar
289
- Then /^I should (not )?see (?:an|the) element for (.*?)$/ do |negate, locator|
279
+ Then /^I should( not)? see (?:an|the) element for (.*?)$/ do |negate, locator|
290
280
  expectation = negate ? :not_to : :to
291
281
  selector = _selector_for(locator)
292
282
  patiently do
@@ -325,7 +315,7 @@ Then /^I should( not)? see a link labeled "([^"]*)"$/ do |negate, label|
325
315
  end.overridable
326
316
 
327
317
  # Checks that an input field contains some value (allowing * as wildcard character)
328
- Then /^the "([^"]*)" field should (not )?contain "([^"]*)"$/ do |label, negate, expected_string|
318
+ Then /^the "([^"]*)" field should( not)? contain "([^"]*)"$/ do |label, negate, expected_string|
329
319
  patiently do
330
320
  field = find_with_disabled(:field, label)
331
321
  field_value = case field.tag_name
@@ -345,7 +335,7 @@ Then /^the "([^"]*)" field should (not )?contain "([^"]*)"$/ do |label, negate,
345
335
  end.overridable
346
336
 
347
337
  # Checks that a multiline textarea contains some value (allowing * as wildcard character)
348
- Then(/^the "(.*?)" field should (not )?contain:$/) do |label, negate, expected_string|
338
+ Then(/^the "(.*?)" field should( not)? contain:$/) do |label, negate, expected_string|
349
339
  patiently do
350
340
  field = find_with_disabled(:field, label)
351
341
  expect(field.value.chomp).send(negate ? :not_to : :to, contain_with_wildcards(expected_string))
@@ -370,17 +360,28 @@ end.overridable
370
360
  Then /^the "([^"]*)" field should have the error "([^"]*)"$/ do |field, error_message|
371
361
  patiently do
372
362
  element = find_with_disabled(:field, field)
373
- classes = element.find(:xpath, '..')[:class].split(' ')
363
+ field_error_finder = Spreewald::FieldErrorFinder.new(page, element)
364
+ expect(field_error_finder.error_present?).to eq true
374
365
 
375
- form_for_input = element.find(:xpath, 'ancestor::form[1]')
376
- using_formtastic = form_for_input && form_for_input.has_css?('.formtastic')
377
- error_class = using_formtastic ? 'error' : 'field_with_errors'
366
+ if Spreewald.field_error_class
367
+ unless Spreewald.error_message_xpath_selector
368
+ raise ArgumentError, 'No XPath was specified for the custom error message element.'
369
+ end
370
+ end
378
371
 
379
- expect(classes).to include(error_class)
372
+ error_message_element = case
373
+ when Spreewald.error_message_xpath_selector
374
+ element.find(:xpath, Spreewald.error_message_xpath_selector)
375
+ when field_error_finder.bootstrap3_error?
376
+ element.find(:xpath, 'parent::*/child::*[@class="help-block"]')
377
+ when field_error_finder.bootstrap45_error?
378
+ element.find(:xpath, 'parent::*/child::*[@class="invalid-feedback"]')
379
+ else
380
+ nil
381
+ end
380
382
 
381
- if using_formtastic
382
- error_paragraph = element.find(:xpath, '../*[@class="inline-errors"][1]')
383
- expect(error_paragraph).to have_content(error_message)
383
+ if error_message_element
384
+ expect(error_message_element).to have_content(error_message)
384
385
  else
385
386
  expect(page).to have_content("#{field.titlecase} #{error_message}")
386
387
  end
@@ -390,9 +391,10 @@ end.overridable
390
391
  Then /^the "([^\"]*)" field should( not)? have an error$/ do |label, negate|
391
392
  patiently do
392
393
  expectation = negate ? :not_to : :to
393
- field = find_with_disabled(:field, label)
394
- expect(field[:id]).to be_present # prevent bad CSS selector if field lacks id
395
- expect(page).send(expectation, have_css(".field_with_errors ##{field[:id]}"))
394
+ element = find_with_disabled(:field, label)
395
+ field_error_finder = Spreewald::FieldErrorFinder.new(page, element)
396
+
397
+ expect(field_error_finder.error_present?).public_send(expectation, (eq true))
396
398
  end
397
399
  end.overridable
398
400
 
@@ -648,18 +650,19 @@ end.overridable
648
650
 
649
651
  # Tests that an input, button, checkbox or radio button with the given label is disabled.
650
652
  Then /^the "([^\"]*)" (field|button|checkbox|radio button) should( not)? be disabled$/ do |label, kind, negate|
651
- element = if kind == 'button'
652
- find_with_disabled(:button, label)
653
- else
654
- find_with_disabled(:field, label)
655
- end
653
+ patiently do
654
+ element = if kind == 'button'
655
+ find_with_disabled(:button, label)
656
+ else
657
+ find_with_disabled(:field, label)
658
+ end
656
659
 
657
- if Spreewald::Comparison.compare_versions(Capybara::VERSION, :<, "2.1")
658
- expect(element[:disabled]).send(negate ? :to : :not_to, eq(nil))
659
- else
660
- expect(!!element.disabled?).to be !negate
660
+ if Spreewald::Comparison.compare_versions(Capybara::VERSION, :<, "2.1")
661
+ expect(element[:disabled]).send(negate ? :to : :not_to, eq(nil))
662
+ else
663
+ expect(!!element.disabled?).to be !negate
664
+ end
661
665
  end
662
-
663
666
  end.overridable
664
667
 
665
668
  # Tests that a field with the given label is visible.
data/lib/spreewald.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # coding: UTF-8
2
2
 
3
3
  require 'cucumber_priority'
4
+ require "spreewald_support/field_errors"
4
5
  require "spreewald_support/version"
5
6
  require "spreewald_support/github"
6
7
  require "spreewald_support/unsupported_email_header"
@@ -0,0 +1,56 @@
1
+ require 'spreewald_support/driver_info'
2
+
3
+ module Spreewald
4
+ def self.field_error_class
5
+ self.instance_variable_get('@field_error_class')
6
+ end
7
+
8
+ def self.field_error_class=(error_class)
9
+ self.instance_variable_set('@field_error_class', error_class)
10
+ end
11
+
12
+ def self.error_message_xpath_selector
13
+ self.instance_variable_get('@error_message_xpath_selector')
14
+ end
15
+
16
+ # The XPath to the HTML-element that renders your validation/error message.
17
+ # The current node to start from is the input-field that is validated.
18
+ def self.error_message_xpath_selector=(message_selector)
19
+ self.instance_variable_set('@error_message_xpath_selector', message_selector)
20
+ end
21
+
22
+ class FieldErrorFinder
23
+ include Spreewald::DriverInfo
24
+
25
+ def initialize(page, element)
26
+ @page = page
27
+ @element = element
28
+ end
29
+
30
+ def error_present?
31
+ custom_error? || bootstrap3_error? || bootstrap45_error? || rails_error?
32
+ end
33
+
34
+ def custom_error?
35
+ Spreewald.field_error_class && @element.has_xpath?("ancestor-or-self::*[class='#{Spreewald.field_error_class}']")
36
+ end
37
+
38
+ def bootstrap3_error?
39
+ @element.has_xpath?('ancestor::div[@class="form-group has-error"]')
40
+ end
41
+
42
+ def bootstrap45_error?
43
+ element_classes = @element[:class] &.split(' ') || []
44
+ invalid_elements = if javascript_capable?
45
+ @page.all(':invalid') # Collect all invalid elements as Bootstrap 4 and 5 support client validation
46
+ end
47
+
48
+ element_classes.include?('is-invalid') || (invalid_elements && invalid_elements.include?(@element))
49
+ end
50
+
51
+ def rails_error?
52
+ parent_element_classes = @element.find(:xpath, '..')[:class] &.split(' ') || []
53
+ parent_element_classes.include?('field_with_errors')
54
+ end
55
+ end
56
+ end
@@ -1,3 +1,3 @@
1
1
  module Spreewald
2
- VERSION = '4.1.1'
2
+ VERSION = '4.3.2'
3
3
  end
@@ -0,0 +1,63 @@
1
+ module Spreewald
2
+ module Steps
3
+ class FollowTheLink
4
+ class NoVisitableLinkFound < StandardError
5
+ def initialize(paths, index)
6
+ error_message = <<~MESSAGE
7
+ Could not follow the #{index} link in the email.
8
+ MESSAGE
9
+ if paths&.empty?
10
+ error_message << "Found no link paths in the email."
11
+ else
12
+ error_message << "Found these link paths in the email: #{paths.join(', ')}"
13
+ end
14
+ super(error_message)
15
+ end
16
+ end
17
+
18
+ URL_PATTERN = %r((?:https?://[^/]+)([^"'\s]+))
19
+
20
+ def initialize(mail, index_in_words)
21
+ @mail = mail
22
+ @index_in_words = index_in_words
23
+ end
24
+
25
+ def run
26
+ index = { nil => 0, 'first' => 0, 'second' => 1, 'third' => 2 }[@index_in_words]
27
+
28
+ paths = if @mail.html_part || body_text_html?
29
+ search_for_links_in_html
30
+ else
31
+ search_for_links_in_plaintext
32
+ end
33
+
34
+ if paths[index]
35
+ visit_path paths[index]
36
+ else
37
+ raise NoVisitableLinkFound.new(paths, @index_in_words) unless paths[index]
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def visit_path(path)
44
+ Capybara.visit(path)
45
+ end
46
+
47
+ def body_text_html?
48
+ @mail.body.to_s.include? "<html>"
49
+ end
50
+
51
+ def search_for_links_in_html
52
+ body = @mail.html_part ? @mail.html_part.body : @mail.body
53
+ dom = Nokogiri::HTML(body.to_s)
54
+ (dom / 'a[href]').map { |a| a['href'].match(URL_PATTERN) }.compact.map { |match| match[1] }
55
+ end
56
+
57
+ def search_for_links_in_plaintext
58
+ mail_body = MailFinder.email_text_body(@mail).to_s
59
+ mail_body.scan(URL_PATTERN).flatten(1)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ require 'spreewald_support/mail_finder'
2
+
3
+ module Spreewald
4
+ module Steps
5
+ class ShowMeTheMails
6
+ def initialize(mails, only_header = false)
7
+ @mails = mails
8
+ @only_header = only_header
9
+ end
10
+
11
+ def run
12
+ if @mails.empty?
13
+ puts "No emails found"
14
+ else
15
+ puts MailFinder.show_mails(@mails, @only_header)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,81 @@
1
+ require "steps/follow_the_link"
2
+
3
+ describe Spreewald::Steps::FollowTheLink do
4
+ it "raises helpful error message if no link is found" do
5
+ mail_without_links = Mail.new do
6
+ html_part do
7
+ body "<html><body>no link</body></html>"
8
+ end
9
+
10
+ text_part do
11
+ body "no link either"
12
+ end
13
+ end
14
+
15
+ step = ->() { Spreewald::Steps::FollowTheLink.new(mail_without_links, "first").run }
16
+ expect(step).to raise_error Spreewald::Steps::FollowTheLink::NoVisitableLinkFound
17
+ end
18
+
19
+ it "finds links in multipart html email" do
20
+ mail = Mail.new do
21
+ html_part do
22
+ 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>"
23
+ end
24
+
25
+ text_part do
26
+ body "no link here"
27
+ end
28
+ end
29
+
30
+ step = Spreewald::Steps::FollowTheLink.new(mail, "first")
31
+ expect(step).to receive(:visit_path).with("/abc")
32
+ step.run
33
+ end
34
+
35
+ it "finds the second link in a multipart html email" do
36
+ mail = Mail.new do
37
+ html_part do
38
+ 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>"
39
+ end
40
+
41
+ text_part do
42
+ body "no link here"
43
+ end
44
+ end
45
+
46
+ step = Spreewald::Steps::FollowTheLink.new(mail, "second")
47
+ expect(step).to receive(:visit_path).with("/def")
48
+ step.run
49
+ end
50
+
51
+ it "finds links in html email" do
52
+ mail = Mail.new do
53
+ text_part do
54
+ body "my link: https://www.example.com/abc"
55
+ end
56
+ end
57
+
58
+ step = Spreewald::Steps::FollowTheLink.new(mail, "first")
59
+ expect(step).to receive(:visit_path).with("/abc")
60
+ step.run
61
+ end
62
+
63
+ it "finds links in non multipart text emails" do
64
+ plaintext_email = Mail.new(body: 'a link: https://www.example.com/abc')
65
+ step = Spreewald::Steps::FollowTheLink.new(plaintext_email, "first")
66
+
67
+ expect(step).to receive(:visit_path).with("/abc")
68
+ step.run
69
+ end
70
+
71
+ it "finds links in non multipart html emails" do
72
+ html_mail = Mail.new(body: <<-HTML)
73
+ <html><body><a href="https://www.example.com/abc">this is a link!</a></body></html>
74
+ HTML
75
+ step = Spreewald::Steps::FollowTheLink.new(html_mail, "first")
76
+
77
+ expect(step).to receive(:visit_path).with("/abc")
78
+ step.run
79
+ end
80
+ end
81
+
@@ -0,0 +1,96 @@
1
+ require "steps/show_me_the_mails"
2
+
3
+ describe Spreewald::Steps::ShowMeTheMails do
4
+ context "without deliveries" do
5
+ it "logs 'no emails found'" do
6
+ step = Spreewald::Steps::ShowMeTheMails.new([])
7
+
8
+ expect { step.run }.to output("No emails found\n").to_stdout
9
+ end
10
+
11
+ it "logs 'no emails found' with only headers enabled" do
12
+ step = Spreewald::Steps::ShowMeTheMails.new([], true)
13
+
14
+ expect { step.run }.to output("No emails found\n").to_stdout
15
+ end
16
+ end
17
+
18
+ context "with deliveries" do
19
+ it "logs the email" do
20
+ mail = Mail.new do
21
+ html_part do
22
+ body "<html><body>html part</body></html>"
23
+ end
24
+ end
25
+
26
+ expected_output = <<~TXT
27
+ E-Mail #0
28
+ --------------------------------------------------------------------------------
29
+ From:
30
+ Subject:
31
+
32
+ html part
33
+ --------------------------------------------------------------------------------
34
+
35
+ TXT
36
+ step = Spreewald::Steps::ShowMeTheMails.new([mail])
37
+ expect { step.run }.to output(expected_output).to_stdout
38
+ end
39
+
40
+ it "logs only headers with only headers enabled" do
41
+ mail = Mail.new do
42
+ html_part do
43
+ body "<html><body>html part</body></html>"
44
+ end
45
+ end
46
+
47
+ expected_output = <<~TXT
48
+ E-Mail #0
49
+ --------------------------------------------------------------------------------
50
+ From:
51
+ Subject:
52
+ --------------------------------------------------------------------------------
53
+
54
+ TXT
55
+ step = Spreewald::Steps::ShowMeTheMails.new([mail], true)
56
+ expect { step.run }.to output(expected_output).to_stdout
57
+ end
58
+ end
59
+
60
+ context "with multiple deliveries" do
61
+ it "logs the emails" do
62
+ mail_one = Mail.new do
63
+ html_part do
64
+ body "<html><body>html part</body></html>"
65
+ end
66
+ end
67
+
68
+ mail_two = Mail.new do
69
+ html_part do
70
+ body "<html><body>html2 part</body></html>"
71
+ end
72
+ end
73
+
74
+ expected_output = <<~TXT
75
+ E-Mail #0
76
+ --------------------------------------------------------------------------------
77
+ From:
78
+ Subject:
79
+
80
+ html part
81
+ --------------------------------------------------------------------------------
82
+
83
+ E-Mail #1
84
+ --------------------------------------------------------------------------------
85
+ From:
86
+ Subject:
87
+
88
+ html2 part
89
+ --------------------------------------------------------------------------------
90
+
91
+ TXT
92
+ step = Spreewald::Steps::ShowMeTheMails.new([mail_one, mail_two])
93
+ expect { step.run }.to output(expected_output).to_stdout
94
+ end
95
+ end
96
+ end
@@ -33,6 +33,11 @@ class StepDefinition
33
33
  "#{kind} #{pretty_step}"
34
34
  end
35
35
 
36
+ def matches_search?(search)
37
+ regexp = Regexp.new(search)
38
+ step =~ regexp || matches_without_optional_negation?(regexp)
39
+ end
40
+
36
41
  private
37
42
 
38
43
  def pretty_step
@@ -45,4 +50,10 @@ class StepDefinition
45
50
  end
46
51
  end
47
52
 
53
+ def matches_without_optional_negation?(regexp)
54
+ without_negation = step.gsub('( not)?', '').gsub('(not )?', '')
55
+ with_negation = step.gsub('( not)?', ' not').gsub('(not )?', 'not ')
56
+ with_negation =~ regexp || without_negation =~ regexp
57
+ end
58
+
48
59
  end
@@ -17,7 +17,7 @@ class StepManager
17
17
  def steps(search = nil)
18
18
  step_files.collect(&:real_steps).flatten.
19
19
  sort_by { |step| [STEP_KINDS.index(step.kind), step.to_s.downcase] }.
20
- select { |definition| search.nil? or definition.step =~ Regexp.new(search) }
20
+ select { |definition| search.nil? || definition.matches_search?(search) }
21
21
  end
22
22
 
23
23
  private
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- spreewald (4.1.1)
4
+ spreewald (4.2.3)
5
5
  cucumber
6
6
  cucumber_priority (>= 0.3.0)
7
7
  rspec (>= 2.13.0)
@@ -15,7 +15,13 @@ class FormsController < ApplicationController
15
15
  def select_fields
16
16
  end
17
17
 
18
- def invalid_form
18
+ def invalid_rails_form
19
19
  end
20
20
 
21
- end
21
+ def invalid_bootstrap3_form
22
+ end
23
+
24
+ def invalid_bootstrap4_form
25
+ end
26
+
27
+ end
@@ -33,6 +33,9 @@ class StaticPagesController < ApplicationController
33
33
  def see_element
34
34
  end
35
35
 
36
+ def should_see
37
+ end
38
+
36
39
  def tab_1
37
40
  end
38
41
 
@@ -0,0 +1,16 @@
1
+ = form_tag do
2
+ .form-group.has-error
3
+ = label_tag 'text_control', 'A'
4
+ = text_field_tag 'text_control', 'Text control value'
5
+ .help-block 'A is invalid'
6
+ .form-group.has-error
7
+ = label_tag 'textarea_control_1', 'B'
8
+ = text_area_tag 'textarea_control_1', "Textarea control line 1\nTextarea control line 2\n"
9
+ .help-block 'B is invalid'
10
+ .form-group.has-error
11
+ = label_tag 'disabled_control', 'Disabled'
12
+ = text_field_tag 'disabled_control', "Disabled control value", disabled: true
13
+ .help-block 'Disabled is invalid'
14
+ .form-group
15
+ = label_tag 'textarea_control_2', 'C'
16
+ = text_area_tag 'textarea_control_2', "Textarea control line 1\nTextarea control line 2\n"
@@ -0,0 +1,18 @@
1
+ = form_tag do
2
+ .form-group
3
+ = label_tag 'text_control', 'A'
4
+ - # Client validation
5
+ = text_field_tag 'text_control', '', class: 'form-control', required: true
6
+ .invalid-feedback 'A is invalid'
7
+ .form-group
8
+ = label_tag 'textarea_control_1', 'B'
9
+ = text_area_tag 'textarea_control_1', '', class: 'form-control', required: true
10
+ .invalid-feedback 'B is invalid'
11
+ .form-group
12
+ = label_tag 'disabled_control', 'Disabled'
13
+ - # Server validation
14
+ = text_field_tag 'disabled_control', "Disabled control value", class: 'form-control is-invalid', disabled: true
15
+ .invalid-feedback 'Disabled is invalid'
16
+ .form-group
17
+ = label_tag 'textarea_control_2', 'C'
18
+ = text_area_tag 'textarea_control_2', "Textarea control line 1\nTextarea control line 2\n"
@@ -0,0 +1,7 @@
1
+ %p Normal text
2
+
3
+ %p Some text matching a regular expression
4
+
5
+ %p Some text with "quotes"
6
+
7
+ %p Some text in the <b>HTML</b>
@@ -23,7 +23,9 @@ Rails.application.routes.draw do
23
23
  get '/forms/form1', to: 'forms#form1'
24
24
  get '/forms/form2', to: 'forms#form2'
25
25
  get '/forms/select_fields', to: 'forms#select_fields'
26
- get '/forms/invalid_form', to: 'forms#invalid_form'
26
+ get '/forms/invalid_rails_form', to: 'forms#invalid_rails_form'
27
+ get '/forms/invalid_bootstrap3_form', to: 'forms#invalid_bootstrap3_form'
28
+ get '/forms/invalid_bootstrap4_form', to: 'forms#invalid_bootstrap4_form'
27
29
 
28
30
  get '/iframes/iframe_1_content', to: 'iframes#iframe_1_content'
29
31
  get '/iframes/iframe_2_content', to: 'iframes#iframe_2_content'
@@ -41,6 +43,7 @@ Rails.application.routes.draw do
41
43
  get '/static_pages/session_1', to: 'static_pages#session_1'
42
44
  get '/static_pages/session_2', to: 'static_pages#session_2'
43
45
  get '/static_pages/session_3', to: 'static_pages#session_3'
46
+ get '/static_pages/should_see', to: 'static_pages#should_see'
44
47
  get '/static_pages/tab_1', to: 'static_pages#tab_1'
45
48
  get '/static_pages/tab_2', to: 'static_pages#tab_2'
46
49
  get '/static_pages/tab_3', to: 'static_pages#tab_3'