ruby_raider 1.1.4 → 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 (278) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/e2e_tests.yml +58 -0
  3. data/.github/workflows/integration.yml +4 -6
  4. data/.github/workflows/reek.yml +6 -5
  5. data/.github/workflows/release.yml +175 -0
  6. data/.github/workflows/rubocop.yml +7 -6
  7. data/.github/workflows/steep.yml +21 -0
  8. data/.github/workflows/system_tests.yml +83 -0
  9. data/.gitignore +1 -1
  10. data/.reek.yml +46 -4
  11. data/.rubocop.yml +24 -0
  12. data/.ruby-version +1 -1
  13. data/README.md +140 -77
  14. data/RELEASE.md +412 -0
  15. data/RELEASE_QUICK_GUIDE.md +77 -0
  16. data/Steepfile +22 -0
  17. data/assets/ruby_raider_logo.svg +51 -0
  18. data/bin/release +186 -0
  19. data/lib/adopter/adopt_menu.rb +146 -0
  20. data/lib/adopter/converters/base_converter.rb +84 -0
  21. data/lib/adopter/converters/identity_converter.rb +53 -0
  22. data/lib/adopter/migration_plan.rb +74 -0
  23. data/lib/adopter/migrator.rb +96 -0
  24. data/lib/adopter/plan_builder.rb +275 -0
  25. data/lib/adopter/project_analyzer.rb +252 -0
  26. data/lib/adopter/project_detector.rb +157 -0
  27. data/lib/commands/adopt_commands.rb +42 -0
  28. data/lib/commands/plugin_commands.rb +0 -2
  29. data/lib/commands/scaffolding_commands.rb +220 -37
  30. data/lib/commands/utility_commands.rb +82 -2
  31. data/lib/generators/automation/automation_generator.rb +0 -7
  32. data/lib/generators/automation/templates/account.tt +9 -5
  33. data/lib/generators/automation/templates/appium_caps.tt +60 -6
  34. data/lib/generators/automation/templates/home.tt +4 -4
  35. data/lib/generators/automation/templates/login.tt +61 -4
  36. data/lib/generators/automation/templates/page.tt +13 -7
  37. data/lib/generators/automation/templates/partials/element.tt +1 -1
  38. data/lib/generators/automation/templates/partials/home_page_selector.tt +4 -4
  39. data/lib/generators/automation/templates/partials/initialize_selector.tt +3 -8
  40. data/lib/generators/automation/templates/partials/pdp_page_selector.tt +4 -4
  41. data/lib/generators/automation/templates/partials/url_methods.tt +0 -1
  42. data/lib/generators/automation/templates/partials/visit_method.tt +11 -1
  43. data/lib/generators/automation/templates/pdp.tt +1 -1
  44. data/lib/generators/common_generator.rb +12 -0
  45. data/lib/generators/cucumber/cucumber_generator.rb +36 -0
  46. data/lib/generators/cucumber/templates/accessibility_feature.tt +5 -0
  47. data/lib/generators/cucumber/templates/accessibility_steps.tt +21 -0
  48. data/lib/generators/cucumber/templates/cucumber.tt +8 -1
  49. data/lib/generators/cucumber/templates/env.tt +6 -4
  50. data/lib/generators/cucumber/templates/feature.tt +0 -4
  51. data/lib/generators/cucumber/templates/partials/appium_env.tt +5 -0
  52. data/lib/generators/cucumber/templates/partials/capybara_env.tt +38 -0
  53. data/lib/generators/cucumber/templates/partials/capybara_world.tt +6 -0
  54. data/lib/generators/cucumber/templates/partials/driver_world.tt +1 -4
  55. data/lib/generators/cucumber/templates/partials/mobile_steps.tt +2 -2
  56. data/lib/generators/cucumber/templates/partials/selenium_env.tt +22 -35
  57. data/lib/generators/cucumber/templates/partials/watir_env.tt +20 -1
  58. data/lib/generators/cucumber/templates/partials/web_steps.tt +10 -15
  59. data/lib/generators/cucumber/templates/performance_feature.tt +5 -0
  60. data/lib/generators/cucumber/templates/performance_steps.tt +17 -0
  61. data/lib/generators/cucumber/templates/steps.tt +2 -2
  62. data/lib/generators/cucumber/templates/visual_feature.tt +5 -0
  63. data/lib/generators/cucumber/templates/visual_steps.tt +19 -0
  64. data/lib/generators/cucumber/templates/world.tt +5 -3
  65. data/lib/generators/generator.rb +50 -7
  66. data/lib/generators/helper_generator.rb +39 -9
  67. data/lib/generators/infrastructure/github_generator.rb +6 -0
  68. data/lib/generators/infrastructure/templates/github.tt +12 -8
  69. data/lib/generators/infrastructure/templates/github_appium.tt +108 -0
  70. data/lib/generators/infrastructure/templates/gitlab.tt +6 -3
  71. data/lib/generators/invoke_generators.rb +43 -9
  72. data/lib/generators/menu_generator.rb +122 -11
  73. data/lib/generators/minitest/minitest_generator.rb +35 -0
  74. data/lib/generators/minitest/templates/accessibility_test.tt +26 -0
  75. data/lib/generators/minitest/templates/performance_test.tt +18 -0
  76. data/lib/generators/minitest/templates/test.tt +64 -0
  77. data/lib/generators/minitest/templates/visual_test.tt +23 -0
  78. data/lib/generators/rspec/rspec_generator.rb +16 -4
  79. data/lib/generators/rspec/templates/accessibility_spec.tt +25 -0
  80. data/lib/generators/rspec/templates/performance_spec.tt +18 -0
  81. data/lib/generators/rspec/templates/spec.tt +13 -41
  82. data/lib/generators/rspec/templates/visual_spec.tt +20 -0
  83. data/lib/generators/template_renderer/partial_cache.rb +126 -0
  84. data/lib/generators/template_renderer/partial_resolver.rb +110 -0
  85. data/lib/generators/template_renderer/template_error.rb +50 -0
  86. data/lib/generators/template_renderer.rb +106 -0
  87. data/lib/generators/templates/common/config.tt +2 -2
  88. data/lib/generators/templates/common/gemfile.tt +36 -9
  89. data/lib/generators/templates/common/git_ignore.tt +6 -1
  90. data/lib/generators/templates/common/partials/mobile_config.tt +5 -1
  91. data/lib/generators/templates/common/partials/web_config.tt +17 -8
  92. data/lib/generators/templates/common/rakefile.tt +36 -0
  93. data/lib/generators/templates/common/read_me.tt +43 -91
  94. data/lib/generators/templates/common/rspec.tt +3 -0
  95. data/lib/generators/templates/common/ruby_version.tt +1 -0
  96. data/lib/generators/templates/helpers/allure_helper.tt +13 -2
  97. data/lib/generators/templates/helpers/browser_helper.tt +13 -2
  98. data/lib/generators/templates/helpers/capybara_helper.tt +32 -0
  99. data/lib/generators/templates/helpers/debug_helper.tt +190 -0
  100. data/lib/generators/templates/helpers/driver_helper.tt +3 -11
  101. data/lib/generators/templates/helpers/partials/allure_imports.tt +3 -1
  102. data/lib/generators/templates/helpers/partials/allure_requirements.tt +3 -1
  103. data/lib/generators/templates/helpers/partials/appium_driver.tt +44 -0
  104. data/lib/generators/templates/helpers/partials/browserstack_config.tt +13 -0
  105. data/lib/generators/templates/helpers/partials/debug_diagnostics.tt +7 -0
  106. data/lib/generators/templates/helpers/partials/debug_start.tt +7 -0
  107. data/lib/generators/templates/helpers/partials/driver_and_options.tt +5 -115
  108. data/lib/generators/templates/helpers/partials/quit_driver.tt +3 -1
  109. data/lib/generators/templates/helpers/partials/screenshot.tt +3 -1
  110. data/lib/generators/templates/helpers/partials/selenium_driver.tt +26 -0
  111. data/lib/generators/templates/helpers/partials/video_start.tt +9 -0
  112. data/lib/generators/templates/helpers/partials/video_stop.tt +4 -0
  113. data/lib/generators/templates/helpers/performance_helper.tt +57 -0
  114. data/lib/generators/templates/helpers/spec_helper.tt +72 -10
  115. data/lib/generators/templates/helpers/test_helper.tt +94 -0
  116. data/lib/generators/templates/helpers/video_helper.tt +270 -0
  117. data/lib/generators/templates/helpers/visual_helper.tt +39 -46
  118. data/lib/llm/client.rb +79 -0
  119. data/lib/llm/config.rb +57 -0
  120. data/lib/llm/prompts.rb +84 -0
  121. data/lib/llm/provider.rb +27 -0
  122. data/lib/llm/providers/anthropic_provider.rb +43 -0
  123. data/lib/llm/providers/ollama_provider.rb +56 -0
  124. data/lib/llm/providers/openai_provider.rb +42 -0
  125. data/lib/llm/response_parser.rb +67 -0
  126. data/lib/plugin/plugin.rb +22 -20
  127. data/lib/plugin/plugin_exposer.rb +16 -38
  128. data/lib/ruby_raider.rb +51 -11
  129. data/lib/scaffolding/crud_generator.rb +94 -0
  130. data/lib/scaffolding/dry_run_presenter.rb +16 -0
  131. data/lib/scaffolding/name_normalizer.rb +63 -0
  132. data/lib/scaffolding/page_introspector.rb +45 -0
  133. data/lib/scaffolding/project_detector.rb +72 -0
  134. data/lib/scaffolding/scaffold_menu.rb +103 -0
  135. data/lib/scaffolding/scaffolding.rb +158 -11
  136. data/lib/scaffolding/templates/component.tt +30 -0
  137. data/lib/scaffolding/templates/feature.tt +4 -4
  138. data/lib/scaffolding/templates/helper.tt +15 -1
  139. data/lib/scaffolding/templates/page_from_url.tt +75 -0
  140. data/lib/scaffolding/templates/page_object.tt +50 -1
  141. data/lib/scaffolding/templates/spec.tt +33 -2
  142. data/lib/scaffolding/templates/spec_from_page.tt +31 -0
  143. data/lib/scaffolding/templates/spec_from_url.tt +46 -0
  144. data/lib/scaffolding/templates/steps.tt +17 -5
  145. data/lib/scaffolding/url_analyzer.rb +179 -0
  146. data/lib/utilities/desktop_downloader.rb +177 -0
  147. data/lib/utilities/logo.rb +83 -0
  148. data/lib/utilities/utilities.rb +53 -20
  149. data/lib/version +1 -1
  150. data/ruby_raider.gemspec +1 -0
  151. data/sig/adopter/adopt_menu.rbs +25 -0
  152. data/sig/adopter/converters/base_converter.rbs +23 -0
  153. data/sig/adopter/converters/identity_converter.rbs +16 -0
  154. data/sig/adopter/migration_plan.rbs +34 -0
  155. data/sig/adopter/migrator.rbs +21 -0
  156. data/sig/adopter/plan_builder.rbs +38 -0
  157. data/sig/adopter/project_analyzer.rbs +39 -0
  158. data/sig/adopter/project_detector.rbs +26 -0
  159. data/sig/commands/adopt_commands.rbs +8 -0
  160. data/sig/commands/loaded_commands.rbs +5 -0
  161. data/sig/commands/plugin_commands.rbs +9 -0
  162. data/sig/commands/scaffolding_commands.rbs +28 -0
  163. data/sig/commands/utility_commands.rbs +21 -0
  164. data/sig/generators/automation/automation_generator.rbs +20 -0
  165. data/sig/generators/common_generator.rbs +12 -0
  166. data/sig/generators/cucumber/cucumber_generator.rbs +16 -0
  167. data/sig/generators/generator.rbs +40 -0
  168. data/sig/generators/helper_generator.rbs +18 -0
  169. data/sig/generators/infrastructure/github_generator.rbs +5 -0
  170. data/sig/generators/infrastructure/gitlab_generator.rbs +4 -0
  171. data/sig/generators/invoke_generators.rbs +10 -0
  172. data/sig/generators/menu_generator.rbs +29 -0
  173. data/sig/generators/minitest/minitest_generator.rbs +8 -0
  174. data/sig/generators/rspec/rspec_generator.rbs +8 -0
  175. data/sig/generators/template_renderer/partial_cache.rbs +20 -0
  176. data/sig/generators/template_renderer/partial_resolver.rbs +20 -0
  177. data/sig/generators/template_renderer/template_error.rbs +19 -0
  178. data/sig/generators/template_renderer.rbs +10 -0
  179. data/sig/llm/client.rbs +15 -0
  180. data/sig/llm/config.rbs +20 -0
  181. data/sig/llm/prompts.rbs +8 -0
  182. data/sig/llm/provider.rbs +12 -0
  183. data/sig/llm/providers/anthropic_provider.rbs +16 -0
  184. data/sig/llm/providers/ollama_provider.rbs +18 -0
  185. data/sig/llm/providers/openai_provider.rbs +16 -0
  186. data/sig/llm/response_parser.rbs +13 -0
  187. data/sig/plugin/plugin.rbs +24 -0
  188. data/sig/plugin/plugin_exposer.rbs +20 -0
  189. data/sig/ruby_raider.rbs +15 -0
  190. data/sig/scaffolding/crud_generator.rbs +16 -0
  191. data/sig/scaffolding/dry_run_presenter.rbs +4 -0
  192. data/sig/scaffolding/name_normalizer.rbs +17 -0
  193. data/sig/scaffolding/page_introspector.rbs +14 -0
  194. data/sig/scaffolding/project_detector.rbs +14 -0
  195. data/sig/scaffolding/scaffold_menu.rbs +18 -0
  196. data/sig/scaffolding/scaffolding.rbs +55 -0
  197. data/sig/scaffolding/url_analyzer.rbs +28 -0
  198. data/sig/utilities/desktop_downloader.rbs +23 -0
  199. data/sig/utilities/logger.rbs +13 -0
  200. data/sig/utilities/logo.rbs +16 -0
  201. data/sig/utilities/utilities.rbs +30 -0
  202. data/sig/vendor/thor.rbs +34 -0
  203. data/sig/vendor/tty_prompt.rbs +15 -0
  204. data/spec/adopter/adopt_menu_spec.rb +176 -0
  205. data/spec/adopter/converters/identity_converter_spec.rb +145 -0
  206. data/spec/adopter/migration_plan_spec.rb +113 -0
  207. data/spec/adopter/migrator_spec.rb +277 -0
  208. data/spec/adopter/plan_builder_spec.rb +298 -0
  209. data/spec/adopter/project_analyzer_spec.rb +337 -0
  210. data/spec/adopter/project_detector_spec.rb +295 -0
  211. data/spec/commands/raider_commands_spec.rb +129 -0
  212. data/spec/generators/fixtures/templates/test.tt +1 -0
  213. data/spec/generators/fixtures/templates/test_partial.tt +1 -0
  214. data/spec/generators/generator_spec.rb +23 -0
  215. data/spec/generators/template_renderer_spec.rb +298 -0
  216. data/spec/integration/commands/scaffolding_commands_spec.rb +2 -2
  217. data/spec/integration/commands/utility_commands_spec.rb +24 -4
  218. data/spec/integration/content/ci_content_spec.rb +119 -0
  219. data/spec/integration/content/common_content_spec.rb +288 -0
  220. data/spec/integration/content/config_content_spec.rb +175 -0
  221. data/spec/integration/content/content_helper.rb +32 -0
  222. data/spec/integration/content/gemfile_content_spec.rb +209 -0
  223. data/spec/integration/content/helper_content_spec.rb +485 -0
  224. data/spec/integration/content/page_content_spec.rb +259 -0
  225. data/spec/integration/content/reporter_content_spec.rb +236 -0
  226. data/spec/integration/content/skip_flags_content_spec.rb +206 -0
  227. data/spec/integration/content/syntax_validation_spec.rb +30 -0
  228. data/spec/integration/content/test_content_spec.rb +266 -0
  229. data/spec/integration/end_to_end_features_spec.rb +690 -0
  230. data/spec/integration/end_to_end_spec.rb +361 -0
  231. data/spec/integration/generators/automation_generator_spec.rb +9 -21
  232. data/spec/integration/generators/axe_addon_spec.rb +150 -0
  233. data/spec/integration/generators/common_generator_spec.rb +48 -49
  234. data/spec/integration/generators/config_features_spec.rb +155 -0
  235. data/spec/integration/generators/cucumber_generator_spec.rb +7 -7
  236. data/spec/integration/generators/debug_helper_spec.rb +68 -0
  237. data/spec/integration/generators/github_generator_spec.rb +8 -8
  238. data/spec/integration/generators/gitlab_generator_spec.rb +8 -8
  239. data/spec/integration/generators/helpers_generator_spec.rb +70 -44
  240. data/spec/integration/generators/lighthouse_addon_spec.rb +132 -0
  241. data/spec/integration/generators/minitest_generator_spec.rb +64 -0
  242. data/spec/integration/generators/reporter_spec.rb +159 -0
  243. data/spec/integration/generators/rspec_generator_spec.rb +7 -7
  244. data/spec/integration/generators/skip_flags_spec.rb +134 -0
  245. data/spec/integration/generators/visual_addon_spec.rb +148 -0
  246. data/spec/integration/settings_helper.rb +1 -4
  247. data/spec/integration/spec_helper.rb +46 -11
  248. data/spec/llm/client_spec.rb +79 -0
  249. data/spec/llm/config_spec.rb +92 -0
  250. data/spec/llm/prompts_spec.rb +49 -0
  251. data/spec/llm/response_parser_spec.rb +92 -0
  252. data/spec/menus/adopter_adopt_menu_spec.rb +97 -0
  253. data/spec/menus/menu_generator_spec.rb +263 -0
  254. data/spec/scaffolding/name_normalizer_spec.rb +113 -0
  255. data/spec/scaffolding/page_introspector_spec.rb +82 -0
  256. data/spec/scaffolding/scaffold_project_detector_spec.rb +104 -0
  257. data/spec/scaffolding/scaffolding_features_spec.rb +311 -0
  258. data/spec/scaffolding/url_analyzer_spec.rb +110 -0
  259. data/spec/system/adopt_matrix_spec.rb +537 -0
  260. data/spec/system/adopt_spec.rb +225 -0
  261. data/spec/system/capybara_spec.rb +42 -0
  262. data/spec/system/selenium_spec.rb +19 -17
  263. data/spec/system/support/system_test_helper.rb +33 -0
  264. data/spec/system/watir_spec.rb +19 -17
  265. data/spec/utilities/desktop_downloader_spec.rb +92 -0
  266. metadata +193 -18
  267. data/.github/workflows/push_gem.yml +0 -37
  268. data/.github/workflows/selenium.yml +0 -22
  269. data/.github/workflows/watir.yml +0 -22
  270. data/lib/generators/automation/templates/partials/android_caps.tt +0 -17
  271. data/lib/generators/automation/templates/partials/cross_platform_caps.tt +0 -25
  272. data/lib/generators/automation/templates/partials/ios_caps.tt +0 -18
  273. data/lib/generators/automation/templates/partials/selenium_account.tt +0 -9
  274. data/lib/generators/automation/templates/partials/selenium_login.tt +0 -34
  275. data/lib/generators/automation/templates/partials/watir_account.tt +0 -7
  276. data/lib/generators/automation/templates/partials/watir_login.tt +0 -32
  277. data/lib/generators/automation/templates/visual_options.tt +0 -16
  278. data/lib/generators/templates/helpers/visual_spec_helper.tt +0 -35
@@ -1,30 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Uncomment for interactive debugging:
4
+ # require 'debug' # Ruby's built-in debugger (binding.break)
5
+ # require 'pry' # Pry debugger (binding.pry)
6
+
3
7
  require_relative '../../page_objects/pages/account'
4
8
  require_relative '../../page_objects/pages/login'
5
9
 
6
10
  Given("I'm a {user} on the login page") do |user|
7
11
  @user = user
8
- @login_page = Login.new(<% if watir? %>browser<% else %>driver<% end %>)
9
- @login_page.visit
12
+ @login_page = <% if capybara? %>Login.new<% elsif watir? %>Login.new(browser)<% else %>Login.new(driver)<% end %>
13
+ @login_page.<% if capybara? %>visit_page<% else %>visit<% end %>
10
14
  end
11
15
 
12
16
  When('I login with my credentials') do
17
+ # binding.break # Uncomment to pause here and inspect state
13
18
  @login_page.login(@user['username'], @user['password'])
14
19
  end
15
20
 
16
- <%- if axe? -%>
17
- Then('the page should be axe clean') do
18
- account = Account.new(driver)
19
- expect(account.page).to be_axe_clean
20
- end
21
- <%- else -%>
22
21
  Then("I'm logged in") do
23
- account_page = Account.new(<% if watir? %>browser<% else %>driver<% end %>)
24
- <%- if visual? -%>
25
- check_page account_page
26
- <%- else -%>
22
+ account_page = <% if capybara? %>Account.new<% elsif watir? %>Account.new(browser)<% else %>Account.new(driver)<% end %>
23
+ account_page.<% if capybara? %>visit_page<% else %>visit<% end %>
27
24
  expect(account_page.header.customer_name).to eq "Welcome back #{@user['name']}"
28
- <%- end -%>
29
- end
30
- <%- end -%>
25
+ end
@@ -0,0 +1,5 @@
1
+ Feature: Performance Audit
2
+
3
+ Scenario: Page meets performance threshold
4
+ Given I audit the home page performance
5
+ Then the performance score should be above the threshold
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../helpers/performance_helper'
4
+
5
+ include PerformanceHelper
6
+
7
+ Given('I audit the home page performance') do
8
+ @result = assert_performance_above('https://raider-test-site.onrender.com/', threshold: 0.7)
9
+ end
10
+
11
+ Then('the performance score should be above the threshold') do
12
+ expect(@result[:status]).not_to eq(:error),
13
+ "Lighthouse error: #{@result[:message]}"
14
+
15
+ expect(@result[:passed]).to be(true),
16
+ "Performance below threshold (#{@result[:threshold]}): #{@result[:scores]}"
17
+ end
@@ -1,5 +1,5 @@
1
1
  <%- if web? -%>
2
- <%= ERB.new(File.read(File.expand_path('./partials/web_steps.tt', __dir__)), trim_mode: '-').result(binding).strip! -%>
2
+ <%= partial('web_steps', strip: true) -%>
3
3
  <%- else -%>
4
- <%= ERB.new(File.read(File.expand_path('./partials/mobile_steps.tt', __dir__)), trim_mode: '-').result(binding).strip! -%>
4
+ <%= partial('mobile_steps', strip: true) -%>
5
5
  <%- end -%>
@@ -0,0 +1,5 @@
1
+ Feature: Visual Regression
2
+
3
+ Scenario: Login page matches baseline
4
+ Given I'm on the login page
5
+ Then the page should match the visual baseline "login_page"
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../helpers/visual_helper'
4
+ require_relative '../../page_objects/pages/login'
5
+
6
+ include VisualHelper
7
+
8
+ Given("I'm on the login page") do
9
+ @login_page = <% if capybara? %>Login.new<% elsif watir? %>Login.new(browser)<% else %>Login.new(driver)<% end %>
10
+ @login_page.<% if capybara? %>visit_page<% else %>visit<% end %>
11
+ end
12
+
13
+ Then('the page should match the visual baseline {string}') do |baseline_name|
14
+ screenshot_path = <% if capybara? %>page.save_screenshot("tmp/visual_#{baseline_name}.png")<% elsif watir? %>browser.screenshot.save("tmp/visual_#{baseline_name}.png")<% else %>driver.save_screenshot("tmp/visual_#{baseline_name}.png")<% end %>
15
+ result = compare_screenshot(baseline_name, screenshot_path)
16
+
17
+ expect(result[:status]).not_to eq(:mismatch),
18
+ "Visual diff: #{(result[:diff].to_f * 100).round(2)}% difference. See: #{result[:diff_path]}"
19
+ end
@@ -1,5 +1,7 @@
1
- <%- if watir? -%>
2
- <%=- ERB.new(File.read(File.expand_path('./partials/watir_world.tt', __dir__)), trim_mode: '-').result(binding).strip! -%>
1
+ <%- if capybara? -%>
2
+ <%=- partial('capybara_world', strip: true) -%>
3
+ <%- elsif watir? -%>
4
+ <%=- partial('watir_world', strip: true) -%>
3
5
  <%- else -%>
4
- <%=- ERB.new(File.read(File.expand_path('./partials/driver_world.tt', __dir__)), trim_mode: '-').result(binding).strip! -%>
6
+ <%=- partial('driver_world', strip: true) -%>
5
7
  <%- end -%>
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'thor'
4
+ require_relative 'template_renderer'
4
5
 
5
6
  class Generator < Thor::Group
6
7
  include Thor::Actions
8
+ include TemplateRenderer
9
+
10
+ LATEST_RUBY = '3.4'
7
11
 
8
12
  argument :automation
9
13
  argument :framework
@@ -12,7 +16,8 @@ class Generator < Thor::Group
12
16
  def self.source_paths
13
17
  base_path = File.dirname(__FILE__)
14
18
  %W[#{base_path}/automation/templates #{base_path}/cucumber/templates
15
- #{base_path}/rspec/templates #{base_path}/templates #{base_path}/infrastructure/templates ]
19
+ #{base_path}/rspec/templates #{base_path}/minitest/templates
20
+ #{base_path}/templates #{base_path}/infrastructure/templates ]
16
21
  end
17
22
 
18
23
  def args
@@ -48,12 +53,20 @@ class Generator < Thor::Group
48
53
  args.include?('rspec')
49
54
  end
50
55
 
56
+ def minitest?
57
+ args.include?('minitest')
58
+ end
59
+
51
60
  def selenium?
52
61
  args.include?('selenium')
53
62
  end
54
63
 
55
- def visual?
56
- args.include?('applitools')
64
+ def capybara?
65
+ args.include?('capybara')
66
+ end
67
+
68
+ def visual_addon?
69
+ args.include?('visual_addon')
57
70
  end
58
71
 
59
72
  def watir?
@@ -61,15 +74,45 @@ class Generator < Thor::Group
61
74
  end
62
75
 
63
76
  def web?
64
- (args & (%w[selenium watir axe applitools])).count.positive?
77
+ (args & %w[selenium watir capybara]).count.positive?
65
78
  end
66
79
 
67
- def axe?
68
- args.include?('axe')
80
+ def axe_addon?
81
+ args.include?('axe_addon')
82
+ end
83
+
84
+ def lighthouse_addon?
85
+ args.include?('lighthouse_addon')
69
86
  end
70
87
 
71
88
  def selenium_based?
72
- (args & %w[selenium axe applitools]).count.positive?
89
+ args.include?('selenium')
90
+ end
91
+
92
+ def skip_allure?
93
+ args.include?('skip_allure')
94
+ end
95
+
96
+ def skip_video?
97
+ args.include?('skip_video')
98
+ end
99
+
100
+ def allure_reporter?
101
+ has_reporter = args.any? { |a| a&.start_with?('reporter_') }
102
+ has_reporter ? args.include?('reporter_allure') : !skip_allure?
103
+ end
104
+
105
+ def junit_reporter?
106
+ args.include?('reporter_junit')
107
+ end
108
+
109
+ def json_reporter?
110
+ args.include?('reporter_json')
111
+ end
112
+
113
+ def ruby_version
114
+ arg = args.find { |a| a&.start_with?('ruby_version:') }
115
+ arg ? arg.split(':', 2).last : LATEST_RUBY
73
116
  end
74
117
 
75
118
  private
@@ -6,12 +6,16 @@ class HelpersGenerator < Generator
6
6
  def generate_helpers
7
7
  generate_browser_helper
8
8
  generate_driver_helper
9
+ generate_capybara_helper
9
10
  generate_appium_helper
10
11
  generate_allure_helper
12
+ generate_video_helper
13
+ generate_debug_helper
14
+ generate_visual_helper
15
+ generate_performance_helper
11
16
 
12
- if visual?
13
- generate_visual_helper
14
- generate_visual_spec_helper
17
+ if minitest?
18
+ generate_test_helper
15
19
  else
16
20
  generate_spec_helper
17
21
  end
@@ -20,40 +24,66 @@ class HelpersGenerator < Generator
20
24
  private
21
25
 
22
26
  def generate_allure_helper
27
+ return unless allure_reporter?
28
+
23
29
  template('helpers/allure_helper.tt', "#{name}/helpers/allure_helper.rb")
24
30
  end
25
31
 
32
+ def generate_video_helper
33
+ return if skip_video?
34
+
35
+ template('helpers/video_helper.tt', "#{name}/helpers/video_helper.rb")
36
+ end
37
+
26
38
  def generate_browser_helper
27
- return if selenium_based? || mobile?
39
+ return if selenium_based? || mobile? || capybara?
28
40
 
29
41
  template('helpers/browser_helper.tt', "#{name}/helpers/browser_helper.rb")
30
42
  end
31
43
 
32
44
  def generate_spec_helper
33
- return if cucumber?
45
+ return if cucumber? || minitest?
34
46
 
35
47
  template('helpers/spec_helper.tt', "#{name}/helpers/spec_helper.rb")
36
48
  end
37
49
 
38
50
  def generate_driver_helper
39
- return if watir?
51
+ return if watir? || capybara?
40
52
 
41
53
  template('helpers/driver_helper.tt', "#{name}/helpers/driver_helper.rb")
42
54
  end
43
55
 
56
+ def generate_capybara_helper
57
+ return unless capybara?
58
+
59
+ template('helpers/capybara_helper.tt', "#{name}/helpers/capybara_helper.rb")
60
+ end
61
+
44
62
  def generate_appium_helper
45
63
  return unless cross_platform?
46
64
 
47
65
  template('helpers/appium_helper.tt', "#{name}/helpers/appium_helper.rb")
48
66
  end
49
67
 
68
+ def generate_test_helper
69
+ template('helpers/test_helper.tt', "#{name}/helpers/test_helper.rb")
70
+ end
71
+
72
+ def generate_debug_helper
73
+ return unless web?
74
+
75
+ template('helpers/debug_helper.tt', "#{name}/helpers/debug_helper.rb")
76
+ end
77
+
50
78
  def generate_visual_helper
79
+ return unless visual_addon? && web?
80
+
51
81
  template('helpers/visual_helper.tt', "#{name}/helpers/visual_helper.rb")
52
82
  end
53
83
 
54
- def generate_visual_spec_helper
55
- return if cucumber?
84
+ def generate_performance_helper
85
+ return unless lighthouse_addon? && web?
56
86
 
57
- template('helpers/visual_spec_helper.tt', "#{name}/helpers/spec_helper.rb")
87
+ template('helpers/performance_helper.tt', "#{name}/helpers/performance_helper.rb")
58
88
  end
59
89
  end
@@ -8,4 +8,10 @@ class GithubGenerator < Generator
8
8
 
9
9
  template('github.tt', "#{name}/.github/workflows/test_pipeline.yml")
10
10
  end
11
+
12
+ def generate_appium_pipeline
13
+ return unless mobile?
14
+
15
+ template('github_appium.tt', "#{name}/.github/workflows/appium_pipeline.yml")
16
+ end
11
17
  end
@@ -16,23 +16,27 @@ jobs:
16
16
  runs-on: ubuntu-latest
17
17
 
18
18
  steps:
19
+ - name: Checkout repository
20
+ uses: actions/checkout@v4
21
+
19
22
  - name: Set up Ruby
20
23
  uses: ruby/setup-ruby@v1
21
24
  with:
22
- ruby-version: 3.4.0
25
+ ruby-version: <%= ruby_version %>.0
23
26
  bundler-cache: true
24
27
 
25
- - name: Checkout repository
26
- uses: actions/checkout@v3
27
-
28
- - name: Install gems
29
- run: bundle install
28
+ - name: Set up Chrome
29
+ uses: browser-actions/setup-chrome@v1
30
+ with:
31
+ chrome-version: stable
30
32
 
31
33
  - name: Create allure-results folder
32
34
  run: mkdir -p allure-results
33
35
 
34
- - name: Build and test with rspec
35
- run: <%- if framework == 'cucumber' -%>cucumber features --format pretty <%- else -%>bundle exec rspec spec --format documentation<%- end -%>
36
+ - name: Run tests
37
+ run: <%- if framework == 'cucumber' -%>bundle exec cucumber features --format pretty<%- elsif minitest? -%>bundle exec ruby -Itest test/test_login_page.rb<%- else -%>bundle exec rspec spec --format documentation<%- end %>
38
+ env:
39
+ HEADLESS: true
36
40
 
37
41
  - name: Get Allure history
38
42
  uses: actions/checkout@v2
@@ -0,0 +1,108 @@
1
+ name: Appium Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ <%- if ios? || cross_platform? -%>
11
+ ios-tests:
12
+ runs-on: macos-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: ruby/setup-ruby@v1
16
+ with:
17
+ ruby-version: <%= ruby_version %>.0
18
+ bundler-cache: true
19
+
20
+ - name: Download iOS app
21
+ uses: dawidd6/action-download-artifact@v6
22
+ with:
23
+ github_token: ${{ secrets.GITHUB_TOKEN }}
24
+ repo: RaiderHQ/raider_test_app
25
+ workflow: build-ios.yml
26
+ name: raider-test-app-ios
27
+ path: apps/
28
+
29
+ - name: Unzip iOS app
30
+ run: |
31
+ cd apps
32
+ unzip RaiderTestApp.app.zip
33
+
34
+ - name: Start iOS Simulator
35
+ uses: futureware-tech/simulator-action@v3
36
+ with:
37
+ model: 'iPhone 15'
38
+ os_version: '17'
39
+
40
+ - name: Install and start Appium
41
+ run: |
42
+ npm install -g appium
43
+ appium driver install xcuitest
44
+ appium &
45
+ sleep 5
46
+
47
+ - name: Run tests
48
+ <%- if cucumber? -%>
49
+ run: bundle exec cucumber features/ --format pretty
50
+ <%- elsif minitest? -%>
51
+ run: bundle exec ruby -Itest test/test_pdp_page.rb
52
+ <%- else -%>
53
+ run: bundle exec rspec spec/ --format documentation
54
+ <%- end -%>
55
+ env:
56
+ APP_PATH: ${{ github.workspace }}/apps/RaiderTestApp.app
57
+ <%- end -%>
58
+
59
+ <%- if android? || cross_platform? -%>
60
+ android-tests:
61
+ runs-on: ubuntu-latest
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+ - uses: ruby/setup-ruby@v1
65
+ with:
66
+ ruby-version: <%= ruby_version %>.0
67
+ bundler-cache: true
68
+
69
+ - name: Download Android app
70
+ uses: dawidd6/action-download-artifact@v6
71
+ with:
72
+ github_token: ${{ secrets.GITHUB_TOKEN }}
73
+ repo: RaiderHQ/raider_test_app
74
+ workflow: build-android.yml
75
+ name: raider-test-app-android
76
+ path: apps/
77
+
78
+ - name: Set up JDK 17
79
+ uses: actions/setup-java@v4
80
+ with:
81
+ java-version: '17'
82
+ distribution: 'temurin'
83
+
84
+ - name: Install and start Appium
85
+ run: |
86
+ npm install -g appium
87
+ appium driver install uiautomator2
88
+ appium &
89
+ sleep 5
90
+
91
+ - name: Run Android Emulator and Tests
92
+ uses: reactivecircus/android-emulator-runner@v2
93
+ with:
94
+ api-level: 34
95
+ target: google_apis
96
+ arch: x86_64
97
+ profile: pixel_8
98
+ script: |
99
+ <%- if cucumber? -%>
100
+ bundle exec cucumber features/ --format pretty
101
+ <%- elsif minitest? -%>
102
+ bundle exec ruby -Itest test/test_pdp_page.rb
103
+ <%- else -%>
104
+ bundle exec rspec spec/ --format documentation
105
+ <%- end -%>
106
+ env:
107
+ APP_PATH: ${{ github.workspace }}/apps/app-release.apk
108
+ <%- end -%>
@@ -4,7 +4,8 @@ stages:
4
4
  - report
5
5
 
6
6
  variables:
7
- RUBY_VERSION: "3.4.0"
7
+ RUBY_VERSION: "<%= ruby_version %>.0"
8
+ HEADLESS: "true"
8
9
 
9
10
  setup_ruby:
10
11
  stage: setup
@@ -18,9 +19,11 @@ setup_ruby:
18
19
  run_tests:
19
20
  stage: test
20
21
  image: ruby:${RUBY_VERSION}
21
- script:
22
+ before_script:
23
+ - apt-get update -qq && apt-get install -y -qq chromium chromium-driver
22
24
  - mkdir -p allure-results
23
- - <%- if framework == 'cucumber' -%> cucumber features --format pretty <%- else -%> bundle exec rspec spec --format documentation <%- end%>
25
+ script:
26
+ - <%- if framework == 'cucumber' -%>bundle exec cucumber features --format pretty<%- elsif minitest? -%>bundle exec ruby -Itest test/test_login_page.rb<%- else -%>bundle exec rspec spec --format documentation<%- end %>
24
27
  artifacts:
25
28
  paths:
26
29
  - allure-results/
@@ -4,10 +4,9 @@ require_relative 'automation/automation_generator'
4
4
  require_relative 'common_generator'
5
5
  require_relative 'cucumber/cucumber_generator'
6
6
  require_relative 'helper_generator'
7
+ require_relative 'minitest/minitest_generator'
7
8
  require_relative 'rspec/rspec_generator'
8
9
 
9
- # :reek:FeatureEnvy { enabled: false }
10
- # :reek:UtilityFunction { enabled: false }
11
10
  module InvokeGenerators
12
11
  module_function
13
12
 
@@ -15,14 +14,16 @@ module InvokeGenerators
15
14
  generators = %w[Automation Common Helpers]
16
15
  framework = structure[:framework]
17
16
  add_generator(generators, framework.capitalize)
18
- add_generator(generators, structure[:ci_platform].capitalize) if structure[:ci_platform]
17
+ add_generator(generators, structure[:ci_platform].capitalize) if !structure[:skip_ci] && (structure[:ci_platform])
18
+ extra_args = collect_skip_flags(structure)
19
19
  generators.each do |generator|
20
20
  invoke_generator({
21
21
  automation: structure[:automation],
22
22
  framework:,
23
23
  generator:,
24
24
  ci_platform: structure[:ci_platform],
25
- name: structure[:name]
25
+ name: structure[:name],
26
+ extra_args:
26
27
  })
27
28
  end
28
29
  end
@@ -31,12 +32,45 @@ module InvokeGenerators
31
32
  gens.each { |generator| generators.push generator }
32
33
  end
33
34
 
35
+ # Generator class lookup cache — avoids repeated Object.const_get string interpolation
36
+ GENERATOR_CLASSES = Hash.new { |h, k| h[k] = Object.const_get("#{k}Generator") }
37
+
34
38
  def invoke_generator(structure = {})
35
- Object.const_get("#{structure[:generator]}Generator")
36
- .new([structure[:automation],
37
- structure[:framework],
38
- structure[:name],
39
- structure[:ci_platform]]).invoke_all
39
+ args = [structure[:automation], structure[:framework], structure[:name], structure[:ci_platform]]
40
+ args.concat(structure[:extra_args] || [])
41
+ generator_class = GENERATOR_CLASSES[structure[:generator]]
42
+ generator = generator_class.new(args)
43
+ # Enable batch mode on the template cache to skip mtime checks during generation
44
+ generator.class.template_renderer.batch_mode = true if generator.class.respond_to?(:template_renderer)
45
+ generator.invoke_all
46
+ end
47
+
48
+ def collect_skip_flags(structure)
49
+ flags = []
50
+ flags << 'skip_allure' if structure[:skip_allure]
51
+ flags << 'skip_video' if structure[:skip_video]
52
+ flags << 'axe_addon' if structure[:accessibility] && !mobile_automation?(structure[:automation])
53
+ flags << 'visual_addon' if structure[:visual] && !mobile_automation?(structure[:automation])
54
+ flags << 'lighthouse_addon' if structure[:performance] && !mobile_automation?(structure[:automation])
55
+ flags << "ruby_version:#{structure[:ruby_version]}" if structure[:ruby_version]
56
+ flags.concat(reporter_flags(structure[:reporter]))
57
+ flags
58
+ end
59
+
60
+ def reporter_flags(reporter)
61
+ case reporter
62
+ when 'allure' then ['reporter_allure']
63
+ when 'junit' then ['reporter_junit']
64
+ when 'json' then ['reporter_json']
65
+ when 'both' then %w[reporter_allure reporter_junit]
66
+ when 'all' then %w[reporter_allure reporter_junit reporter_json]
67
+ when 'none' then ['reporter_none']
68
+ else []
69
+ end
70
+ end
71
+
72
+ def mobile_automation?(automation)
73
+ %w[ios android cross_platform].include?(automation)
40
74
  end
41
75
 
42
76
  def to_bool(string)