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
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require_relative '../../lib/adopter/adopt_menu'
5
+ require_relative 'support/system_test_helper'
6
+
7
+ describe 'Adopt end-to-end' do
8
+ include SystemTestHelper
9
+
10
+ let(:source_dir) { "tmp_adopt_e2e_source_#{automation}" }
11
+ let(:output_dir) { "tmp_adopt_e2e_#{automation}_#{framework}" }
12
+
13
+ before do
14
+ FileUtils.mkdir_p("#{source_dir}/pages")
15
+ FileUtils.mkdir_p("#{source_dir}/spec")
16
+
17
+ File.write("#{source_dir}/Gemfile", <<~GEMFILE)
18
+ gem 'rspec'
19
+ gem 'selenium-webdriver'
20
+ gem 'faker'
21
+ GEMFILE
22
+
23
+ File.write("#{source_dir}/pages/login_page.rb", <<~RUBY)
24
+ class LoginPage < BasePage
25
+ def login(user, pass)
26
+ driver.find_element(id: 'user').send_keys user
27
+ end
28
+ end
29
+ RUBY
30
+
31
+ File.write("#{source_dir}/spec/login_spec.rb", <<~RUBY)
32
+ describe 'Login' do
33
+ it 'can log in' do
34
+ expect(true).to eq true
35
+ end
36
+ end
37
+ RUBY
38
+ end
39
+
40
+ after do
41
+ FileUtils.rm_rf(source_dir)
42
+ FileUtils.rm_rf(output_dir)
43
+ end
44
+
45
+ shared_examples 'valid adopted project' do
46
+ it 'creates a complete raider project structure' do
47
+ expect(File).to exist("#{output_dir}/Gemfile")
48
+ expect(File).to exist("#{output_dir}/Rakefile")
49
+ expect(File).to exist("#{output_dir}/Readme.md")
50
+ expect(File).to exist("#{output_dir}/.rubocop.yml")
51
+ end
52
+
53
+ it 'converts pages into raider paths' do
54
+ expect(File).to exist("#{output_dir}/page_objects/pages/login.rb")
55
+ end
56
+
57
+ it 'adds frozen_string_literal to converted pages' do
58
+ page = File.read("#{output_dir}/page_objects/pages/login.rb")
59
+ expect(page).to include('# frozen_string_literal: true')
60
+ end
61
+
62
+ it 'updates base class to Page' do
63
+ page = File.read("#{output_dir}/page_objects/pages/login.rb")
64
+ expect(page).to include('class LoginPage < Page')
65
+ end
66
+
67
+ it 'merges custom gems into Gemfile' do
68
+ gemfile = File.read("#{output_dir}/Gemfile")
69
+ expect(gemfile).to include("gem 'faker'")
70
+ end
71
+ end
72
+
73
+ context 'selenium to selenium (identity conversion)' do
74
+ let(:automation) { 'selenium' }
75
+ let(:framework) { 'rspec' }
76
+
77
+ before do
78
+ Adopter::AdoptMenu.adopt(
79
+ source_path: source_dir, output_path: output_dir,
80
+ target_automation: 'selenium', target_framework: 'rspec'
81
+ )
82
+ end
83
+
84
+ include_examples 'valid adopted project'
85
+
86
+ it 'generates rspec test files' do
87
+ expect(File).to exist("#{output_dir}/spec")
88
+ end
89
+
90
+ it 'generates selenium helpers' do
91
+ expect(File).to exist("#{output_dir}/helpers/driver_helper.rb")
92
+ end
93
+
94
+ it 'converts page instantiation to use driver' do
95
+ result = Adopter::AdoptMenu.adopt(
96
+ source_path: source_dir, output_path: "#{output_dir}_check",
97
+ target_automation: 'selenium', target_framework: 'rspec'
98
+ )
99
+
100
+ page = result[:plan].converted_pages.first.content
101
+ expect(page).not_to include('LoginPage.new(browser)')
102
+
103
+ FileUtils.rm_rf("#{output_dir}_check")
104
+ end
105
+ end
106
+
107
+ context 'selenium to capybara' do
108
+ let(:automation) { 'capybara' }
109
+ let(:framework) { 'rspec' }
110
+
111
+ before do
112
+ Adopter::AdoptMenu.adopt(
113
+ source_path: source_dir, output_path: output_dir,
114
+ target_automation: 'capybara', target_framework: 'rspec'
115
+ )
116
+ end
117
+
118
+ include_examples 'valid adopted project'
119
+
120
+ it 'generates capybara helpers' do
121
+ expect(File).to exist("#{output_dir}/helpers/capybara_helper.rb")
122
+ end
123
+
124
+ it 'does not generate driver_helper' do
125
+ expect(File).not_to exist("#{output_dir}/helpers/driver_helper.rb")
126
+ end
127
+ end
128
+
129
+ context 'selenium to watir + minitest' do
130
+ let(:automation) { 'watir' }
131
+ let(:framework) { 'minitest' }
132
+
133
+ before do
134
+ Adopter::AdoptMenu.adopt(
135
+ source_path: source_dir, output_path: output_dir,
136
+ target_automation: 'watir', target_framework: 'minitest'
137
+ )
138
+ end
139
+
140
+ include_examples 'valid adopted project'
141
+
142
+ it 'generates watir helpers' do
143
+ expect(File).to exist("#{output_dir}/helpers/browser_helper.rb")
144
+ end
145
+
146
+ it 'generates minitest test helper' do
147
+ expect(File).to exist("#{output_dir}/helpers/test_helper.rb")
148
+ end
149
+
150
+ it 'generates minitest test directory' do
151
+ expect(File).to exist("#{output_dir}/test")
152
+ end
153
+ end
154
+
155
+ context 'selenium to selenium + cucumber' do
156
+ let(:automation) { 'selenium' }
157
+ let(:framework) { 'cucumber' }
158
+
159
+ before do
160
+ FileUtils.mkdir_p("#{source_dir}/features/step_definitions")
161
+ File.write("#{source_dir}/features/login.feature", <<~GHERKIN)
162
+ Feature: Login
163
+ Scenario: Valid login
164
+ Given I am on the login page
165
+ GHERKIN
166
+ File.write("#{source_dir}/features/step_definitions/login_steps.rb", <<~RUBY)
167
+ Given('I am on the login page') do
168
+ @page = LoginPage.new(driver)
169
+ end
170
+ RUBY
171
+ File.write("#{source_dir}/Gemfile", "gem 'cucumber'\ngem 'selenium-webdriver'\ngem 'faker'\n")
172
+
173
+ Adopter::AdoptMenu.adopt(
174
+ source_path: source_dir, output_path: output_dir,
175
+ target_automation: 'selenium', target_framework: 'cucumber'
176
+ )
177
+ end
178
+
179
+ include_examples 'valid adopted project'
180
+
181
+ it 'copies feature files' do
182
+ expect(File).to exist("#{output_dir}/features/login.feature")
183
+ end
184
+
185
+ it 'converts step definitions' do
186
+ expect(File).to exist("#{output_dir}/features/step_definitions/login_steps.rb")
187
+ end
188
+
189
+ it 'generates cucumber support files' do
190
+ expect(File).to exist("#{output_dir}/features/support/env.rb")
191
+ end
192
+ end
193
+
194
+ context 'with config overrides' do
195
+ let(:automation) { 'selenium' }
196
+ let(:framework) { 'rspec' }
197
+
198
+ it 'applies browser and url overrides' do
199
+ Adopter::AdoptMenu.adopt(
200
+ source_path: source_dir, output_path: output_dir,
201
+ target_automation: 'selenium', target_framework: 'rspec',
202
+ browser: 'firefox', url: 'https://example.com'
203
+ )
204
+
205
+ config = YAML.safe_load(File.read("#{output_dir}/config/config.yml"), permitted_classes: [Symbol])
206
+ expect(config['browser']).to eq('firefox')
207
+ expect(config['url']).to eq('https://example.com')
208
+ end
209
+ end
210
+
211
+ context 'with CI platform' do
212
+ let(:automation) { 'selenium' }
213
+ let(:framework) { 'rspec' }
214
+
215
+ it 'generates github CI configuration' do
216
+ Adopter::AdoptMenu.adopt(
217
+ source_path: source_dir, output_path: output_dir,
218
+ target_automation: 'selenium', target_framework: 'rspec',
219
+ ci_platform: 'github'
220
+ )
221
+
222
+ expect(File).to exist("#{output_dir}/.github")
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/ruby_raider'
4
+ require_relative 'support/system_test_helper'
5
+
6
+ FRAMEWORKS = %w[cucumber rspec minitest].freeze unless defined?(FRAMEWORKS)
7
+
8
+ describe 'Capybara based frameworks' do
9
+ include SystemTestHelper
10
+
11
+ before(:all) do # rubocop:disable RSpec/BeforeAfterAll
12
+ FRAMEWORKS.each do |framework|
13
+ RubyRaider::Raider
14
+ .new.invoke(:new, nil, %W[capybara_#{framework} -p framework:#{framework} automation:capybara])
15
+ end
16
+ end
17
+
18
+ after(:all) do # rubocop:disable RSpec/BeforeAfterAll
19
+ FRAMEWORKS.each { |framework| FileUtils.rm_rf("capybara_#{framework}") }
20
+ end
21
+
22
+ shared_examples 'runs tests successfully' do |framework|
23
+ it 'installs dependencies and runs tests without errors' do
24
+ result = run_tests_with(framework, 'capybara')
25
+ expect(result[:success]).to be(true),
26
+ "Tests failed for capybara_#{framework}.\n" \
27
+ "STDOUT: #{result[:stdout]}\nSTDERR: #{result[:stderr]}"
28
+ end
29
+ end
30
+
31
+ context 'with rspec' do
32
+ include_examples 'runs tests successfully', 'rspec'
33
+ end
34
+
35
+ context 'with cucumber' do
36
+ include_examples 'runs tests successfully', 'cucumber'
37
+ end
38
+
39
+ context 'with minitest' do
40
+ include_examples 'runs tests successfully', 'minitest'
41
+ end
42
+ end
@@ -1,40 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../../lib/ruby_raider'
4
+ require_relative 'support/system_test_helper'
2
5
 
3
- FRAMEWORKS = %w[cucumber rspec].freeze
6
+ FRAMEWORKS = %w[cucumber rspec minitest].freeze
4
7
 
5
8
  describe 'Selenium based frameworks' do
6
- before do
9
+ include SystemTestHelper
10
+
11
+ before(:all) do # rubocop:disable RSpec/BeforeAfterAll
7
12
  FRAMEWORKS.each do |framework|
8
13
  RubyRaider::Raider
9
14
  .new.invoke(:new, nil, %W[selenium_#{framework} -p framework:#{framework} automation:selenium])
10
15
  end
11
16
  end
12
17
 
13
- after do
14
- FRAMEWORKS.each do |framework|
15
- FileUtils.rm_rf("selenium_#{framework}")
16
- end
18
+ after(:all) do # rubocop:disable RSpec/BeforeAfterAll
19
+ FRAMEWORKS.each { |framework| FileUtils.rm_rf("selenium_#{framework}") }
17
20
  end
18
21
 
19
- shared_examples 'creates web automation framework' do |type|
20
- it 'executes without errors' do
21
- run_tests_with(type)
22
- expect($stdout).not_to match(/StandardError/)
22
+ shared_examples 'runs tests successfully' do |framework|
23
+ it 'installs dependencies and runs tests without errors' do
24
+ result = run_tests_with(framework, 'selenium')
25
+ expect(result[:success]).to be(true),
26
+ "Tests failed for selenium_#{framework}.\n" \
27
+ "STDOUT: #{result[:stdout]}\nSTDERR: #{result[:stderr]}"
23
28
  end
24
29
  end
25
30
 
26
31
  context 'with rspec' do
27
- include_examples 'creates web automation framework', 'rspec'
32
+ include_examples 'runs tests successfully', 'rspec'
28
33
  end
29
34
 
30
35
  context 'with cucumber' do
31
- include_examples 'creates web automation framework', 'cucumber'
36
+ include_examples 'runs tests successfully', 'cucumber'
32
37
  end
33
38
 
34
- private
35
-
36
- def run_tests_with(framework)
37
- folder = framework == 'rspec' ? 'spec' : 'features'
38
- system("cd selenium_#{framework} && bundle install && raider utility browser_options chrome headless && bundle exec #{framework} #{folder}")
39
+ context 'with minitest' do
40
+ include_examples 'runs tests successfully', 'minitest'
39
41
  end
40
42
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module SystemTestHelper
6
+ def test_command_for(framework)
7
+ case framework
8
+ when 'cucumber' then 'bundle exec cucumber features --format pretty'
9
+ when 'minitest' then 'bundle exec ruby -Itest test/test_login_page.rb'
10
+ else 'bundle exec rspec spec --format documentation'
11
+ end
12
+ end
13
+
14
+ def run_tests_with(framework, automation)
15
+ project = "#{automation}_#{framework}"
16
+
17
+ Bundler.with_unbundled_env do
18
+ Dir.chdir(project) do
19
+ result = run_command('bundle install --quiet')
20
+ return result unless result[:success]
21
+
22
+ run_command(test_command_for(framework), env: { 'HEADLESS' => 'true' })
23
+ end
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def run_command(command, env: {})
30
+ stdout, stderr, status = Open3.capture3(env, command)
31
+ { success: status.success?, stdout:, stderr: }
32
+ end
33
+ end
@@ -1,40 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../../lib/ruby_raider'
4
+ require_relative 'support/system_test_helper'
2
5
 
3
- FRAMEWORKS = %w[cucumber rspec].freeze
6
+ FRAMEWORKS = %w[cucumber rspec minitest].freeze unless defined?(FRAMEWORKS)
4
7
 
5
8
  describe 'Watir based frameworks' do
6
- before do
9
+ include SystemTestHelper
10
+
11
+ before(:all) do # rubocop:disable RSpec/BeforeAfterAll
7
12
  FRAMEWORKS.each do |framework|
8
13
  RubyRaider::Raider
9
14
  .new.invoke(:new, nil, %W[watir_#{framework} -p framework:#{framework} automation:watir])
10
15
  end
11
16
  end
12
17
 
13
- after do
14
- FRAMEWORKS.each do |framework|
15
- FileUtils.rm_rf("watir_#{framework}")
16
- end
18
+ after(:all) do # rubocop:disable RSpec/BeforeAfterAll
19
+ FRAMEWORKS.each { |framework| FileUtils.rm_rf("watir_#{framework}") }
17
20
  end
18
21
 
19
- shared_examples 'creates web automation framework' do |type|
20
- it 'executes without errors' do
21
- run_tests_with(type)
22
- expect($stdout).not_to match(/StandardError/)
22
+ shared_examples 'runs tests successfully' do |framework|
23
+ it 'installs dependencies and runs tests without errors' do
24
+ result = run_tests_with(framework, 'watir')
25
+ expect(result[:success]).to be(true),
26
+ "Tests failed for watir_#{framework}.\n" \
27
+ "STDOUT: #{result[:stdout]}\nSTDERR: #{result[:stderr]}"
23
28
  end
24
29
  end
25
30
 
26
31
  context 'with rspec' do
27
- include_examples 'creates web automation framework', 'rspec'
32
+ include_examples 'runs tests successfully', 'rspec'
28
33
  end
29
34
 
30
35
  context 'with cucumber' do
31
- include_examples 'creates web automation framework', 'cucumber'
36
+ include_examples 'runs tests successfully', 'cucumber'
32
37
  end
33
38
 
34
- private
35
-
36
- def run_tests_with(framework)
37
- folder = framework == 'rspec' ? 'spec' : 'features'
38
- system("cd watir_#{framework} && bundle install && raider utility browser_options chrome headless && bundle exec #{framework} #{folder}")
39
+ context 'with minitest' do
40
+ include_examples 'runs tests successfully', 'minitest'
39
41
  end
40
42
  end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/utilities/desktop_downloader'
4
+
5
+ describe DesktopDownloader do
6
+ describe '.platform' do
7
+ it 'returns a recognized platform string' do
8
+ expect(%w[mac_arm mac_intel windows linux_appimage linux_deb]).to include(described_class.platform) # rubocop:disable RSpec/ExpectActual
9
+ end
10
+ end
11
+
12
+ describe '.platform_display_name' do
13
+ it 'returns a human-readable name' do
14
+ expect(described_class.platform_display_name).to be_a(String)
15
+ expect(described_class.platform_display_name).not_to eq('Unknown')
16
+ end
17
+
18
+ it 'matches the detected platform' do
19
+ expected_names = {
20
+ 'mac_arm' => 'macOS (Apple Silicon)',
21
+ 'mac_intel' => 'macOS (Intel)',
22
+ 'windows' => 'Windows',
23
+ 'linux_deb' => 'Linux (deb)',
24
+ 'linux_appimage' => 'Linux (AppImage)'
25
+ }
26
+ expect(described_class.platform_display_name).to eq(expected_names[described_class.platform])
27
+ end
28
+ end
29
+
30
+ describe 'PLATFORM_PATTERNS' do
31
+ it 'has patterns for all supported platforms' do
32
+ expect(described_class::PLATFORM_PATTERNS.keys).to contain_exactly(
33
+ 'mac_arm', 'mac_intel', 'windows', 'linux_deb', 'linux_appimage'
34
+ )
35
+ end
36
+
37
+ it 'mac patterns match .dmg files' do
38
+ expect(described_class::PLATFORM_PATTERNS['mac_arm']).to match('Raider-Desktop-1.0.0.dmg')
39
+ expect(described_class::PLATFORM_PATTERNS['mac_intel']).to match('Raider-Desktop-1.0.0.dmg')
40
+ end
41
+
42
+ it 'windows pattern matches setup.exe files' do
43
+ expect(described_class::PLATFORM_PATTERNS['windows']).to match('Raider-Desktop-1.0.0-setup.exe')
44
+ end
45
+
46
+ it 'linux deb pattern matches .deb files' do
47
+ expect(described_class::PLATFORM_PATTERNS['linux_deb']).to match('raider-desktop_1.0.0_amd64.deb')
48
+ end
49
+
50
+ it 'linux appimage pattern matches .AppImage files' do
51
+ expect(described_class::PLATFORM_PATTERNS['linux_appimage']).to match('Raider-Desktop-1.0.0.AppImage')
52
+ end
53
+
54
+ it 'does not cross-match patterns' do
55
+ expect(described_class::PLATFORM_PATTERNS['windows']).not_to match('Raider-Desktop.dmg')
56
+ expect(described_class::PLATFORM_PATTERNS['mac_arm']).not_to match('Raider-Desktop-setup.exe')
57
+ end
58
+ end
59
+
60
+ describe '.latest_version' do
61
+ context 'when GitHub API is reachable' do
62
+ it 'returns a version string or nil' do
63
+ version = described_class.latest_version
64
+ # May be nil if rate-limited or offline, that's OK
65
+ expect(version).to be_nil.or(match(/\Av?\d+\.\d+/))
66
+ end
67
+ end
68
+ end
69
+
70
+ describe '.download_url' do
71
+ context 'when GitHub API is reachable' do
72
+ it 'returns a URL string or nil' do
73
+ url = described_class.download_url
74
+ expect(url).to be_nil.or(match(%r{\Ahttps://}))
75
+ end
76
+ end
77
+ end
78
+
79
+ describe 'REPO' do
80
+ it 'points to the correct GitHub repository' do
81
+ expect(described_class::REPO).to eq('RaiderHQ/raider_desktop')
82
+ end
83
+ end
84
+
85
+ describe 'API_URL' do
86
+ it 'is a valid GitHub releases API endpoint' do
87
+ expect(described_class::API_URL).to eq(
88
+ 'https://api.github.com/repos/RaiderHQ/raider_desktop/releases/latest'
89
+ )
90
+ end
91
+ end
92
+ end