ruby_raider 2.0.0 → 3.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 (224) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/e2e_tests.yml +58 -0
  3. data/.github/workflows/steep.yml +21 -0
  4. data/.gitignore +1 -1
  5. data/.reek.yml +46 -4
  6. data/.ruby-version +1 -1
  7. data/README.md +138 -77
  8. data/Steepfile +22 -0
  9. data/assets/ruby_raider_logo.svg +51 -0
  10. data/lib/adopter/adopt_menu.rb +11 -15
  11. data/lib/adopter/converters/base_converter.rb +1 -2
  12. data/lib/adopter/converters/identity_converter.rb +3 -6
  13. data/lib/adopter/migration_plan.rb +0 -1
  14. data/lib/adopter/plan_builder.rb +2 -5
  15. data/lib/adopter/project_analyzer.rb +1 -5
  16. data/lib/adopter/project_detector.rb +3 -5
  17. data/lib/commands/adopt_commands.rb +0 -1
  18. data/lib/commands/plugin_commands.rb +0 -2
  19. data/lib/commands/scaffolding_commands.rb +220 -37
  20. data/lib/commands/utility_commands.rb +82 -2
  21. data/lib/generators/automation/automation_generator.rb +0 -7
  22. data/lib/generators/automation/templates/partials/element.tt +1 -1
  23. data/lib/generators/automation/templates/partials/initialize_selector.tt +0 -7
  24. data/lib/generators/automation/templates/partials/url_methods.tt +0 -1
  25. data/lib/generators/common_generator.rb +12 -0
  26. data/lib/generators/cucumber/cucumber_generator.rb +36 -0
  27. data/lib/generators/cucumber/templates/accessibility_feature.tt +5 -0
  28. data/lib/generators/cucumber/templates/accessibility_steps.tt +21 -0
  29. data/lib/generators/cucumber/templates/cucumber.tt +8 -1
  30. data/lib/generators/cucumber/templates/feature.tt +0 -4
  31. data/lib/generators/cucumber/templates/partials/appium_env.tt +5 -0
  32. data/lib/generators/cucumber/templates/partials/capybara_env.tt +19 -1
  33. data/lib/generators/cucumber/templates/partials/driver_world.tt +1 -4
  34. data/lib/generators/cucumber/templates/partials/selenium_env.tt +22 -35
  35. data/lib/generators/cucumber/templates/partials/watir_env.tt +20 -1
  36. data/lib/generators/cucumber/templates/partials/web_steps.tt +6 -12
  37. data/lib/generators/cucumber/templates/performance_feature.tt +5 -0
  38. data/lib/generators/cucumber/templates/performance_steps.tt +17 -0
  39. data/lib/generators/cucumber/templates/visual_feature.tt +5 -0
  40. data/lib/generators/cucumber/templates/visual_steps.tt +19 -0
  41. data/lib/generators/generator.rb +38 -7
  42. data/lib/generators/helper_generator.rb +24 -7
  43. data/lib/generators/infrastructure/templates/github.tt +1 -1
  44. data/lib/generators/infrastructure/templates/github_appium.tt +2 -2
  45. data/lib/generators/infrastructure/templates/gitlab.tt +1 -1
  46. data/lib/generators/invoke_generators.rb +42 -9
  47. data/lib/generators/menu_generator.rb +120 -11
  48. data/lib/generators/minitest/minitest_generator.rb +16 -4
  49. data/lib/generators/minitest/templates/accessibility_test.tt +26 -0
  50. data/lib/generators/minitest/templates/performance_test.tt +18 -0
  51. data/lib/generators/minitest/templates/test.tt +5 -34
  52. data/lib/generators/minitest/templates/visual_test.tt +23 -0
  53. data/lib/generators/rspec/rspec_generator.rb +16 -4
  54. data/lib/generators/rspec/templates/accessibility_spec.tt +25 -0
  55. data/lib/generators/rspec/templates/performance_spec.tt +18 -0
  56. data/lib/generators/rspec/templates/spec.tt +5 -35
  57. data/lib/generators/rspec/templates/visual_spec.tt +20 -0
  58. data/lib/generators/template_renderer/partial_cache.rb +11 -1
  59. data/lib/generators/template_renderer/partial_resolver.rb +17 -10
  60. data/lib/generators/template_renderer.rb +17 -1
  61. data/lib/generators/templates/common/gemfile.tt +21 -6
  62. data/lib/generators/templates/common/git_ignore.tt +6 -1
  63. data/lib/generators/templates/common/partials/mobile_config.tt +5 -1
  64. data/lib/generators/templates/common/partials/web_config.tt +16 -7
  65. data/lib/generators/templates/common/rakefile.tt +36 -0
  66. data/lib/generators/templates/common/read_me.tt +41 -91
  67. data/lib/generators/templates/common/rspec.tt +3 -0
  68. data/lib/generators/templates/common/ruby_version.tt +1 -0
  69. data/lib/generators/templates/helpers/allure_helper.tt +11 -0
  70. data/lib/generators/templates/helpers/browser_helper.tt +12 -2
  71. data/lib/generators/templates/helpers/capybara_helper.tt +5 -1
  72. data/lib/generators/templates/helpers/debug_helper.tt +190 -0
  73. data/lib/generators/templates/helpers/driver_helper.tt +2 -10
  74. data/lib/generators/templates/helpers/partials/appium_driver.tt +0 -2
  75. data/lib/generators/templates/helpers/partials/debug_diagnostics.tt +7 -0
  76. data/lib/generators/templates/helpers/partials/debug_start.tt +7 -0
  77. data/lib/generators/templates/helpers/partials/driver_and_options.tt +1 -3
  78. data/lib/generators/templates/helpers/partials/selenium_driver.tt +8 -7
  79. data/lib/generators/templates/helpers/partials/video_start.tt +9 -0
  80. data/lib/generators/templates/helpers/partials/video_stop.tt +4 -0
  81. data/lib/generators/templates/helpers/performance_helper.tt +57 -0
  82. data/lib/generators/templates/helpers/spec_helper.tt +57 -8
  83. data/lib/generators/templates/helpers/test_helper.tt +69 -1
  84. data/lib/generators/templates/helpers/video_helper.tt +270 -0
  85. data/lib/generators/templates/helpers/visual_helper.tt +39 -46
  86. data/lib/llm/client.rb +79 -0
  87. data/lib/llm/config.rb +57 -0
  88. data/lib/llm/prompts.rb +84 -0
  89. data/lib/llm/provider.rb +27 -0
  90. data/lib/llm/providers/anthropic_provider.rb +43 -0
  91. data/lib/llm/providers/ollama_provider.rb +56 -0
  92. data/lib/llm/providers/openai_provider.rb +42 -0
  93. data/lib/llm/response_parser.rb +67 -0
  94. data/lib/plugin/plugin.rb +22 -20
  95. data/lib/plugin/plugin_exposer.rb +16 -38
  96. data/lib/ruby_raider.rb +47 -12
  97. data/lib/scaffolding/crud_generator.rb +94 -0
  98. data/lib/scaffolding/dry_run_presenter.rb +16 -0
  99. data/lib/scaffolding/name_normalizer.rb +63 -0
  100. data/lib/scaffolding/page_introspector.rb +45 -0
  101. data/lib/scaffolding/project_detector.rb +72 -0
  102. data/lib/scaffolding/scaffold_menu.rb +103 -0
  103. data/lib/scaffolding/scaffolding.rb +158 -11
  104. data/lib/scaffolding/templates/component.tt +30 -0
  105. data/lib/scaffolding/templates/feature.tt +4 -4
  106. data/lib/scaffolding/templates/helper.tt +15 -1
  107. data/lib/scaffolding/templates/page_from_url.tt +75 -0
  108. data/lib/scaffolding/templates/page_object.tt +50 -1
  109. data/lib/scaffolding/templates/spec.tt +33 -2
  110. data/lib/scaffolding/templates/spec_from_page.tt +31 -0
  111. data/lib/scaffolding/templates/spec_from_url.tt +46 -0
  112. data/lib/scaffolding/templates/steps.tt +17 -5
  113. data/lib/scaffolding/url_analyzer.rb +179 -0
  114. data/lib/utilities/desktop_downloader.rb +177 -0
  115. data/lib/utilities/logo.rb +83 -0
  116. data/lib/utilities/utilities.rb +53 -20
  117. data/lib/version +1 -1
  118. data/ruby_raider.gemspec +1 -0
  119. data/sig/adopter/adopt_menu.rbs +25 -0
  120. data/sig/adopter/converters/base_converter.rbs +23 -0
  121. data/sig/adopter/converters/identity_converter.rbs +16 -0
  122. data/sig/adopter/migration_plan.rbs +34 -0
  123. data/sig/adopter/migrator.rbs +21 -0
  124. data/sig/adopter/plan_builder.rbs +38 -0
  125. data/sig/adopter/project_analyzer.rbs +39 -0
  126. data/sig/adopter/project_detector.rbs +26 -0
  127. data/sig/commands/adopt_commands.rbs +8 -0
  128. data/sig/commands/loaded_commands.rbs +5 -0
  129. data/sig/commands/plugin_commands.rbs +9 -0
  130. data/sig/commands/scaffolding_commands.rbs +28 -0
  131. data/sig/commands/utility_commands.rbs +21 -0
  132. data/sig/generators/automation/automation_generator.rbs +20 -0
  133. data/sig/generators/common_generator.rbs +12 -0
  134. data/sig/generators/cucumber/cucumber_generator.rbs +16 -0
  135. data/sig/generators/generator.rbs +40 -0
  136. data/sig/generators/helper_generator.rbs +18 -0
  137. data/sig/generators/infrastructure/github_generator.rbs +5 -0
  138. data/sig/generators/infrastructure/gitlab_generator.rbs +4 -0
  139. data/sig/generators/invoke_generators.rbs +10 -0
  140. data/sig/generators/menu_generator.rbs +29 -0
  141. data/sig/generators/minitest/minitest_generator.rbs +8 -0
  142. data/sig/generators/rspec/rspec_generator.rbs +8 -0
  143. data/sig/generators/template_renderer/partial_cache.rbs +20 -0
  144. data/sig/generators/template_renderer/partial_resolver.rbs +20 -0
  145. data/sig/generators/template_renderer/template_error.rbs +19 -0
  146. data/sig/generators/template_renderer.rbs +10 -0
  147. data/sig/llm/client.rbs +15 -0
  148. data/sig/llm/config.rbs +20 -0
  149. data/sig/llm/prompts.rbs +8 -0
  150. data/sig/llm/provider.rbs +12 -0
  151. data/sig/llm/providers/anthropic_provider.rbs +16 -0
  152. data/sig/llm/providers/ollama_provider.rbs +18 -0
  153. data/sig/llm/providers/openai_provider.rbs +16 -0
  154. data/sig/llm/response_parser.rbs +13 -0
  155. data/sig/plugin/plugin.rbs +24 -0
  156. data/sig/plugin/plugin_exposer.rbs +20 -0
  157. data/sig/ruby_raider.rbs +15 -0
  158. data/sig/scaffolding/crud_generator.rbs +16 -0
  159. data/sig/scaffolding/dry_run_presenter.rbs +4 -0
  160. data/sig/scaffolding/name_normalizer.rbs +17 -0
  161. data/sig/scaffolding/page_introspector.rbs +14 -0
  162. data/sig/scaffolding/project_detector.rbs +14 -0
  163. data/sig/scaffolding/scaffold_menu.rbs +18 -0
  164. data/sig/scaffolding/scaffolding.rbs +55 -0
  165. data/sig/scaffolding/url_analyzer.rbs +28 -0
  166. data/sig/utilities/desktop_downloader.rbs +23 -0
  167. data/sig/utilities/logger.rbs +13 -0
  168. data/sig/utilities/logo.rbs +16 -0
  169. data/sig/utilities/utilities.rbs +30 -0
  170. data/sig/vendor/thor.rbs +34 -0
  171. data/sig/vendor/tty_prompt.rbs +15 -0
  172. data/spec/adopter/adopt_menu_spec.rb +12 -12
  173. data/spec/adopter/migration_plan_spec.rb +1 -1
  174. data/spec/adopter/migrator_spec.rb +2 -2
  175. data/spec/adopter/project_detector_spec.rb +1 -1
  176. data/spec/commands/raider_commands_spec.rb +129 -0
  177. data/spec/generators/generator_spec.rb +23 -0
  178. data/spec/integration/commands/scaffolding_commands_spec.rb +1 -1
  179. data/spec/integration/commands/utility_commands_spec.rb +23 -3
  180. data/spec/integration/content/ci_content_spec.rb +119 -0
  181. data/spec/integration/content/common_content_spec.rb +288 -0
  182. data/spec/integration/content/config_content_spec.rb +175 -0
  183. data/spec/integration/content/content_helper.rb +32 -0
  184. data/spec/integration/content/gemfile_content_spec.rb +209 -0
  185. data/spec/integration/content/helper_content_spec.rb +485 -0
  186. data/spec/integration/content/page_content_spec.rb +259 -0
  187. data/spec/integration/content/reporter_content_spec.rb +236 -0
  188. data/spec/integration/content/skip_flags_content_spec.rb +206 -0
  189. data/spec/integration/content/syntax_validation_spec.rb +30 -0
  190. data/spec/integration/content/test_content_spec.rb +266 -0
  191. data/spec/integration/end_to_end_features_spec.rb +690 -0
  192. data/spec/integration/end_to_end_spec.rb +52 -16
  193. data/spec/integration/generators/automation_generator_spec.rb +0 -12
  194. data/spec/integration/generators/axe_addon_spec.rb +150 -0
  195. data/spec/integration/generators/common_generator_spec.rb +12 -13
  196. data/spec/integration/generators/config_features_spec.rb +155 -0
  197. data/spec/integration/generators/debug_helper_spec.rb +68 -0
  198. data/spec/integration/generators/helpers_generator_spec.rb +0 -12
  199. data/spec/integration/generators/lighthouse_addon_spec.rb +132 -0
  200. data/spec/integration/generators/minitest_generator_spec.rb +0 -6
  201. data/spec/integration/generators/reporter_spec.rb +159 -0
  202. data/spec/integration/generators/skip_flags_spec.rb +134 -0
  203. data/spec/integration/generators/visual_addon_spec.rb +148 -0
  204. data/spec/integration/settings_helper.rb +0 -3
  205. data/spec/integration/spec_helper.rb +30 -13
  206. data/spec/llm/client_spec.rb +79 -0
  207. data/spec/llm/config_spec.rb +92 -0
  208. data/spec/llm/prompts_spec.rb +49 -0
  209. data/spec/llm/response_parser_spec.rb +92 -0
  210. data/spec/menus/adopter_adopt_menu_spec.rb +97 -0
  211. data/spec/menus/menu_generator_spec.rb +263 -0
  212. data/spec/scaffolding/name_normalizer_spec.rb +113 -0
  213. data/spec/scaffolding/page_introspector_spec.rb +82 -0
  214. data/spec/scaffolding/scaffold_project_detector_spec.rb +104 -0
  215. data/spec/scaffolding/scaffolding_features_spec.rb +311 -0
  216. data/spec/scaffolding/url_analyzer_spec.rb +110 -0
  217. data/spec/system/adopt_matrix_spec.rb +537 -0
  218. data/spec/system/adopt_spec.rb +225 -0
  219. data/spec/system/support/system_test_helper.rb +0 -2
  220. data/spec/utilities/desktop_downloader_spec.rb +92 -0
  221. metadata +150 -5
  222. data/lib/generators/automation/templates/visual_options.tt +0 -16
  223. data/lib/generators/templates/helpers/partials/axe_driver.tt +0 -10
  224. data/lib/generators/templates/helpers/visual_spec_helper.tt +0 -35
@@ -1,10 +1,13 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ ruby '~> <%= ruby_version %>.0'
4
+
3
5
  gem 'activesupport'
4
6
  <% if mobile? %>
5
7
  gem 'appium_lib'
6
8
  gem 'appium_console'
7
9
  <% end %>
10
+ <%- if allure_reporter? -%>
8
11
  <%- if cucumber? -%>
9
12
  gem 'allure-cucumber', '2.28.0'
10
13
  <%- elsif minitest? -%>
@@ -13,24 +16,32 @@ gem 'allure-ruby-commons', '2.28.0'
13
16
  gem 'allure-rspec', '2.28.0'
14
17
  gem 'allure-ruby-commons', '2.28.0'
15
18
  <%- end -%>
19
+ <%- end -%>
16
20
  <%- if capybara? -%>
17
21
  gem 'capybara'
18
22
  gem 'selenium-webdriver'
19
23
  <%- end -%>
20
- <%- if axe? -%>
24
+ <%- if axe_addon? -%>
25
+ <%- if minitest? -%>
26
+ gem 'axe-core-minitest'
27
+ <%- else -%>
21
28
  gem 'axe-core-rspec'
29
+ <%- end -%>
22
30
  gem 'axe-core-selenium'
23
31
  <%- end -%>
24
- <%- if visual? -%>
25
- gem 'eyes_selenium', '~> 4.6', '>= 4.6.1'
26
- gem 'eyes_universal', '~> 3.3', '>= 3.3.1'
32
+ <%- if visual_addon? -%>
33
+ gem 'chunky_png'
27
34
  <%- end -%>
28
- <%- unless visual? -%>
29
35
  gem 'parallel_split_test'
30
36
  gem 'parallel_tests'
31
- <%- end -%>
32
37
  gem 'rake'
33
38
  gem 'reek'
39
+ <%- if rspec? -%>
40
+ gem 'rspec-retry'
41
+ <%- end -%>
42
+ <%- if junit_reporter? && rspec? -%>
43
+ gem 'rspec_junit_formatter'
44
+ <%- end -%>
34
45
  gem '<%= framework %>'
35
46
  <%- if cucumber? -%>
36
47
  gem 'rspec'
@@ -52,3 +63,7 @@ gem 'selenium-webdriver'
52
63
  <%- if watir? -%>
53
64
  gem 'watir'
54
65
  <%- end -%>
66
+ <%- if web? -%>
67
+ gem 'debug', '>= 1.0'
68
+ gem 'pry'
69
+ <%- end -%>
@@ -1 +1,6 @@
1
- allure-results
1
+ <%- if allure_reporter? -%>
2
+ allure-results
3
+ <%- end -%>
4
+ <%- if rspec? -%>
5
+ spec/examples.txt
6
+ <%- end -%>
@@ -1 +1,5 @@
1
- platform: :ios
1
+ platform: :ios
2
+
3
+ video:
4
+ enabled: false
5
+ strategy: auto # auto, appium, or screen
@@ -1,11 +1,9 @@
1
1
  browser: chrome
2
2
  url: 'https://raider-test-site.onrender.com/'
3
-
4
- <%- if selenium_based? -%>
5
- driver_options:
6
- :timeouts:
7
- :implicit: 10000 # 10 seconds
8
- <% end -%>
3
+ timeout: 10 # seconds — used for implicit waits and max wait time
4
+ viewport:
5
+ width: 1920
6
+ height: 1080
9
7
 
10
8
  browser_arguments:
11
9
  chrome:
@@ -15,4 +13,15 @@ browser_arguments:
15
13
  - search-engine-choice-country
16
14
  firefox:
17
15
  - acceptInsecureCerts
18
- - no-sandbox
16
+ - no-sandbox
17
+
18
+ video:
19
+ enabled: false
20
+ strategy: auto # auto, cdp, or screen
21
+
22
+ debug:
23
+ enabled: false # also toggled by DEBUG=true env var
24
+ console_logs: true # capture browser console logs on failure
25
+ action_logging: true # log driver actions with timestamps
26
+ network_logging: true # capture HTTP requests on failure (Chrome/Edge only)
27
+ log_dir: 'debug_logs'
@@ -2,3 +2,39 @@ desc 'Print Ruby Raider version'
2
2
  task :raider do
3
3
  system 'raider version'
4
4
  end
5
+ <%- if rspec? -%>
6
+
7
+ require 'rspec/core/rake_task'
8
+
9
+ RSpec::Core::RakeTask.new(:spec)
10
+ RSpec::Core::RakeTask.new(:smoke) do |t|
11
+ t.rspec_opts = '--tag smoke'
12
+ end
13
+ RSpec::Core::RakeTask.new(:regression) do |t|
14
+ t.rspec_opts = '--tag regression'
15
+ end
16
+
17
+ task default: :spec
18
+ <%- elsif cucumber? -%>
19
+
20
+ require 'cucumber/rake/task'
21
+
22
+ Cucumber::Rake::Task.new(:features)
23
+ Cucumber::Rake::Task.new(:smoke) do |t|
24
+ t.cucumber_opts = '--tags @smoke'
25
+ end
26
+ Cucumber::Rake::Task.new(:regression) do |t|
27
+ t.cucumber_opts = '--tags @regression'
28
+ end
29
+
30
+ task default: :features
31
+ <%- elsif minitest? -%>
32
+
33
+ require 'rake/testtask'
34
+
35
+ Rake::TestTask.new(:test) do |t|
36
+ t.test_files = FileList['test/**/test_*.rb']
37
+ end
38
+
39
+ task default: :test
40
+ <%- end -%>
@@ -4,10 +4,10 @@
4
4
  <br />
5
5
  <div align="center">
6
6
  <a href="https://github.com/RubyRaider/ruby_raider">
7
- <img src="https://private-user-images.githubusercontent.com/33221555/391053089-3a1a492f-a70e-45ff-8fd0-5f83cef91f49.svg?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzI4ODUyNTEsIm5iZiI6MTczMjg4NDk1MSwicGF0aCI6Ii8zMzIyMTU1NS8zOTEwNTMwODktM2ExYTQ5MmYtYTcwZS00NWZmLThmZDAtNWY4M2NlZjkxZjQ5LnN2Zz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDExMjklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMTI5VDEyNTU1MVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTQ1MDM2ZjAzMmIwMWRmZjdlMjBkMWYxNGFkNTAxYTM0OTEyZjhmNjQ4YmE5NWMwOWE4MTY1Njc5ZjllNTMxYjQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.EnwLs1vZClwzNl1el0SRflyUJrwzno_LhBnnAXMHz7E" alt="Logo" style="width:200px;">
7
+ <img src="https://www.ruby-raider.com/assets/icon-DYY74ofR.png" alt="Logo" style="width:200px;">
8
8
  </a>
9
9
  <p align="center">
10
- <a href="https://github.com/RubyRaider/ruby_raider#getting-started"><strong>Explore the docs »</strong></a>
10
+ <a href="https://github.com/RubyRaider/ruby_raider#getting-started"><strong>Explore the docs</strong></a>
11
11
  <br />
12
12
  <br />
13
13
  <a href="https://rubygems.org/gems/ruby_raider">Rubygems</a>
@@ -21,121 +21,71 @@
21
21
 
22
22
  ## What is Ruby Raider?
23
23
 
24
- Ruby Raider is a generator and scaffolding gem to make UI test automation easier
24
+ Ruby Raider is a generator and scaffolding gem to make UI test automation easier.
25
25
 
26
- ### At the moment Ruby Raider supports generating the following frameworks:
26
+ ### Supported Frameworks
27
27
 
28
- | Web Testing Framework | Visual Testing Framework | Mobile Testing Framework | Accessibility Testing Framework |
29
- |-----------------------|-----------------------------------|------------------------------------|---------------------------------|
30
- | Cucumber and Selenium | Cucumber, Applitools and Selenium | Cucumber and Appium for IOS | Cucumber and Axe for web |
31
- | Rspec and Selenium | Rspec, Applitools and Selenium | Rspec and Appium for IOS | Rspec and Axe for web |
32
- | Cucumber and Watir | | Cucumber and Appium for Android | |
33
- | Rspec and Watir | | Rspec and Appium for Android | |
34
- | | | Cucumber and Appium Cross-platform | |
35
- | | | Rspec and Appium Cross-platform | |
28
+ | Web Testing Framework | Mobile Testing Framework |
29
+ |-----------------------|------------------------------------|
30
+ | Cucumber and Selenium | Cucumber and Appium for iOS |
31
+ | RSpec and Selenium | RSpec and Appium for iOS |
32
+ | Cucumber and Watir | Cucumber and Appium for Android |
33
+ | RSpec and Watir | RSpec and Appium for Android |
34
+ | Cucumber and Capybara | Cucumber and Appium Cross-platform |
35
+ | RSpec and Capybara | RSpec and Appium Cross-platform |
36
+ | Minitest and Selenium | Minitest and Appium for iOS |
37
+ | Minitest and Watir | Minitest and Appium for Android |
38
+ | Minitest and Capybara | Minitest and Appium Cross-platform |
39
+
40
+ **Optional add-ons for web projects:**
41
+ - **Accessibility testing (axe)**: `--accessibility` flag
42
+ - **Visual regression testing (chunky_png)**: `--visual` flag
43
+ - **Performance auditing (Lighthouse)**: `--performance` flag
36
44
 
37
45
  ***The web tests run against the [Raider Test Store](https://raider-test-site.onrender.com/).***
38
46
 
39
- ***In order to run the Appium tests, download the example [app](https://github.com/RaiderHQ/raider_test_app).***
40
- ***Remember to use the full path of the app that you download in the capabilities file and start the server using one of
41
- the commands below:***
47
+ ***To run Appium tests, download the example [app](https://github.com/RaiderHQ/raider_test_app) and start the server:***
42
48
 
43
- ```ruby
49
+ ```bash
44
50
  raider u start_appium
45
- appium --base /wd/hub
46
51
  ```
47
52
 
48
- ***In order to run the visual tests with applitools, you need to create an account and get your api key, you can read
49
- more [here](https://applitools.com/docs/topics/overview/obtain-api-key.html#:~:text=If%20you%20already%20have%20an,Your%20key%20will%20be%20displayed.)
50
- .***
51
-
52
- ***To use the open ai integration you need to set up the OPENAI_ACCESS_TOKEN environment variable and
53
- you can also set the optional OPENAI_ORGANIZATION_ID if you have an organization***
54
-
55
- This works in all the platforms (Tested on Mac OS, Linux and Windows).
53
+ This works on all platforms (Mac OS, Linux and Windows).
56
54
 
57
- ## Getting started
55
+ ## Getting Started
58
56
 
59
- To get the project up and running.
60
-
61
- **Just do:**
62
-
63
- ```ruby
57
+ ```bash
64
58
  gem install ruby_raider
65
- ```
66
-
67
- **Then do:**
68
-
69
- ```ruby
70
59
  raider new [name_of_project]
71
60
  ```
72
61
 
73
- Then a TUI/CLI will appear where the configuration of which frameworks you want to be generated/scaffolded can be
74
- selected.
75
-
76
- Select the ones you will like to work with.
62
+ Or with parameters:
77
63
 
78
- If you already know which frameworks you want to use, you can do:
79
-
80
- ```ruby
64
+ ```bash
81
65
  raider new [name_of_project] -p framework:[framework] automation:[automation_type]
82
66
  ```
83
67
 
84
- An example of the command above would be:
68
+ ### Commands
85
69
 
86
- ```ruby
87
- raider new test_project -p framework:rspec automation:selenium
88
70
  ```
89
-
90
- ### Ruby raider provides the following list of basic commands
91
-
92
- ###### Anything between square brackets([...]) is where your imput goes
93
-
94
- ```ruby
95
- Commands :
96
- raider generate # Provides access to all the scaffolding commands
97
- raider help [COMMAND] # Describe available commands or one specific command
98
- raider new [PROJECT_NAME] # Creates a new framework based on settings picked
99
- raider utility # Provides access to all the utility commands
100
- raider version # It shows the version of Ruby Raider you are currently using
71
+ raider generate # Scaffolding commands
72
+ raider utility # Utility commands
73
+ raider plugin_manager # Plugin management
74
+ raider new [NAME] # Create new project
75
+ raider version # Show version
76
+ raider help [COMMAND] # Describe commands
101
77
  ```
102
78
 
103
- All the basic commands have their corresponding shortcut:
104
-
105
- * g for generate
106
- * n for new
107
- * u for utility
108
- * v for version
109
-
110
- ### Scaffolding Commands
111
-
112
- Ruby Raider also supports scaffolding:
113
-
114
- * To create a new page object you do: ```raider g page [PAGE_NAME]```
115
- * To create a new spec you do: ```raider g spec [SPEC_NAME]```
116
- * To create a new feature you do: ```raider g feature [FEATURE_NAME]```
117
- * To create a new steps definition you do: ```raider g steps [STEPS_NAME]```
118
- * To create both a page/spec or a page/feature/steps you do: ```raider g scaffold [SCAFFOLD_NAME]```
119
-
120
- It's possible to add the option --path or p if you want to specify where to create your features, pages, helpers and
121
- specs.
79
+ Shortcuts: `g` (generate), `n` (new), `u` (utility), `v` (version), `pm` (plugin_manager)
122
80
 
123
- If you want to set the default path for the creation of your features, helpers and specs:
81
+ ### Scaffolding
124
82
 
125
- ```ruby
126
- raider u path [PATH_NAME] - -feature or f
127
- raider u path [PATH_NAME] - -spec or s
128
- raider u path [PATH_NAME] - -helper or h
129
83
  ```
130
-
131
- If you don't specify an option, path will assume you want to change the default path for pages.
132
-
133
- ### Appium Server Command
134
-
135
- To initialise Appium server run this command:
136
-
137
- ```ruby
138
- raider u start_appium
84
+ raider g page [NAME] # Create page object
85
+ raider g spec [NAME] # Create RSpec test
86
+ raider g feature [NAME] # Create Cucumber feature
87
+ raider g steps [NAME] # Create step definitions
88
+ raider g scaffold [NAME] # Create page + test + steps
139
89
  ```
140
90
 
141
91
  ### Sponsors
@@ -0,0 +1,3 @@
1
+ -I .
2
+ --require helpers/spec_helper
3
+ --format documentation
@@ -0,0 +1 @@
1
+ <%= ruby_version %>
@@ -21,6 +21,17 @@ module AllureHelper
21
21
  test_case: true
22
22
  )
23
23
  end
24
+
25
+ def add_video(name, file)
26
+ return unless file && File.exist?(file)
27
+
28
+ Allure.add_attachment(
29
+ name: "Recording: #{name}",
30
+ source: File.new(file),
31
+ type: 'video/mp4',
32
+ test_case: true
33
+ )
34
+ end
24
35
  <%- if rspec? -%>
25
36
 
26
37
  def formatter
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/core_ext/string/inflections'
3
4
  require 'yaml'
4
5
  require 'watir'
5
6
 
@@ -16,8 +17,17 @@ module BrowserHelper
16
17
  end
17
18
 
18
19
  def create_browser(*args)
19
- args = args.empty? ? config['browser_arguments'][config['browser']] : args
20
+ Watir.default_timeout = config.fetch('timeout', 10)
21
+ browser_name = config['browser'].to_s
22
+ args = args.empty? ? config['browser_arguments'][browser_name] : args
20
23
  args += ['--headless'] if ENV['HEADLESS'] && !args.include?('--headless')
21
- Watir::Browser.new(config['browser'], options: { args: args })
24
+ capitalized = browser_name == 'ie' ? browser_name.upcase : browser_name.capitalize
25
+ browser_options = "Selenium::WebDriver::#{capitalized}::Options".constantize.new(args:)
26
+ debug_cfg = config['debug'] || {}
27
+ if %w[chrome edge msedge].include?(browser_name.downcase) &&
28
+ (debug_cfg.fetch('enabled', false) || ENV['DEBUG']&.downcase == 'true')
29
+ browser_options.add_option('goog:loggingPrefs', { browser: 'ALL', performance: 'ALL' })
30
+ end
31
+ Watir::Browser.new(browser_name.to_sym, options: browser_options)
22
32
  end
23
33
  end
@@ -13,7 +13,7 @@ module CapybaraHelper
13
13
  capybara_config.default_driver = :selenium
14
14
  capybara_config.javascript_driver = :selenium
15
15
  capybara_config.app_host = config['url']
16
- capybara_config.default_max_wait_time = 10
16
+ capybara_config.default_max_wait_time = config.fetch('timeout', 10)
17
17
  capybara_config.run_server = false
18
18
  end
19
19
 
@@ -22,6 +22,10 @@ module CapybaraHelper
22
22
  args = config['browser_arguments'][config['browser']] || []
23
23
  args += ['--headless'] if ENV['HEADLESS'] && !args.include?('--headless')
24
24
  options = Selenium::WebDriver::Chrome::Options.new(args:)
25
+ debug_cfg = config['debug'] || {}
26
+ if debug_cfg.fetch('enabled', false) || ENV['DEBUG']&.downcase == 'true'
27
+ options.add_option('goog:loggingPrefs', { browser: 'ALL', performance: 'ALL' })
28
+ end
25
29
  Capybara::Selenium::Driver.new(app, browser:, options:)
26
30
  end
27
31
  end
@@ -0,0 +1,190 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'yaml'
5
+ require 'logger'
6
+ require 'json'
7
+
8
+ module DebugHelper
9
+ LOG_DIR = 'debug_logs'
10
+
11
+ module_function
12
+
13
+ # --- Configuration ---
14
+
15
+ def config
16
+ @config ||= begin
17
+ yml = YAML.load_file('config/config.yml')
18
+ yml['debug'] || {}
19
+ rescue StandardError
20
+ {}
21
+ end
22
+ end
23
+
24
+ def enabled?
25
+ ENV['DEBUG']&.downcase == 'true' || config.fetch('enabled', false)
26
+ end
27
+
28
+ def console_logs?
29
+ enabled? && config.fetch('console_logs', true)
30
+ end
31
+
32
+ def action_logging?
33
+ enabled? && config.fetch('action_logging', true)
34
+ end
35
+
36
+ def network_logging?
37
+ enabled? && config.fetch('network_logging', true)
38
+ end
39
+
40
+ def log_dir
41
+ config.fetch('log_dir', LOG_DIR)
42
+ end
43
+
44
+ def ensure_log_dir
45
+ FileUtils.mkdir_p(log_dir)
46
+ end
47
+
48
+ # --- Driver Resolution ---
49
+
50
+ def resolve_selenium_driver(obj)
51
+ if obj.respond_to?(:driver) && !obj.is_a?(Selenium::WebDriver::Driver)
52
+ obj.driver
53
+ elsif obj.respond_to?(:browser) && obj.browser.respond_to?(:driver)
54
+ obj.browser.driver
55
+ else
56
+ obj
57
+ end
58
+ rescue StandardError
59
+ obj
60
+ end
61
+
62
+ # --- Failure Diagnostics (returns structured hash for desktop integration) ---
63
+
64
+ def capture_failure_diagnostics(driver_or_browser, test_name, exception: nil)
65
+ return {} unless enabled?
66
+
67
+ ensure_log_dir
68
+ sel_driver = resolve_selenium_driver(driver_or_browser)
69
+ safe_name = sanitize(test_name)
70
+ diagnostics = { test_name: test_name, timestamp: Time.now.iso8601 }
71
+
72
+ diagnostics[:url] = sel_driver.current_url rescue 'unknown'
73
+ diagnostics[:title] = sel_driver.title rescue 'unknown'
74
+
75
+ if exception
76
+ diagnostics[:error_message] = exception.message
77
+ diagnostics[:error_class] = exception.class.name
78
+ diagnostics[:stack_trace] = exception.backtrace&.first(20) || []
79
+ end
80
+
81
+ diagnostics[:console_logs] = capture_console_logs(sel_driver) if console_logs?
82
+ diagnostics[:network_log_path] = capture_network_logs(sel_driver, safe_name) if network_logging?
83
+
84
+ # HTML snapshot
85
+ html_path = File.join(log_dir, "#{safe_name}_page.html")
86
+ File.write(html_path, sel_driver.page_source) rescue nil
87
+ diagnostics[:html_snapshot] = html_path
88
+
89
+ # Write diagnostics JSON (desktop app reads this)
90
+ summary_path = File.join(log_dir, "#{safe_name}_diagnostics.json")
91
+ File.write(summary_path, JSON.pretty_generate(diagnostics))
92
+ diagnostics[:summary_path] = summary_path
93
+
94
+ diagnostics
95
+ rescue StandardError => e
96
+ warn "[debug] Failed to capture diagnostics: #{e.message}"
97
+ {}
98
+ end
99
+
100
+ # --- Console Log Capture ---
101
+
102
+ def capture_console_logs(sel_driver)
103
+ return [] unless chrome_or_edge?(sel_driver)
104
+
105
+ sel_driver.logs.get(:browser).map { |entry| { level: entry.level, message: entry.message, timestamp: entry.timestamp } }
106
+ rescue StandardError
107
+ []
108
+ end
109
+
110
+ # --- Action Logger ---
111
+
112
+ class ActionLogger
113
+ def initialize(test_name)
114
+ DebugHelper.ensure_log_dir
115
+ log_path = File.join(DebugHelper.log_dir, "#{DebugHelper.sanitize(test_name)}_actions.log")
116
+ @logger = Logger.new(log_path)
117
+ @logger.formatter = proc { |severity, datetime, _progname, msg|
118
+ "[#{datetime.strftime('%H:%M:%S.%L')}] #{severity}: #{msg}\n"
119
+ }
120
+ end
121
+
122
+ def log(action, details = '')
123
+ @logger.info("#{action} #{details}".strip)
124
+ end
125
+
126
+ def close
127
+ @logger.close
128
+ rescue StandardError
129
+ nil
130
+ end
131
+ end
132
+
133
+ class NullActionLogger
134
+ def log(_action, _details = '') = nil
135
+ def close = nil
136
+ end
137
+
138
+ def action_logger_for(test_name)
139
+ action_logging? ? ActionLogger.new(test_name) : NullActionLogger.new
140
+ end
141
+
142
+ # --- Network Logging Setup ---
143
+
144
+ def enable_network_logging(driver_or_browser)
145
+ return unless network_logging?
146
+
147
+ sel_driver = resolve_selenium_driver(driver_or_browser)
148
+ return unless chrome_or_edge?(sel_driver)
149
+
150
+ sel_driver.execute_cdp('Network.enable')
151
+ rescue StandardError => e
152
+ warn "[debug] Could not enable network logging: #{e.message}"
153
+ end
154
+
155
+ # --- Network Log Capture ---
156
+
157
+ def capture_network_logs(sel_driver, safe_name)
158
+ return unless chrome_or_edge?(sel_driver)
159
+
160
+ logs = sel_driver.logs.get(:performance)
161
+ return if logs.empty?
162
+
163
+ entries = logs.filter_map do |entry|
164
+ parsed = JSON.parse(entry.message)['message'] rescue next
165
+ parsed if parsed.is_a?(Hash) && parsed['method']&.start_with?('Network.')
166
+ end
167
+
168
+ return if entries.empty?
169
+
170
+ network_path = File.join(log_dir, "#{safe_name}_network.json")
171
+ File.write(network_path, JSON.pretty_generate(entries))
172
+ network_path
173
+ rescue StandardError => e
174
+ warn "[debug] Failed to capture network logs: #{e.message}"
175
+ nil
176
+ end
177
+
178
+ # --- Helpers ---
179
+
180
+ def chrome_or_edge?(driver)
181
+ browser_name = driver.capabilities[:browser_name].to_s.downcase
182
+ %w[chrome chromium msedge edge].any? { |b| browser_name.include?(b) }
183
+ rescue StandardError
184
+ false
185
+ end
186
+
187
+ def sanitize(name)
188
+ name.to_s.gsub(/[^a-zA-Z0-9_-]/, '_')[0..80]
189
+ end
190
+ end
@@ -1,26 +1,18 @@
1
1
  # frozen_string_literal: true
2
- <% if axe? -%>
3
- require 'axe-selenium'
4
- <% end -%>
2
+
5
3
  require 'yaml'
6
- <%- unless axe? %>
7
4
  <%- if selenium_based? -%>
8
5
  require 'active_support/inflector'
9
6
  require 'selenium-webdriver'
10
7
  <%- else -%>
11
8
  require 'appium_lib'
12
9
  <%- end -%>
13
- <%- end -%>
14
10
 
15
11
  module DriverHelper
16
- <%- if selenium_based? && !axe? -%>
12
+ <%- if selenium_based? -%>
17
13
  def driver(*opts)
18
14
  @driver ||= create_driver(*opts)
19
15
  end
20
- <%- elsif axe? -%>
21
- def driver(browser = :chrome, js_path = nil, skip_iframes = nil)
22
- @driver ||= create_driver(browser, js_path, skip_iframes)
23
- end
24
16
  <%- else -%>
25
17
  def driver
26
18
  @driver ||= create_driver
@@ -11,7 +11,6 @@
11
11
  @platform_caps ||= YAML.load_file('config/capabilities.yml')[platform]
12
12
  end
13
13
 
14
- # :reek:UtilityFunction
15
14
  def parsed_caps
16
15
  platform_caps['appium:options']['app'] = parse_app_path(platform_caps['appium:options']['app'])
17
16
  platform_caps
@@ -22,7 +21,6 @@
22
21
  end
23
22
  <%- else -%>
24
23
 
25
- # :reek:UtilityFunction
26
24
  def parsed_caps
27
25
  caps = YAML.load_file('config/capabilities.yml')
28
26
  caps['appium:options']['app'] = app_path(caps['appium:options']['app'])
@@ -0,0 +1,7 @@
1
+ <% if capybara? %>
2
+ DebugHelper.capture_failure_diagnostics(Capybara.current_session.driver, example_name, exception: @_exception)
3
+ <% elsif selenium_based? %>
4
+ DebugHelper.capture_failure_diagnostics(driver, example_name, exception: @_exception)
5
+ <% elsif watir? %>
6
+ DebugHelper.capture_failure_diagnostics(browser, example_name, exception: @_exception)
7
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <% if capybara? %>
2
+ DebugHelper.enable_network_logging(Capybara.current_session.driver)
3
+ <% elsif selenium_based? %>
4
+ DebugHelper.enable_network_logging(driver)
5
+ <% elsif watir? %>
6
+ DebugHelper.enable_network_logging(browser)
7
+ <% end %>
@@ -1,6 +1,4 @@
1
- <% if axe? -%>
2
- <%= partial('axe_driver', strip: true) %>
3
- <%- elsif selenium_based? -%>
1
+ <% if selenium_based? -%>
4
2
  <%= partial('selenium_driver', strip: true) %>
5
3
  <%- else -%>
6
4
  <%= partial('appium_driver', strip: true) %>