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
@@ -340,15 +340,6 @@ describe 'Generated VideoHelper' do
340
340
  expect(warnings).to eq(["[video] first reason; recording disabled for this run\n"])
341
341
  end
342
342
 
343
- it 'records frames of a Watir browser through its Selenium driver' do
344
- browser = double('browser', wd: driver)
345
- recorder = VideoHelper.recorder_for(browser)
346
- recorder.start
347
-
348
- expect(recorder.stop(keep: true)).to end_with('video.webm')
349
- expect(shots.size).to eq(1)
350
- end
351
-
352
343
  context 'when the ruby_raider gem has no ffmpeg support' do
353
344
  it 'disables video with an update hint' do
354
345
  allow(VideoHelper).to receive(:require).with('ruby_raider/ffmpeg').and_raise(LoadError)
@@ -113,12 +113,4 @@ describe 'Browser update after framework creation' do
113
113
  context 'with selenium + rspec' do
114
114
  include_examples 'updates browser config after creation', 'rspec', 'selenium'
115
115
  end
116
-
117
- context 'with selenium + cucumber' do
118
- include_examples 'updates browser config after creation', 'cucumber', 'selenium'
119
- end
120
-
121
- context 'with watir + rspec' do
122
- include_examples 'updates browser config after creation', 'rspec', 'watir'
123
- end
124
116
  end
@@ -48,62 +48,24 @@ describe ScaffoldingCommands do
48
48
  scaffold.new.invoke(:spec, nil, %W[#{name} --path #{new_path}])
49
49
  expect(Pathname.new("#{new_path}/#{name}_spec.rb")).to be_file
50
50
  end
51
- end
52
-
53
- context 'with a features folder' do
54
- let(:new_path) { 'test_folder' }
55
-
56
- path = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
57
-
58
- before do
59
- Dir.chdir path
60
- end
61
-
62
- it 'scaffolds for cucumber creating a feature' do
63
- scaffold.new.invoke(:scaffold, nil, %W[#{name}])
64
- expect(Pathname.new("features/#{name}.feature")).to be_file
65
- end
66
-
67
- it 'scaffolds for cucumber creating a page' do
68
- scaffold.new.invoke(:scaffold, nil, %W[#{name}])
69
- expect(Pathname.new("page_objects/pages/#{name}.rb")).to be_file
70
- end
71
-
72
- it 'scaffolds for cucumber creating a steps definition' do
73
- scaffold.new.invoke(:scaffold, nil, %W[#{name}])
74
- expect(Pathname.new("features/step_definitions/#{name}_steps.rb")).to be_file
75
- end
76
51
 
77
52
  it 'creates a helper' do
78
53
  scaffold.new.invoke(:helper, nil, %W[#{name}])
79
54
  expect(Pathname.new("helpers/#{name}_helper.rb")).to be_file
80
55
  end
81
56
 
82
- it 'creates a steps definition' do
83
- scaffold.new.invoke(:steps, nil, %W[#{name}])
84
- expect(Pathname.new("features/step_definitions/#{name}_steps.rb")).to be_file
85
- end
86
-
87
- it 'creates a feature' do
88
- scaffold.new.invoke(:feature, nil, %W[#{name} --path #{new_path}])
89
- expect(Pathname.new("#{new_path}/#{name}.feature")).to be_file
90
- end
91
-
92
57
  it 'creates a helper with a path' do
93
58
  scaffold.new.invoke(:helper, nil, %W[#{name} --path #{new_path}])
94
59
  expect(Pathname.new("#{new_path}/#{name}_helper.rb")).to be_file
95
60
  end
96
61
  end
97
62
 
98
- describe 'waiting examples' do
99
- let(:tmp_dir) { 'tmp_scaffold_wait_helper_test' }
100
- let(:selenium_example) { "driver.find_element(id: 'element_id')" }
101
- let(:waiting_example) { "click({ id: 'element_id' })" }
63
+ describe 'selenium examples' do
64
+ let(:tmp_dir) { 'tmp_scaffold_examples_test' }
102
65
 
103
- def scaffold_in_project(gem_name, kind, wait_helper:)
104
- FileUtils.mkdir_p("#{tmp_dir}/helpers")
105
- File.write("#{tmp_dir}/Gemfile", "gem 'rspec'\ngem '#{gem_name}'\n")
106
- File.write("#{tmp_dir}/helpers/wait_helper.rb", '') if wait_helper
66
+ def scaffold_in_project(kind)
67
+ FileUtils.mkdir_p(tmp_dir)
68
+ File.write("#{tmp_dir}/Gemfile", "gem 'rspec'\ngem 'selenium-webdriver'\n")
107
69
  Dir.chdir(tmp_dir) { scaffold.new.invoke(kind, nil, %w[foo]) }
108
70
  end
109
71
 
@@ -112,35 +74,15 @@ describe ScaffoldingCommands do
112
74
  FileUtils.rm_rf(tmp_dir)
113
75
  end
114
76
 
115
- it 'shows the waiting example in a page when the project has the wait helper' do
116
- scaffold_in_project('selenium-webdriver', :page, wait_helper: true)
117
- content = File.read("#{tmp_dir}/page_objects/pages/foo.rb")
118
- expect(content).to include(waiting_example)
119
- expect(content).not_to include(selenium_example)
120
- end
121
-
122
- it 'keeps the driver example in a page without the wait helper' do
123
- scaffold_in_project('selenium-webdriver', :page, wait_helper: false)
124
- content = File.read("#{tmp_dir}/page_objects/pages/foo.rb")
125
- expect(content).to include(selenium_example)
126
- expect(content).not_to include(waiting_example)
127
- end
128
-
129
- it 'shows the waiting example in a component when the project has the wait helper' do
130
- scaffold_in_project('selenium-webdriver', :component, wait_helper: true)
131
- expect(File.read("#{tmp_dir}/page_objects/components/foo.rb")).to include("component.find_element(css: '.selector').click")
132
- end
133
-
134
- it 'keeps the driver example in a component without the wait helper' do
135
- scaffold_in_project('selenium-webdriver', :component, wait_helper: false)
136
- expect(File.read("#{tmp_dir}/page_objects/components/foo.rb")).to include("driver.find_element(css: '.selector')")
77
+ it 'shows the by_role example in a page' do
78
+ scaffold_in_project(:page)
79
+ expect(File.read("#{tmp_dir}/page_objects/pages/foo.rb"))
80
+ .to include("# Example: def submit_button = driver.find_element(by_role('button', name: 'Submit'))")
137
81
  end
138
82
 
139
- it 'leaves Watir output unchanged even with a wait helper present' do
140
- scaffold_in_project('watir', :page, wait_helper: true)
141
- content = File.read("#{tmp_dir}/page_objects/pages/foo.rb")
142
- expect(content).to include("browser.text_field(id: 'element_id')")
143
- expect(content).not_to include(waiting_example)
83
+ it 'shows the component example in a component' do
84
+ scaffold_in_project(:component)
85
+ expect(File.read("#{tmp_dir}/page_objects/components/foo.rb")).to include("# Example: component.find_element(css: '.selector').click")
144
86
  end
145
87
  end
146
88
  end
@@ -48,66 +48,44 @@ describe UtilityCommands do
48
48
  config = YAML.load_file('config/config.yml')
49
49
  expect(config['browser_arguments']['firefox']).to eql %w[headless start-maximized start-fullscreen]
50
50
  end
51
- end
52
-
53
- context 'with timeout and viewport commands' do
54
- path = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
55
51
 
56
- before do
57
- Dir.chdir path
52
+ it 'changes the path for pages' do
53
+ utility.new.invoke(:path, nil, %W[#{path}])
54
+ config = YAML.load_file('config/config.yml')
55
+ expect(config['page_path']).to eql path
58
56
  end
59
57
 
60
- it 'updates the timeout' do
61
- utility.new.invoke(:timeout, nil, %w[30])
58
+ it 'deletes the browser arguments when passed with the delete parameter' do
59
+ utility.new.invoke(:browser, nil, %w[:firefox --opts headless --delete])
62
60
  config = YAML.load_file('config/config.yml')
63
- expect(config['timeout']).to eq 30
61
+ expect(config.dig('browser_arguments', 'firefox')).to eq([])
64
62
  end
65
63
 
66
- it 'updates the viewport' do
67
- utility.new.invoke(:viewport, nil, %w[375x812])
64
+ it 'deletes the browser arguments' do
65
+ utility.new.invoke(:browser, nil, %w[:firefox --opts headless])
66
+ utility.new.invoke(:browser, nil, %w[--delete])
68
67
  config = YAML.load_file('config/config.yml')
69
- expect(config['viewport']).to eq({ 'width' => 375, 'height' => 812 })
68
+ expect(config.dig('browser_arguments', 'firefox')).to eq([])
70
69
  end
71
70
  end
72
71
 
73
- context 'with a features folder' do
74
- let(:new_path) { 'test_folder' }
75
-
76
- path = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
72
+ context 'with timeout and viewport commands' do
73
+ path = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
77
74
 
78
75
  before do
79
76
  Dir.chdir path
80
77
  end
81
78
 
82
- it 'changes the path for pages' do
83
- utility.new.invoke(:path, nil, %W[#{path}])
84
- config = YAML.load_file('config/config.yml')
85
- expect(config['page_path']).to eql path
86
- end
87
-
88
- it 'changes the path for features' do
89
- utility.new.invoke(:path, nil, %W[#{path} -f])
90
- config = YAML.load_file('config/config.yml')
91
- expect(config['feature_path']).to eql path
92
- end
93
-
94
- it 'updates the browser arguments for the current browser' do
95
- utility.new.invoke(:browser, nil, %w[:firefox --opts headless])
96
- config = YAML.load_file('config/config.yml')
97
- expect(config['browser_arguments']['firefox']).to eql %w[headless]
98
- end
99
-
100
- it 'deletes the browser arguments when passed with the delete parameter' do
101
- utility.new.invoke(:browser, nil, %w[:firefox --opts headless --delete])
79
+ it 'updates the timeout' do
80
+ utility.new.invoke(:timeout, nil, %w[30])
102
81
  config = YAML.load_file('config/config.yml')
103
- expect(config.dig('browser_arguments', 'firefox')).to eq([])
82
+ expect(config['timeout']).to eq 30
104
83
  end
105
84
 
106
- it 'deletes the browser arguments' do
107
- utility.new.invoke(:browser, nil, %w[:firefox --opts headless])
108
- utility.new.invoke(:browser, nil, %w[--delete])
85
+ it 'updates the viewport' do
86
+ utility.new.invoke(:viewport, nil, %w[375x812])
109
87
  config = YAML.load_file('config/config.yml')
110
- expect(config.dig('browser_arguments', 'firefox')).to eq([])
88
+ expect(config['viewport']).to eq({ 'width' => 375, 'height' => 812 })
111
89
  end
112
90
  end
113
91
 
@@ -8,7 +8,7 @@ require_relative '../../../lib/ruby_raider/ffmpeg'
8
8
  # UseRubyVersion@0 versionSpec '3.4' resolves against the hosted tool cache, which lists Ruby 3.4.x
9
9
  # (3.2, 3.3, 3.4, 4.0): https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md
10
10
  describe 'Azure Pipelines content' do
11
- combos = FRAMEWORKS.product(%w[selenium watir], [false, true])
11
+ combos = FRAMEWORKS.product(%w[selenium], [false, true])
12
12
 
13
13
  before(:all) do # rubocop:disable RSpec/BeforeAfterAll
14
14
  combos.each do |framework, automation, axe|
@@ -27,11 +27,7 @@ describe 'Azure Pipelines content' do
27
27
  let(:raw) { read_generated(name, 'azure-pipelines.yml') }
28
28
  let(:yml) { YAML.safe_load(raw) }
29
29
  let(:run_command) do
30
- if framework == 'cucumber'
31
- 'bundle exec raider-reporter exec -- bundle exec cucumber features/ --format pretty'
32
- else
33
- 'bundle exec raider-reporter exec -- bundle exec rspec spec/ --format documentation'
34
- end
30
+ 'bundle exec raider-reporter exec -- bundle exec rspec spec/ --format documentation'
35
31
  end
36
32
 
37
33
  it 'has a tests job with ruby, bundle install, run command and an always-published artifact' do
@@ -37,14 +37,6 @@ describe 'CI pipeline content' do
37
37
  end
38
38
  end
39
39
 
40
- shared_examples 'github cucumber pipeline' do |project_name|
41
- subject(:pipeline) { read_generated(project_name, '.github/workflows/test_pipeline.yml') }
42
-
43
- it 'runs cucumber' do
44
- expect(pipeline).to include('cucumber')
45
- end
46
- end
47
-
48
40
  shared_examples 'github triggers' do |project_name, file|
49
41
  subject(:pipeline) { read_generated(project_name, ".github/workflows/#{file}") }
50
42
 
@@ -257,42 +249,6 @@ describe 'CI pipeline content' do
257
249
  include_examples 'github without allure steps', name
258
250
  end
259
251
 
260
- context 'with cucumber and selenium' do
261
- name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
262
- include_examples 'github ffmpeg cache', name, 'test_pipeline.yml', %w[build], 'cucumber'
263
- include_examples 'valid github pipeline', name
264
- include_examples 'github cucumber pipeline', name
265
- include_examples 'github triggers', name, 'test_pipeline.yml'
266
- include_examples 'github raider wiring', name, 'test_pipeline.yml', 'cucumber'
267
- include_examples 'github raider-comment job', name, 'test_pipeline.yml', %w[build]
268
- include_examples 'github raider-gate job', name, 'test_pipeline.yml', %w[build]
269
- include_examples 'github without allure steps', name
270
- end
271
-
272
- context 'with rspec and watir' do
273
- name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
274
- include_examples 'github ffmpeg cache', name, 'test_pipeline.yml', %w[build]
275
- include_examples 'valid github pipeline', name
276
- include_examples 'github rspec pipeline', name
277
- include_examples 'github triggers', name, 'test_pipeline.yml'
278
- include_examples 'github raider wiring', name, 'test_pipeline.yml'
279
- include_examples 'github raider-comment job', name, 'test_pipeline.yml', %w[build]
280
- include_examples 'github raider-gate job', name, 'test_pipeline.yml', %w[build]
281
- include_examples 'github without allure steps', name
282
- end
283
-
284
- context 'with cucumber and watir' do
285
- name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}"
286
- include_examples 'github ffmpeg cache', name, 'test_pipeline.yml', %w[build], 'cucumber'
287
- include_examples 'valid github pipeline', name
288
- include_examples 'github cucumber pipeline', name
289
- include_examples 'github triggers', name, 'test_pipeline.yml'
290
- include_examples 'github raider wiring', name, 'test_pipeline.yml', 'cucumber'
291
- include_examples 'github raider-comment job', name, 'test_pipeline.yml', %w[build]
292
- include_examples 'github raider-gate job', name, 'test_pipeline.yml', %w[build]
293
- include_examples 'github without allure steps', name
294
- end
295
-
296
252
  appium_jobs = { 'android' => %w[android-tests], 'ios' => %w[ios-tests],
297
253
  'cross_platform' => %w[ios-tests android-tests] }
298
254
 
@@ -308,20 +264,10 @@ describe 'CI pipeline content' do
308
264
  include_examples 'github triggers', name, 'appium_pipeline.yml'
309
265
  include_examples 'github raider wiring', name, 'appium_pipeline.yml'
310
266
  end
311
-
312
- context "with cucumber and #{automation}" do
313
- name = "#{FrameworkIndex::CUCUMBER}_#{automation}"
314
- include_examples 'github appium shards', name, 'cucumber', appium_shards[automation]
315
- include_examples 'github ffmpeg cache', name, 'appium_pipeline.yml', test_jobs, 'cucumber'
316
- include_examples 'github triggers', name, 'appium_pipeline.yml'
317
- include_examples 'github raider wiring', name, 'appium_pipeline.yml', 'cucumber'
318
- include_examples 'github raider-comment job', name, 'appium_pipeline.yml', test_jobs
319
- include_examples 'github raider-gate job', name, 'appium_pipeline.yml', test_jobs
320
- end
321
267
  end
322
268
 
323
269
  context 'with the saved login state' do
324
- workflows = FRAMEWORKS.product(%w[selenium watir]).map { |f, a| ["#{f}_#{a}", 'test_pipeline.yml'] } +
270
+ workflows = FRAMEWORKS.product(%w[selenium]).map { |f, a| ["#{f}_#{a}", 'test_pipeline.yml'] } +
325
271
  FRAMEWORKS.product(%w[android ios cross_platform]).map { |f, a| ["#{f}_#{a}", 'appium_pipeline.yml'] }
326
272
 
327
273
  workflows.each do |name, file|
@@ -37,40 +37,6 @@ describe 'Common file content' do
37
37
  it 'sets default task to spec' do
38
38
  expect(rakefile).to include('task default: :spec')
39
39
  end
40
-
41
- it 'does not include cucumber tasks' do
42
- expect(rakefile).not_to include('Cucumber::Rake::Task')
43
- end
44
- end
45
-
46
- shared_examples 'cucumber rakefile with tag tasks' do |project_name|
47
- subject(:rakefile) { read_generated(project_name, 'Rakefile') }
48
-
49
- it 'requires cucumber/rake/task' do
50
- expect(rakefile).to include("require 'cucumber/rake/task'")
51
- end
52
-
53
- it 'defines features task' do
54
- expect(rakefile).to include('Rake::Task.new(:features)')
55
- end
56
-
57
- it 'defines smoke task' do
58
- expect(rakefile).to include('Rake::Task.new(:smoke)')
59
- expect(rakefile).to include("'--tags @smoke'")
60
- end
61
-
62
- it 'defines regression task' do
63
- expect(rakefile).to include('Rake::Task.new(:regression)')
64
- expect(rakefile).to include("'--tags @regression'")
65
- end
66
-
67
- it 'sets default task to features' do
68
- expect(rakefile).to include('task default: :features')
69
- end
70
-
71
- it 'does not include rspec tasks' do
72
- expect(rakefile).not_to include('RSpec::Core::RakeTask')
73
- end
74
40
  end
75
41
 
76
42
  # --- .rspec file ---
@@ -95,12 +61,6 @@ describe 'Common file content' do
95
61
  end
96
62
  end
97
63
 
98
- shared_examples 'no rspec dotfile' do |project_name|
99
- it 'does not have .rspec file' do
100
- expect(File).not_to exist(File.join(project_name, '.rspec'))
101
- end
102
- end
103
-
104
64
  # --- .gitignore ---
105
65
 
106
66
  shared_examples 'rspec gitignore' do |project_name|
@@ -119,26 +79,6 @@ describe 'Common file content' do
119
79
  end
120
80
  end
121
81
 
122
- shared_examples 'non-rspec gitignore' do |project_name|
123
- subject(:gitignore) { read_generated(project_name, '.gitignore') }
124
-
125
- it 'does not include allure-results' do
126
- expect(gitignore).not_to include('allure-results')
127
- end
128
-
129
- it 'does not include spec/examples.txt' do
130
- expect(gitignore).not_to include('spec/examples.txt')
131
- end
132
-
133
- it 'includes raider-results' do
134
- expect(gitignore).to include('raider-results')
135
- end
136
-
137
- it 'includes rerun.txt' do
138
- expect(gitignore).to include('rerun.txt')
139
- end
140
- end
141
-
142
82
  shared_examples 'web gitignore for saved logins' do |project_name|
143
83
  subject(:lines) { read_generated(project_name, '.gitignore').lines.map(&:strip) }
144
84
 
@@ -190,28 +130,6 @@ describe 'Common file content' do
190
130
  end
191
131
  end
192
132
 
193
- shared_examples 'gemfile without rspec-retry' do |project_name|
194
- subject(:gemfile) { read_generated(project_name, 'Gemfile') }
195
-
196
- it 'does not include rspec-retry gem' do
197
- expect(gemfile).not_to include("gem 'rspec-retry'")
198
- end
199
- end
200
-
201
- # --- Cucumber retry config (C4) ---
202
-
203
- shared_examples 'cucumber config with retry' do |project_name|
204
- subject(:cucumber_yml) { read_generated(project_name, 'cucumber.yml') }
205
-
206
- it 'includes --retry flag' do
207
- expect(cucumber_yml).to include('--retry')
208
- end
209
-
210
- it 'writes failed scenarios to rerun.txt for Re-run Failed' do
211
- expect(cucumber_yml).to include('--format rerun --out rerun.txt')
212
- end
213
- end
214
-
215
133
  # --- RSpec contexts ---
216
134
 
217
135
  context 'with rspec and selenium' do
@@ -225,43 +143,8 @@ describe 'Common file content' do
225
143
  it_behaves_like 'web gitignore for saved logins', name
226
144
  end
227
145
 
228
- context 'with rspec and watir' do
229
- name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
230
- it_behaves_like 'valid rakefile', name
231
- it_behaves_like 'rspec rakefile with tag tasks', name
232
- it_behaves_like 'has rspec dotfile', name
233
- it_behaves_like 'rspec gitignore', name
234
- it_behaves_like 'spec helper with retry config', name
235
- it_behaves_like 'gemfile with rspec-retry', name
236
- it_behaves_like 'web gitignore for saved logins', name
237
- end
238
-
239
- # --- Cucumber contexts ---
240
-
241
- context 'with cucumber and selenium' do
242
- name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
243
- it_behaves_like 'valid rakefile', name
244
- it_behaves_like 'cucumber rakefile with tag tasks', name
245
- it_behaves_like 'no rspec dotfile', name
246
- it_behaves_like 'non-rspec gitignore', name
247
- it_behaves_like 'gemfile without rspec-retry', name
248
- it_behaves_like 'cucumber config with retry', name
249
- it_behaves_like 'web gitignore for saved logins', name
250
- end
251
-
252
- context 'with cucumber and watir' do
253
- name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}"
254
- it_behaves_like 'valid rakefile', name
255
- it_behaves_like 'cucumber rakefile with tag tasks', name
256
- it_behaves_like 'no rspec dotfile', name
257
- it_behaves_like 'non-rspec gitignore', name
258
- it_behaves_like 'gemfile without rspec-retry', name
259
- it_behaves_like 'cucumber config with retry', name
260
- it_behaves_like 'web gitignore for saved logins', name
261
- end
262
-
263
146
  %w[android ios cross_platform].each do |automation|
264
- %w[rspec cucumber].each do |framework|
147
+ FRAMEWORKS.each do |framework|
265
148
  context "with #{framework} and #{automation}" do
266
149
  it_behaves_like 'mobile gitignore without saved logins', "#{framework}_#{automation}"
267
150
  end
@@ -75,6 +75,23 @@ describe 'Config file content' do
75
75
  end
76
76
  end
77
77
 
78
+ shared_examples 'screenshots config' do |project_name|
79
+ it 'has the screenshots block between trace and login_state' do
80
+ raw = read_generated(project_name, 'config/config.yml')
81
+ config = YAML.safe_load(raw, permitted_classes: [Symbol])
82
+ expect(config['screenshots']).to eq('threshold' => 0.2, 'max_diff_pixels' => 0)
83
+ expect(raw).to include('# max_diff_ratio: 0.001')
84
+ expect(raw.index('screenshots:')).to be > raw.index('trace:')
85
+ expect(raw.index('screenshots:')).to be < raw.index('login_state:')
86
+ end
87
+ end
88
+
89
+ shared_examples 'no screenshots config' do |project_name|
90
+ it 'has no screenshots block' do
91
+ expect(read_generated(project_name, 'config/config.yml')).not_to include('screenshots')
92
+ end
93
+ end
94
+
78
95
  shared_examples 'login state config' do |project_name|
79
96
  it 'has a login_state max_age of an hour' do
80
97
  config = YAML.safe_load(read_generated(project_name, 'config/config.yml'), permitted_classes: [Symbol])
@@ -90,22 +107,7 @@ describe 'Config file content' do
90
107
  include_examples 'selenium config with timeout', name
91
108
  include_examples 'video config', name
92
109
  include_examples 'trace config', name
93
- include_examples 'login state config', name
94
- end
95
-
96
- context 'with rspec and watir' do
97
- name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
98
- include_examples 'valid web config', name
99
- include_examples 'config without driver_options', name
100
- include_examples 'no trace config', name
101
- include_examples 'login state config', name
102
- end
103
-
104
- context 'with cucumber and selenium' do
105
- name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
106
- include_examples 'valid web config', name
107
- include_examples 'selenium config with timeout', name
108
- include_examples 'trace config', name
110
+ include_examples 'screenshots config', name
109
111
  include_examples 'login state config', name
110
112
  end
111
113
 
@@ -132,7 +134,7 @@ describe 'Config file content' do
132
134
  end
133
135
 
134
136
  # appium_lib connects to http://127.0.0.1:4723 and ignores a url capability, so none is generated.
135
- %w[rspec cucumber].product(%w[android ios cross_platform]).each do |framework, automation|
137
+ FRAMEWORKS.product(%w[android ios cross_platform]).each do |framework, automation|
136
138
  it "has no unused url capability or /wd/hub path in #{framework} #{automation} capabilities" do
137
139
  caps = read_generated("#{framework}_#{automation}", 'config/capabilities.yml')
138
140
  local = caps.split(/^browserstack:/).first
@@ -158,8 +160,8 @@ describe 'Config file content' do
158
160
  end
159
161
 
160
162
  describe 'Config timeout wiring' do
161
- %w[rspec cucumber].each do |framework|
162
- # Single-platform Appium projects have no config.yml; WaitHelper falls back to its default of 10.
163
+ FRAMEWORKS.each do |framework|
164
+ # Single-platform Appium projects have no config.yml; the runtime falls back to its default of 10.
163
165
  %w[selenium cross_platform].each do |automation|
164
166
  it "sets timeout 10 in #{framework} #{automation}" do
165
167
  config = YAML.safe_load(read_generated("#{framework}_#{automation}", 'config/config.yml'), permitted_classes: [Symbol])
@@ -168,18 +170,19 @@ describe 'Config timeout wiring' do
168
170
  end
169
171
  end
170
172
 
171
- it 'describes the selenium timeout as an action and eventually wait' do
172
- expect(read_generated('rspec_selenium', 'config/config.yml'))
173
- .to include('# seconds that actions and eventually wait before failing')
174
- end
173
+ config_lines = [
174
+ 'timeout: 10 # seconds that finds, actions and assertions wait before failing',
175
+ 'strict: true # find_element fails when a locator matches more than one element; find_elements never does',
176
+ 'actionability: true # actions wait until the element is ready (visible, enabled, stable, receives events; ' \
177
+ 'on native apps visible and enabled); force: true skips it'
178
+ ].freeze
175
179
 
176
- it 'describes the mobile timeout as an action and eventually wait' do
177
- expect(read_generated('rspec_cross_platform', 'config/config.yml'))
178
- .to include('timeout: 10 # seconds that actions and eventually wait before failing')
179
- end
180
-
181
- it 'leaves the watir timeout comment unchanged' do
182
- expect(read_generated('rspec_watir', 'config/config.yml'))
183
- .to include('timeout: 10 # seconds — used for implicit waits and max wait time')
180
+ %w[rspec_selenium rspec_cross_platform].each do |project|
181
+ it "writes timeout, strict and actionability in order in #{project}" do
182
+ lines = read_generated(project, 'config/config.yml').lines.map(&:chomp)
183
+ start = lines.index(config_lines.first)
184
+ expect(start).not_to be_nil
185
+ expect(lines[start, 3]).to eq(config_lines)
186
+ end
184
187
  end
185
188
  end