ruby_raider 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/e2e_tests.yml +58 -0
  3. data/.github/workflows/steep.yml +21 -0
  4. data/.gitignore +1 -1
  5. data/.reek.yml +46 -4
  6. data/.ruby-version +1 -1
  7. data/README.md +138 -77
  8. data/Steepfile +22 -0
  9. data/assets/ruby_raider_logo.svg +51 -0
  10. data/lib/adopter/adopt_menu.rb +11 -15
  11. data/lib/adopter/converters/base_converter.rb +1 -2
  12. data/lib/adopter/converters/identity_converter.rb +3 -6
  13. data/lib/adopter/migration_plan.rb +0 -1
  14. data/lib/adopter/plan_builder.rb +2 -5
  15. data/lib/adopter/project_analyzer.rb +1 -5
  16. data/lib/adopter/project_detector.rb +3 -5
  17. data/lib/commands/adopt_commands.rb +0 -1
  18. data/lib/commands/plugin_commands.rb +0 -2
  19. data/lib/commands/scaffolding_commands.rb +220 -37
  20. data/lib/commands/utility_commands.rb +82 -2
  21. data/lib/generators/automation/automation_generator.rb +0 -7
  22. data/lib/generators/automation/templates/partials/element.tt +1 -1
  23. data/lib/generators/automation/templates/partials/initialize_selector.tt +0 -7
  24. data/lib/generators/automation/templates/partials/url_methods.tt +0 -1
  25. data/lib/generators/common_generator.rb +12 -0
  26. data/lib/generators/cucumber/cucumber_generator.rb +36 -0
  27. data/lib/generators/cucumber/templates/accessibility_feature.tt +5 -0
  28. data/lib/generators/cucumber/templates/accessibility_steps.tt +21 -0
  29. data/lib/generators/cucumber/templates/cucumber.tt +8 -1
  30. data/lib/generators/cucumber/templates/feature.tt +0 -4
  31. data/lib/generators/cucumber/templates/partials/appium_env.tt +5 -0
  32. data/lib/generators/cucumber/templates/partials/capybara_env.tt +19 -1
  33. data/lib/generators/cucumber/templates/partials/driver_world.tt +1 -4
  34. data/lib/generators/cucumber/templates/partials/selenium_env.tt +22 -35
  35. data/lib/generators/cucumber/templates/partials/watir_env.tt +20 -1
  36. data/lib/generators/cucumber/templates/partials/web_steps.tt +6 -12
  37. data/lib/generators/cucumber/templates/performance_feature.tt +5 -0
  38. data/lib/generators/cucumber/templates/performance_steps.tt +17 -0
  39. data/lib/generators/cucumber/templates/visual_feature.tt +5 -0
  40. data/lib/generators/cucumber/templates/visual_steps.tt +19 -0
  41. data/lib/generators/generator.rb +38 -7
  42. data/lib/generators/helper_generator.rb +24 -7
  43. data/lib/generators/infrastructure/templates/github.tt +1 -1
  44. data/lib/generators/infrastructure/templates/github_appium.tt +2 -2
  45. data/lib/generators/infrastructure/templates/gitlab.tt +1 -1
  46. data/lib/generators/invoke_generators.rb +42 -9
  47. data/lib/generators/menu_generator.rb +120 -11
  48. data/lib/generators/minitest/minitest_generator.rb +16 -4
  49. data/lib/generators/minitest/templates/accessibility_test.tt +26 -0
  50. data/lib/generators/minitest/templates/performance_test.tt +18 -0
  51. data/lib/generators/minitest/templates/test.tt +5 -34
  52. data/lib/generators/minitest/templates/visual_test.tt +23 -0
  53. data/lib/generators/rspec/rspec_generator.rb +16 -4
  54. data/lib/generators/rspec/templates/accessibility_spec.tt +25 -0
  55. data/lib/generators/rspec/templates/performance_spec.tt +18 -0
  56. data/lib/generators/rspec/templates/spec.tt +5 -35
  57. data/lib/generators/rspec/templates/visual_spec.tt +20 -0
  58. data/lib/generators/template_renderer/partial_cache.rb +11 -1
  59. data/lib/generators/template_renderer/partial_resolver.rb +17 -10
  60. data/lib/generators/template_renderer.rb +17 -1
  61. data/lib/generators/templates/common/gemfile.tt +21 -6
  62. data/lib/generators/templates/common/git_ignore.tt +6 -1
  63. data/lib/generators/templates/common/partials/mobile_config.tt +5 -1
  64. data/lib/generators/templates/common/partials/web_config.tt +16 -7
  65. data/lib/generators/templates/common/rakefile.tt +36 -0
  66. data/lib/generators/templates/common/read_me.tt +41 -91
  67. data/lib/generators/templates/common/rspec.tt +3 -0
  68. data/lib/generators/templates/common/ruby_version.tt +1 -0
  69. data/lib/generators/templates/helpers/allure_helper.tt +11 -0
  70. data/lib/generators/templates/helpers/browser_helper.tt +12 -2
  71. data/lib/generators/templates/helpers/capybara_helper.tt +5 -1
  72. data/lib/generators/templates/helpers/debug_helper.tt +190 -0
  73. data/lib/generators/templates/helpers/driver_helper.tt +2 -10
  74. data/lib/generators/templates/helpers/partials/appium_driver.tt +0 -2
  75. data/lib/generators/templates/helpers/partials/debug_diagnostics.tt +7 -0
  76. data/lib/generators/templates/helpers/partials/debug_start.tt +7 -0
  77. data/lib/generators/templates/helpers/partials/driver_and_options.tt +1 -3
  78. data/lib/generators/templates/helpers/partials/selenium_driver.tt +8 -7
  79. data/lib/generators/templates/helpers/partials/video_start.tt +9 -0
  80. data/lib/generators/templates/helpers/partials/video_stop.tt +4 -0
  81. data/lib/generators/templates/helpers/performance_helper.tt +57 -0
  82. data/lib/generators/templates/helpers/spec_helper.tt +57 -8
  83. data/lib/generators/templates/helpers/test_helper.tt +69 -1
  84. data/lib/generators/templates/helpers/video_helper.tt +270 -0
  85. data/lib/generators/templates/helpers/visual_helper.tt +39 -46
  86. data/lib/llm/client.rb +79 -0
  87. data/lib/llm/config.rb +57 -0
  88. data/lib/llm/prompts.rb +84 -0
  89. data/lib/llm/provider.rb +27 -0
  90. data/lib/llm/providers/anthropic_provider.rb +43 -0
  91. data/lib/llm/providers/ollama_provider.rb +56 -0
  92. data/lib/llm/providers/openai_provider.rb +42 -0
  93. data/lib/llm/response_parser.rb +67 -0
  94. data/lib/plugin/plugin.rb +22 -20
  95. data/lib/plugin/plugin_exposer.rb +16 -38
  96. data/lib/ruby_raider.rb +47 -12
  97. data/lib/scaffolding/crud_generator.rb +94 -0
  98. data/lib/scaffolding/dry_run_presenter.rb +16 -0
  99. data/lib/scaffolding/name_normalizer.rb +63 -0
  100. data/lib/scaffolding/page_introspector.rb +45 -0
  101. data/lib/scaffolding/project_detector.rb +72 -0
  102. data/lib/scaffolding/scaffold_menu.rb +103 -0
  103. data/lib/scaffolding/scaffolding.rb +158 -11
  104. data/lib/scaffolding/templates/component.tt +30 -0
  105. data/lib/scaffolding/templates/feature.tt +4 -4
  106. data/lib/scaffolding/templates/helper.tt +15 -1
  107. data/lib/scaffolding/templates/page_from_url.tt +75 -0
  108. data/lib/scaffolding/templates/page_object.tt +50 -1
  109. data/lib/scaffolding/templates/spec.tt +33 -2
  110. data/lib/scaffolding/templates/spec_from_page.tt +31 -0
  111. data/lib/scaffolding/templates/spec_from_url.tt +46 -0
  112. data/lib/scaffolding/templates/steps.tt +17 -5
  113. data/lib/scaffolding/url_analyzer.rb +179 -0
  114. data/lib/utilities/desktop_downloader.rb +177 -0
  115. data/lib/utilities/logo.rb +83 -0
  116. data/lib/utilities/utilities.rb +53 -20
  117. data/lib/version +1 -1
  118. data/ruby_raider.gemspec +1 -0
  119. data/sig/adopter/adopt_menu.rbs +25 -0
  120. data/sig/adopter/converters/base_converter.rbs +23 -0
  121. data/sig/adopter/converters/identity_converter.rbs +16 -0
  122. data/sig/adopter/migration_plan.rbs +34 -0
  123. data/sig/adopter/migrator.rbs +21 -0
  124. data/sig/adopter/plan_builder.rbs +38 -0
  125. data/sig/adopter/project_analyzer.rbs +39 -0
  126. data/sig/adopter/project_detector.rbs +26 -0
  127. data/sig/commands/adopt_commands.rbs +8 -0
  128. data/sig/commands/loaded_commands.rbs +5 -0
  129. data/sig/commands/plugin_commands.rbs +9 -0
  130. data/sig/commands/scaffolding_commands.rbs +28 -0
  131. data/sig/commands/utility_commands.rbs +21 -0
  132. data/sig/generators/automation/automation_generator.rbs +20 -0
  133. data/sig/generators/common_generator.rbs +12 -0
  134. data/sig/generators/cucumber/cucumber_generator.rbs +16 -0
  135. data/sig/generators/generator.rbs +40 -0
  136. data/sig/generators/helper_generator.rbs +18 -0
  137. data/sig/generators/infrastructure/github_generator.rbs +5 -0
  138. data/sig/generators/infrastructure/gitlab_generator.rbs +4 -0
  139. data/sig/generators/invoke_generators.rbs +10 -0
  140. data/sig/generators/menu_generator.rbs +29 -0
  141. data/sig/generators/minitest/minitest_generator.rbs +8 -0
  142. data/sig/generators/rspec/rspec_generator.rbs +8 -0
  143. data/sig/generators/template_renderer/partial_cache.rbs +20 -0
  144. data/sig/generators/template_renderer/partial_resolver.rbs +20 -0
  145. data/sig/generators/template_renderer/template_error.rbs +19 -0
  146. data/sig/generators/template_renderer.rbs +10 -0
  147. data/sig/llm/client.rbs +15 -0
  148. data/sig/llm/config.rbs +20 -0
  149. data/sig/llm/prompts.rbs +8 -0
  150. data/sig/llm/provider.rbs +12 -0
  151. data/sig/llm/providers/anthropic_provider.rbs +16 -0
  152. data/sig/llm/providers/ollama_provider.rbs +18 -0
  153. data/sig/llm/providers/openai_provider.rbs +16 -0
  154. data/sig/llm/response_parser.rbs +13 -0
  155. data/sig/plugin/plugin.rbs +24 -0
  156. data/sig/plugin/plugin_exposer.rbs +20 -0
  157. data/sig/ruby_raider.rbs +15 -0
  158. data/sig/scaffolding/crud_generator.rbs +16 -0
  159. data/sig/scaffolding/dry_run_presenter.rbs +4 -0
  160. data/sig/scaffolding/name_normalizer.rbs +17 -0
  161. data/sig/scaffolding/page_introspector.rbs +14 -0
  162. data/sig/scaffolding/project_detector.rbs +14 -0
  163. data/sig/scaffolding/scaffold_menu.rbs +18 -0
  164. data/sig/scaffolding/scaffolding.rbs +55 -0
  165. data/sig/scaffolding/url_analyzer.rbs +28 -0
  166. data/sig/utilities/desktop_downloader.rbs +23 -0
  167. data/sig/utilities/logger.rbs +13 -0
  168. data/sig/utilities/logo.rbs +16 -0
  169. data/sig/utilities/utilities.rbs +30 -0
  170. data/sig/vendor/thor.rbs +34 -0
  171. data/sig/vendor/tty_prompt.rbs +15 -0
  172. data/spec/adopter/adopt_menu_spec.rb +12 -12
  173. data/spec/adopter/migration_plan_spec.rb +1 -1
  174. data/spec/adopter/migrator_spec.rb +2 -2
  175. data/spec/adopter/project_detector_spec.rb +1 -1
  176. data/spec/commands/raider_commands_spec.rb +129 -0
  177. data/spec/generators/generator_spec.rb +23 -0
  178. data/spec/integration/commands/scaffolding_commands_spec.rb +1 -1
  179. data/spec/integration/commands/utility_commands_spec.rb +23 -3
  180. data/spec/integration/content/ci_content_spec.rb +119 -0
  181. data/spec/integration/content/common_content_spec.rb +288 -0
  182. data/spec/integration/content/config_content_spec.rb +175 -0
  183. data/spec/integration/content/content_helper.rb +32 -0
  184. data/spec/integration/content/gemfile_content_spec.rb +209 -0
  185. data/spec/integration/content/helper_content_spec.rb +485 -0
  186. data/spec/integration/content/page_content_spec.rb +259 -0
  187. data/spec/integration/content/reporter_content_spec.rb +236 -0
  188. data/spec/integration/content/skip_flags_content_spec.rb +206 -0
  189. data/spec/integration/content/syntax_validation_spec.rb +30 -0
  190. data/spec/integration/content/test_content_spec.rb +266 -0
  191. data/spec/integration/end_to_end_features_spec.rb +690 -0
  192. data/spec/integration/end_to_end_spec.rb +52 -16
  193. data/spec/integration/generators/automation_generator_spec.rb +0 -12
  194. data/spec/integration/generators/axe_addon_spec.rb +150 -0
  195. data/spec/integration/generators/common_generator_spec.rb +12 -13
  196. data/spec/integration/generators/config_features_spec.rb +155 -0
  197. data/spec/integration/generators/debug_helper_spec.rb +68 -0
  198. data/spec/integration/generators/helpers_generator_spec.rb +0 -12
  199. data/spec/integration/generators/lighthouse_addon_spec.rb +132 -0
  200. data/spec/integration/generators/minitest_generator_spec.rb +0 -6
  201. data/spec/integration/generators/reporter_spec.rb +159 -0
  202. data/spec/integration/generators/skip_flags_spec.rb +134 -0
  203. data/spec/integration/generators/visual_addon_spec.rb +148 -0
  204. data/spec/integration/settings_helper.rb +0 -3
  205. data/spec/integration/spec_helper.rb +30 -13
  206. data/spec/llm/client_spec.rb +79 -0
  207. data/spec/llm/config_spec.rb +92 -0
  208. data/spec/llm/prompts_spec.rb +49 -0
  209. data/spec/llm/response_parser_spec.rb +92 -0
  210. data/spec/menus/adopter_adopt_menu_spec.rb +97 -0
  211. data/spec/menus/menu_generator_spec.rb +263 -0
  212. data/spec/scaffolding/name_normalizer_spec.rb +113 -0
  213. data/spec/scaffolding/page_introspector_spec.rb +82 -0
  214. data/spec/scaffolding/scaffold_project_detector_spec.rb +104 -0
  215. data/spec/scaffolding/scaffolding_features_spec.rb +311 -0
  216. data/spec/scaffolding/url_analyzer_spec.rb +110 -0
  217. data/spec/system/adopt_matrix_spec.rb +537 -0
  218. data/spec/system/adopt_spec.rb +225 -0
  219. data/spec/system/support/system_test_helper.rb +0 -2
  220. data/spec/utilities/desktop_downloader_spec.rb +92 -0
  221. metadata +150 -5
  222. data/lib/generators/automation/templates/visual_options.tt +0 -16
  223. data/lib/generators/templates/helpers/partials/axe_driver.tt +0 -10
  224. data/lib/generators/templates/helpers/visual_spec_helper.tt +0 -35
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require_relative 'content_helper'
5
+
6
+ describe 'CI pipeline content' do
7
+ # --- GitHub Actions ---
8
+
9
+ shared_examples 'valid github pipeline' do |project_name|
10
+ subject(:pipeline) { read_generated("#{project_name}_github", '.github/workflows/test_pipeline.yml') }
11
+
12
+ it 'is valid YAML' do
13
+ expect { YAML.safe_load(pipeline) }.not_to raise_error
14
+ end
15
+
16
+ it 'has name' do
17
+ expect(pipeline).to match(/^name:/)
18
+ end
19
+
20
+ it 'has jobs section' do
21
+ expect(pipeline).to include('jobs:')
22
+ end
23
+
24
+ it 'sets up Ruby' do
25
+ expect(pipeline).to include('ruby')
26
+ end
27
+
28
+ it 'installs dependencies' do
29
+ expect(pipeline).to include('bundler-cache: true').or include('bundle install')
30
+ end
31
+ end
32
+
33
+ shared_examples 'github rspec pipeline' do |project_name|
34
+ subject(:pipeline) { read_generated("#{project_name}_github", '.github/workflows/test_pipeline.yml') }
35
+
36
+ it 'runs rspec' do
37
+ expect(pipeline).to include('rspec')
38
+ end
39
+ end
40
+
41
+ shared_examples 'github cucumber pipeline' do |project_name|
42
+ subject(:pipeline) { read_generated("#{project_name}_github", '.github/workflows/test_pipeline.yml') }
43
+
44
+ it 'runs cucumber' do
45
+ expect(pipeline).to include('cucumber')
46
+ end
47
+ end
48
+
49
+ shared_examples 'github minitest pipeline' do |project_name|
50
+ subject(:pipeline) { read_generated("#{project_name}_github", '.github/workflows/test_pipeline.yml') }
51
+
52
+ it 'runs minitest' do
53
+ expect(pipeline).to match(/minitest|ruby.*test/)
54
+ end
55
+ end
56
+
57
+ context 'with rspec and selenium on github' do
58
+ name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
59
+ include_examples 'valid github pipeline', name
60
+ include_examples 'github rspec pipeline', name
61
+ end
62
+
63
+ context 'with cucumber and selenium on github' do
64
+ name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
65
+ include_examples 'valid github pipeline', name
66
+ include_examples 'github cucumber pipeline', name
67
+ end
68
+
69
+ context 'with minitest and selenium on github' do
70
+ name = "#{FrameworkIndex::MINITEST}_#{AutomationIndex::SELENIUM}"
71
+ include_examples 'valid github pipeline', name
72
+ include_examples 'github minitest pipeline', name
73
+ end
74
+
75
+ context 'with rspec and capybara on github' do
76
+ name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CAPYBARA}"
77
+ include_examples 'valid github pipeline', name
78
+ include_examples 'github rspec pipeline', name
79
+ end
80
+
81
+ context 'with rspec and watir on github' do
82
+ name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
83
+ include_examples 'valid github pipeline', name
84
+ include_examples 'github rspec pipeline', name
85
+ end
86
+
87
+ # --- GitLab CI ---
88
+
89
+ shared_examples 'valid gitlab pipeline' do |project_name|
90
+ subject(:pipeline) { read_generated("#{project_name}_gitlab", 'gitlab-ci.yml') }
91
+
92
+ it 'is valid YAML' do
93
+ expect { YAML.safe_load(pipeline) }.not_to raise_error
94
+ end
95
+
96
+ it 'has stages' do
97
+ expect(pipeline).to include('stages:')
98
+ end
99
+
100
+ it 'has script section' do
101
+ expect(pipeline).to include('script:')
102
+ end
103
+ end
104
+
105
+ context 'with rspec and selenium on gitlab' do
106
+ name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
107
+ include_examples 'valid gitlab pipeline', name
108
+ end
109
+
110
+ context 'with cucumber and selenium on gitlab' do
111
+ name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
112
+ include_examples 'valid gitlab pipeline', name
113
+ end
114
+
115
+ context 'with minitest and selenium on gitlab' do
116
+ name = "#{FrameworkIndex::MINITEST}_#{AutomationIndex::SELENIUM}"
117
+ include_examples 'valid gitlab pipeline', name
118
+ end
119
+ end
@@ -0,0 +1,288 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'content_helper'
4
+
5
+ describe 'Common file content' do
6
+ # --- Rakefile ---
7
+
8
+ shared_examples 'valid rakefile' do |project_name|
9
+ subject(:rakefile) { read_generated(project_name, 'Rakefile') }
10
+
11
+ it 'has raider version task' do
12
+ expect(rakefile).to include('task :raider')
13
+ end
14
+ end
15
+
16
+ shared_examples 'rspec rakefile with tag tasks' do |project_name|
17
+ subject(:rakefile) { read_generated(project_name, 'Rakefile') }
18
+
19
+ it 'requires rspec/core/rake_task' do
20
+ expect(rakefile).to include("require 'rspec/core/rake_task'")
21
+ end
22
+
23
+ it 'defines spec task' do
24
+ expect(rakefile).to include('RakeTask.new(:spec)')
25
+ end
26
+
27
+ it 'defines smoke task' do
28
+ expect(rakefile).to include('RakeTask.new(:smoke)')
29
+ expect(rakefile).to include("'--tag smoke'")
30
+ end
31
+
32
+ it 'defines regression task' do
33
+ expect(rakefile).to include('RakeTask.new(:regression)')
34
+ expect(rakefile).to include("'--tag regression'")
35
+ end
36
+
37
+ it 'sets default task to spec' do
38
+ expect(rakefile).to include('task default: :spec')
39
+ end
40
+
41
+ it 'does not include cucumber tasks' do
42
+ expect(rakefile).not_to include('Cucumber::Rake::Task')
43
+ end
44
+ end
45
+
46
+ shared_examples 'cucumber rakefile with tag tasks' do |project_name|
47
+ subject(:rakefile) { read_generated(project_name, 'Rakefile') }
48
+
49
+ it 'requires cucumber/rake/task' do
50
+ expect(rakefile).to include("require 'cucumber/rake/task'")
51
+ end
52
+
53
+ it 'defines features task' do
54
+ expect(rakefile).to include('Rake::Task.new(:features)')
55
+ end
56
+
57
+ it 'defines smoke task' do
58
+ expect(rakefile).to include('Rake::Task.new(:smoke)')
59
+ expect(rakefile).to include("'--tags @smoke'")
60
+ end
61
+
62
+ it 'defines regression task' do
63
+ expect(rakefile).to include('Rake::Task.new(:regression)')
64
+ expect(rakefile).to include("'--tags @regression'")
65
+ end
66
+
67
+ it 'sets default task to features' do
68
+ expect(rakefile).to include('task default: :features')
69
+ end
70
+
71
+ it 'does not include rspec tasks' do
72
+ expect(rakefile).not_to include('RSpec::Core::RakeTask')
73
+ end
74
+ end
75
+
76
+ shared_examples 'minitest rakefile with default task' do |project_name|
77
+ subject(:rakefile) { read_generated(project_name, 'Rakefile') }
78
+
79
+ it 'requires rake/testtask' do
80
+ expect(rakefile).to include("require 'rake/testtask'")
81
+ end
82
+
83
+ it 'defines test task' do
84
+ expect(rakefile).to include('Rake::TestTask.new(:test)')
85
+ end
86
+
87
+ it 'sets default task to test' do
88
+ expect(rakefile).to include('task default: :test')
89
+ end
90
+ end
91
+
92
+ # --- .rspec file ---
93
+
94
+ shared_examples 'has rspec dotfile' do |project_name|
95
+ subject(:rspec_file) { read_generated(project_name, '.rspec') }
96
+
97
+ it 'exists' do
98
+ expect(File).to exist(File.join(project_name, '.rspec'))
99
+ end
100
+
101
+ it 'requires spec_helper' do
102
+ expect(rspec_file).to include('--require helpers/spec_helper')
103
+ end
104
+
105
+ it 'uses documentation format' do
106
+ expect(rspec_file).to include('--format documentation')
107
+ end
108
+ end
109
+
110
+ shared_examples 'no rspec dotfile' do |project_name|
111
+ it 'does not have .rspec file' do
112
+ expect(File).not_to exist(File.join(project_name, '.rspec'))
113
+ end
114
+ end
115
+
116
+ # --- .gitignore ---
117
+
118
+ shared_examples 'rspec gitignore' do |project_name|
119
+ subject(:gitignore) { read_generated(project_name, '.gitignore') }
120
+
121
+ it 'includes allure-results' do
122
+ expect(gitignore).to include('allure-results')
123
+ end
124
+
125
+ it 'includes spec/examples.txt' do
126
+ expect(gitignore).to include('spec/examples.txt')
127
+ end
128
+ end
129
+
130
+ shared_examples 'non-rspec gitignore' do |project_name|
131
+ subject(:gitignore) { read_generated(project_name, '.gitignore') }
132
+
133
+ it 'includes allure-results' do
134
+ expect(gitignore).to include('allure-results')
135
+ end
136
+
137
+ it 'does not include spec/examples.txt' do
138
+ expect(gitignore).not_to include('spec/examples.txt')
139
+ end
140
+ end
141
+
142
+ # --- Spec helper retry config (C4) ---
143
+
144
+ shared_examples 'spec helper with retry config' do |project_name|
145
+ subject(:helper) { read_generated(project_name, 'helpers/spec_helper.rb') }
146
+
147
+ it 'requires rspec/retry' do
148
+ expect(helper).to include("require 'rspec/retry'")
149
+ end
150
+
151
+ it 'enables verbose retry' do
152
+ expect(helper).to include('config.verbose_retry = true')
153
+ end
154
+
155
+ it 'enables failure messages display' do
156
+ expect(helper).to include('config.display_try_failure_messages = true')
157
+ end
158
+
159
+ it 'sets retry count from env' do
160
+ expect(helper).to include("config.default_retry_count = ENV.fetch('RETRY_COUNT', 0).to_i")
161
+ end
162
+
163
+ it 'has example_status_persistence_file_path' do
164
+ expect(helper).to include("config.example_status_persistence_file_path = 'spec/examples.txt'")
165
+ end
166
+ end
167
+
168
+ # --- Gemfile retry gem (C4) ---
169
+
170
+ shared_examples 'gemfile with rspec-retry' do |project_name|
171
+ subject(:gemfile) { read_generated(project_name, 'Gemfile') }
172
+
173
+ it 'includes rspec-retry gem' do
174
+ expect(gemfile).to include("gem 'rspec-retry'")
175
+ end
176
+ end
177
+
178
+ shared_examples 'gemfile without rspec-retry' do |project_name|
179
+ subject(:gemfile) { read_generated(project_name, 'Gemfile') }
180
+
181
+ it 'does not include rspec-retry gem' do
182
+ expect(gemfile).not_to include("gem 'rspec-retry'")
183
+ end
184
+ end
185
+
186
+ # --- Cucumber retry config (C4) ---
187
+
188
+ shared_examples 'cucumber config with retry' do |project_name|
189
+ subject(:cucumber_yml) { read_generated(project_name, 'cucumber.yml') }
190
+
191
+ it 'includes --retry flag' do
192
+ expect(cucumber_yml).to include('--retry')
193
+ end
194
+ end
195
+
196
+ # --- RSpec contexts ---
197
+
198
+ context 'with rspec and selenium' do
199
+ name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
200
+ it_behaves_like 'valid rakefile', name
201
+ it_behaves_like 'rspec rakefile with tag tasks', name
202
+ it_behaves_like 'has rspec dotfile', name
203
+ it_behaves_like 'rspec gitignore', name
204
+ it_behaves_like 'spec helper with retry config', name
205
+ it_behaves_like 'gemfile with rspec-retry', name
206
+ end
207
+
208
+ context 'with rspec and watir' do
209
+ name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
210
+ it_behaves_like 'valid rakefile', name
211
+ it_behaves_like 'rspec rakefile with tag tasks', name
212
+ it_behaves_like 'has rspec dotfile', name
213
+ it_behaves_like 'rspec gitignore', name
214
+ it_behaves_like 'spec helper with retry config', name
215
+ it_behaves_like 'gemfile with rspec-retry', name
216
+ end
217
+
218
+ context 'with rspec and capybara' do
219
+ name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CAPYBARA}"
220
+ it_behaves_like 'valid rakefile', name
221
+ it_behaves_like 'rspec rakefile with tag tasks', name
222
+ it_behaves_like 'has rspec dotfile', name
223
+ it_behaves_like 'rspec gitignore', name
224
+ it_behaves_like 'spec helper with retry config', name
225
+ it_behaves_like 'gemfile with rspec-retry', name
226
+ end
227
+
228
+ # --- Cucumber contexts ---
229
+
230
+ context 'with cucumber and selenium' do
231
+ name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
232
+ it_behaves_like 'valid rakefile', name
233
+ it_behaves_like 'cucumber rakefile with tag tasks', name
234
+ it_behaves_like 'no rspec dotfile', name
235
+ it_behaves_like 'non-rspec gitignore', name
236
+ it_behaves_like 'gemfile without rspec-retry', name
237
+ it_behaves_like 'cucumber config with retry', name
238
+ end
239
+
240
+ context 'with cucumber and watir' do
241
+ name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}"
242
+ it_behaves_like 'valid rakefile', name
243
+ it_behaves_like 'cucumber rakefile with tag tasks', name
244
+ it_behaves_like 'no rspec dotfile', name
245
+ it_behaves_like 'non-rspec gitignore', name
246
+ it_behaves_like 'gemfile without rspec-retry', name
247
+ it_behaves_like 'cucumber config with retry', name
248
+ end
249
+
250
+ context 'with cucumber and capybara' do
251
+ name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::CAPYBARA}"
252
+ it_behaves_like 'valid rakefile', name
253
+ it_behaves_like 'cucumber rakefile with tag tasks', name
254
+ it_behaves_like 'no rspec dotfile', name
255
+ it_behaves_like 'non-rspec gitignore', name
256
+ it_behaves_like 'gemfile without rspec-retry', name
257
+ it_behaves_like 'cucumber config with retry', name
258
+ end
259
+
260
+ # --- Minitest contexts ---
261
+
262
+ context 'with minitest and selenium' do
263
+ name = "#{FrameworkIndex::MINITEST}_#{AutomationIndex::SELENIUM}"
264
+ it_behaves_like 'valid rakefile', name
265
+ it_behaves_like 'minitest rakefile with default task', name
266
+ it_behaves_like 'no rspec dotfile', name
267
+ it_behaves_like 'non-rspec gitignore', name
268
+ it_behaves_like 'gemfile without rspec-retry', name
269
+ end
270
+
271
+ context 'with minitest and watir' do
272
+ name = "#{FrameworkIndex::MINITEST}_#{AutomationIndex::WATIR}"
273
+ it_behaves_like 'valid rakefile', name
274
+ it_behaves_like 'minitest rakefile with default task', name
275
+ it_behaves_like 'no rspec dotfile', name
276
+ it_behaves_like 'non-rspec gitignore', name
277
+ it_behaves_like 'gemfile without rspec-retry', name
278
+ end
279
+
280
+ context 'with minitest and capybara' do
281
+ name = "#{FrameworkIndex::MINITEST}_#{AutomationIndex::CAPYBARA}"
282
+ it_behaves_like 'valid rakefile', name
283
+ it_behaves_like 'minitest rakefile with default task', name
284
+ it_behaves_like 'no rspec dotfile', name
285
+ it_behaves_like 'non-rspec gitignore', name
286
+ it_behaves_like 'gemfile without rspec-retry', name
287
+ end
288
+ end
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require_relative 'content_helper'
5
+
6
+ describe 'Config file content' do
7
+ shared_examples 'valid web config' do |project_name|
8
+ subject(:config_content) { read_generated(project_name, 'config/config.yml') }
9
+
10
+ let(:config) { YAML.safe_load(config_content, permitted_classes: [Symbol]) }
11
+
12
+ it 'has browser key' do
13
+ expect(config).to have_key('browser')
14
+ expect(config['browser']).to eq('chrome')
15
+ end
16
+
17
+ it 'has url key' do
18
+ expect(config).to have_key('url')
19
+ expect(config['url']).to include('http')
20
+ end
21
+
22
+ it 'has browser_arguments section' do
23
+ expect(config_content).to include('browser_arguments:')
24
+ expect(config_content).to include('chrome:')
25
+ expect(config_content).to include('firefox:')
26
+ end
27
+ end
28
+
29
+ shared_examples 'selenium config with timeout' do |project_name|
30
+ subject(:config_content) { read_generated(project_name, 'config/config.yml') }
31
+
32
+ let(:config) { YAML.safe_load(config_content, permitted_classes: [Symbol]) }
33
+
34
+ it 'has timeout key' do
35
+ expect(config).to have_key('timeout')
36
+ expect(config['timeout']).to eq(10)
37
+ end
38
+
39
+ it 'has viewport section' do
40
+ expect(config).to have_key('viewport')
41
+ expect(config['viewport']['width']).to eq(1920)
42
+ expect(config['viewport']['height']).to eq(1080)
43
+ end
44
+ end
45
+
46
+ shared_examples 'config without driver_options' do |project_name|
47
+ subject(:config_content) { read_generated(project_name, 'config/config.yml') }
48
+
49
+ it 'does not have driver_options section' do
50
+ expect(config_content).not_to include('driver_options:')
51
+ end
52
+ end
53
+
54
+ shared_examples 'config with video section' do |project_name|
55
+ subject(:config_content) { read_generated(project_name, 'config/config.yml') }
56
+
57
+ let(:config) { YAML.safe_load(config_content, permitted_classes: [Symbol]) }
58
+
59
+ it 'has video section' do
60
+ expect(config).to have_key('video')
61
+ end
62
+
63
+ it 'has video enabled key defaulting to false' do
64
+ expect(config['video']['enabled']).to be false
65
+ end
66
+
67
+ it 'has video strategy key' do
68
+ expect(config['video']['strategy']).to eq('auto')
69
+ end
70
+ end
71
+
72
+ shared_examples 'config with debug section' do |project_name|
73
+ subject(:config_content) { read_generated(project_name, 'config/config.yml') }
74
+
75
+ let(:config) { YAML.safe_load(config_content, permitted_classes: [Symbol]) }
76
+
77
+ it 'has debug section' do
78
+ expect(config).to have_key('debug')
79
+ end
80
+
81
+ it 'has debug enabled key defaulting to false' do
82
+ expect(config['debug']['enabled']).to be false
83
+ end
84
+
85
+ it 'has debug console_logs key' do
86
+ expect(config['debug']['console_logs']).to be true
87
+ end
88
+
89
+ it 'has debug action_logging key' do
90
+ expect(config['debug']['action_logging']).to be true
91
+ end
92
+
93
+ it 'has debug network_logging key' do
94
+ expect(config['debug']['network_logging']).to be true
95
+ end
96
+
97
+ it 'has debug log_dir key' do
98
+ expect(config['debug']['log_dir']).to eq('debug_logs')
99
+ end
100
+ end
101
+
102
+ # --- Web config per automation ---
103
+
104
+ context 'with rspec and selenium' do
105
+ name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
106
+ include_examples 'valid web config', name
107
+ include_examples 'selenium config with timeout', name
108
+ include_examples 'config with video section', name
109
+ include_examples 'config with debug section', name
110
+ end
111
+
112
+ context 'with rspec and watir' do
113
+ name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
114
+ include_examples 'valid web config', name
115
+ include_examples 'config without driver_options', name
116
+ include_examples 'config with video section', name
117
+ include_examples 'config with debug section', name
118
+ end
119
+
120
+ context 'with rspec and capybara' do
121
+ name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CAPYBARA}"
122
+ include_examples 'valid web config', name
123
+ include_examples 'config without driver_options', name
124
+ include_examples 'config with video section', name
125
+ include_examples 'config with debug section', name
126
+ end
127
+
128
+ context 'with cucumber and selenium' do
129
+ name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
130
+ include_examples 'valid web config', name
131
+ include_examples 'selenium config with timeout', name
132
+ include_examples 'config with video section', name
133
+ include_examples 'config with debug section', name
134
+ end
135
+
136
+ context 'with minitest and selenium' do
137
+ name = "#{FrameworkIndex::MINITEST}_#{AutomationIndex::SELENIUM}"
138
+ include_examples 'valid web config', name
139
+ include_examples 'selenium config with timeout', name
140
+ include_examples 'config with video section', name
141
+ include_examples 'config with debug section', name
142
+ end
143
+
144
+ context 'with minitest and watir' do
145
+ name = "#{FrameworkIndex::MINITEST}_#{AutomationIndex::WATIR}"
146
+ include_examples 'valid web config', name
147
+ include_examples 'config without driver_options', name
148
+ include_examples 'config with video section', name
149
+ include_examples 'config with debug section', name
150
+ end
151
+
152
+ context 'with minitest and capybara' do
153
+ name = "#{FrameworkIndex::MINITEST}_#{AutomationIndex::CAPYBARA}"
154
+ include_examples 'valid web config', name
155
+ include_examples 'config without driver_options', name
156
+ include_examples 'config with video section', name
157
+ include_examples 'config with debug section', name
158
+ end
159
+
160
+ # --- Mobile config ---
161
+
162
+ context 'with rspec and appium android' do
163
+ subject(:caps) { read_generated("#{FrameworkIndex::RSPEC}_#{AutomationIndex::ANDROID}", 'config/capabilities.yml') }
164
+
165
+ it 'contains expected configuration keys' do
166
+ expect(caps).to include('platformName')
167
+ expect(caps).to include('automationName')
168
+ expect(caps).to include('deviceName')
169
+ end
170
+
171
+ it 'has platform capabilities' do
172
+ expect(caps).to match(/platformName/i)
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper'
4
+
5
+ module ContentHelper
6
+ def read_generated(project, relative_path)
7
+ File.read(File.join(project, relative_path))
8
+ end
9
+
10
+ def project(framework, automation, ci_platform = nil)
11
+ ci_platform ? "#{framework}_#{automation}_#{ci_platform}" : "#{framework}_#{automation}"
12
+ end
13
+ end
14
+
15
+ RSpec::Matchers.define :have_frozen_string_literal do
16
+ match { |content| content.include?('# frozen_string_literal: true') }
17
+ failure_message { 'expected file to contain frozen_string_literal magic comment' }
18
+ end
19
+
20
+ RSpec::Matchers.define :have_valid_ruby_syntax do
21
+ match do |content|
22
+ RubyVM::InstructionSequence.compile(content)
23
+ true
24
+ rescue SyntaxError
25
+ false
26
+ end
27
+ failure_message { |_content| "expected valid Ruby syntax but got SyntaxError: #{$ERROR_INFO&.message}" }
28
+ end
29
+
30
+ RSpec.configure do |config|
31
+ config.include(ContentHelper)
32
+ end