ruby_raider 3.10.0 → 3.12.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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/reek.yml +5 -1
  3. data/.github/workflows/release.yml +2 -1
  4. data/.github/workflows/system_tests.yml +1 -1
  5. data/.reek.yml +13 -0
  6. data/README.md +44 -4
  7. data/lib/commands/utility_commands.rb +1 -1
  8. data/lib/generators/automation/automation_generator.rb +15 -10
  9. data/lib/generators/automation/templates/appium_caps.tt +2 -4
  10. data/lib/generators/automation/templates/home.tt +1 -2
  11. data/lib/generators/automation/templates/login.tt +6 -6
  12. data/lib/generators/automation/templates/page.tt +10 -3
  13. data/lib/generators/automation/templates/partials/home_page_selector.tt +4 -6
  14. data/lib/generators/automation/templates/partials/pdp_page_selector.tt +4 -6
  15. data/lib/generators/automation/templates/pdp.tt +3 -2
  16. data/lib/generators/cucumber/cucumber_generator.rb +15 -2
  17. data/lib/generators/cucumber/templates/feature.tt +5 -0
  18. data/lib/generators/cucumber/templates/partials/driver_world.tt +9 -0
  19. data/lib/generators/cucumber/templates/partials/mobile_steps.tt +1 -1
  20. data/lib/generators/cucumber/templates/partials/selenium_env.tt +20 -0
  21. data/lib/generators/cucumber/templates/partials/watir_env.tt +16 -0
  22. data/lib/generators/cucumber/templates/partials/web_steps.tt +8 -0
  23. data/lib/generators/generator.rb +15 -4
  24. data/lib/generators/helper_generator.rb +15 -0
  25. data/lib/generators/invoke_generators.rb +23 -0
  26. data/lib/generators/menu_generator.rb +26 -14
  27. data/lib/generators/rspec/rspec_generator.rb +10 -3
  28. data/lib/generators/rspec/templates/spec.tt +27 -1
  29. data/lib/generators/template_renderer/template_error.rb +8 -8
  30. data/lib/generators/templates/common/git_ignore.tt +4 -1
  31. data/lib/generators/templates/common/partials/mobile_config.tt +1 -0
  32. data/lib/generators/templates/common/partials/web_config.tt +5 -2
  33. data/lib/generators/templates/common/read_me.tt +508 -0
  34. data/lib/generators/templates/helpers/partials/selenium_driver.tt +1 -3
  35. data/lib/generators/templates/helpers/raider_element.tt +159 -0
  36. data/lib/generators/templates/helpers/session_state.tt +246 -0
  37. data/lib/generators/templates/helpers/spec_helper.tt +28 -0
  38. data/lib/generators/templates/helpers/wait_helper.tt +470 -0
  39. data/lib/ruby_raider/ffmpeg.rb +7 -7
  40. data/lib/ruby_raider.rb +2 -0
  41. data/lib/scaffolding/project_detector.rb +6 -0
  42. data/lib/scaffolding/scaffolding.rb +4 -0
  43. data/lib/scaffolding/templates/component.tt +4 -0
  44. data/lib/scaffolding/templates/page_object.tt +8 -0
  45. data/lib/version +1 -1
  46. data/ruby_raider.gemspec +1 -0
  47. data/sig/generators/generator.rbs +2 -0
  48. data/sig/scaffolding/project_detector.rbs +1 -0
  49. data/sig/scaffolding/scaffolding.rbs +1 -0
  50. data/spec/commands/raider_commands_spec.rb +24 -0
  51. data/spec/fixtures/watir_master/cucumber_watir/Readme.md.snapshot +175 -0
  52. data/spec/fixtures/watir_master/cucumber_watir/features/step_definitions/login_steps.rb.snapshot +24 -0
  53. data/spec/fixtures/watir_master/cucumber_watir/page_objects/abstract/page.rb.snapshot +39 -0
  54. data/spec/fixtures/watir_master/cucumber_watir/page_objects/pages/login.rb.snapshot +33 -0
  55. data/spec/fixtures/watir_master/rspec_watir/Readme.md.snapshot +174 -0
  56. data/spec/fixtures/watir_master/rspec_watir/page_objects/abstract/page.rb.snapshot +39 -0
  57. data/spec/fixtures/watir_master/rspec_watir/page_objects/pages/login.rb.snapshot +33 -0
  58. data/spec/fixtures/watir_master/rspec_watir/spec/login_page_spec.rb.snapshot +49 -0
  59. data/spec/integration/commands/scaffolding_commands_spec.rb +49 -0
  60. data/spec/integration/commands/utility_commands_spec.rb +8 -0
  61. data/spec/integration/content/azure_content_spec.rb +4 -0
  62. data/spec/integration/content/ci_content_spec.rb +11 -0
  63. data/spec/integration/content/common_content_spec.rb +27 -0
  64. data/spec/integration/content/config_content_spec.rb +62 -0
  65. data/spec/integration/content/cucumber_reporter_content_spec.rb +25 -0
  66. data/spec/integration/content/helper_content_spec.rb +111 -0
  67. data/spec/integration/content/page_content_spec.rb +75 -4
  68. data/spec/integration/content/readme_content_spec.rb +149 -0
  69. data/spec/integration/content/syntax_validation_spec.rb +38 -0
  70. data/spec/integration/content/test_content_spec.rb +82 -0
  71. data/spec/integration/end_to_end_spec.rb +73 -28
  72. data/spec/integration/generators/automation_generator_spec.rb +50 -0
  73. data/spec/integration/generators/common_generator_spec.rb +20 -0
  74. data/spec/integration/generators/config_features_spec.rb +2 -2
  75. data/spec/integration/generators/cucumber_generator_spec.rb +36 -0
  76. data/spec/integration/generators/helpers_generator_spec.rb +60 -0
  77. data/spec/integration/generators/invoke_generators_spec.rb +70 -0
  78. data/spec/integration/generators/rspec_generator_spec.rb +20 -0
  79. data/spec/integration/helpers/session_state_spec.rb +474 -0
  80. data/spec/integration/helpers/wait_helper_mobile_spec.rb +281 -0
  81. data/spec/integration/helpers/wait_helper_spec.rb +496 -0
  82. data/spec/integration/helpers/wait_helper_support.rb +183 -0
  83. data/spec/integration/settings_helper.rb +4 -1
  84. data/spec/integration/spec_helper.rb +2 -2
  85. data/spec/menus/menu_generator_spec.rb +64 -2
  86. data/spec/scaffolding/scaffold_project_detector_spec.rb +12 -0
  87. metadata +31 -2
@@ -116,18 +116,41 @@ describe 'Test file content' do
116
116
  end
117
117
  end
118
118
 
119
+ shared_examples 'logged in example' do |project_name|
120
+ it 'adds a :logged_in example that reuses the saved login and keeps the login example' do
121
+ spec = read_generated(project_name, 'spec/login_page_spec.rb')
122
+ expect(spec).to include("describe 'Account', :logged_in", 'opens the account page with the saved login',
123
+ "describe 'Login' do", 'can successfully log in')
124
+ end
125
+ end
126
+
127
+ shared_examples 'logged in scenario' do |project_name|
128
+ it 'adds a @logged_in scenario and keeps the login scenario' do
129
+ feature = read_generated(project_name, 'features/login.feature')
130
+ expect(feature).to include("@logged_in\nScenario: A logged-in user opens the account page",
131
+ "Given I'm a registered user\n", 'Scenario: A user can login')
132
+ end
133
+
134
+ it 'defines the step that picks the user without logging in' do
135
+ steps = read_generated(project_name, 'features/step_definitions/login_steps.rb')
136
+ expect(steps).to include(%q(Given("I'm a {user}") do |user|))
137
+ end
138
+ end
139
+
119
140
  # --- RSpec contexts ---
120
141
 
121
142
  context 'with rspec and selenium' do
122
143
  name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
123
144
  include_examples 'valid rspec spec', name
124
145
  include_examples 'selenium rspec spec', name
146
+ include_examples 'logged in example', name
125
147
  end
126
148
 
127
149
  context 'with rspec and watir' do
128
150
  name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
129
151
  include_examples 'valid rspec spec', name
130
152
  include_examples 'watir rspec spec', name
153
+ include_examples 'logged in example', name
131
154
  end
132
155
 
133
156
  # --- Cucumber contexts ---
@@ -138,6 +161,7 @@ describe 'Test file content' do
138
161
  include_examples 'valid cucumber env', name
139
162
  include_examples 'valid cucumber world', name
140
163
  include_examples 'valid cucumber config', name
164
+ include_examples 'logged in scenario', name
141
165
  end
142
166
 
143
167
  context 'with cucumber and watir' do
@@ -146,5 +170,63 @@ describe 'Test file content' do
146
170
  include_examples 'valid cucumber env', name
147
171
  include_examples 'valid cucumber world', name
148
172
  include_examples 'valid cucumber config', name
173
+ include_examples 'logged in scenario', name
174
+ end
175
+ end
176
+
177
+ describe 'Cucumber world WaitHelper wiring' do
178
+ %w[selenium ios android cross_platform].each do |automation|
179
+ it "makes WaitHelper available to steps in #{automation}" do
180
+ world = read_generated("cucumber_#{automation}", 'features/support/world.rb')
181
+ expect(world).to include("require_relative '../../helpers/wait_helper'", 'World(WaitHelper)')
182
+ end
183
+ end
184
+
185
+ it 'leaves the watir world without WaitHelper' do
186
+ expect(read_generated('cucumber_watir', 'features/support/world.rb')).not_to include('WaitHelper')
187
+ end
188
+ end
189
+
190
+ describe 'Example tests on the wait helper' do
191
+ it 'wraps every assertion of the selenium rspec spec in eventually' do
192
+ spec = read_generated('rspec_selenium', 'spec/login_page_spec.rb')
193
+ expect(spec.scan('eventually { expect(').size).to eq(3)
194
+ expect(spec.scan(/^ +expect\(/)).to be_empty
195
+ end
196
+
197
+ it "wraps the selenium cucumber Then step's assertion in eventually" do
198
+ steps = read_generated('cucumber_selenium', 'features/step_definitions/login_steps.rb')
199
+ expect(steps).to include('eventually { expect(account_page.header.customer_name).to eq ')
200
+ end
201
+
202
+ %w[ios android cross_platform].each do |automation|
203
+ it "wraps the #{automation} rspec assertion in eventually" do
204
+ spec = read_generated("rspec_#{automation}", 'spec/pdp_page_spec.rb')
205
+ expect(spec).to include("eventually { expect(pdp_page.add_to_cart_text).to eq 'Add to Cart' }")
206
+ end
207
+
208
+ it "wraps the #{automation} cucumber Then step's assertion in eventually" do
209
+ steps = read_generated("cucumber_#{automation}", 'features/step_definitions/home_steps.rb')
210
+ expect(steps).to include("eventually { expect(pdp_page.add_to_cart_text).to eq 'Add to Cart' }")
211
+ end
212
+ end
213
+ end
214
+
215
+ # The Watir output must stay as master generated it (1274a66); the snapshots in
216
+ # spec/fixtures/watir_master were generated from that commit's lib.
217
+ # To regenerate: `git archive 1274a66 lib` into a scratch dir, generate rspec and cucumber Watir projects there,
218
+ # then apply only the Readme deprecation-line delta (the `> **Deprecated:**` line under the heading block).
219
+ describe 'Watir example output' do
220
+ snapshots = File.expand_path('../../fixtures/watir_master', __dir__)
221
+
222
+ { 'rspec_watir' => %w[page_objects/pages/login.rb page_objects/abstract/page.rb spec/login_page_spec.rb Readme.md],
223
+ 'cucumber_watir' => %w[page_objects/pages/login.rb page_objects/abstract/page.rb
224
+ features/step_definitions/login_steps.rb Readme.md] }.each do |project, files|
225
+ files.each do |file|
226
+ it "keeps #{project}/#{file} as master generates it" do
227
+ expected = File.read(File.join(snapshots, project, "#{file}.snapshot"))
228
+ expect(read_generated(project, file)).to eq(expected)
229
+ end
230
+ end
149
231
  end
150
232
  end
@@ -269,6 +269,29 @@ describe 'End-to-End Project Generation and Execution' do
269
269
  context 'Web Automation Frameworks' do
270
270
  describe 'Selenium + RSpec' do
271
271
  include_examples 'executable rspec project', 'rspec_selenium'
272
+
273
+ it 'saves the login once and reuses it', :aggregate_failures, :slow do
274
+ skip 'Bundle install failed' unless bundle_install('rspec_selenium')
275
+
276
+ state_file = File.join('rspec_selenium', '.raider', 'auth', 'user.json')
277
+ FileUtils.rm_rf(File.join('rspec_selenium', '.raider'))
278
+ first = run_in_project('rspec_selenium', 'bundle exec rspec spec/', env: { 'HEADLESS' => 'true' })
279
+ failed = ->(run, index) { "Run #{index} failed.\nSTDOUT: #{run[:stdout]}\nSTDERR: #{run[:stderr]}" }
280
+ raise failed.call(first, 1) unless first[:exit_code].zero? # show run 1's output, not a missing state file
281
+
282
+ expect(File).to exist(state_file)
283
+ saved = JSON.parse(File.read(state_file))
284
+ second = run_in_project('rspec_selenium', 'bundle exec rspec spec/', env: { 'HEADLESS' => 'true' })
285
+ expect(second[:exit_code]).to eq(0), failed.call(second, 2)
286
+ expect(File.stat(state_file).mode & 0o777).to eq(0o600)
287
+ expect(saved).to include('format' => 1, 'origin' => 'https://raider-test-site.onrender.com')
288
+ expect(JSON.parse(File.read(state_file))['saved_at']).to eq(saved['saved_at'])
289
+ cookie_values = saved['cookies'].map { |cookie| cookie['value'].to_s }
290
+ expect(cookie_values.reject(&:empty?)).not_to be_empty
291
+ output = [first, second].map { |run| run[:stdout] + run[:stderr] }.join
292
+ # Short values like "1" or "en" can appear in any output; a leaked token is long.
293
+ cookie_values.select { |value| value.length >= 8 }.each { |value| expect(output).not_to include(value) }
294
+ end
272
295
  end
273
296
 
274
297
  describe 'Watir + RSpec' do
@@ -375,6 +398,40 @@ describe 'End-to-End Project Generation and Execution' do
375
398
  end
376
399
  end
377
400
 
401
+ # An empty skeleton (examples: false) still passes its run, so its CI is green until tests are added
402
+ def generate_skeleton_project(framework)
403
+ name = "skeleton_e2e_#{framework}_selenium"
404
+ unless LazyProjectGenerator::GENERATED.include?(name)
405
+ generate_framework(framework:, automation: 'selenium', name:, examples: false)
406
+ LazyProjectGenerator::GENERATED.add(name)
407
+ end
408
+ name
409
+ end
410
+
411
+ context 'Empty skeleton projects (examples: false)' do
412
+ it 'runs bundle exec rspec on a selenium rspec skeleton with 0 examples', :aggregate_failures do
413
+ project = generate_skeleton_project('rspec')
414
+ skip 'Bundle install failed' unless bundle_install(project)
415
+
416
+ ['rspec', 'rspec spec/'].each do |command|
417
+ result = run_in_project(project, "bundle exec #{command}", timeout: 120)
418
+ expect(result[:exit_code]).to eq(0), "#{command}\nSTDOUT: #{result[:stdout]}\nSTDERR: #{result[:stderr]}"
419
+ expect(result[:stdout]).to include('0 examples, 0 failures')
420
+ end
421
+ end
422
+
423
+ it 'runs bundle exec cucumber on a selenium cucumber skeleton with 0 scenarios', :aggregate_failures do
424
+ project = generate_skeleton_project('cucumber')
425
+ skip 'Bundle install failed' unless bundle_install(project)
426
+
427
+ ['cucumber', 'cucumber features'].each do |command|
428
+ result = run_in_project(project, "bundle exec #{command}", timeout: 120)
429
+ expect(result[:exit_code]).to eq(0), "#{command}\nSTDOUT: #{result[:stdout]}\nSTDERR: #{result[:stderr]}"
430
+ expect(result[:stdout]).to include('0 scenarios')
431
+ end
432
+ end
433
+ end
434
+
378
435
  # Failure video replay against real browsers. Needs an ffmpeg with libvpx (RAIDER_FFMPEG_PATH), because the
379
436
  # RaiderHQ ffmpeg release has no checksums yet. Skipped when it, or the browser, is missing. Firefox can be
380
437
  # pointed at a specific binary with FIREFOX_BINARY.
@@ -660,38 +717,26 @@ describe 'End-to-End Project Generation and Execution' do
660
717
 
661
718
  # Verify template system performance (caching working)
662
719
  context 'Template System Performance' do
663
- it 'benefits from template caching on second generation' do
720
+ it 'compiles each partial once and reuses it on the second generation' do
664
721
  require_relative '../../lib/generators/generator'
665
722
 
666
- # Clear cache
667
723
  Generator.clear_template_cache
724
+ compiled = []
725
+ allow_any_instance_of(TemplateRenderer::PartialCache).to(
726
+ receive(:compile_template).and_wrap_original { |original, *args| compiled << args.first && original.call(*args) }
727
+ )
668
728
 
669
- # First generation (cache miss)
670
- start_time = Time.now
671
- settings1 = create_settings(framework: 'rspec', automation: 'selenium')
672
- settings1[:name] = 'test_cache_1'
673
- generate_framework(settings1)
674
- first_duration = Time.now - start_time
675
-
676
- # Second generation (cache hit)
677
- start_time = Time.now
678
- settings2 = create_settings(framework: 'rspec', automation: 'selenium')
679
- settings2[:name] = 'test_cache_2'
680
- generate_framework(settings2)
681
- second_duration = Time.now - start_time
682
-
683
- # Second generation should be faster (or similar if I/O dominates)
684
- # At minimum, cache should not slow things down
685
- expect(second_duration).to be <= (first_duration * 1.2)
686
-
687
- # Cleanup
688
- FileUtils.rm_rf('test_cache_1')
689
- FileUtils.rm_rf('test_cache_2')
690
-
691
- # Verify cache has entries
692
- stats = Generator.template_cache_stats
693
- expect(stats[:size]).to be > 0
694
- puts "\n📊 Template cache: #{stats[:size]} entries, ~#{stats[:memory_estimate] / 1024}KB"
729
+ %w[test_cache_1 test_cache_2].map do |name|
730
+ before = compiled.size
731
+ generate_framework(create_settings(framework: 'rspec', automation: 'selenium').merge(name:))
732
+ compiled.size - before
733
+ end => [first, second]
734
+
735
+ expect(first).to be_positive
736
+ expect(second).to eq(0)
737
+ expect(Generator.template_cache_stats[:size]).to be_positive
738
+ ensure
739
+ FileUtils.rm_rf(%w[test_cache_1 test_cache_2])
695
740
  end
696
741
  end
697
742
  end
@@ -71,4 +71,54 @@ describe AutomationGenerator do
71
71
  context 'with cucumber and appium cross platform' do
72
72
  include_examples 'creates mobile automation framework', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::CROSS_PLATFORM}"
73
73
  end
74
+
75
+ describe 'without example tests' do
76
+ %w[rspec cucumber].product(%w[selenium ios cross_platform]).each do |framework, automation|
77
+ context "with #{framework} and #{automation}" do
78
+ let(:name) { ensure_project(framework:, automation:, examples: false) }
79
+
80
+ it 'creates no example pages' do
81
+ expect(Dir.glob("#{name}/page_objects/pages/*.rb")).to be_empty
82
+ end
83
+
84
+ it 'keeps the pages folder with a .keep' do
85
+ expect(File).to exist("#{name}/page_objects/pages/.keep")
86
+ end
87
+
88
+ it 'creates the abstract page' do
89
+ expect(File).to exist("#{name}/page_objects/abstract/page.rb")
90
+ end
91
+
92
+ it 'gives the abstract page no header component' do
93
+ expect(File.read("#{name}/page_objects/abstract/page.rb")).not_to include('Header')
94
+ end
95
+
96
+ it 'creates no models' do
97
+ expect(File).not_to exist("#{name}/models")
98
+ end
99
+ end
100
+ end
101
+
102
+ context 'with a web project' do
103
+ let(:name) { ensure_project(framework: 'rspec', automation: 'selenium', examples: false) }
104
+
105
+ it 'creates the abstract component' do
106
+ expect(File).to exist("#{name}/page_objects/abstract/component.rb")
107
+ end
108
+
109
+ it 'keeps the components folder with a .keep and no example component' do
110
+ expect(Dir.children("#{name}/page_objects/components")).to eq(['.keep'])
111
+ end
112
+ end
113
+
114
+ context 'with watir' do
115
+ it 'still creates the examples, because the Watir templates are frozen' do
116
+ InvokeGenerators.generate_framework(framework: 'rspec', automation: 'watir', name: 'skeleton_watir',
117
+ examples: false)
118
+ expect(File).to exist('skeleton_watir/page_objects/pages/login.rb')
119
+ ensure
120
+ FileUtils.rm_rf('skeleton_watir')
121
+ end
122
+ end
123
+ end
74
124
  end
@@ -107,4 +107,24 @@ describe CommonGenerator do
107
107
  include_examples 'creates a config file', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}"
108
108
  include_examples 'creates a gitignore file', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}"
109
109
  end
110
+
111
+ describe 'without example tests' do
112
+ %w[rspec cucumber].product(%w[selenium ios cross_platform]).each do |framework, automation|
113
+ context "with #{framework} and #{automation}" do
114
+ let(:name) { ensure_project(framework:, automation:, examples: false) }
115
+ let(:ci_file) { automation == 'selenium' ? 'test_pipeline.yml' : 'appium_pipeline.yml' }
116
+
117
+ it 'creates the README, Gemfile, Rakefile and CI file' do
118
+ %W[Readme.md Gemfile Rakefile .github/workflows/#{ci_file}].each do |file|
119
+ expect(File).to exist("#{name}/#{file}")
120
+ end
121
+ end
122
+
123
+ it 'creates the settings' do
124
+ settings = automation == 'ios' ? 'config/capabilities.yml' : 'config/config.yml'
125
+ expect(File).to exist("#{name}/#{settings}")
126
+ end
127
+ end
128
+ end
129
+ end
110
130
  end
@@ -35,9 +35,9 @@ describe 'Config features for generated projects' do
35
35
  expect(config['driver_options']).to be_nil
36
36
  end
37
37
 
38
- it 'generates driver_helper with timeout from config' do
38
+ it 'generates driver_helper without an implicit wait' do
39
39
  helper = File.read('config_selenium_test/helpers/driver_helper.rb')
40
- expect(helper).to include("config.fetch('timeout', 10)")
40
+ expect(helper).not_to include('implicit_wait')
41
41
  end
42
42
 
43
43
  it 'generates spec_helper with viewport-aware window setup' do
@@ -61,4 +61,40 @@ describe CucumberGenerator do
61
61
  include_examples 'creates cucumber files', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}", 'login'
62
62
  include_examples 'creates factories for web projects', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}", 'login'
63
63
  end
64
+
65
+ describe 'without example tests' do
66
+ %w[selenium ios cross_platform].each do |automation|
67
+ context "with cucumber and #{automation}" do
68
+ let(:name) { ensure_project(framework: 'cucumber', automation:, examples: false) }
69
+
70
+ it 'creates no feature files' do
71
+ expect(Dir.glob("#{name}/features/**/*.feature")).to be_empty
72
+ end
73
+
74
+ it 'keeps an empty step_definitions folder' do
75
+ expect(Dir.children("#{name}/features/step_definitions")).to eq(['.keep'])
76
+ end
77
+
78
+ it 'creates the support files' do
79
+ expect(Dir.children("#{name}/features/support")).to contain_exactly('env.rb', 'world.rb')
80
+ end
81
+
82
+ it 'creates the cucumber.yml file' do
83
+ expect(File).to exist("#{name}/cucumber.yml")
84
+ end
85
+
86
+ it 'creates no user factory' do
87
+ expect(File).not_to exist("#{name}/models/user_factory.rb")
88
+ end
89
+ end
90
+ end
91
+
92
+ it 'creates no accessibility example' do
93
+ InvokeGenerators.generate_framework(framework: 'cucumber', automation: 'selenium', name: 'skeleton_axe_cucumber',
94
+ examples: false, accessibility: true)
95
+ expect(Dir.glob('skeleton_axe_cucumber/features/**/accessibility*')).to be_empty
96
+ ensure
97
+ FileUtils.rm_rf('skeleton_axe_cucumber')
98
+ end
99
+ end
64
100
  end
@@ -10,6 +10,18 @@ describe HelpersGenerator do
10
10
  end
11
11
  end
12
12
 
13
+ shared_examples 'creates a session state helper' do |name|
14
+ it 'creates a session state helper file' do
15
+ expect(File).to exist("#{name}/helpers/session_state.rb")
16
+ end
17
+ end
18
+
19
+ shared_examples 'skips the session state helper' do |name|
20
+ it 'does not create a session state helper file' do
21
+ expect(File).not_to exist("#{name}/helpers/session_state.rb")
22
+ end
23
+ end
24
+
13
25
  shared_examples 'creates selenium helpers' do |name|
14
26
  it 'creates a driver helper file' do
15
27
  expect(File).to exist("#{name}/helpers/driver_helper.rb")
@@ -20,6 +32,18 @@ describe HelpersGenerator do
20
32
  it 'creates a browser helper file' do
21
33
  expect(File).to exist("#{name}/helpers/browser_helper.rb")
22
34
  end
35
+
36
+ it 'does not create the wait helper or the element wrapper' do
37
+ expect(File).not_to exist("#{name}/helpers/wait_helper.rb")
38
+ expect(File).not_to exist("#{name}/helpers/raider_element.rb")
39
+ end
40
+ end
41
+
42
+ shared_examples 'creates the wait helper' do |name|
43
+ it 'creates the wait helper and the element wrapper' do
44
+ expect(File).to exist("#{name}/helpers/wait_helper.rb")
45
+ expect(File).to exist("#{name}/helpers/raider_element.rb")
46
+ end
23
47
  end
24
48
 
25
49
  shared_examples 'creates rspec helpers' do |name|
@@ -42,63 +66,99 @@ describe HelpersGenerator do
42
66
 
43
67
  context 'with rspec and selenium' do
44
68
  include_examples 'creates common helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
69
+ include_examples 'creates a session state helper', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
45
70
  include_examples 'creates selenium helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
71
+ include_examples 'creates the wait helper', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
46
72
  include_examples 'creates rspec helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
47
73
  end
48
74
 
49
75
  context 'with rspec and watir' do
50
76
  include_examples 'creates common helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
77
+ include_examples 'creates a session state helper', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
51
78
  include_examples 'creates watir helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
52
79
  include_examples 'creates rspec helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
53
80
  end
54
81
 
55
82
  context 'with cucumber and selenium' do
56
83
  include_examples 'creates common helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
84
+ include_examples 'creates a session state helper', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
57
85
  include_examples 'creates selenium helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
86
+ include_examples 'creates the wait helper', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
58
87
  include_examples 'creates cucumber helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
59
88
  end
60
89
 
61
90
  context 'with cucumber and watir' do
62
91
  include_examples 'creates common helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}"
92
+ include_examples 'creates a session state helper', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}"
63
93
  include_examples 'creates watir helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}"
64
94
  include_examples 'creates cucumber helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}"
65
95
  end
66
96
 
67
97
  context 'with rspec and appium android' do
68
98
  include_examples 'creates common helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::ANDROID}"
99
+ include_examples 'skips the session state helper', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::ANDROID}"
69
100
  include_examples 'creates selenium helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::ANDROID}"
101
+ include_examples 'creates the wait helper', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::ANDROID}"
70
102
  include_examples 'creates rspec helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::ANDROID}"
71
103
  end
72
104
 
73
105
  context 'with rspec and appium ios' do
74
106
  include_examples 'creates common helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::IOS}"
107
+ include_examples 'skips the session state helper', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::IOS}"
75
108
  include_examples 'creates selenium helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::IOS}"
109
+ include_examples 'creates the wait helper', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::IOS}"
76
110
  include_examples 'creates rspec helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::IOS}"
77
111
  end
78
112
 
79
113
  context 'with cucumber and appium android' do
80
114
  include_examples 'creates common helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::ANDROID}"
115
+ include_examples 'skips the session state helper', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::ANDROID}"
81
116
  include_examples 'creates selenium helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::ANDROID}"
117
+ include_examples 'creates the wait helper', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::ANDROID}"
82
118
  include_examples 'creates cucumber helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::ANDROID}"
83
119
  end
84
120
 
85
121
  context 'with cucumber and appium ios' do
86
122
  include_examples 'creates common helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::IOS}"
123
+ include_examples 'skips the session state helper', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::IOS}"
87
124
  include_examples 'creates selenium helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::IOS}"
125
+ include_examples 'creates the wait helper', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::IOS}"
88
126
  include_examples 'creates cucumber helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::IOS}"
89
127
  end
90
128
 
91
129
  context 'with rspec and appium cross platform' do
92
130
  include_examples 'creates common helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}"
131
+ include_examples 'skips the session state helper', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}"
93
132
  include_examples 'creates selenium helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}"
133
+ include_examples 'creates the wait helper', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}"
94
134
  include_examples 'creates rspec helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}"
95
135
  include_examples 'creates cross platform helpers', "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}"
96
136
  end
97
137
 
98
138
  context 'with cucumber and appium cross platform' do
99
139
  include_examples 'creates common helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::CROSS_PLATFORM}"
140
+ include_examples 'skips the session state helper', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::CROSS_PLATFORM}"
100
141
  include_examples 'creates selenium helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::CROSS_PLATFORM}"
142
+ include_examples 'creates the wait helper', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::CROSS_PLATFORM}"
101
143
  include_examples 'creates cucumber helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::CROSS_PLATFORM}"
102
144
  include_examples 'creates cross platform helpers', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::CROSS_PLATFORM}"
103
145
  end
146
+
147
+ describe 'without example tests' do
148
+ %w[rspec cucumber].product(%w[selenium ios cross_platform]).each do |framework, automation|
149
+ context "with #{framework} and #{automation}" do
150
+ let(:name) { ensure_project(framework:, automation:, examples: false) }
151
+
152
+ it 'creates the wait helper and RaiderElement' do
153
+ expect(File).to exist("#{name}/helpers/wait_helper.rb")
154
+ expect(File).to exist("#{name}/helpers/raider_element.rb")
155
+ end
156
+ end
157
+ end
158
+
159
+ it 'keeps the session state for web' do
160
+ name = ensure_project(framework: 'rspec', automation: 'selenium', examples: false)
161
+ expect(File).to exist("#{name}/helpers/session_state.rb")
162
+ end
163
+ end
104
164
  end
@@ -49,4 +49,74 @@ describe InvokeGenerators do
49
49
  expect(File).not_to exist('case_bad_ci')
50
50
  end
51
51
  end
52
+
53
+ describe '.collect_flags' do
54
+ it 'adds no_examples when examples is false' do
55
+ expect(described_class.collect_flags(automation: 'selenium', examples: false)).to include('no_examples')
56
+ end
57
+
58
+ it 'keeps the examples by default' do
59
+ expect(described_class.collect_flags(automation: 'selenium')).not_to include('no_examples')
60
+ end
61
+
62
+ it 'keeps the examples for watir, whose templates are frozen' do
63
+ expect(described_class.collect_flags(automation: 'watir', examples: false)).not_to include('no_examples')
64
+ end
65
+ end
66
+
67
+ context 'with the Watir deprecation notice' do
68
+ let(:notice) do
69
+ 'Watir is deprecated and will be removed in the next major version of ruby_raider; new projects should use Selenium.'
70
+ end
71
+
72
+ it 'prints it for watir' do
73
+ expect { described_class.generate_framework(framework: 'rspec', automation: 'watir', name: 'case_dep') }
74
+ .to output(/#{Regexp.escape(notice)}/).to_stdout
75
+ end
76
+
77
+ it 'does not print it for selenium' do
78
+ expect { described_class.generate_framework(framework: 'rspec', automation: 'selenium', name: 'case_nodep') }
79
+ .not_to output(/Watir is deprecated/).to_stdout
80
+ end
81
+
82
+ it 'still prints it for raider new with automation:watir' do
83
+ root = File.expand_path('../../..', __dir__)
84
+ out, status = Open3.capture2e('ruby', "#{root}/bin/raider", 'new', 'case_cli_watir', '-p',
85
+ 'framework:rspec', 'automation:watir')
86
+ expect(status.success?).to be(true)
87
+ expect(out).to include(notice)
88
+ expect(File).to exist('case_cli_watir/.rspec')
89
+ end
90
+ end
91
+
92
+ context 'with examples false for watir' do
93
+ it 'says the examples are kept' do
94
+ expect { described_class.generate_framework(framework: 'rspec', automation: 'watir', name: 'case_watir', examples: false) }
95
+ .to output(/Watir projects always include the example tests/).to_stdout
96
+ end
97
+ end
98
+ end
99
+
100
+ describe 'Projects named like a generator option' do
101
+ after { FileUtils.rm_rf(%w[no_examples watir selenium]) }
102
+
103
+ it 'keeps the example tests in a project named no_examples' do
104
+ InvokeGenerators.generate_framework(automation: 'selenium', framework: 'rspec', name: 'no_examples')
105
+ expect(File).to exist('no_examples/spec/login_page_spec.rb')
106
+ expect(File).to exist('no_examples/page_objects/pages/login.rb')
107
+ end
108
+
109
+ it 'gives a Selenium project named watir the wait helper it wires in' do
110
+ InvokeGenerators.generate_framework(automation: 'selenium', framework: 'cucumber', name: 'watir')
111
+ expect(File).to exist('watir/helpers/wait_helper.rb')
112
+ expect(File.read('watir/features/support/env.rb')).not_to include('Watir')
113
+ expect(File.read('watir/page_objects/abstract/page.rb')).to include('include WaitHelper')
114
+ end
115
+
116
+ it 'keeps a Watir project named selenium on Watir' do
117
+ InvokeGenerators.generate_framework(automation: 'watir', framework: 'rspec', name: 'selenium')
118
+ expect(File).not_to exist('selenium/helpers/wait_helper.rb')
119
+ expect(File.read('selenium/page_objects/abstract/page.rb')).to include('browser.element')
120
+ expect(File.read('selenium/page_objects/abstract/page.rb')).not_to include('find_element')
121
+ end
52
122
  end
@@ -46,4 +46,24 @@ describe RspecGenerator do
46
46
  include_examples 'creates rspec files examples',
47
47
  "#{FrameworkIndex::RSPEC}_#{AutomationIndex::CROSS_PLATFORM}", 'pdp'
48
48
  end
49
+
50
+ describe 'without example tests' do
51
+ %w[selenium ios cross_platform].each do |automation|
52
+ context "with rspec and #{automation}" do
53
+ let(:name) { ensure_project(framework: 'rspec', automation:, examples: false) }
54
+
55
+ it 'creates an empty spec folder' do
56
+ expect(Dir.children("#{name}/spec")).to eq(['.keep'])
57
+ end
58
+ end
59
+ end
60
+
61
+ it 'creates no accessibility example' do
62
+ InvokeGenerators.generate_framework(framework: 'rspec', automation: 'selenium', name: 'skeleton_axe_rspec',
63
+ examples: false, accessibility: true)
64
+ expect(Dir.children('skeleton_axe_rspec/spec')).to eq(['.keep'])
65
+ ensure
66
+ FileUtils.rm_rf('skeleton_axe_rspec')
67
+ end
68
+ end
49
69
  end