cucumber-rails 1.7.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +197 -19
  3. data/CONTRIBUTING.md +16 -14
  4. data/LICENSE +1 -1
  5. data/README.md +27 -21
  6. data/lib/cucumber/rails.rb +23 -17
  7. data/lib/cucumber/rails/action_dispatch.rb +21 -0
  8. data/lib/cucumber/rails/application.rb +16 -7
  9. data/lib/cucumber/rails/capybara.rb +2 -0
  10. data/lib/cucumber/rails/capybara/javascript_emulation.rb +42 -21
  11. data/lib/cucumber/rails/capybara/select_dates_and_times.rb +3 -1
  12. data/lib/cucumber/rails/database.rb +24 -56
  13. data/lib/cucumber/rails/database/deletion_strategy.rb +13 -0
  14. data/lib/cucumber/rails/database/shared_connection_strategy.rb +27 -0
  15. data/lib/cucumber/rails/database/strategy.rb +33 -0
  16. data/lib/cucumber/rails/database/truncation_strategy.rb +13 -0
  17. data/lib/cucumber/rails/hooks.rb +2 -0
  18. data/lib/cucumber/rails/hooks/active_record.rb +8 -4
  19. data/lib/cucumber/rails/hooks/allow_rescue.rb +2 -0
  20. data/lib/cucumber/rails/hooks/database_cleaner.rb +11 -3
  21. data/lib/cucumber/rails/hooks/mail.rb +3 -1
  22. data/lib/cucumber/rails/rspec.rb +3 -1
  23. data/lib/cucumber/rails/world.rb +24 -7
  24. data/lib/generators/cucumber/{install/USAGE → USAGE} +0 -0
  25. data/lib/generators/cucumber/{install/install_generator.rb → install_generator.rb} +18 -9
  26. data/lib/generators/cucumber/{install/templates → templates}/config/cucumber.yml.erb +0 -0
  27. data/lib/generators/cucumber/{install/templates → templates}/script/cucumber +1 -0
  28. data/lib/generators/cucumber/{install/templates → templates}/support/_rails_each_run.rb.erb +0 -0
  29. data/lib/generators/cucumber/{install/templates → templates}/support/_rails_prefork.rb.erb +0 -0
  30. data/lib/generators/cucumber/{install/templates → templates}/support/capybara.rb +2 -0
  31. data/lib/generators/cucumber/{install/templates → templates}/support/edit_warning.txt +0 -0
  32. data/lib/generators/cucumber/{install/templates → templates}/support/rails.rb.erb +0 -0
  33. data/lib/generators/cucumber/{install/templates → templates}/support/rails_spork.rb.erb +0 -0
  34. data/lib/generators/cucumber/{install/templates → templates}/tasks/cucumber.rake.erb +0 -0
  35. metadata +100 -169
  36. data/.github/ISSUE_TEMPLATE.md +0 -52
  37. data/.github/PULL_REQUEST_TEMPLATE.md +0 -42
  38. data/.gitignore +0 -13
  39. data/.rspec +0 -1
  40. data/.rubocop.yml +0 -1
  41. data/.rubocop_todo.yml +0 -443
  42. data/.travis.yml +0 -45
  43. data/Appraisals +0 -32
  44. data/Gemfile +0 -7
  45. data/Rakefile +0 -49
  46. data/bin/install_geckodriver.sh +0 -19
  47. data/bin/install_webpacker.sh +0 -9
  48. data/config/.gitignore +0 -1
  49. data/config/cucumber.yml +0 -17
  50. data/cucumber-rails.gemspec +0 -44
  51. data/dev_tasks/cucumber.rake +0 -3
  52. data/dev_tasks/rspec.rake +0 -3
  53. data/dev_tasks/yard.rake +0 -35
  54. data/dev_tasks/yard/default/layout/html/bubble_32x32.png +0 -0
  55. data/dev_tasks/yard/default/layout/html/footer.erb +0 -5
  56. data/dev_tasks/yard/default/layout/html/index.erb +0 -1
  57. data/dev_tasks/yard/default/layout/html/layout.erb +0 -25
  58. data/dev_tasks/yard/default/layout/html/logo.erb +0 -1
  59. data/dev_tasks/yard/default/layout/html/setup.rb +0 -4
  60. data/features/allow_rescue.feature +0 -65
  61. data/features/annotations.feature +0 -22
  62. data/features/capybara_javascript_drivers.feature +0 -73
  63. data/features/choose_javascript_database_strategy.feature +0 -145
  64. data/features/database_cleaner.feature +0 -44
  65. data/features/disable_automatic_database_cleaning.feature +0 -55
  66. data/features/emulate_javascript.feature +0 -94
  67. data/features/install_cucumber_rails.feature +0 -14
  68. data/features/no_database.feature +0 -61
  69. data/features/raising_errors.feature +0 -16
  70. data/features/rerun_profile.feature +0 -46
  71. data/features/rest_api.feature +0 -47
  72. data/features/step_definitions/cucumber_rails_steps.rb +0 -153
  73. data/features/support/aruba.rb +0 -3
  74. data/features/support/bundler_pre_support.rb +0 -28
  75. data/features/support/env.rb +0 -40
  76. data/features/support/fixtures/bundler-1.0.21.gem +0 -0
  77. data/features/support/fixtures/bundler-1.1.rc.gem +0 -0
  78. data/features/support/legacy_web_steps_support.rb +0 -289
  79. data/gemfiles/rails_4_2.gemfile +0 -10
  80. data/gemfiles/rails_5_0.gemfile +0 -10
  81. data/gemfiles/rails_5_1.gemfile +0 -10
  82. data/gemfiles/rails_5_2.gemfile +0 -10
  83. data/gemfiles/rails_6_0.gemfile +0 -8
  84. data/lib/cucumber/rails/action_controller.rb +0 -13
  85. data/spec/cucumber/rails/database_spec.rb +0 -57
  86. data/spec/generators/cucumber/install/install_generator_spec.rb +0 -47
  87. data/spec/spec_helper.rb +0 -14
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActionController::Base.class_eval do
4
+ cattr_accessor :allow_rescue
5
+ end
6
+
7
+ module Cucumber
8
+ module Rails
9
+ module ActionDispatch
10
+ module ShowExceptions
11
+ def call(env)
12
+ env['action_dispatch.show_detailed_exceptions'] = !ActionController::Base.allow_rescue
13
+ env['action_dispatch.show_exceptions'] = !env['action_dispatch.show_detailed_exceptions']
14
+ super(env)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ ActionDispatch::ShowExceptions.prepend(Cucumber::Rails::ActionDispatch::ShowExceptions)
@@ -1,17 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails/application'
2
4
 
3
5
  # Make sure the ActionDispatch::ShowExceptions middleware is always enabled,
4
6
  # regardless of what is in config/environments/test.rb
5
7
  # Instead we are overriding ActionDispatch::ShowExceptions to be able to
6
8
  # toggle whether or not exceptions are raised.
7
- class Rails::Application
8
- alias __cucumber_orig_initialize__ initialize!
9
9
 
10
- def initialize!
11
- ad = config.action_dispatch
12
- def ad.show_exceptions
13
- true
10
+ module Cucumber
11
+ module Rails
12
+ module Application
13
+ def initialize!
14
+ ad = config.action_dispatch
15
+
16
+ def ad.show_exceptions
17
+ true
18
+ end
19
+
20
+ super
21
+ end
14
22
  end
15
- __cucumber_orig_initialize__
16
23
  end
17
24
  end
25
+
26
+ Rails::Application.prepend(Cucumber::Rails::Application)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'capybara'
2
4
  require 'capybara/rails'
3
5
  require 'capybara/cucumber'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Cucumber
2
4
  module Rails
3
5
  module Capybara
@@ -11,7 +13,9 @@ module Cucumber
11
13
 
12
14
  def click_with_javascript_emulation(*)
13
15
  if link_with_non_get_http_method?
14
- ::Capybara::RackTest::Form.new(driver, js_form(element_node.document, self[:href], emulated_method)).submit(self)
16
+ ::Capybara::RackTest::Form.new(
17
+ driver, js_form(element_node.document, self[:href], emulated_method)
18
+ ).submit(self)
15
19
  else
16
20
  click_without_javascript_emulation
17
21
  end
@@ -44,29 +48,42 @@ module Cucumber
44
48
  js_form['action'] = action
45
49
  js_form['method'] = method
46
50
 
47
- if emulated_method and emulated_method.downcase != method.downcase
48
- input = document.create_element('input')
49
- input['type'] = 'hidden'
50
- input['name'] = '_method'
51
- input['value'] = emulated_method
52
- js_form.add_child(input)
53
- end
51
+ add_hidden_method_input(document, js_form) unless same?(emulated_method, method)
54
52
 
55
- # rails will wipe the session if the CSRF token is not sent
56
- # with non-GET requests
57
- if csrf? && emulated_method.downcase != 'get'
58
- input = document.create_element('input')
59
- input['type'] = 'hidden'
60
- input['name'] = csrf_param
61
- input['value'] = csrf_token
62
- js_form.add_child(input)
63
- end
53
+ # rails will wipe the session if the CSRF token is not sent with non-GET requests
54
+ add_hidden_csrf_input(document, js_form) if csrf? && !get?(emulated_method)
64
55
 
65
56
  js_form
66
57
  end
67
58
 
59
+ def same?(emulated_method, method)
60
+ emulated_method.casecmp(method).zero?
61
+ end
62
+
63
+ def add_hidden_method_input(document, js_form)
64
+ input = document.create_element('input')
65
+ input['type'] = 'hidden'
66
+ input['name'] = '_method'
67
+ input['value'] = emulated_method
68
+ js_form.add_child(input)
69
+ end
70
+
71
+ def get?(emulated_method)
72
+ same?(emulated_method, 'get')
73
+ end
74
+
75
+ def add_hidden_csrf_input(document, js_form)
76
+ input = document.create_element('input')
77
+ input['type'] = 'hidden'
78
+ input['name'] = csrf_param
79
+ input['value'] = csrf_token
80
+ js_form.add_child(input)
81
+ end
82
+
68
83
  def link_with_non_get_http_method?
69
- tag_name == 'a' && element_node['data-method'] && element_node['data-method'] =~ /(?:delete|put|post)/
84
+ tag_name == 'a' &&
85
+ element_node['data-method'] &&
86
+ element_node['data-method'] =~ /(?:delete|put|post)/
70
87
  end
71
88
 
72
89
  def emulated_method
@@ -74,15 +91,19 @@ module Cucumber
74
91
  end
75
92
 
76
93
  def element_node
77
- self.native
94
+ native
78
95
  end
79
96
  end
80
97
  end
81
98
  end
82
99
  end
83
100
 
84
- class Capybara::RackTest::Node
85
- include ::Cucumber::Rails::Capybara::JavascriptEmulation
101
+ module Capybara
102
+ module RackTest
103
+ class Node
104
+ include ::Cucumber::Rails::Capybara::JavascriptEmulation
105
+ end
106
+ end
86
107
  end
87
108
 
88
109
  Before('not @no-js-emulation') do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Cucumber
2
4
  module Rails
3
5
  module Capybara
@@ -9,7 +11,7 @@ module Cucumber
9
11
  base_dom_id = get_base_dom_id_from_label_tag(options[:from])
10
12
 
11
13
  find(:xpath, ".//select[@id='#{base_dom_id}_1i']").select(date.year.to_s)
12
- find(:xpath, ".//select[@id='#{base_dom_id}_2i']").select(I18n.l date, format: '%B')
14
+ find(:xpath, ".//select[@id='#{base_dom_id}_2i']").select(I18n.l(date, format: '%B'))
13
15
  find(:xpath, ".//select[@id='#{base_dom_id}_3i']").select(date.day.to_s)
14
16
  end
15
17
 
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Cucumber
2
4
  module Rails
3
5
  module Database
4
- CUSTOM_STRATEGY_INTERFACE = %w{ before_js before_non_js }
6
+ CUSTOM_STRATEGY_INTERFACE = %w[before_js before_non_js].freeze
5
7
 
6
8
  class InvalidStrategy < ArgumentError; end
7
9
 
@@ -13,16 +15,21 @@ module Cucumber
13
15
  strategy_type =
14
16
  case strategy
15
17
  when Symbol
16
- map[strategy] || raise(InvalidStrategy, "The strategy '#{strategy}' is not understood. Please use one of #{map.keys.join(',')}")
18
+ map[strategy] || throw_invalid_strategy_error(strategy)
17
19
  when Class
18
20
  strategy
19
21
  end
20
22
 
21
- @strategy = strategy_type.new(*strategy_opts)
23
+ @strategy = strategy_type.new(*strategy_opts)
22
24
 
23
25
  validate_interface!
24
26
  end
25
27
 
28
+ def default_strategy!
29
+ self.javascript_strategy = :truncation
30
+ self.autorun_database_cleaner = true
31
+ end
32
+
26
33
  def before_js
27
34
  @strategy.before_js
28
35
  end
@@ -35,7 +42,7 @@ module Cucumber
35
42
  @strategy.after
36
43
  end
37
44
 
38
- private
45
+ private
39
46
 
40
47
  def map
41
48
  {
@@ -46,68 +53,29 @@ module Cucumber
46
53
  }
47
54
  end
48
55
 
49
- def validate_interface!
50
- unless CUSTOM_STRATEGY_INTERFACE.all? { |m| @strategy.respond_to?(m) }
51
- raise(ArgumentError, "Strategy must respond to all of: #{CUSTOM_STRATEGY_INTERFACE.map{ |method| "##{method}" } * ' ' } !")
52
- end
53
- end
54
- end
55
-
56
- class Strategy
57
- def initialize(options = {})
58
- @options = options
59
- end
60
-
61
- def before_js(strategy)
62
- @original_strategy = DatabaseCleaner.connections.first.strategy # that feels like a nasty hack
63
- DatabaseCleaner.strategy = strategy, @options
64
- end
65
-
66
- def before_non_js
67
- # no-op
68
- end
69
-
70
- def after
71
- return unless @original_strategy
72
- DatabaseCleaner.strategy = @original_strategy
73
- @original_strategy = nil
56
+ def throw_invalid_strategy_error(strategy)
57
+ raise(InvalidStrategy, "The strategy '#{strategy}' is not understood. Please use one of #{mapped_keys}")
74
58
  end
75
- end
76
59
 
77
- class TruncationStrategy < Strategy
78
- def before_js
79
- super :truncation
60
+ def mapped_keys
61
+ map.keys.join(', ')
80
62
  end
81
- end
82
63
 
83
- class DeletionStrategy < Strategy
84
- def before_js
85
- super :deletion
86
- end
87
- end
64
+ def validate_interface!
65
+ return if CUSTOM_STRATEGY_INTERFACE.all? { |m| @strategy.respond_to?(m) }
88
66
 
89
- class SharedConnectionStrategy < Strategy
90
- def before_js
91
- # Forces all threads to share a connection on a per-model basis,
92
- # as connections may vary per model as per establish_connection. This works
93
- # on Capybara because it starts the web server in a thread.
94
- ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
95
- ActiveRecord::Base.descendants.each do |model|
96
- model.shared_connection = model.connection
97
- end
67
+ throw_invalid_strategy_interface_error
98
68
  end
99
69
 
100
- def before_non_js
101
- # Do not use a shared connection unless we're in a @javascript scenario
102
- ActiveRecord::Base.shared_connection = nil
103
- ActiveRecord::Base.descendants.each do |model|
104
- model.shared_connection = nil
105
- end
70
+ def throw_invalid_strategy_interface_error
71
+ raise(
72
+ ArgumentError,
73
+ "Strategy must respond to all of: #{CUSTOM_STRATEGY_INTERFACE.map { |method| "##{method}" } * ' '} !"
74
+ )
106
75
  end
107
76
  end
108
77
 
109
- Database.javascript_strategy = :truncation
110
- Database.autorun_database_cleaner = true
78
+ default_strategy!
111
79
  end
112
80
  end
113
81
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Rails
5
+ module Database
6
+ class DeletionStrategy < Strategy
7
+ def before_js
8
+ super :deletion
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Rails
5
+ module Database
6
+ class SharedConnectionStrategy < Strategy
7
+ def before_js
8
+ # Forces all threads to share a connection on a per-model basis,
9
+ # as connections may vary per model as per establish_connection. This works
10
+ # on Capybara because it starts the web server in a thread.
11
+ ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
12
+ ActiveRecord::Base.descendants.each do |model|
13
+ model.shared_connection = model.connection
14
+ end
15
+ end
16
+
17
+ def before_non_js
18
+ # Do not use a shared connection unless we're in a @javascript scenario
19
+ ActiveRecord::Base.shared_connection = nil
20
+ ActiveRecord::Base.descendants.each do |model|
21
+ model.shared_connection = nil
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Rails
5
+ module Database
6
+ class Strategy
7
+ def initialize(options = {})
8
+ @options = options
9
+ end
10
+
11
+ def before_js(strategy)
12
+ @original_strategy = if defined?(DatabaseCleaner::VERSION) && Gem::Version.new(DatabaseCleaner::VERSION) >= Gem::Version.new('1.8.0.beta')
13
+ DatabaseCleaner.cleaners.values.first.strategy # that feels like a nasty hack
14
+ else
15
+ DatabaseCleaner.connections.first.strategy # that feels like a nasty hack
16
+ end
17
+ DatabaseCleaner.strategy = strategy, @options
18
+ end
19
+
20
+ def before_non_js
21
+ # no-op
22
+ end
23
+
24
+ def after
25
+ return unless @original_strategy
26
+
27
+ DatabaseCleaner.strategy = @original_strategy
28
+ @original_strategy = nil
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Rails
5
+ module Database
6
+ class TruncationStrategy < Strategy
7
+ def before_js
8
+ super :truncation
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'cucumber/rails/hooks/active_record'
2
4
  require 'cucumber/rails/hooks/database_cleaner'
3
5
  require 'cucumber/rails/hooks/allow_rescue'
@@ -1,9 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  if defined?(ActiveRecord::Base)
2
- class ActiveRecord::Base
3
- class_attribute :shared_connection
4
+ module ActiveRecord
5
+ class Base
6
+ class_attribute :shared_connection
4
7
 
5
- def self.connection
6
- self.shared_connection || retrieve_connection
8
+ def self.connection
9
+ shared_connection || retrieve_connection
10
+ end
7
11
  end
8
12
  end
9
13
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Before('@allow-rescue') do
2
4
  @__orig_allow_rescue = ActionController::Base.allow_rescue
3
5
  ActionController::Base.allow_rescue = true
@@ -1,6 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
- require 'database_cleaner'
4
+ require 'database_cleaner/core'
5
+ rescue LoadError
6
+ begin
7
+ require 'database_cleaner'
8
+ rescue LoadError
9
+ Cucumber.logger.debug('neither database_cleaner v1 or v2 present')
10
+ end
11
+ end
3
12
 
13
+ if defined?(DatabaseCleaner)
4
14
  Before('not @no-database-cleaner') do
5
15
  DatabaseCleaner.start if Cucumber::Rails::Database.autorun_database_cleaner
6
16
  end
@@ -8,6 +18,4 @@ begin
8
18
  After('not @no-database-cleaner') do
9
19
  DatabaseCleaner.clean if Cucumber::Rails::Database.autorun_database_cleaner
10
20
  end
11
-
12
- rescue LoadError => ignore_if_database_cleaner_not_present
13
21
  end