spreewald 4.2.3 → 4.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d3a85d0ee7a8a0ebd403ef168a1788a21ce14dd3b3966aa431b1d0481f25e05
4
- data.tar.gz: f68eb3cecf0e1792fada9ec58a664f6d8652fb700ebd07cee9a9789c260690a4
3
+ metadata.gz: e10c60e2e7cc0636a4cfa38bcd509de5f6e1d1077e796b0e80bfb59eae84f9a3
4
+ data.tar.gz: 9543765c53174dfab02096267b5ff9c5498a555d730b3a9a0d95b6b10a78b40a
5
5
  SHA512:
6
- metadata.gz: 8276a0f55cfbdab771e028d05117291ce3cff8ad082e66a8a6828805392ae7e36c26240033fa6f9e37e1de25f2c6c9ff6f5a3a6c7f8b4b16210a1287819a5cf8
7
- data.tar.gz: 35d84f7231336eb6edf2e44c91d128b6ebb38a2f7c0119906c0df9f29f94f41d5f2b5ba51532156fd465533adfa8fbc061ce824d9f90b433a0c20ee50fc76d01
6
+ metadata.gz: b1189c2293c12c110640dcae56c73a2ccebf395d0fcf52d39ed50180e045da393fef78485602b303fd6882a268424ed5d16fd27ce1936551d1efb352f6e8869d
7
+ data.tar.gz: '08050f1748090f777465abf05636b0479375d5043f0d08865b07011e20fcddadb3b60c67574dd7c05895d54539a539bc213dfbac1decac949b7b8a83f439d8e5'
data/CHANGELOG.md CHANGED
@@ -3,6 +3,13 @@ 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
+ ## 4.3.2
7
+ - Added built-in support for Rails and Bootstrap (3-5) error classes to the steps
8
+ - `The ... field should have the error ...`
9
+ - `The ... field should have an error`
10
+ - Added the possibility to specify custom error classes and message selectors for these steps
11
+ using `Spreewald.field_error_class` and `Spreewald.error_message_xpath_selector` in your configuration.
12
+
6
13
  ## 4.2.2
7
14
  - Fixes the "Show me the email" step (#171)
8
15
  - Fixes the "I follow the link in the email" step. (#172, #173)
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
- gemika (0.5.0)
5
- rake (12.3.2)
4
+ gemika (0.6.1)
5
+ rake (13.0.3)
6
6
 
7
7
  PLATFORMS
8
8
  ruby
@@ -12,4 +12,4 @@ DEPENDENCIES
12
12
  rake
13
13
 
14
14
  BUNDLED WITH
15
- 2.2.3
15
+ 2.2.17
data/Gemfile.ruby266.lock CHANGED
@@ -1,60 +1,77 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
- aruba (1.0.0)
5
- childprocess (~> 3.0)
6
- contracts (~> 0.16.0)
7
- cucumber (>= 2.4, < 4.0)
8
- ffi (~> 1.9)
4
+ aruba (2.0.0)
5
+ bundler (>= 1.17, < 3.0)
6
+ childprocess (>= 2.0, < 5.0)
7
+ contracts (>= 0.16.0, < 0.18.0)
8
+ cucumber (>= 4.0, < 8.0)
9
9
  rspec-expectations (~> 3.4)
10
10
  thor (~> 1.0)
11
- backports (3.17.0)
12
11
  builder (3.2.4)
13
- childprocess (3.0.0)
12
+ childprocess (4.0.0)
14
13
  contracts (0.16.0)
15
- cucumber (3.1.2)
16
- builder (>= 2.1.2)
17
- cucumber-core (~> 3.2.0)
18
- cucumber-expressions (~> 6.0.1)
19
- cucumber-wire (~> 0.0.1)
20
- diff-lcs (~> 1.3)
21
- gherkin (~> 5.1.0)
22
- multi_json (>= 1.7.5, < 2.0)
23
- multi_test (>= 0.1.2)
24
- cucumber-core (3.2.1)
25
- backports (>= 3.8.0)
26
- cucumber-tag_expressions (~> 1.1.0)
27
- gherkin (~> 5.0)
28
- cucumber-expressions (6.0.1)
29
- cucumber-tag_expressions (1.1.1)
30
- cucumber-wire (0.0.1)
31
- diff-lcs (1.3)
32
- ffi (1.12.2)
33
- gemika (0.5.0)
34
- gherkin (5.1.0)
14
+ cucumber (7.1.0)
15
+ builder (~> 3.2, >= 3.2.4)
16
+ cucumber-core (~> 10.1, >= 10.1.0)
17
+ cucumber-create-meta (~> 6.0, >= 6.0.1)
18
+ cucumber-cucumber-expressions (~> 14.0, >= 14.0.0)
19
+ cucumber-gherkin (~> 22.0, >= 22.0.0)
20
+ cucumber-html-formatter (~> 17.0, >= 17.0.0)
21
+ cucumber-messages (~> 17.1, >= 17.1.1)
22
+ cucumber-wire (~> 6.2, >= 6.2.0)
23
+ diff-lcs (~> 1.4, >= 1.4.4)
24
+ mime-types (~> 3.3, >= 3.3.1)
25
+ multi_test (~> 0.1, >= 0.1.2)
26
+ sys-uname (~> 1.2, >= 1.2.2)
27
+ cucumber-core (10.1.0)
28
+ cucumber-gherkin (~> 22.0, >= 22.0.0)
29
+ cucumber-messages (~> 17.1, >= 17.1.1)
30
+ cucumber-tag-expressions (~> 4.0, >= 4.0.2)
31
+ cucumber-create-meta (6.0.4)
32
+ cucumber-messages (~> 17.1, >= 17.1.1)
33
+ sys-uname (~> 1.2, >= 1.2.2)
34
+ cucumber-cucumber-expressions (14.0.0)
35
+ cucumber-gherkin (22.0.0)
36
+ cucumber-messages (~> 17.1, >= 17.1.1)
37
+ cucumber-html-formatter (17.0.0)
38
+ cucumber-messages (~> 17.1, >= 17.1.0)
39
+ cucumber-messages (17.1.1)
40
+ cucumber-tag-expressions (4.1.0)
41
+ cucumber-wire (6.2.0)
42
+ cucumber-core (~> 10.1, >= 10.1.0)
43
+ cucumber-cucumber-expressions (~> 14.0, >= 14.0.0)
44
+ cucumber-messages (~> 17.1, >= 17.1.1)
45
+ diff-lcs (1.4.4)
46
+ ffi (1.15.4)
47
+ gemika (0.6.1)
35
48
  mail (2.7.1)
36
49
  mini_mime (>= 0.1.1)
37
- mini_mime (1.0.2)
38
- multi_json (1.14.1)
50
+ mime-types (3.4.1)
51
+ mime-types-data (~> 3.2015)
52
+ mime-types-data (3.2021.1115)
53
+ mini_mime (1.1.2)
39
54
  multi_test (0.1.2)
40
55
  nokogiri (1.11.1-x86_64-linux)
41
56
  racc (~> 1.4)
42
57
  racc (1.5.2)
43
58
  rake (13.0.3)
44
- rspec (3.9.0)
45
- rspec-core (~> 3.9.0)
46
- rspec-expectations (~> 3.9.0)
47
- rspec-mocks (~> 3.9.0)
48
- rspec-core (3.9.1)
49
- rspec-support (~> 3.9.1)
50
- rspec-expectations (3.9.1)
59
+ rspec (3.10.0)
60
+ rspec-core (~> 3.10.0)
61
+ rspec-expectations (~> 3.10.0)
62
+ rspec-mocks (~> 3.10.0)
63
+ rspec-core (3.10.1)
64
+ rspec-support (~> 3.10.0)
65
+ rspec-expectations (3.10.1)
51
66
  diff-lcs (>= 1.2.0, < 2.0)
52
- rspec-support (~> 3.9.0)
53
- rspec-mocks (3.9.1)
67
+ rspec-support (~> 3.10.0)
68
+ rspec-mocks (3.10.2)
54
69
  diff-lcs (>= 1.2.0, < 2.0)
55
- rspec-support (~> 3.9.0)
56
- rspec-support (3.9.2)
57
- thor (1.0.1)
70
+ rspec-support (~> 3.10.0)
71
+ rspec-support (3.10.2)
72
+ sys-uname (1.2.2)
73
+ ffi (~> 1.1)
74
+ thor (1.1.0)
58
75
 
59
76
  PLATFORMS
60
77
  ruby
@@ -72,4 +89,4 @@ RUBY VERSION
72
89
  ruby 2.6.6p146
73
90
 
74
91
  BUNDLED WITH
75
- 2.2.14
92
+ 2.2.17
data/Gemfile.ruby300.lock CHANGED
@@ -1,71 +1,59 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
- activesupport (6.1.3.1)
5
- concurrent-ruby (~> 1.0, >= 1.0.2)
6
- i18n (>= 1.6, < 2)
7
- minitest (>= 5.1)
8
- tzinfo (~> 2.0)
9
- zeitwerk (~> 2.3)
10
- aruba (1.0.4)
4
+ aruba (2.0.0)
5
+ bundler (>= 1.17, < 3.0)
11
6
  childprocess (>= 2.0, < 5.0)
12
- contracts (~> 0.16.0)
13
- cucumber (>= 2.4, < 6.0)
7
+ contracts (>= 0.16.0, < 0.18.0)
8
+ cucumber (>= 4.0, < 8.0)
14
9
  rspec-expectations (~> 3.4)
15
10
  thor (~> 1.0)
16
11
  builder (3.2.4)
17
12
  childprocess (4.0.0)
18
- concurrent-ruby (1.1.8)
19
13
  contracts (0.16.0)
20
- cucumber (5.3.0)
14
+ cucumber (7.1.0)
21
15
  builder (~> 3.2, >= 3.2.4)
22
- cucumber-core (~> 8.0, >= 8.0.1)
23
- cucumber-create-meta (~> 2.0, >= 2.0.2)
24
- cucumber-cucumber-expressions (~> 10.3, >= 10.3.0)
25
- cucumber-gherkin (~> 15.0, >= 15.0.2)
26
- cucumber-html-formatter (~> 9.0, >= 9.0.0)
27
- cucumber-messages (~> 13.1, >= 13.1.0)
28
- cucumber-wire (~> 4.0, >= 4.0.1)
16
+ cucumber-core (~> 10.1, >= 10.1.0)
17
+ cucumber-create-meta (~> 6.0, >= 6.0.1)
18
+ cucumber-cucumber-expressions (~> 14.0, >= 14.0.0)
19
+ cucumber-gherkin (~> 22.0, >= 22.0.0)
20
+ cucumber-html-formatter (~> 17.0, >= 17.0.0)
21
+ cucumber-messages (~> 17.1, >= 17.1.1)
22
+ cucumber-wire (~> 6.2, >= 6.2.0)
29
23
  diff-lcs (~> 1.4, >= 1.4.4)
24
+ mime-types (~> 3.3, >= 3.3.1)
30
25
  multi_test (~> 0.1, >= 0.1.2)
31
- sys-uname (~> 1.2, >= 1.2.1)
32
- cucumber-core (8.0.1)
33
- cucumber-gherkin (~> 15.0, >= 15.0.2)
34
- cucumber-messages (~> 13.0, >= 13.0.1)
35
- cucumber-tag-expressions (~> 2.0, >= 2.0.4)
36
- cucumber-create-meta (2.0.4)
37
- cucumber-messages (~> 13.1, >= 13.1.0)
38
- sys-uname (~> 1.2, >= 1.2.1)
39
- cucumber-cucumber-expressions (10.3.0)
40
- cucumber-gherkin (15.0.2)
41
- cucumber-messages (~> 13.0, >= 13.0.1)
42
- cucumber-html-formatter (9.0.0)
43
- cucumber-messages (~> 13.0, >= 13.0.1)
44
- cucumber-messages (13.2.1)
45
- protobuf-cucumber (~> 3.10, >= 3.10.8)
46
- cucumber-tag-expressions (2.0.4)
47
- cucumber-wire (4.0.1)
48
- cucumber-core (~> 8.0, >= 8.0.1)
49
- cucumber-cucumber-expressions (~> 10.3, >= 10.3.0)
50
- cucumber-messages (~> 13.0, >= 13.0.1)
26
+ sys-uname (~> 1.2, >= 1.2.2)
27
+ cucumber-core (10.1.0)
28
+ cucumber-gherkin (~> 22.0, >= 22.0.0)
29
+ cucumber-messages (~> 17.1, >= 17.1.1)
30
+ cucumber-tag-expressions (~> 4.0, >= 4.0.2)
31
+ cucumber-create-meta (6.0.4)
32
+ cucumber-messages (~> 17.1, >= 17.1.1)
33
+ sys-uname (~> 1.2, >= 1.2.2)
34
+ cucumber-cucumber-expressions (14.0.0)
35
+ cucumber-gherkin (22.0.0)
36
+ cucumber-messages (~> 17.1, >= 17.1.1)
37
+ cucumber-html-formatter (17.0.0)
38
+ cucumber-messages (~> 17.1, >= 17.1.0)
39
+ cucumber-messages (17.1.1)
40
+ cucumber-tag-expressions (4.1.0)
41
+ cucumber-wire (6.2.0)
42
+ cucumber-core (~> 10.1, >= 10.1.0)
43
+ cucumber-cucumber-expressions (~> 14.0, >= 14.0.0)
44
+ cucumber-messages (~> 17.1, >= 17.1.1)
51
45
  diff-lcs (1.4.4)
52
- ffi (1.15.0)
53
- gemika (0.5.0)
54
- i18n (1.8.10)
55
- concurrent-ruby (~> 1.0)
46
+ ffi (1.15.4)
47
+ gemika (0.6.1)
56
48
  mail (2.7.1)
57
49
  mini_mime (>= 0.1.1)
58
- middleware (0.1.0)
50
+ mime-types (3.4.1)
51
+ mime-types-data (~> 3.2015)
52
+ mime-types-data (3.2021.1115)
59
53
  mini_mime (1.0.3)
60
- minitest (5.14.4)
61
54
  multi_test (0.1.2)
62
55
  nokogiri (1.11.2-x86_64-linux)
63
56
  racc (~> 1.4)
64
- protobuf-cucumber (3.10.8)
65
- activesupport (>= 3.2)
66
- middleware
67
- thor
68
- thread_safe
69
57
  racc (1.5.2)
70
58
  rake (13.0.3)
71
59
  rspec (3.10.0)
@@ -84,10 +72,6 @@ GEM
84
72
  sys-uname (1.2.2)
85
73
  ffi (~> 1.1)
86
74
  thor (1.1.0)
87
- thread_safe (0.3.6)
88
- tzinfo (2.0.4)
89
- concurrent-ruby (~> 1.0)
90
- zeitwerk (2.4.2)
91
75
 
92
76
  PLATFORMS
93
77
  x86_64-linux
data/README.md CHANGED
@@ -298,7 +298,7 @@ the step definitions.
298
298
  * **When I switch back to the whole page**
299
299
 
300
300
  This step can be used to switch back to the whole page if you switched
301
- to operating inside an iframe before (step `I switch to the ... iframe`)
301
+ to operating inside an iframe before (step `I switch to the ... iframe`).
302
302
 
303
303
  Please note: This step is only available for Capybara >= 3.
304
304
 
@@ -460,26 +460,20 @@ deprecation notice. Decide for yourself whether you want to use them:
460
460
  Attach a file to a file upload form field
461
461
 
462
462
 
463
- * **Then I should see "..."**
463
+ * **Then I should( not)? see "..."**
464
464
 
465
465
  Checks that some text appears on the page
466
466
 
467
467
  Note that this does not detect if the text might be hidden via CSS
468
468
 
469
469
 
470
- * **Then I should see /.../**
470
+ * **Then I should( not)? see /.../**
471
471
 
472
472
  Checks that a regexp appears on the page
473
473
 
474
474
  Note that this does not detect if the text might be hidden via CSS
475
475
 
476
476
 
477
- * **Then I should not see "..."**
478
-
479
-
480
- * **Then I should not see /.../**
481
-
482
-
483
477
  * **Then I should( not)? see a field "..."**
484
478
 
485
479
  Checks for the existance of an input field (given its id or label)
@@ -494,26 +488,23 @@ deprecation notice. Decide for yourself whether you want to use them:
494
488
  See [here](https://makandracards.com/makandra/1225-test-that-a-number-or-money-amount-is-shown-with-cucumber) for details
495
489
 
496
490
 
497
- * **Then I should see '...'**
491
+ * **Then I should( not)? see '...'**
498
492
 
499
493
  Like `Then I should see`, but with single instead of double quotes. In case
500
494
  the expected string contains quotes as well.
501
495
 
502
496
 
503
- * **Then I should see "..." in the HTML**
497
+ * **Then I should( not)? see "..." in the HTML**
504
498
 
505
499
  Check that the raw HTML contains a string
506
500
 
507
501
 
508
- * **Then I should not see "..." in the HTML**
509
-
510
-
511
502
  * **Then I should see an error**
512
503
 
513
504
  Checks that status code is 400..599
514
505
 
515
506
 
516
- * **Then I should (not )?see (an|the) element "..."**
507
+ * **Then I should( not)? see (an|the) element "..."**
517
508
 
518
509
  Check that an element with the given selector is present on the page.
519
510
 
@@ -525,7 +516,7 @@ deprecation notice. Decide for yourself whether you want to use them:
525
516
  Then I should not see the element ".sidebar"
526
517
 
527
518
 
528
- * **Then I should (not )?see (an|the) element for ...**
519
+ * **Then I should( not)? see (an|the) element for ...**
529
520
 
530
521
  Check that an element with the given [selector alias](https://github.com/makandra/spreewald/blob/master/examples/selectors.rb) is present on the page.
531
522
 
@@ -555,12 +546,12 @@ deprecation notice. Decide for yourself whether you want to use them:
555
546
  Checks that the page contains a link with a given text or title attribute.
556
547
 
557
548
 
558
- * **Then the "..." field should (not )?contain "..."**
549
+ * **Then the "..." field should( not)? contain "..."**
559
550
 
560
551
  Checks that an input field contains some value (allowing * as wildcard character)
561
552
 
562
553
 
563
- * **Then the "..." field should (not )?contain:**
554
+ * **Then the "..." field should( not)? contain:**
564
555
 
565
556
  Checks that a multiline textarea contains some value (allowing * as wildcard character)
566
557
 
data/Rakefile CHANGED
@@ -17,14 +17,16 @@ namespace :matrix do
17
17
 
18
18
  if gemfile.nil? || ruby.nil?
19
19
  warn 'Please state the Gemfile and Ruby version to be used for the Testrun!'
20
+ exit 1
20
21
  else
21
- run_tests(gemfile, ruby)
22
+ success = run_tests(gemfile, ruby)
23
+ exit success ? 0 : 1
22
24
  end
23
25
  end
24
26
 
25
27
 
26
28
  desc "Run all tests which are available for current Ruby (#{RUBY_VERSION})"
27
- task :tests, [:gemfile, :ruby] do |_t, args|
29
+ task :tests do
28
30
  Gemika::Matrix.from_ci_config.each do |row|
29
31
  run_tests(row.gemfile, row.ruby)
30
32
  end
data/examples/paths.rb CHANGED
@@ -51,6 +51,13 @@ module NavigationHelpers
51
51
 
52
52
  private
53
53
 
54
+ def path_to_show_or_edit(action_prose, model_prose, identifier)
55
+ model = model_prose_to_class(model_prose)
56
+ route = "#{action_prose == 'form' ? 'edit_' : ''}#{model_prose_to_route_segment(model_prose)}_path"
57
+ # For find_by_anything see https://makandracards.com/makandra/6361-find-an-activerecord-by-any-column-useful-for-cucumber-steps
58
+ send(route, model.find_by_anything!(identifier))
59
+ end
60
+
54
61
  def model_prose_to_class(model_prose)
55
62
  model_prose.gsub(' ', '_').classify.constantize
56
63
  end
@@ -11,11 +11,15 @@ Feature: The `spreewald` binary
11
11
  Then the output should contain:
12
12
  """
13
13
  # All Spreewald steps containing 'should not see'
14
- Then I should not see "..."
15
- Then I should not see "..." in the HTML
16
- Then I should not see /.../
17
- """
18
- But the output should not contain "Then I should see"
14
+ Then I should( not)? see "..."
15
+ Then I should( not)? see "..." in the HTML
16
+ Then I should( not)? see "..." inside any "..."
17
+ Then I should( not)? see '...'
18
+ Then I should( not)? see (an|the) element "..."
19
+ Then I should( not)? see (an|the) element for ...
20
+ Then I should( not)? see /.../
21
+ """
22
+ But the output should not contain "Then show me the page"
19
23
  And the output should not contain "mail"
20
24
 
21
25
 
@@ -43,15 +47,15 @@ Feature: The `spreewald` binary
43
47
  """
44
48
  Then(/it strips parentheses/) do
45
49
  Then /^(?:|I )should see \/([^\/]*)\/$/ do
46
- Then(/^the "(.*?)" field should (not )?contain:$/) do
50
+ Then(/^the "(.*?)" field should( not)? contain:$/) do
47
51
  """
48
52
 
49
53
  When I run `spreewald`
50
54
  Then the output should contain "Then it strips parentheses"
51
- And the output should contain "Then I should see /.../"
55
+ And the output should contain "Then I should( not)? see /.../"
52
56
  And the output should contain:
53
57
  """
54
- Then the "..." field should (not )?contain:
58
+ Then the "..." field should( not)? contain:
55
59
  """
56
60
 
57
61
 
@@ -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.2.3'
2
+ VERSION = '4.3.2'
3
3
  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
@@ -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'
@@ -1,6 +1,6 @@
1
1
  Feature: Web steps
2
2
 
3
- Scenario: /^the "([^"]*)" field should (not )?contain "([^"]*)"$/
3
+ Scenario: /^the "([^"]*)" field should( not)? contain "([^"]*)"$/
4
4
  When I go to "/forms/form1"
5
5
  Then the "Text control" field should contain "Text control value"
6
6
  Then the "Text control" field should not contain "false text"
@@ -11,7 +11,7 @@ Feature: Web steps
11
11
  Then the "Empty control" field should contain ""
12
12
 
13
13
 
14
- Scenario: /^the "([^"]*)" field should (not )?contain:/
14
+ Scenario: /^the "([^"]*)" field should( not)? contain:/
15
15
  When I go to "/forms/form2"
16
16
  Then the "Text control" field should contain:
17
17
  """
@@ -31,16 +31,28 @@ Feature: Web steps
31
31
  """
32
32
  """
33
33
 
34
-
34
+ @javascript
35
35
  Scenario: /^the "([^\"]*)" field should( not)? have an error$/
36
- When I go to "/forms/invalid_form"
36
+ When I go to "/forms/invalid_rails_form"
37
37
  Then the "A" field should have an error
38
38
  Then the "B" field should have an error
39
39
  Then the "Disabled" field should have an error
40
40
  Then the "C" field should not have an error
41
41
 
42
+
43
+ @javascript
42
44
  Scenario: /^the "([^"]*)" field should have the error "([^"]*)"$/
43
- When I go to "/forms/invalid_form"
45
+ When I go to "/forms/invalid_rails_form"
46
+ Then the "A" field should have the error "is invalid"
47
+ Then the "B" field should have the error "is invalid"
48
+ Then the "Disabled" field should have the error "is invalid"
49
+
50
+ When I go to "/forms/invalid_bootstrap3_form"
51
+ Then the "A" field should have the error "is invalid"
52
+ Then the "B" field should have the error "is invalid"
53
+ Then the "Disabled" field should have the error "is invalid"
54
+
55
+ When I go to "/forms/invalid_bootstrap4_form"
44
56
  Then the "A" field should have the error "is invalid"
45
57
  Then the "B" field should have the error "is invalid"
46
58
  Then the "Disabled" field should have the error "is invalid"
@@ -200,7 +212,7 @@ Feature: Web steps
200
212
  And "div with style: display: none" should be hidden within ".container"
201
213
 
202
214
 
203
- Scenario: /^I should (not )?see (?:an|the) element "([^"]+)"$/
215
+ Scenario: /^I should( not)? see (?:an|the) element "([^"]+)"$/
204
216
  When I go to "/static_pages/see_element"
205
217
  Then I should see an element ".panel"
206
218
  And I should see the element ".panel"
@@ -210,7 +222,7 @@ Feature: Web steps
210
222
  But I should not see the element ".timeline"
211
223
 
212
224
 
213
- Scenario: /^I should (not )?see (?:an|the) element for (.*?)$/
225
+ Scenario: /^I should( not)? see (?:an|the) element for (.*?)$/
214
226
  When I go to "/static_pages/see_element"
215
227
  Then I should see an element for a panel
216
228
  And I should see the element for a panel
@@ -220,7 +232,26 @@ Feature: Web steps
220
232
  And I should not see the element for the timeline
221
233
 
222
234
 
223
- Scenario: /^((?:|I )should see "([^"]*)" within (.*[^:])$/
235
+ Scenario: /^((?:|I )should( not)? see "([^"]*)"$/
236
+ When I go to "/static_pages/should_see"
237
+ Then I should see "Normal text"
238
+ But I should not see "Some special text"
239
+
240
+
241
+ Scenario: /^((?:|I )should( not)? see '([^']*)'$/
242
+ When I go to "/static_pages/should_see"
243
+ Then I should see 'Some text with "quotes"'
244
+ But I should not see 'Some special text with "quotes"'
245
+
246
+
247
+ Scenario: /^I should( not)? see "([^\"]*)" in the HTML$/
248
+ When I go to "/static_pages/should_see"
249
+ Then I should see "Some text in the <b>HTML</b>" in the HTML
250
+ And I should see "Some text in the HTML"
251
+ But I should not see "Some text in the <strong>HTML</strong>" in the HTML
252
+
253
+
254
+ Scenario: /^((?:|I )should( not)? see "([^"]*)" within (.*[^:])$/
224
255
  When I go to "/static_pages/within"
225
256
  Then I should see "Role" within ".table"
226
257
  And I should see "Permissions" within a table
@@ -232,7 +263,8 @@ Feature: Web steps
232
263
  And I should not see "Outside Table" within a table
233
264
  But I should see "Outside Table"
234
265
 
235
- Scenario: /^(?:|I )should see \/([^\/]*)\/$/
266
+
267
+ Scenario: /^(?:|I )should( not)? see \/([^\/]*)\/$/
236
268
  When I go to "/static_pages/within"
237
269
  Then I should see /Shared Text/
238
270
  And I should see /Unique Text/
@@ -241,13 +273,8 @@ Feature: Web steps
241
273
  But I should not see /Nonsense/
242
274
  And I should not see /http://other-domain.com/
243
275
 
244
- # making sure it works with a within scope correctly when the same element is available outside
245
- Then I should not see /Outside Table/ within ".table"
246
- And I should not see /Outside Table/ within a table
247
- But I should see /Outside Table/
248
-
249
276
 
250
- Scenario: /^(?:|I )should see \/([^\/]*)\/ within (.*[^:])$/
277
+ Scenario: /^(?:|I )should( not)? see \/([^\/]*)\/ within (.*[^:])$/
251
278
  When I go to "/static_pages/within"
252
279
  Then I should see /Shared Text/ within ".scoped-element"
253
280
  And I should see /Shared Text/ within ".unrelated-element"
@@ -257,6 +284,11 @@ Feature: Web steps
257
284
  But I should not see /Unique Text/ within ".unrelated-element"
258
285
  And I should not see /http://other-domain.com/ within ".unrelated-element"
259
286
 
287
+ # making sure it works with a within scope correctly when the same element is available outside
288
+ Then I should not see /Outside Table/ within ".table"
289
+ And I should not see /Outside Table/ within a table
290
+ But I should see /Outside Table/
291
+
260
292
 
261
293
  Scenario: /^(.*) within (.*[^:])$/ with a Capybara::Node::Element
262
294
  When I go to "/static_pages/within"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spreewald
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.3
4
+ version: 4.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Kraze
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-19 00:00:00.000000000 Z
11
+ date: 2021-11-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cucumber
@@ -165,6 +165,7 @@ files:
165
165
  - lib/spreewald_support/compatibility.rb
166
166
  - lib/spreewald_support/custom_matchers.rb
167
167
  - lib/spreewald_support/driver_info.rb
168
+ - lib/spreewald_support/field_errors.rb
168
169
  - lib/spreewald_support/github.rb
169
170
  - lib/spreewald_support/mail_finder.rb
170
171
  - lib/spreewald_support/mail_to_plaintext_converter.rb
@@ -262,7 +263,9 @@ files:
262
263
  - tests/shared/app/views/forms/disabled_elements.html.haml
263
264
  - tests/shared/app/views/forms/form1.html.haml
264
265
  - tests/shared/app/views/forms/form2.html.haml
265
- - tests/shared/app/views/forms/invalid_form.html.haml
266
+ - tests/shared/app/views/forms/invalid_bootstrap3_form.html.haml
267
+ - tests/shared/app/views/forms/invalid_bootstrap4_form.html.haml
268
+ - tests/shared/app/views/forms/invalid_rails_form.html.haml
266
269
  - tests/shared/app/views/forms/select_fields.html.haml
267
270
  - tests/shared/app/views/iframes/iframe_1_content.haml
268
271
  - tests/shared/app/views/iframes/iframe_2_content.haml
@@ -293,6 +296,7 @@ files:
293
296
  - tests/shared/app/views/static_pages/session_1.haml
294
297
  - tests/shared/app/views/static_pages/session_2.haml
295
298
  - tests/shared/app/views/static_pages/session_3.haml
299
+ - tests/shared/app/views/static_pages/should_see.haml
296
300
  - tests/shared/app/views/static_pages/tab_1.haml
297
301
  - tests/shared/app/views/static_pages/tab_2.haml
298
302
  - tests/shared/app/views/static_pages/tab_3.haml
@@ -422,7 +426,9 @@ test_files:
422
426
  - tests/shared/app/views/forms/disabled_elements.html.haml
423
427
  - tests/shared/app/views/forms/form1.html.haml
424
428
  - tests/shared/app/views/forms/form2.html.haml
425
- - tests/shared/app/views/forms/invalid_form.html.haml
429
+ - tests/shared/app/views/forms/invalid_bootstrap3_form.html.haml
430
+ - tests/shared/app/views/forms/invalid_bootstrap4_form.html.haml
431
+ - tests/shared/app/views/forms/invalid_rails_form.html.haml
426
432
  - tests/shared/app/views/forms/select_fields.html.haml
427
433
  - tests/shared/app/views/iframes/iframe_1_content.haml
428
434
  - tests/shared/app/views/iframes/iframe_2_content.haml
@@ -453,6 +459,7 @@ test_files:
453
459
  - tests/shared/app/views/static_pages/session_1.haml
454
460
  - tests/shared/app/views/static_pages/session_2.haml
455
461
  - tests/shared/app/views/static_pages/session_3.haml
462
+ - tests/shared/app/views/static_pages/should_see.haml
456
463
  - tests/shared/app/views/static_pages/tab_1.haml
457
464
  - tests/shared/app/views/static_pages/tab_2.haml
458
465
  - tests/shared/app/views/static_pages/tab_3.haml