cucumber-rails 1.7.0 → 2.3.0

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