ruby_raider 1.1.4 → 2.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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/integration.yml +4 -6
  3. data/.github/workflows/reek.yml +6 -5
  4. data/.github/workflows/release.yml +175 -0
  5. data/.github/workflows/rubocop.yml +7 -6
  6. data/.github/workflows/system_tests.yml +83 -0
  7. data/.gitignore +1 -1
  8. data/.rubocop.yml +24 -0
  9. data/README.md +3 -1
  10. data/RELEASE.md +412 -0
  11. data/RELEASE_QUICK_GUIDE.md +77 -0
  12. data/bin/release +186 -0
  13. data/lib/adopter/adopt_menu.rb +150 -0
  14. data/lib/adopter/converters/base_converter.rb +85 -0
  15. data/lib/adopter/converters/identity_converter.rb +56 -0
  16. data/lib/adopter/migration_plan.rb +75 -0
  17. data/lib/adopter/migrator.rb +96 -0
  18. data/lib/adopter/plan_builder.rb +278 -0
  19. data/lib/adopter/project_analyzer.rb +256 -0
  20. data/lib/adopter/project_detector.rb +159 -0
  21. data/lib/commands/adopt_commands.rb +43 -0
  22. data/lib/generators/automation/templates/account.tt +9 -5
  23. data/lib/generators/automation/templates/appium_caps.tt +60 -6
  24. data/lib/generators/automation/templates/home.tt +4 -4
  25. data/lib/generators/automation/templates/login.tt +61 -4
  26. data/lib/generators/automation/templates/page.tt +13 -7
  27. data/lib/generators/automation/templates/partials/home_page_selector.tt +4 -4
  28. data/lib/generators/automation/templates/partials/initialize_selector.tt +3 -1
  29. data/lib/generators/automation/templates/partials/pdp_page_selector.tt +4 -4
  30. data/lib/generators/automation/templates/partials/visit_method.tt +11 -1
  31. data/lib/generators/automation/templates/pdp.tt +1 -1
  32. data/lib/generators/cucumber/templates/env.tt +6 -4
  33. data/lib/generators/cucumber/templates/partials/capybara_env.tt +20 -0
  34. data/lib/generators/cucumber/templates/partials/capybara_world.tt +6 -0
  35. data/lib/generators/cucumber/templates/partials/mobile_steps.tt +2 -2
  36. data/lib/generators/cucumber/templates/partials/web_steps.tt +4 -3
  37. data/lib/generators/cucumber/templates/steps.tt +2 -2
  38. data/lib/generators/cucumber/templates/world.tt +5 -3
  39. data/lib/generators/generator.rb +14 -2
  40. data/lib/generators/helper_generator.rb +16 -3
  41. data/lib/generators/infrastructure/github_generator.rb +6 -0
  42. data/lib/generators/infrastructure/templates/github.tt +11 -7
  43. data/lib/generators/infrastructure/templates/github_appium.tt +108 -0
  44. data/lib/generators/infrastructure/templates/gitlab.tt +5 -2
  45. data/lib/generators/invoke_generators.rb +1 -0
  46. data/lib/generators/menu_generator.rb +2 -0
  47. data/lib/generators/minitest/minitest_generator.rb +23 -0
  48. data/lib/generators/minitest/templates/test.tt +93 -0
  49. data/lib/generators/rspec/templates/spec.tt +12 -10
  50. data/lib/generators/template_renderer/partial_cache.rb +116 -0
  51. data/lib/generators/template_renderer/partial_resolver.rb +103 -0
  52. data/lib/generators/template_renderer/template_error.rb +50 -0
  53. data/lib/generators/template_renderer.rb +90 -0
  54. data/lib/generators/templates/common/config.tt +2 -2
  55. data/lib/generators/templates/common/gemfile.tt +15 -3
  56. data/lib/generators/templates/common/partials/web_config.tt +1 -1
  57. data/lib/generators/templates/common/read_me.tt +3 -1
  58. data/lib/generators/templates/helpers/allure_helper.tt +2 -2
  59. data/lib/generators/templates/helpers/browser_helper.tt +1 -0
  60. data/lib/generators/templates/helpers/capybara_helper.tt +28 -0
  61. data/lib/generators/templates/helpers/driver_helper.tt +1 -1
  62. data/lib/generators/templates/helpers/partials/allure_imports.tt +3 -1
  63. data/lib/generators/templates/helpers/partials/allure_requirements.tt +3 -1
  64. data/lib/generators/templates/helpers/partials/appium_driver.tt +46 -0
  65. data/lib/generators/templates/helpers/partials/axe_driver.tt +10 -0
  66. data/lib/generators/templates/helpers/partials/browserstack_config.tt +13 -0
  67. data/lib/generators/templates/helpers/partials/driver_and_options.tt +6 -114
  68. data/lib/generators/templates/helpers/partials/quit_driver.tt +3 -1
  69. data/lib/generators/templates/helpers/partials/screenshot.tt +3 -1
  70. data/lib/generators/templates/helpers/partials/selenium_driver.tt +25 -0
  71. data/lib/generators/templates/helpers/spec_helper.tt +17 -4
  72. data/lib/generators/templates/helpers/test_helper.tt +26 -0
  73. data/lib/generators/templates/helpers/visual_spec_helper.tt +1 -1
  74. data/lib/ruby_raider.rb +5 -0
  75. data/lib/version +1 -1
  76. data/spec/adopter/adopt_menu_spec.rb +176 -0
  77. data/spec/adopter/converters/identity_converter_spec.rb +145 -0
  78. data/spec/adopter/migration_plan_spec.rb +113 -0
  79. data/spec/adopter/migrator_spec.rb +277 -0
  80. data/spec/adopter/plan_builder_spec.rb +298 -0
  81. data/spec/adopter/project_analyzer_spec.rb +337 -0
  82. data/spec/adopter/project_detector_spec.rb +295 -0
  83. data/spec/generators/fixtures/templates/test.tt +1 -0
  84. data/spec/generators/fixtures/templates/test_partial.tt +1 -0
  85. data/spec/generators/template_renderer_spec.rb +298 -0
  86. data/spec/integration/commands/scaffolding_commands_spec.rb +2 -2
  87. data/spec/integration/commands/utility_commands_spec.rb +2 -2
  88. data/spec/integration/end_to_end_spec.rb +325 -0
  89. data/spec/integration/generators/automation_generator_spec.rb +11 -11
  90. data/spec/integration/generators/common_generator_spec.rb +40 -40
  91. data/spec/integration/generators/cucumber_generator_spec.rb +7 -7
  92. data/spec/integration/generators/github_generator_spec.rb +8 -8
  93. data/spec/integration/generators/gitlab_generator_spec.rb +8 -8
  94. data/spec/integration/generators/helpers_generator_spec.rb +73 -35
  95. data/spec/integration/generators/minitest_generator_spec.rb +70 -0
  96. data/spec/integration/generators/rspec_generator_spec.rb +7 -7
  97. data/spec/integration/settings_helper.rb +1 -1
  98. data/spec/integration/spec_helper.rb +20 -2
  99. data/spec/system/capybara_spec.rb +42 -0
  100. data/spec/system/selenium_spec.rb +19 -17
  101. data/spec/system/support/system_test_helper.rb +35 -0
  102. data/spec/system/watir_spec.rb +19 -17
  103. metadata +46 -16
  104. data/.github/workflows/push_gem.yml +0 -37
  105. data/.github/workflows/selenium.yml +0 -22
  106. data/.github/workflows/watir.yml +0 -22
  107. data/lib/generators/automation/templates/partials/android_caps.tt +0 -17
  108. data/lib/generators/automation/templates/partials/cross_platform_caps.tt +0 -25
  109. data/lib/generators/automation/templates/partials/ios_caps.tt +0 -18
  110. data/lib/generators/automation/templates/partials/selenium_account.tt +0 -9
  111. data/lib/generators/automation/templates/partials/selenium_login.tt +0 -34
  112. data/lib/generators/automation/templates/partials/watir_account.tt +0 -7
  113. data/lib/generators/automation/templates/partials/watir_login.tt +0 -32
@@ -0,0 +1,337 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'rspec'
5
+ require_relative '../../lib/adopter/project_analyzer'
6
+
7
+ RSpec.describe Adopter::ProjectAnalyzer do
8
+ let(:project_dir) { 'tmp_analyzer_project' }
9
+
10
+ before { FileUtils.mkdir_p(project_dir) }
11
+
12
+ after { FileUtils.rm_rf(project_dir) }
13
+
14
+ describe '#analyze' do
15
+ context 'with a selenium + rspec project' do
16
+ before do
17
+ File.write("#{project_dir}/Gemfile", <<~GEMFILE)
18
+ gem 'rspec'
19
+ gem 'selenium-webdriver'
20
+ gem 'faker'
21
+ gem 'httparty'
22
+ GEMFILE
23
+ FileUtils.mkdir_p("#{project_dir}/pages")
24
+ FileUtils.mkdir_p("#{project_dir}/spec")
25
+
26
+ File.write("#{project_dir}/pages/login_page.rb", <<~RUBY)
27
+ class LoginPage < BasePage
28
+ def login(username, password)
29
+ driver.find_element(id: 'user').send_keys username
30
+ driver.find_element(id: 'pass').send_keys password
31
+ driver.find_element(id: 'submit').click
32
+ end
33
+
34
+ private
35
+
36
+ def username_field
37
+ driver.find_element(id: 'user')
38
+ end
39
+ end
40
+ RUBY
41
+
42
+ File.write("#{project_dir}/spec/login_spec.rb", <<~RUBY)
43
+ describe 'Login' do
44
+ let(:login_page) { LoginPage.new(driver) }
45
+
46
+ it 'can log in with valid credentials' do
47
+ expect(header).to eq 'Welcome'
48
+ end
49
+
50
+ it 'shows error with invalid credentials' do
51
+ expect(error).to eq 'Invalid'
52
+ end
53
+ end
54
+ RUBY
55
+ end
56
+
57
+ it 'returns a complete analysis hash' do
58
+ analysis = described_class.new(project_dir).analyze
59
+ expect(analysis).to include(
60
+ automation: 'selenium',
61
+ framework: 'rspec',
62
+ source_dsl: :selenium
63
+ )
64
+ end
65
+
66
+ it 'discovers page objects' do
67
+ analysis = described_class.new(project_dir).analyze
68
+ expect(analysis[:pages].length).to eq(1)
69
+ expect(analysis[:pages].first).to include(
70
+ class_name: 'LoginPage',
71
+ base_class: 'BasePage'
72
+ )
73
+ end
74
+
75
+ it 'extracts public methods from pages' do
76
+ analysis = described_class.new(project_dir).analyze
77
+ expect(analysis[:pages].first[:methods]).to eq(['login'])
78
+ end
79
+
80
+ it 'discovers test files' do
81
+ analysis = described_class.new(project_dir).analyze
82
+ expect(analysis[:tests].length).to eq(1)
83
+ expect(analysis[:tests].first[:type]).to eq(:rspec)
84
+ end
85
+
86
+ it 'extracts test method names' do
87
+ analysis = described_class.new(project_dir).analyze
88
+ expect(analysis[:tests].first[:test_methods]).to include(
89
+ 'can log in with valid credentials',
90
+ 'shows error with invalid credentials'
91
+ )
92
+ end
93
+
94
+ it 'identifies custom gems' do
95
+ analysis = described_class.new(project_dir).analyze
96
+ expect(analysis[:custom_gems]).to contain_exactly('faker', 'httparty')
97
+ end
98
+ end
99
+
100
+ context 'with a capybara/site_prism project' do
101
+ before do
102
+ File.write("#{project_dir}/Gemfile", <<~GEMFILE)
103
+ gem 'capybara'
104
+ gem 'site_prism'
105
+ gem 'rspec'
106
+ gem 'selenium-webdriver'
107
+ GEMFILE
108
+ FileUtils.mkdir_p("#{project_dir}/pages")
109
+
110
+ File.write("#{project_dir}/pages/login_page.rb", <<~RUBY)
111
+ class LoginPage < SitePrism::Page
112
+ set_url '/login'
113
+ element :email_field, '#email'
114
+ element :password_field, '#password'
115
+ end
116
+ RUBY
117
+ end
118
+
119
+ it 'detects site_prism dsl' do
120
+ analysis = described_class.new(project_dir).analyze
121
+ expect(analysis[:source_dsl]).to eq(:site_prism)
122
+ end
123
+
124
+ it 'detects capybara automation' do
125
+ analysis = described_class.new(project_dir).analyze
126
+ expect(analysis[:automation]).to eq('capybara')
127
+ end
128
+ end
129
+
130
+ context 'with a capybara DSL project (no site_prism)' do
131
+ before do
132
+ File.write("#{project_dir}/Gemfile", <<~GEMFILE)
133
+ gem 'capybara'
134
+ gem 'rspec'
135
+ GEMFILE
136
+ FileUtils.mkdir_p("#{project_dir}/pages")
137
+
138
+ File.write("#{project_dir}/pages/login_page.rb", <<~RUBY)
139
+ class LoginPage < BasePage
140
+ include Capybara::DSL
141
+
142
+ def login(email, password)
143
+ fill_in 'email', with: email
144
+ fill_in 'password', with: password
145
+ click_button 'Login'
146
+ end
147
+ end
148
+ RUBY
149
+ end
150
+
151
+ it 'detects capybara dsl' do
152
+ analysis = described_class.new(project_dir).analyze
153
+ expect(analysis[:source_dsl]).to eq(:capybara)
154
+ end
155
+ end
156
+
157
+ context 'with a watir project' do
158
+ before do
159
+ File.write("#{project_dir}/Gemfile", "gem 'watir'\ngem 'rspec'\n")
160
+ FileUtils.mkdir_p("#{project_dir}/pages")
161
+
162
+ File.write("#{project_dir}/pages/login_page.rb", <<~RUBY)
163
+ class LoginPage < Page
164
+ def login(username, password)
165
+ browser.text_field(id: 'user').set username
166
+ browser.button(id: 'submit').click
167
+ end
168
+ end
169
+ RUBY
170
+ end
171
+
172
+ it 'detects watir dsl' do
173
+ analysis = described_class.new(project_dir).analyze
174
+ expect(analysis[:source_dsl]).to eq(:watir)
175
+ end
176
+ end
177
+
178
+ context 'with a minitest project' do
179
+ before do
180
+ File.write("#{project_dir}/Gemfile", "gem 'minitest'\ngem 'selenium-webdriver'\n")
181
+ FileUtils.mkdir_p("#{project_dir}/pages")
182
+ FileUtils.mkdir_p("#{project_dir}/test")
183
+
184
+ File.write("#{project_dir}/pages/login_page.rb", <<~RUBY)
185
+ class LoginPage < BasePage
186
+ def login(u, p)
187
+ driver.find_element(id: 'user').send_keys u
188
+ end
189
+ end
190
+ RUBY
191
+
192
+ File.write("#{project_dir}/test/test_login.rb", <<~RUBY)
193
+ class TestLogin < Minitest::Test
194
+ def test_successful_login
195
+ assert_equal 'Welcome', header
196
+ end
197
+
198
+ def test_failed_login
199
+ assert_equal 'Error', message
200
+ end
201
+ end
202
+ RUBY
203
+ end
204
+
205
+ it 'discovers minitest files' do
206
+ analysis = described_class.new(project_dir).analyze
207
+ expect(analysis[:tests].length).to eq(1)
208
+ expect(analysis[:tests].first[:type]).to eq(:minitest)
209
+ end
210
+
211
+ it 'extracts minitest method names' do
212
+ analysis = described_class.new(project_dir).analyze
213
+ expect(analysis[:tests].first[:test_methods]).to contain_exactly(
214
+ 'test_successful_login', 'test_failed_login'
215
+ )
216
+ end
217
+ end
218
+
219
+ context 'with a cucumber project' do
220
+ before do
221
+ File.write("#{project_dir}/Gemfile", "gem 'cucumber'\ngem 'selenium-webdriver'\n")
222
+ FileUtils.mkdir_p("#{project_dir}/pages")
223
+ FileUtils.mkdir_p("#{project_dir}/features/step_definitions")
224
+
225
+ File.write("#{project_dir}/pages/login_page.rb", <<~RUBY)
226
+ class LoginPage < BasePage
227
+ def login(u, p)
228
+ driver.find_element(id: 'user').send_keys u
229
+ end
230
+ end
231
+ RUBY
232
+
233
+ File.write("#{project_dir}/features/login.feature", <<~GHERKIN)
234
+ Feature: Login
235
+
236
+ Scenario: Successful login
237
+ Given I am on the login page
238
+ When I enter valid credentials
239
+ Then I see the dashboard
240
+
241
+ Scenario: Failed login
242
+ Given I am on the login page
243
+ When I enter invalid credentials
244
+ Then I see an error
245
+ GHERKIN
246
+
247
+ File.write("#{project_dir}/features/step_definitions/login_steps.rb", <<~RUBY)
248
+ Given('I am on the login page') do
249
+ visit '/login'
250
+ end
251
+
252
+ When('I enter valid credentials') do
253
+ fill_in 'email', with: 'test@test.com'
254
+ end
255
+
256
+ Then('I see the dashboard') do
257
+ expect(page).to have_content 'Dashboard'
258
+ end
259
+ RUBY
260
+ end
261
+
262
+ it 'discovers feature files' do
263
+ analysis = described_class.new(project_dir).analyze
264
+ expect(analysis[:features].length).to eq(1)
265
+ expect(analysis[:features].first[:scenarios]).to eq(2)
266
+ end
267
+
268
+ it 'discovers step definitions' do
269
+ analysis = described_class.new(project_dir).analyze
270
+ expect(analysis[:step_definitions].length).to eq(1)
271
+ expect(analysis[:step_definitions].first[:steps]).to eq(3)
272
+ end
273
+ end
274
+
275
+ context 'with an appium project' do
276
+ before do
277
+ File.write("#{project_dir}/Gemfile", "gem 'appium_lib'\ngem 'rspec'\n")
278
+ end
279
+
280
+ it 'raises MobileProjectError' do
281
+ expect { described_class.new(project_dir).analyze }
282
+ .to raise_error(Adopter::MobileProjectError, /Mobile.*cannot be adopted/)
283
+ end
284
+ end
285
+
286
+ context 'with overrides' do
287
+ before do
288
+ File.write("#{project_dir}/Gemfile", "gem 'rspec'\ngem 'selenium-webdriver'\n")
289
+ FileUtils.mkdir_p("#{project_dir}/spec")
290
+ end
291
+
292
+ it 'applies overrides to detection' do
293
+ analysis = described_class.new(project_dir, browser: 'firefox').analyze
294
+ expect(analysis[:browser]).to eq('firefox')
295
+ end
296
+ end
297
+
298
+ context 'with helpers' do
299
+ before do
300
+ File.write("#{project_dir}/Gemfile", "gem 'rspec'\ngem 'selenium-webdriver'\n")
301
+ FileUtils.mkdir_p("#{project_dir}/spec/support")
302
+
303
+ File.write("#{project_dir}/spec/support/driver_setup.rb", <<~RUBY)
304
+ module DriverHelper
305
+ def driver
306
+ @driver ||= Selenium::WebDriver.for :chrome
307
+ end
308
+
309
+ def create_driver
310
+ Selenium::WebDriver.for :chrome
311
+ end
312
+ end
313
+ RUBY
314
+ end
315
+
316
+ it 'discovers helpers with roles' do
317
+ analysis = described_class.new(project_dir).analyze
318
+ driver_helper = analysis[:helpers].find { |h| h[:role] == :driver }
319
+ expect(driver_helper).not_to be_nil
320
+ expect(driver_helper[:modules_defined]).to include('DriverHelper')
321
+ end
322
+ end
323
+
324
+ context 'with no page objects' do
325
+ before do
326
+ File.write("#{project_dir}/Gemfile", "gem 'rspec'\ngem 'selenium-webdriver'\n")
327
+ FileUtils.mkdir_p("#{project_dir}/spec")
328
+ end
329
+
330
+ it 'returns empty pages and raw dsl' do
331
+ analysis = described_class.new(project_dir).analyze
332
+ expect(analysis[:pages]).to eq([])
333
+ expect(analysis[:source_dsl]).to eq(:raw)
334
+ end
335
+ end
336
+ end
337
+ end
@@ -0,0 +1,295 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'rspec'
5
+ require_relative '../../lib/adopter/project_detector'
6
+
7
+ RSpec.describe Adopter::ProjectDetector do
8
+ let(:project_dir) { 'tmp_test_project' }
9
+
10
+ before { FileUtils.mkdir_p(project_dir) }
11
+
12
+ after { FileUtils.rm_rf(project_dir) }
13
+
14
+ describe '.detect' do
15
+ it 'returns a hash with detection results' do
16
+ expect(described_class.detect(project_dir)).to be_a(Hash)
17
+ end
18
+
19
+ it 'excludes nil values from the result' do
20
+ expect(described_class.detect(project_dir).values).not_to include(nil)
21
+ end
22
+ end
23
+
24
+ describe '.detect_framework' do
25
+ subject(:framework) { described_class.detect_framework(project_dir) }
26
+
27
+ context 'when Gemfile contains rspec' do
28
+ before { File.write("#{project_dir}/Gemfile", "gem 'rspec'\n") }
29
+
30
+ it { is_expected.to eq('rspec') }
31
+ end
32
+
33
+ context 'when Gemfile contains cucumber' do
34
+ before { File.write("#{project_dir}/Gemfile", "gem 'cucumber'\n") }
35
+
36
+ it { is_expected.to eq('cucumber') }
37
+ end
38
+
39
+ context 'when Gemfile contains minitest' do
40
+ before { File.write("#{project_dir}/Gemfile", "gem 'minitest'\n") }
41
+
42
+ it { is_expected.to eq('minitest') }
43
+ end
44
+
45
+ context 'when no Gemfile but spec/ exists' do
46
+ before { FileUtils.mkdir_p("#{project_dir}/spec") }
47
+
48
+ it { is_expected.to eq('rspec') }
49
+ end
50
+
51
+ context 'when no Gemfile but features/ exists' do
52
+ before { FileUtils.mkdir_p("#{project_dir}/features") }
53
+
54
+ it { is_expected.to eq('cucumber') }
55
+ end
56
+
57
+ context 'when no Gemfile but test/ exists' do
58
+ before { FileUtils.mkdir_p("#{project_dir}/test") }
59
+
60
+ it { is_expected.to eq('minitest') }
61
+ end
62
+
63
+ context 'when nothing is present' do
64
+ it { is_expected.to be_nil }
65
+ end
66
+ end
67
+
68
+ describe '.detect_automation' do
69
+ subject(:automation) { described_class.detect_automation(project_dir) }
70
+
71
+ %w[selenium-webdriver watir appium_lib].zip(%w[selenium watir appium]).each do |gem_name, expected|
72
+ context "with #{gem_name} in Gemfile" do
73
+ before { File.write("#{project_dir}/Gemfile", "gem '#{gem_name}'\n") }
74
+
75
+ it { is_expected.to eq(expected) }
76
+ end
77
+ end
78
+
79
+ { 'eyes_selenium' => 'applitools', 'axe-core-selenium' => 'axe',
80
+ 'capybara' => 'capybara', 'site_prism' => 'capybara' }.each do |gem_name, expected|
81
+ context "with #{gem_name} in Gemfile" do
82
+ before { File.write("#{project_dir}/Gemfile", "gem '#{gem_name}'\n") }
83
+
84
+ it { is_expected.to eq(expected) }
85
+ end
86
+ end
87
+
88
+ context 'with capybara and selenium-webdriver in Gemfile' do
89
+ before { File.write("#{project_dir}/Gemfile", "gem 'capybara'\ngem 'selenium-webdriver'\n") }
90
+
91
+ it 'prioritizes capybara over selenium' do
92
+ expect(automation).to eq('capybara')
93
+ end
94
+ end
95
+
96
+ context 'with no Gemfile but require in source files' do
97
+ before do
98
+ FileUtils.mkdir_p("#{project_dir}/spec")
99
+ File.write("#{project_dir}/spec/test.rb", "require 'selenium-webdriver'\n")
100
+ end
101
+
102
+ it { is_expected.to eq('selenium') }
103
+ end
104
+
105
+ context 'with no Gemfile but capybara require in source files' do
106
+ before do
107
+ FileUtils.mkdir_p("#{project_dir}/spec")
108
+ File.write("#{project_dir}/spec/test.rb", "require 'capybara'\n")
109
+ end
110
+
111
+ it { is_expected.to eq('capybara') }
112
+ end
113
+
114
+ context 'with no Gemfile but site_prism require in source files' do
115
+ before do
116
+ FileUtils.mkdir_p("#{project_dir}/spec")
117
+ File.write("#{project_dir}/spec/test.rb", "require 'site_prism'\n")
118
+ end
119
+
120
+ it { is_expected.to eq('capybara') }
121
+ end
122
+ end
123
+
124
+ describe '.detect_page_path' do
125
+ subject(:page_path) { described_class.detect_page_path(project_dir) }
126
+
127
+ { 'page_objects/pages' => 'page_objects/pages', 'pages' => 'pages', 'page' => 'page' }.each do |dir, expected|
128
+ context "with #{dir} directory" do
129
+ before { FileUtils.mkdir_p("#{project_dir}/#{dir}") }
130
+
131
+ it { is_expected.to eq(expected) }
132
+ end
133
+ end
134
+ end
135
+
136
+ describe '.detect_spec_path' do
137
+ subject(:spec_path) { described_class.detect_spec_path(project_dir) }
138
+
139
+ { 'spec' => 'spec', 'test' => 'test', 'tests' => 'tests' }.each do |dir, expected|
140
+ context "with #{dir} directory" do
141
+ before { FileUtils.mkdir_p("#{project_dir}/#{dir}") }
142
+
143
+ it { is_expected.to eq(expected) }
144
+ end
145
+ end
146
+ end
147
+
148
+ describe '.detect_feature_path' do
149
+ context 'with features directory' do
150
+ before { FileUtils.mkdir_p("#{project_dir}/features") }
151
+
152
+ it 'detects features path' do
153
+ expect(described_class.detect_feature_path(project_dir)).to eq('features')
154
+ end
155
+ end
156
+ end
157
+
158
+ describe '.detect_helper_path' do
159
+ subject(:helper_path) { described_class.detect_helper_path(project_dir) }
160
+
161
+ { 'helpers' => 'helpers', 'support' => 'support', 'features/support' => 'features/support' }.each do |dir, expected|
162
+ context "with #{dir} directory" do
163
+ before { FileUtils.mkdir_p("#{project_dir}/#{dir}") }
164
+
165
+ it { is_expected.to eq(expected) }
166
+ end
167
+ end
168
+ end
169
+
170
+ describe '.detect_browser' do
171
+ subject(:browser) { described_class.detect_browser(project_dir) }
172
+
173
+ context 'with browser in spec_helper' do
174
+ before do
175
+ FileUtils.mkdir_p("#{project_dir}/spec")
176
+ File.write("#{project_dir}/spec/spec_helper.rb", "browser = :firefox\n")
177
+ end
178
+
179
+ it { is_expected.to eq('firefox') }
180
+ end
181
+
182
+ context 'with browser in config.yml' do
183
+ before do
184
+ FileUtils.mkdir_p("#{project_dir}/config")
185
+ File.write("#{project_dir}/config/config.yml", "browser: chrome\n")
186
+ end
187
+
188
+ it { is_expected.to eq('chrome') }
189
+ end
190
+ end
191
+
192
+ describe '.detect_url' do
193
+ subject(:url) { described_class.detect_url(project_dir) }
194
+
195
+ context 'with base_url in spec_helper' do
196
+ before do
197
+ FileUtils.mkdir_p("#{project_dir}/spec")
198
+ File.write("#{project_dir}/spec/spec_helper.rb", "base_url = 'https://example.com'\n")
199
+ end
200
+
201
+ it { is_expected.to eq('https://example.com') }
202
+ end
203
+
204
+ context 'with app_host in env.rb' do
205
+ before do
206
+ FileUtils.mkdir_p("#{project_dir}/features/support")
207
+ File.write("#{project_dir}/features/support/env.rb", "app_host = 'https://staging.example.com'\n")
208
+ end
209
+
210
+ it { is_expected.to eq('https://staging.example.com') }
211
+ end
212
+ end
213
+
214
+ describe '.detect_ci_platform' do
215
+ subject(:ci_platform) { described_class.detect_ci_platform(project_dir) }
216
+
217
+ context 'with .github/workflows directory' do
218
+ before { FileUtils.mkdir_p("#{project_dir}/.github/workflows") }
219
+
220
+ it { is_expected.to eq('github') }
221
+ end
222
+
223
+ context 'with .gitlab-ci.yml file' do
224
+ before { File.write("#{project_dir}/.gitlab-ci.yml", "stages:\n - test\n") }
225
+
226
+ it { is_expected.to eq('gitlab') }
227
+ end
228
+
229
+ context 'with no CI configuration' do
230
+ it { is_expected.to be_nil }
231
+ end
232
+ end
233
+
234
+ describe 'full project detection' do
235
+ before do
236
+ File.write("#{project_dir}/Gemfile", <<~GEMFILE)
237
+ source 'https://rubygems.org'
238
+ gem 'rspec'
239
+ gem 'selenium-webdriver'
240
+ gem 'rake'
241
+ GEMFILE
242
+ FileUtils.mkdir_p("#{project_dir}/spec")
243
+ FileUtils.mkdir_p("#{project_dir}/page_objects/pages")
244
+ FileUtils.mkdir_p("#{project_dir}/helpers")
245
+ FileUtils.mkdir_p("#{project_dir}/.github/workflows")
246
+ FileUtils.mkdir_p("#{project_dir}/config")
247
+ File.write("#{project_dir}/config/config.yml", "browser: chrome\nurl: 'https://example.com'\n")
248
+ end
249
+
250
+ it 'detects all components of a complete project' do
251
+ expect(described_class.detect(project_dir)).to include(
252
+ automation: 'selenium',
253
+ framework: 'rspec',
254
+ page_path: 'page_objects/pages',
255
+ spec_path: 'spec',
256
+ helper_path: 'helpers',
257
+ browser: 'chrome',
258
+ url: 'https://example.com',
259
+ ci_platform: 'github'
260
+ )
261
+ end
262
+ end
263
+
264
+ describe 'full capybara + minitest project detection' do
265
+ before do
266
+ File.write("#{project_dir}/Gemfile", <<~GEMFILE)
267
+ source 'https://rubygems.org'
268
+ gem 'minitest'
269
+ gem 'capybara'
270
+ gem 'selenium-webdriver'
271
+ gem 'site_prism'
272
+ gem 'rake'
273
+ GEMFILE
274
+ FileUtils.mkdir_p("#{project_dir}/test")
275
+ FileUtils.mkdir_p("#{project_dir}/pages")
276
+ FileUtils.mkdir_p("#{project_dir}/support")
277
+ File.write("#{project_dir}/.gitlab-ci.yml", "stages:\n - test\n")
278
+ FileUtils.mkdir_p("#{project_dir}/config")
279
+ File.write("#{project_dir}/config/config.yml", "browser: firefox\nurl: 'https://staging.example.com'\n")
280
+ end
281
+
282
+ it 'detects capybara + minitest project' do
283
+ expect(described_class.detect(project_dir)).to include(
284
+ automation: 'capybara',
285
+ framework: 'minitest',
286
+ page_path: 'pages',
287
+ spec_path: 'test',
288
+ helper_path: 'support',
289
+ browser: 'firefox',
290
+ url: 'https://staging.example.com',
291
+ ci_platform: 'gitlab'
292
+ )
293
+ end
294
+ end
295
+ end
@@ -0,0 +1 @@
1
+ Test content
@@ -0,0 +1 @@
1
+ Test partial content