ruby_raider 2.0.0 → 3.0.1

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 (228) 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 +246 -38
  20. data/lib/commands/utility_commands.rb +92 -3
  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 +13 -3
  71. data/lib/generators/templates/helpers/capybara_helper.tt +6 -2
  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 +9 -8
  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 +96 -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 +61 -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/commands/scaffolding_commands_spec.rb +22 -0
  178. data/spec/generators/generator_spec.rb +23 -0
  179. data/spec/integration/commands/scaffolding_commands_spec.rb +1 -1
  180. data/spec/integration/commands/utility_commands_spec.rb +29 -9
  181. data/spec/integration/content/ci_content_spec.rb +119 -0
  182. data/spec/integration/content/common_content_spec.rb +288 -0
  183. data/spec/integration/content/config_content_spec.rb +175 -0
  184. data/spec/integration/content/content_helper.rb +32 -0
  185. data/spec/integration/content/gemfile_content_spec.rb +209 -0
  186. data/spec/integration/content/helper_content_spec.rb +485 -0
  187. data/spec/integration/content/page_content_spec.rb +259 -0
  188. data/spec/integration/content/reporter_content_spec.rb +236 -0
  189. data/spec/integration/content/skip_flags_content_spec.rb +206 -0
  190. data/spec/integration/content/syntax_validation_spec.rb +30 -0
  191. data/spec/integration/content/test_content_spec.rb +266 -0
  192. data/spec/integration/end_to_end_features_spec.rb +690 -0
  193. data/spec/integration/end_to_end_spec.rb +52 -16
  194. data/spec/integration/generators/automation_generator_spec.rb +0 -12
  195. data/spec/integration/generators/axe_addon_spec.rb +150 -0
  196. data/spec/integration/generators/common_generator_spec.rb +12 -13
  197. data/spec/integration/generators/config_features_spec.rb +155 -0
  198. data/spec/integration/generators/debug_helper_spec.rb +68 -0
  199. data/spec/integration/generators/helpers_generator_spec.rb +0 -12
  200. data/spec/integration/generators/lighthouse_addon_spec.rb +132 -0
  201. data/spec/integration/generators/minitest_generator_spec.rb +0 -6
  202. data/spec/integration/generators/reporter_spec.rb +159 -0
  203. data/spec/integration/generators/skip_flags_spec.rb +134 -0
  204. data/spec/integration/generators/visual_addon_spec.rb +148 -0
  205. data/spec/integration/scaffolding_e2e_spec.rb +775 -0
  206. data/spec/integration/settings_helper.rb +0 -3
  207. data/spec/integration/spec_helper.rb +30 -13
  208. data/spec/llm/client_spec.rb +79 -0
  209. data/spec/llm/config_spec.rb +92 -0
  210. data/spec/llm/prompts_spec.rb +49 -0
  211. data/spec/llm/response_parser_spec.rb +92 -0
  212. data/spec/menus/adopter_adopt_menu_spec.rb +97 -0
  213. data/spec/menus/menu_generator_spec.rb +263 -0
  214. data/spec/scaffolding/name_normalizer_spec.rb +113 -0
  215. data/spec/scaffolding/page_introspector_spec.rb +82 -0
  216. data/spec/scaffolding/scaffold_project_detector_spec.rb +142 -0
  217. data/spec/scaffolding/scaffolding_features_spec.rb +311 -0
  218. data/spec/scaffolding/url_analyzer_spec.rb +110 -0
  219. data/spec/system/adopt_matrix_spec.rb +537 -0
  220. data/spec/system/adopt_spec.rb +225 -0
  221. data/spec/system/support/system_test_helper.rb +0 -2
  222. data/spec/utilities/desktop_downloader_spec.rb +92 -0
  223. data/spec/utilities/headless_config_spec.rb +89 -0
  224. data/spec/utilities/utilities_spec.rb +105 -0
  225. metadata +154 -5
  226. data/lib/generators/automation/templates/visual_options.tt +0 -16
  227. data/lib/generators/templates/helpers/partials/axe_driver.tt +0 -10
  228. 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
@@ -2,9 +2,7 @@
2
2
 
3
3
  require 'open3'
4
4
 
5
- # :reek:UtilityFunction
6
5
  module SystemTestHelper
7
- # :reek:ControlParameter
8
6
  def test_command_for(framework)
9
7
  case framework
10
8
  when 'cucumber' then 'bundle exec cucumber features --format pretty'
@@ -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
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'yaml'
5
+ require 'erb'
6
+
7
+ RSpec.describe 'Headless config support in driver templates' do
8
+ let(:tmp_dir) { 'tmp_headless_test' }
9
+
10
+ before do
11
+ FileUtils.mkdir_p(tmp_dir)
12
+ Dir.chdir(tmp_dir)
13
+ end
14
+
15
+ after do
16
+ Dir.chdir('..')
17
+ FileUtils.rm_rf(tmp_dir)
18
+ end
19
+
20
+ describe 'selenium driver template' do
21
+ it 'checks config headless key' do
22
+ content = File.read(File.expand_path('../../lib/generators/templates/helpers/partials/selenium_driver.tt',
23
+ __dir__))
24
+ expect(content).to include("@config['headless']")
25
+ end
26
+
27
+ it 'checks ENV HEADLESS' do
28
+ content = File.read(File.expand_path('../../lib/generators/templates/helpers/partials/selenium_driver.tt',
29
+ __dir__))
30
+ expect(content).to include("ENV['HEADLESS']")
31
+ end
32
+ end
33
+
34
+ describe 'capybara helper template' do
35
+ it 'checks config headless key' do
36
+ content = File.read(File.expand_path('../../lib/generators/templates/helpers/capybara_helper.tt', __dir__))
37
+ expect(content).to include("config['headless']")
38
+ end
39
+ end
40
+
41
+ describe 'browser helper template (watir)' do
42
+ it 'checks config headless key' do
43
+ content = File.read(File.expand_path('../../lib/generators/templates/helpers/browser_helper.tt', __dir__))
44
+ expect(content).to include("config['headless']")
45
+ end
46
+ end
47
+
48
+ describe 'headless via config.yml' do
49
+ it 'config key is used when YAML has headless: true' do
50
+ FileUtils.mkdir_p('config')
51
+ File.write('config/config.yml', <<~YAML)
52
+ browser: chrome
53
+ headless: true
54
+ browser_arguments:
55
+ chrome:
56
+ - no-sandbox
57
+ YAML
58
+
59
+ config = YAML.load_file('config/config.yml')
60
+ args = config['browser_arguments'][config['browser']]
61
+
62
+ # Simulate the template logic
63
+ args += ['--headless'] if (ENV['HEADLESS'] || config['headless']) && !args.include?('--headless')
64
+
65
+ expect(args).to include('--headless')
66
+ end
67
+
68
+ it 'config key is not used when headless: false' do
69
+ FileUtils.mkdir_p('config')
70
+ File.write('config/config.yml', <<~YAML)
71
+ browser: chrome
72
+ headless: false
73
+ browser_arguments:
74
+ chrome:
75
+ - no-sandbox
76
+ YAML
77
+
78
+ config = YAML.load_file('config/config.yml')
79
+ args = config['browser_arguments'][config['browser']]
80
+
81
+ # Temporarily clear ENV to isolate config behavior
82
+ original_env = ENV.delete('HEADLESS')
83
+ args += ['--headless'] if (ENV['HEADLESS'] || config['headless']) && !args.include?('--headless')
84
+ ENV['HEADLESS'] = original_env if original_env
85
+
86
+ expect(args).not_to include('--headless')
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'yaml'
5
+ require_relative '../../lib/utilities/utilities'
6
+
7
+ RSpec.describe Utilities do
8
+ let(:tmp_dir) { 'tmp_utilities_test' }
9
+ let(:config_path) { 'config/config.yml' }
10
+
11
+ before do
12
+ FileUtils.mkdir_p(tmp_dir)
13
+ Dir.chdir(tmp_dir)
14
+ FileUtils.mkdir_p('config')
15
+ File.write(config_path, <<~YAML)
16
+ browser: chrome
17
+ url: 'http://localhost:3000'
18
+ timeout: 10
19
+ viewport:
20
+ width: 1920
21
+ height: 1080
22
+ browser_arguments:
23
+ chrome:
24
+ - no-sandbox
25
+ - disable-dev-shm-usage
26
+ firefox:
27
+ - acceptInsecureCerts
28
+ YAML
29
+ # Reset cached config between tests
30
+ described_class.instance_variable_set(:@config, nil)
31
+ end
32
+
33
+ after do
34
+ Dir.chdir('..')
35
+ FileUtils.rm_rf(tmp_dir)
36
+ end
37
+
38
+ describe '.browser_options=' do
39
+ it 'writes to browser_arguments for the current browser' do
40
+ described_class.browser_options = %w[no-sandbox headless]
41
+ config = YAML.load_file(config_path)
42
+ expect(config['browser_arguments']['chrome']).to eq(%w[no-sandbox headless])
43
+ end
44
+
45
+ it 'writes to the correct browser key when browser is firefox' do
46
+ described_class.browser = 'firefox'
47
+ described_class.instance_variable_set(:@config, nil)
48
+ described_class.browser_options = %w[headless]
49
+ config = YAML.load_file(config_path)
50
+ expect(config['browser_arguments']['firefox']).to eq(%w[headless])
51
+ end
52
+
53
+ it 'preserves other browser arguments' do
54
+ described_class.browser_options = %w[headless]
55
+ config = YAML.load_file(config_path)
56
+ expect(config['browser_arguments']['firefox']).to eq(%w[acceptInsecureCerts])
57
+ end
58
+ end
59
+
60
+ describe '.delete_browser_options' do
61
+ it 'removes browser_arguments for the current browser' do
62
+ described_class.delete_browser_options
63
+ config = YAML.load_file(config_path)
64
+ expect(config['browser_arguments']['chrome']).to be_nil
65
+ end
66
+
67
+ it 'preserves other browser arguments' do
68
+ described_class.delete_browser_options
69
+ config = YAML.load_file(config_path)
70
+ expect(config['browser_arguments']['firefox']).to eq(%w[acceptInsecureCerts])
71
+ end
72
+ end
73
+
74
+ describe '.headless=' do
75
+ it 'sets headless to true' do
76
+ described_class.headless = true
77
+ config = YAML.load_file(config_path)
78
+ expect(config['headless']).to be true
79
+ end
80
+
81
+ it 'sets headless to false' do
82
+ described_class.headless = true
83
+ described_class.instance_variable_set(:@config, nil)
84
+ described_class.headless = false
85
+ config = YAML.load_file(config_path)
86
+ expect(config['headless']).to be false
87
+ end
88
+ end
89
+
90
+ describe '.viewport=' do
91
+ it 'sets viewport dimensions' do
92
+ described_class.viewport = '375x812'
93
+ config = YAML.load_file(config_path)
94
+ expect(config['viewport']).to eq({ 'width' => 375, 'height' => 812 })
95
+ end
96
+ end
97
+
98
+ describe '.browser_options= writes to browser_arguments not browser_options' do
99
+ it 'does not create a browser_options key' do
100
+ described_class.browser_options = %w[headless]
101
+ config = YAML.load_file(config_path)
102
+ expect(config).not_to have_key('browser_options')
103
+ end
104
+ end
105
+ end