ruby_raider 3.13.0 → 4.0.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 (225) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/runtime.yml +38 -0
  3. data/.github/workflows/system_tests.yml +1 -23
  4. data/.reek.yml +1 -0
  5. data/.rspec +1 -0
  6. data/Gemfile +2 -0
  7. data/README.md +16 -49
  8. data/RELEASE.md +22 -0
  9. data/bin/raider +5 -0
  10. data/lib/commands/scaffolding_commands.rb +2 -25
  11. data/lib/commands/utility_commands.rb +23 -3
  12. data/lib/generators/automation/automation_generator.rb +0 -5
  13. data/lib/generators/automation/templates/component.tt +1 -0
  14. data/lib/generators/automation/templates/home.tt +2 -2
  15. data/lib/generators/automation/templates/login.tt +6 -26
  16. data/lib/generators/automation/templates/page.tt +23 -18
  17. data/lib/generators/automation/templates/partials/home_page_selector.tt +1 -2
  18. data/lib/generators/automation/templates/partials/initialize_selector.tt +0 -8
  19. data/lib/generators/automation/templates/partials/pdp_page_selector.tt +1 -2
  20. data/lib/generators/automation/templates/partials/url_methods.tt +8 -2
  21. data/lib/generators/automation/templates/partials/visit_method.tt +0 -5
  22. data/lib/generators/automation/templates/pdp.tt +1 -9
  23. data/lib/generators/common_generator.rb +0 -2
  24. data/lib/generators/generator.rb +12 -19
  25. data/lib/generators/helper_generator.rb +21 -19
  26. data/lib/generators/infrastructure/templates/azure_pipelines.tt +1 -1
  27. data/lib/generators/infrastructure/templates/github.tt +2 -3
  28. data/lib/generators/infrastructure/templates/github_appium.tt +0 -8
  29. data/lib/generators/invoke_generators.rb +4 -23
  30. data/lib/generators/menu_generator.rb +1 -9
  31. data/lib/generators/rspec/templates/accessibility_spec.tt +1 -9
  32. data/lib/generators/rspec/templates/spec.tt +8 -24
  33. data/lib/generators/template_renderer/partial_cache.rb +3 -1
  34. data/lib/generators/template_renderer.rb +1 -1
  35. data/lib/generators/templates/common/gemfile.tt +3 -10
  36. data/lib/generators/templates/common/git_ignore.tt +0 -5
  37. data/lib/generators/templates/common/partials/mobile_config.tt +3 -1
  38. data/lib/generators/templates/common/partials/web_config.tt +10 -1
  39. data/lib/generators/templates/common/rakefile.tt +0 -15
  40. data/lib/generators/templates/common/read_me.tt +357 -250
  41. data/lib/generators/templates/common/rubocop.tt +0 -2
  42. data/lib/generators/templates/helpers/driver_helper.tt +8 -0
  43. data/lib/generators/templates/helpers/gesture_helper.tt +78 -0
  44. data/lib/generators/templates/helpers/network_helper.tt +521 -0
  45. data/lib/generators/templates/helpers/partials/quit_driver.tt +0 -2
  46. data/lib/generators/templates/helpers/partials/screenshot.tt +0 -2
  47. data/lib/generators/templates/helpers/partials/selenium_driver.tt +5 -2
  48. data/lib/generators/templates/helpers/screenshot_helper.tt +490 -0
  49. data/lib/generators/templates/helpers/spec_helper.tt +39 -29
  50. data/lib/generators/templates/helpers/trace_helper.tt +240 -95
  51. data/lib/generators/templates/helpers/video_helper.tt +3 -8
  52. data/lib/ruby_raider/runtime/actionability.rb +129 -0
  53. data/lib/ruby_raider/runtime/actionable.rb +49 -0
  54. data/lib/ruby_raider/runtime/by_role.rb +55 -0
  55. data/lib/ruby_raider/runtime/config.rb +79 -0
  56. data/lib/ruby_raider/runtime/context.rb +38 -0
  57. data/lib/ruby_raider/runtime/errors.rb +69 -0
  58. data/lib/ruby_raider/runtime/finders.rb +73 -0
  59. data/lib/ruby_raider/runtime/js/actionability.js +134 -0
  60. data/lib/ruby_raider/runtime/js/role_engine.js +315 -0
  61. data/lib/ruby_raider/runtime/locator_converter.rb +72 -0
  62. data/lib/ruby_raider/runtime/matchers/base.rb +222 -0
  63. data/lib/ruby_raider/runtime/matchers/element.rb +183 -0
  64. data/lib/ruby_raider/runtime/matchers/page.rb +71 -0
  65. data/lib/ruby_raider/runtime/matchers/presence.rb +41 -0
  66. data/lib/ruby_raider/runtime/matchers/retrying_block.rb +104 -0
  67. data/lib/ruby_raider/runtime/observer.rb +170 -0
  68. data/lib/ruby_raider/runtime/role_finder.rb +83 -0
  69. data/lib/ruby_raider/runtime/rspec.rb +78 -0
  70. data/lib/ruby_raider/runtime/selectors.rb +60 -0
  71. data/lib/ruby_raider/runtime/strict.rb +142 -0
  72. data/lib/ruby_raider/runtime/wait.rb +84 -0
  73. data/lib/ruby_raider/runtime.rb +20 -0
  74. data/lib/scaffolding/name_normalizer.rb +1 -1
  75. data/lib/scaffolding/project_detector.rb +2 -28
  76. data/lib/scaffolding/scaffolding.rb +0 -20
  77. data/lib/scaffolding/templates/component.tt +0 -14
  78. data/lib/scaffolding/templates/page_object.tt +2 -14
  79. data/lib/scaffolding/templates/spec.tt +1 -9
  80. data/lib/utilities/utilities.rb +10 -8
  81. data/lib/version +1 -1
  82. data/ruby_raider.gemspec +2 -1
  83. data/sig/commands/scaffolding_commands.rbs +0 -2
  84. data/sig/commands/utility_commands.rbs +6 -0
  85. data/sig/generators/generator.rbs +0 -4
  86. data/sig/generators/helper_generator.rbs +0 -1
  87. data/sig/generators/menu_generator.rbs +0 -1
  88. data/sig/ruby_raider/runtime/actionability.rbs +25 -0
  89. data/sig/ruby_raider/runtime/actionable.rbs +13 -0
  90. data/sig/ruby_raider/runtime/by_role.rbs +15 -0
  91. data/sig/ruby_raider/runtime/config.rbs +26 -0
  92. data/sig/ruby_raider/runtime/context.rbs +12 -0
  93. data/sig/ruby_raider/runtime/errors.rbs +36 -0
  94. data/sig/ruby_raider/runtime/finders.rbs +26 -0
  95. data/sig/ruby_raider/runtime/locator_converter.rbs +21 -0
  96. data/sig/ruby_raider/runtime/matchers/base.rbs +64 -0
  97. data/sig/ruby_raider/runtime/matchers/element.rbs +78 -0
  98. data/sig/ruby_raider/runtime/matchers/page.rbs +38 -0
  99. data/sig/ruby_raider/runtime/matchers/presence.rbs +21 -0
  100. data/sig/ruby_raider/runtime/matchers/retrying_block.rbs +27 -0
  101. data/sig/ruby_raider/runtime/observer.rbs +46 -0
  102. data/sig/ruby_raider/runtime/role_finder.rbs +18 -0
  103. data/sig/ruby_raider/runtime/selectors.rbs +21 -0
  104. data/sig/ruby_raider/runtime/strict.rbs +35 -0
  105. data/sig/ruby_raider/runtime/wait.rbs +17 -0
  106. data/sig/ruby_raider/runtime.rbs +2 -0
  107. data/sig/scaffolding/project_detector.rbs +0 -4
  108. data/sig/scaffolding/scaffolding.rbs +0 -5
  109. data/sig/utilities/utilities.rbs +2 -1
  110. data/sig/vendor/selenium_webdriver.rbs +71 -0
  111. data/spec/commands/raider_commands_spec.rb +38 -3
  112. data/spec/commands/scaffolding_commands_spec.rb +27 -0
  113. data/spec/commands/utility_commands_spec.rb +53 -0
  114. data/spec/generators/gesture_helper_spec.rb +123 -0
  115. data/spec/generators/network_helper_spec.rb +634 -0
  116. data/spec/generators/screenshot_helper_spec.rb +776 -0
  117. data/spec/generators/template_renderer_spec.rb +0 -4
  118. data/spec/generators/trace_helper_spec.rb +489 -97
  119. data/spec/generators/video_helper_spec.rb +0 -9
  120. data/spec/integration/commands/browser_update_after_creation_spec.rb +0 -8
  121. data/spec/integration/commands/scaffolding_commands_spec.rb +12 -70
  122. data/spec/integration/commands/utility_commands_spec.rb +19 -41
  123. data/spec/integration/content/azure_content_spec.rb +2 -6
  124. data/spec/integration/content/ci_content_spec.rb +1 -55
  125. data/spec/integration/content/common_content_spec.rb +1 -118
  126. data/spec/integration/content/config_content_spec.rb +34 -31
  127. data/spec/integration/content/gemfile_content_spec.rb +7 -72
  128. data/spec/integration/content/helper_content_spec.rb +105 -99
  129. data/spec/integration/content/page_content_spec.rb +85 -87
  130. data/spec/integration/content/readme_content_spec.rb +134 -75
  131. data/spec/integration/content/rspec_reporter_content_spec.rb +2 -2
  132. data/spec/integration/content/rubocop_content_spec.rb +1 -1
  133. data/spec/integration/content/syntax_validation_spec.rb +2 -2
  134. data/spec/integration/content/test_content_spec.rb +23 -147
  135. data/spec/integration/end_to_end_features_spec.rb +1 -43
  136. data/spec/integration/end_to_end_spec.rb +319 -326
  137. data/spec/integration/generators/automation_generator_spec.rb +3 -37
  138. data/spec/integration/generators/axe_addon_spec.rb +2 -35
  139. data/spec/integration/generators/azure_generator_spec.rb +1 -1
  140. data/spec/integration/generators/common_generator_spec.rb +1 -40
  141. data/spec/integration/generators/config_features_spec.rb +1 -24
  142. data/spec/integration/generators/github_generator_spec.rb +0 -12
  143. data/spec/integration/generators/helpers_generator_spec.rb +74 -80
  144. data/spec/integration/generators/invoke_generators_spec.rb +54 -45
  145. data/spec/integration/generators/rspec_generator_spec.rb +0 -6
  146. data/spec/integration/scaffolding_e2e_spec.rb +17 -179
  147. data/spec/integration/spec_helper.rb +4 -6
  148. data/spec/integration/trace_format_checker.rb +11 -2
  149. data/spec/integration/trace_page_server.rb +72 -5
  150. data/spec/menus/menu_generator_spec.rb +14 -39
  151. data/spec/runtime/actionability_spec.rb +207 -0
  152. data/spec/runtime/actionable_spec.rb +125 -0
  153. data/spec/runtime/browser/actionability_script_browser_spec.rb +150 -0
  154. data/spec/runtime/browser/actionable_browser_spec.rb +98 -0
  155. data/spec/runtime/browser/finders_browser_spec.rb +148 -0
  156. data/spec/runtime/browser/matchers_browser_spec.rb +67 -0
  157. data/spec/runtime/browser/retrying_block_browser_spec.rb +37 -0
  158. data/spec/runtime/browser/role_engine_browser_spec.rb +184 -0
  159. data/spec/runtime/browser/strict_browser_spec.rb +38 -0
  160. data/spec/runtime/by_role_spec.rb +52 -0
  161. data/spec/runtime/config_spec.rb +79 -0
  162. data/spec/runtime/context_spec.rb +73 -0
  163. data/spec/runtime/errors_spec.rb +89 -0
  164. data/spec/runtime/finders_spec.rb +165 -0
  165. data/spec/runtime/fixtures/actionability.html +70 -0
  166. data/spec/runtime/fixtures/locators.html +46 -0
  167. data/spec/runtime/fixtures/matchers.html +33 -0
  168. data/spec/runtime/fixtures/roles.html +162 -0
  169. data/spec/runtime/matchers/base_spec.rb +165 -0
  170. data/spec/runtime/matchers/element_spec.rb +277 -0
  171. data/spec/runtime/matchers/page_spec.rb +102 -0
  172. data/spec/runtime/matchers/presence_spec.rb +59 -0
  173. data/spec/runtime/matchers/retrying_block_spec.rb +165 -0
  174. data/spec/runtime/observer_spec.rb +341 -0
  175. data/spec/runtime/role_finder_spec.rb +156 -0
  176. data/spec/runtime/role_query_spec.rb +75 -0
  177. data/spec/runtime/selectors_spec.rb +135 -0
  178. data/spec/runtime/strict_spec.rb +257 -0
  179. data/spec/runtime/support/browser.rb +48 -0
  180. data/spec/runtime/support/fake_bridge.rb +117 -0
  181. data/spec/runtime/wait_spec.rb +71 -0
  182. data/spec/scaffolding/name_normalizer_spec.rb +3 -2
  183. data/spec/scaffolding/scaffold_project_detector_spec.rb +4 -43
  184. data/spec/system/selenium_spec.rb +1 -5
  185. data/spec/system/support/system_test_helper.rb +2 -5
  186. data/spec/utilities/headless_config_spec.rb +0 -7
  187. data/spec/utilities/utilities_spec.rb +24 -0
  188. metadata +113 -48
  189. data/lib/generators/automation/templates/header.tt +0 -9
  190. data/lib/generators/cucumber/cucumber_generator.rb +0 -58
  191. data/lib/generators/cucumber/templates/accessibility_feature.tt +0 -5
  192. data/lib/generators/cucumber/templates/accessibility_steps.tt +0 -17
  193. data/lib/generators/cucumber/templates/cucumber.tt +0 -1
  194. data/lib/generators/cucumber/templates/env.tt +0 -7
  195. data/lib/generators/cucumber/templates/feature.tt +0 -21
  196. data/lib/generators/cucumber/templates/partials/appium_env.tt +0 -26
  197. data/lib/generators/cucumber/templates/partials/driver_world.tt +0 -18
  198. data/lib/generators/cucumber/templates/partials/mobile_steps.tt +0 -20
  199. data/lib/generators/cucumber/templates/partials/selenium_env.tt +0 -120
  200. data/lib/generators/cucumber/templates/partials/watir_env.tt +0 -48
  201. data/lib/generators/cucumber/templates/partials/watir_world.tt +0 -4
  202. data/lib/generators/cucumber/templates/partials/web_steps.tt +0 -28
  203. data/lib/generators/cucumber/templates/steps.tt +0 -5
  204. data/lib/generators/cucumber/templates/user_factory.tt +0 -15
  205. data/lib/generators/cucumber/templates/world.tt +0 -7
  206. data/lib/generators/templates/helpers/browser_helper.tt +0 -31
  207. data/lib/generators/templates/helpers/raider_element.tt +0 -159
  208. data/lib/generators/templates/helpers/wait_helper.tt +0 -611
  209. data/lib/scaffolding/templates/feature.tt +0 -6
  210. data/lib/scaffolding/templates/steps.tt +0 -19
  211. data/sig/generators/cucumber/cucumber_generator.rbs +0 -12
  212. data/spec/fixtures/watir_master/cucumber_watir/Readme.md.snapshot +0 -175
  213. data/spec/fixtures/watir_master/cucumber_watir/features/step_definitions/login_steps.rb.snapshot +0 -24
  214. data/spec/fixtures/watir_master/cucumber_watir/page_objects/abstract/page.rb.snapshot +0 -37
  215. data/spec/fixtures/watir_master/cucumber_watir/page_objects/pages/login.rb.snapshot +0 -33
  216. data/spec/fixtures/watir_master/rspec_watir/Readme.md.snapshot +0 -174
  217. data/spec/fixtures/watir_master/rspec_watir/page_objects/abstract/page.rb.snapshot +0 -37
  218. data/spec/fixtures/watir_master/rspec_watir/page_objects/pages/login.rb.snapshot +0 -33
  219. data/spec/fixtures/watir_master/rspec_watir/spec/login_page_spec.rb.snapshot +0 -49
  220. data/spec/integration/content/cucumber_reporter_content_spec.rb +0 -161
  221. data/spec/integration/generators/cucumber_generator_spec.rb +0 -100
  222. data/spec/integration/helpers/wait_helper_mobile_spec.rb +0 -281
  223. data/spec/integration/helpers/wait_helper_spec.rb +0 -679
  224. data/spec/integration/helpers/wait_helper_support.rb +0 -183
  225. data/spec/system/watir_spec.rb +0 -38
@@ -42,53 +42,17 @@ describe 'Gemfile content' do
42
42
  expect(gemfile).to include("gem 'rubocop-rspec'")
43
43
  end
44
44
 
45
- it 'does not include cucumber' do
46
- expect(gemfile).not_to include("gem 'cucumber'")
47
- end
48
-
49
45
  it 'does not include minitest' do
50
46
  expect(gemfile).not_to include("gem 'minitest'\n")
51
47
  end
52
48
  end
53
49
 
54
- shared_examples 'contains cucumber gems' do |project_name|
55
- subject(:gemfile) { read_generated(project_name, 'Gemfile') }
56
-
57
- it 'includes cucumber' do
58
- expect(gemfile).to include("gem 'cucumber'")
59
- end
60
-
61
- it 'does not include allure-cucumber' do
62
- expect(gemfile).not_to include('allure')
63
- end
64
-
65
- it 'includes rspec as cucumber dependency' do
66
- expect(gemfile).to include("gem 'rspec'")
67
- end
68
- end
69
-
70
50
  shared_examples 'contains selenium gems' do |project_name|
71
51
  subject(:gemfile) { read_generated(project_name, 'Gemfile') }
72
52
 
73
53
  it 'includes selenium-webdriver' do
74
54
  expect(gemfile).to include("gem 'selenium-webdriver'")
75
55
  end
76
-
77
- it 'does not include watir' do
78
- expect(gemfile).not_to include("gem 'watir'")
79
- end
80
- end
81
-
82
- shared_examples 'contains watir gems' do |project_name|
83
- subject(:gemfile) { read_generated(project_name, 'Gemfile') }
84
-
85
- it 'includes watir' do
86
- expect(gemfile).to include("gem 'watir'")
87
- end
88
-
89
- it 'does not include selenium-webdriver' do
90
- expect(gemfile).not_to include("gem 'selenium-webdriver'")
91
- end
92
56
  end
93
57
 
94
58
  context 'with rspec and selenium' do
@@ -98,27 +62,6 @@ describe 'Gemfile content' do
98
62
  include_examples 'contains selenium gems', name
99
63
  end
100
64
 
101
- context 'with rspec and watir' do
102
- name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
103
- include_examples 'contains common gems', name
104
- include_examples 'contains rspec gems', name
105
- include_examples 'contains watir gems', name
106
- end
107
-
108
- context 'with cucumber and selenium' do
109
- name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
110
- include_examples 'contains common gems', name
111
- include_examples 'contains cucumber gems', name
112
- include_examples 'contains selenium gems', name
113
- end
114
-
115
- context 'with cucumber and watir' do
116
- name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}"
117
- include_examples 'contains common gems', name
118
- include_examples 'contains cucumber gems', name
119
- include_examples 'contains watir gems', name
120
- end
121
-
122
65
  describe 'raider_reporter and ruby_raider pin' do
123
66
  major_minor = File.read('lib/version').strip.split('.').first(2).join('.')
124
67
 
@@ -127,7 +70,11 @@ describe 'Gemfile content' do
127
70
  let(:gemfile) { read_generated("#{FrameworkIndex::RSPEC}_#{automation}", 'Gemfile') }
128
71
 
129
72
  it 'includes raider_reporter' do
130
- expect(gemfile).to include("gem 'raider_reporter', '~> 0.12'")
73
+ expect(gemfile).to include("gem 'raider_reporter', '~> 1.0'")
74
+ end
75
+
76
+ it "#{automation == 'selenium' ? 'includes' : 'leaves out'} chunky_png" do
77
+ expect(gemfile.include?("gem 'chunky_png'")).to eq(automation == 'selenium')
131
78
  end
132
79
 
133
80
  it 'has no allure gems' do
@@ -137,21 +84,9 @@ describe 'Gemfile content' do
137
84
  it 'pins ruby_raider to the generator major.minor' do
138
85
  expect(gemfile).to include("gem 'ruby_raider', '~> #{major_minor}'")
139
86
  end
140
- end
141
-
142
- context "with cucumber and #{automation}" do
143
- let(:gemfile) { read_generated("#{FrameworkIndex::CUCUMBER}_#{automation}", 'Gemfile') }
144
-
145
- it 'includes raider_reporter' do
146
- expect(gemfile).to include("gem 'raider_reporter', '~> 0.12'")
147
- end
148
-
149
- it 'drops allure-cucumber' do
150
- expect(gemfile).not_to include('allure')
151
- end
152
87
 
153
- it 'pins ruby_raider to the generator major.minor' do
154
- expect(gemfile).to include("gem 'ruby_raider', '~> #{major_minor}'")
88
+ it 'pins ruby_raider to the 4.0 release line' do
89
+ expect(gemfile).to include("gem 'ruby_raider', '~> 4.0'")
155
90
  end
156
91
  end
157
92
  end
@@ -36,20 +36,34 @@ describe 'Helper file content' do
36
36
  expect(helper).to include("require 'selenium-webdriver'")
37
37
  end
38
38
 
39
- it 'does not require watir' do
40
- expect(helper).not_to include("require 'watir'")
39
+ it 'requires the runtime right after selenium-webdriver' do
40
+ lines = helper.lines.map(&:chomp)
41
+ expect(lines[lines.index("require 'selenium-webdriver'") + 1]).to eq("require 'ruby_raider/runtime'")
41
42
  end
42
43
 
43
44
  it 'does not reference Capybara' do
44
45
  expect(helper).not_to include('Capybara')
45
46
  end
46
47
 
48
+ it 'requires network_helper before trace_helper' do
49
+ expect(helper).to include("require_relative 'network_helper'")
50
+ expect(helper.index("require_relative 'network_helper'")).to be < helper.index("require_relative 'trace_helper'")
51
+ end
52
+
53
+ it 'requires screenshot_helper next to network_helper' do
54
+ expect(helper).to include("require_relative 'screenshot_helper'")
55
+ expect(helper.index("require_relative 'screenshot_helper'")).to be > helper.index("require_relative 'network_helper'")
56
+ expect(helper.index("require_relative 'screenshot_helper'")).to be < helper.index("require_relative 'trace_helper'")
57
+ end
58
+
47
59
  it 'requires trace_helper' do
48
60
  expect(helper).to include("require_relative 'trace_helper'")
49
61
  end
50
62
 
51
63
  it 'sets web_socket_url only for chrome, edge and firefox and not with TRACE=off' do
52
- expect(helper).to include('options.web_socket_url = true if defined?(TraceHelper) && TraceHelper.bidi?(load_browser)')
64
+ expect(helper).to include('bidi = (defined?(TraceHelper) && TraceHelper.bidi?(load_browser)) ||',
65
+ '(defined?(NetworkHelper) && NetworkHelper.bidi?(load_browser))')
66
+ expect(helper).to include('options.web_socket_url = true if bidi')
53
67
  end
54
68
 
55
69
  it 'fans the video and trace listeners out through one listener, each guarded by defined?' do
@@ -77,18 +91,10 @@ describe 'Helper file content' do
77
91
  expect(helper).to match(/module BrowserHelper/)
78
92
  end
79
93
 
80
- it 'requires watir' do
81
- expect(helper).to include("require 'watir'")
82
- end
83
-
84
94
  it 'defines browser method' do
85
95
  expect(helper).to match(/def browser/)
86
96
  end
87
97
 
88
- it 'creates Watir::Browser' do
89
- expect(helper).to include('Watir::Browser.new')
90
- end
91
-
92
98
  it 'does not require selenium-webdriver' do
93
99
  expect(helper).not_to include("require 'selenium-webdriver'")
94
100
  end
@@ -118,6 +124,11 @@ describe 'Helper file content' do
118
124
  it 'configures RSpec' do
119
125
  expect(helper).to include('RSpec.configure')
120
126
  end
127
+
128
+ it 'requires the rspec runtime and includes the Raider matchers and helpers' do
129
+ expect(helper).to include("require 'ruby_raider/runtime/rspec'", 'config.include(Raider::Matchers)',
130
+ 'config.include(Raider::Helpers)')
131
+ end
121
132
  end
122
133
 
123
134
  shared_examples 'raider reporter spec helper' do |project_name, screenshot_call|
@@ -137,7 +148,7 @@ describe 'Helper file content' do
137
148
 
138
149
  it 'screenshots only on failure' do
139
150
  lines = helper.lines
140
- start = lines.index { |line| line.include?('if example.exception') }
151
+ start = lines.index { |line| line.match?(/if (example\.exception|failure)$/) }
141
152
  expect(start).not_to be_nil
142
153
  indent = lines[start][/\A */].size
143
154
  body = lines[(start + 1)..].take_while { |line| line.strip.empty? || line[/\A */].size > indent }
@@ -173,7 +184,7 @@ describe 'Helper file content' do
173
184
  end
174
185
 
175
186
  it 'attaches "video" only when example.exception && VideoHelper.final_attempt?(example)' do
176
- expect(after_hook).to match(/example\.exception\s*(\?|&&)\s*VideoHelper\.final_attempt\?\(example\)/)
187
+ expect(after_hook).to match(/(example\.exception|failure)\s*(\?|&&)\s*VideoHelper\.final_attempt\?\(example\)/)
177
188
  expect(after_hook).to include("RaiderReporter.attach('video', video_path, type: #{video_type}) if video_path")
178
189
  end
179
190
 
@@ -183,7 +194,7 @@ describe 'Helper file content' do
183
194
  after_hook.index(/driver\.quit|browser\.quit/)]
184
195
  expect(order).to all(be_an(Integer)).and eq(order.compact.sort)
185
196
  expect(after_hook.scan(/driver\.quit|browser\.quit/).size).to eq(1)
186
- expect(after_hook[order[2]..]).to match(/\n (@trace_recorder&\.cleanup\n )?@video_recorder&\.cleanup\n (driver|browser)\.quit(_driver)?\n end\n/)
197
+ expect(after_hook[order[2]..]).to match(/\n (@trace_recorder&\.cleanup\n )?@video_recorder&\.cleanup\n (driver|browser)\.quit(_driver)?\n( raise mock_error if mock_error\n)? end\n/)
187
198
  end
188
199
 
189
200
  it 'keeps the screenshot attachment' do
@@ -203,11 +214,12 @@ describe 'Helper file content' do
203
214
  end
204
215
 
205
216
  it 'keeps the trace for TRACE=on or a final-attempt failure, falling back to keeping failures without a video helper' do
206
- expect(after_hook).to include('TraceHelper.keep_all? || (example.exception && (defined?(VideoHelper) ? VideoHelper.final_attempt?(example) : true))')
217
+ expect(after_hook).to match(/TraceHelper\.keep_all\? \|\| \((example\.exception|failure) && \(defined\?\(VideoHelper\) \? VideoHelper\.final_attempt\?\(example\) : true\)\)/)
207
218
  end
208
219
 
209
220
  it 'counts the attempt from the rspec-retry metadata and hands the recorder the test' do
210
- expect(after_hook).to include('example.metadata[:retry_attempts].to_i + 1', 'error: example.exception')
221
+ expect(after_hook).to include('example.metadata[:retry_attempts].to_i + 1')
222
+ expect(after_hook).to match(/error: (example\.exception|failure) \}/)
211
223
  expect(after_hook).to include('@trace_recorder&.stop(keep: keep_trace, test: trace_test)')
212
224
  end
213
225
 
@@ -220,6 +232,32 @@ describe 'Helper file content' do
220
232
  end
221
233
  end
222
234
 
235
+ shared_examples 'network mock after hook' do |project_name|
236
+ subject(:helper) { read_generated(project_name, 'helpers/spec_helper.rb') }
237
+
238
+ let(:after_hook) { helper[/config\.after\(:each\).*\z/m] }
239
+
240
+ it 'finishes the router first and counts a mock error as a failure' do
241
+ expect(after_hook).to include('mock_error = NetworkHelper.finish(driver) if defined?(NetworkHelper)', 'failure = example.exception || mock_error')
242
+ expect(after_hook.index('mock_error = NetworkHelper.finish')).to be < after_hook.index('TraceHelper.keep_all?')
243
+ expect(after_hook).not_to include('example.exception ?', 'error: example.exception')
244
+ end
245
+
246
+ it 'raises the mock error after the driver has quit' do
247
+ expect(after_hook.index('raise mock_error if mock_error')).to be > after_hook.index('driver.quit')
248
+ end
249
+
250
+ it 'is valid Ruby' do
251
+ expect(helper).to have_valid_ruby_syntax
252
+ end
253
+ end
254
+
255
+ shared_examples 'no network mock wiring' do |project_name|
256
+ it 'leaves spec_helper.rb without NetworkHelper' do
257
+ expect(read_generated(project_name, 'helpers/spec_helper.rb')).not_to include('NetworkHelper', 'mock_error')
258
+ end
259
+ end
260
+
223
261
  shared_examples 'no trace wiring' do |project_name, file|
224
262
  it "leaves #{file} without trace code" do
225
263
  expect(read_generated(project_name, file)).not_to match(/trace/i)
@@ -242,22 +280,6 @@ describe 'Helper file content' do
242
280
  end
243
281
  end
244
282
 
245
- shared_examples 'watir spec helper' do |project_name|
246
- subject(:helper) { read_generated(project_name, 'helpers/spec_helper.rb') }
247
-
248
- it 'includes BrowserHelper' do
249
- expect(helper).to include('include(BrowserHelper)')
250
- end
251
-
252
- it 'requires browser_helper' do
253
- expect(helper).to include("require_relative 'browser_helper'")
254
- end
255
-
256
- it 'maximizes window via browser' do
257
- expect(helper).to include('browser.window.maximize')
258
- end
259
- end
260
-
261
283
  # --- Video helper ---
262
284
 
263
285
  shared_examples 'valid video helper' do |project_name|
@@ -348,13 +370,6 @@ describe 'Helper file content' do
348
370
  it_behaves_like 'video listener wiring', name, 'driver_helper.rb'
349
371
  end
350
372
 
351
- context 'with cucumber and watir video' do
352
- name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}"
353
- it_behaves_like 'valid video helper', name
354
- it_behaves_like 'web video helper', name
355
- it_behaves_like 'video listener wiring', name, 'browser_helper.rb'
356
- end
357
-
358
373
  context 'with rspec and ios video' do
359
374
  name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::IOS}"
360
375
  it_behaves_like 'valid video helper', name
@@ -379,55 +394,29 @@ describe 'Helper file content' do
379
394
  it_behaves_like 'selenium spec helper', name
380
395
  end
381
396
 
382
- context 'with rspec and watir' do
383
- name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
384
- it_behaves_like 'valid browser helper', name
385
- it_behaves_like 'valid spec helper', name
386
- it_behaves_like 'watir spec helper', name
387
- end
388
-
389
- # --- Cucumber + automation contexts (no spec_helper/test_helper) ---
390
-
391
- context 'with cucumber and selenium' do
392
- name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
393
- it_behaves_like 'valid driver helper', name
394
- it_behaves_like 'selenium driver helper', name
395
- end
396
-
397
- context 'with cucumber and watir' do
398
- name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}"
399
- it_behaves_like 'valid browser helper', name
400
- end
401
-
402
397
  # --- Raider reporter wiring (every rspec automation) ---
403
398
 
404
399
  AUTOMATION_TYPES.each do |automation|
405
400
  context "with rspec and #{automation} raider reporter wiring" do
406
401
  name = "#{FrameworkIndex::RSPEC}_#{automation}"
407
402
  screenshot_call = {
408
- 'selenium' => 'driver.save_screenshot(screenshot_path)',
409
- 'watir' => 'browser.screenshot.save(screenshot_path)'
403
+ 'selenium' => 'driver.save_screenshot(screenshot_path)'
410
404
  }.fetch(automation, 'driver.screenshot(screenshot_path)')
411
405
  it_behaves_like 'raider reporter spec helper', name, screenshot_call
412
- it_behaves_like 'video spec helper wiring', name, automation == 'watir' ? 'browser' : 'driver',
413
- %w[selenium watir].include?(automation) ? ':webm' : ':mp4'
406
+ it_behaves_like 'video spec helper wiring', name, 'driver', automation == 'selenium' ? ':webm' : ':mp4'
414
407
  if automation == 'selenium'
415
408
  it_behaves_like 'trace spec helper wiring', name
409
+ it_behaves_like 'network mock after hook', name
416
410
  else
417
411
  it_behaves_like 'no trace wiring', name, 'helpers/spec_helper.rb'
418
- end
419
- end
420
-
421
- context "with cucumber and #{automation}" do
422
- it 'does not generate the allure helper' do
423
- expect(File).not_to exist("#{FrameworkIndex::CUCUMBER}_#{automation}/helpers/allure_helper.rb")
412
+ it_behaves_like 'no network mock wiring', name
424
413
  end
425
414
  end
426
415
  end
427
416
 
428
417
  # --- Opt-in login reuse ---
429
418
 
430
- { 'selenium' => 'driver', 'watir' => 'browser.driver' }.each do |automation, target|
419
+ { 'selenium' => 'driver' }.each do |automation, target|
431
420
  context "with rspec and #{automation} login reuse" do
432
421
  subject(:helper) { read_generated("#{FrameworkIndex::RSPEC}_#{automation}", 'helpers/spec_helper.rb') }
433
422
 
@@ -438,7 +427,7 @@ describe 'Helper file content' do
438
427
  it 'reuses the saved login for the driver, falling back to the real login' do
439
428
  expect(helper).to include("SessionState.new(#{target}).reuse(")
440
429
  expect(helper).to include("user = ModelFactory.for('users')['registered user']", ".login(user['username'], user['password'])")
441
- expect(helper).to include("header.customer_name == \"Welcome back \#{user['name']}\"")
430
+ expect(helper).to include("welcome_message.text == \"Welcome back \#{user['name']}\"")
442
431
  end
443
432
 
444
433
  it 'requires the models and pages the login needs' do
@@ -461,15 +450,26 @@ end
461
450
  describe 'Auto-waiting helper wiring' do
462
451
  %w[selenium ios android cross_platform].each do |automation|
463
452
  context "with rspec and #{automation}" do
464
- it 'includes WaitHelper in the spec helper' do
453
+ it 'leaves the wait helper out of the spec helper' do
454
+ helper = read_generated("#{FrameworkIndex::RSPEC}_#{automation}", 'helpers/spec_helper.rb')
455
+ expect(helper).not_to include('wait_helper', 'WaitHelper')
456
+ end
457
+
458
+ it "#{automation == 'selenium' ? 'includes' : 'leaves out'} NetworkHelper in the spec helper" do
465
459
  helper = read_generated("#{FrameworkIndex::RSPEC}_#{automation}", 'helpers/spec_helper.rb')
466
- expect(helper).to include("require_relative 'wait_helper'", 'config.include(WaitHelper)')
460
+ expect(helper.include?('config.include(NetworkHelper)')).to eq(automation == 'selenium')
461
+ end
462
+
463
+ it "#{automation == 'selenium' ? 'includes' : 'leaves out'} ScreenshotHelper in the spec helper" do
464
+ helper = read_generated("#{FrameworkIndex::RSPEC}_#{automation}", 'helpers/spec_helper.rb')
465
+ expect(helper.include?('config.include(ScreenshotHelper)')).to eq(automation == 'selenium')
466
+ expect(helper.include?("require_relative 'screenshot_helper'")).to eq(automation == 'selenium')
467
467
  end
468
468
  end
469
469
  end
470
470
 
471
471
  %w[ios android cross_platform].each do |automation|
472
- %w[rspec cucumber].each do |framework|
472
+ FRAMEWORKS.each do |framework|
473
473
  it "does not pass a wait to appium_lib in #{framework} #{automation}" do
474
474
  driver = read_generated("#{framework}_#{automation}", 'helpers/driver_helper.rb')
475
475
  expect(driver).not_to match(/\bwait:/)
@@ -477,7 +477,7 @@ describe 'Auto-waiting helper wiring' do
477
477
  end
478
478
  end
479
479
 
480
- %w[rspec cucumber].each do |framework|
480
+ FRAMEWORKS.each do |framework|
481
481
  it "returns the new driver without a redundant assignment in #{framework} selenium" do
482
482
  driver = read_generated("#{framework}_selenium", 'helpers/driver_helper.rb')
483
483
  expect(driver).to include(" Selenium::WebDriver.for(browser.to_sym, **arguments)\n end")
@@ -488,14 +488,6 @@ describe 'Auto-waiting helper wiring' do
488
488
  driver = read_generated("#{framework}_selenium", 'helpers/driver_helper.rb')
489
489
  expect(driver).not_to include('implicit_wait')
490
490
  end
491
-
492
- it "keeps Watir untouched in #{framework} watir" do
493
- project = "#{framework}_watir"
494
- expect(File.exist?(File.join(project, 'helpers/wait_helper.rb'))).to be(false)
495
- expect(read_generated(project, 'helpers/browser_helper.rb')).to include('Watir.default_timeout')
496
- files = Dir.glob(File.join(project, '**/*.rb')).map { |f| File.read(f) }
497
- expect(files.grep(/WaitHelper/)).to be_empty
498
- end
499
491
  end
500
492
 
501
493
  describe 'without example tests' do
@@ -511,22 +503,6 @@ describe 'Auto-waiting helper wiring' do
511
503
  expect(helper).to have_valid_ruby_syntax
512
504
  end
513
505
  end
514
-
515
- context "with cucumber and #{automation}" do
516
- let(:name) { ensure_project(framework: 'cucumber', automation:, examples: false) }
517
-
518
- it 'names no example class or hook in the env and the World' do
519
- %w[env.rb world.rb].each do |file|
520
- expect(read_generated(name, "features/support/#{file}")).not_to match(/Login|Account|logged_in|factory/)
521
- end
522
- end
523
-
524
- it 'has a valid env and World' do
525
- %w[env.rb world.rb].each do |file|
526
- expect(read_generated(name, "features/support/#{file}")).to have_valid_ruby_syntax
527
- end
528
- end
529
- end
530
506
  end
531
507
 
532
508
  it 'keeps the session state require in the selenium rspec spec helper' do
@@ -536,3 +512,33 @@ describe 'Auto-waiting helper wiring' do
536
512
  end
537
513
  end
538
514
  end
515
+
516
+ describe 'ScreenshotHelper reset between tests' do
517
+ it 'resets in the RSpec before(:each) of Selenium web projects only' do
518
+ selenium = read_generated('rspec_selenium', 'helpers/spec_helper.rb')
519
+ expect(selenium[/config\.before\(:each\) do.*?^ end$/m]).to include('ScreenshotHelper.reset')
520
+ %w[rspec_ios rspec_android].each do |project|
521
+ expect(read_generated(project, 'helpers/spec_helper.rb')).not_to include('ScreenshotHelper')
522
+ end
523
+ end
524
+ end
525
+
526
+ describe 'Runtime wiring in generated helpers' do
527
+ { 'selenium' => "require 'selenium-webdriver'", 'ios' => "require 'appium_lib'",
528
+ 'android' => "require 'appium_lib'", 'cross_platform' => "require 'appium_lib'" }.each do |automation, anchor|
529
+ context "with rspec and #{automation}" do
530
+ let(:name) { "#{FrameworkIndex::RSPEC}_#{automation}" }
531
+
532
+ it "requires the runtime right after #{anchor}" do
533
+ lines = read_generated(name, 'helpers/driver_helper.rb').lines.map(&:chomp)
534
+ expect(lines[lines.index(anchor) + 1]).to eq("require 'ruby_raider/runtime'")
535
+ end
536
+
537
+ it 'requires the rspec runtime and includes the matchers and helpers in spec_helper' do
538
+ expect(read_generated(name, 'helpers/spec_helper.rb'))
539
+ .to include("require 'ruby_raider/runtime/rspec'", 'config.include(Raider::Matchers)',
540
+ 'config.include(Raider::Helpers)')
541
+ end
542
+ end
543
+ end
544
+ end