ruby_raider 3.2.1 → 3.4.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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/README.md +21 -9
  4. data/RELEASE.md +18 -0
  5. data/lib/commands/scaffolding_commands.rb +6 -14
  6. data/lib/generators/cucumber/templates/accessibility_steps.tt +10 -10
  7. data/lib/generators/generator.rb +5 -0
  8. data/lib/generators/infrastructure/templates/github.tt +39 -0
  9. data/lib/generators/infrastructure/templates/github_appium.tt +47 -2
  10. data/lib/generators/templates/common/gemfile.tt +2 -1
  11. data/lib/generators/templates/common/git_ignore.tt +1 -0
  12. data/lib/generators/templates/common/read_me.tt +17 -0
  13. data/lib/generators/templates/helpers/partials/screenshot.tt +3 -3
  14. data/lib/generators/templates/helpers/spec_helper.tt +10 -5
  15. data/lib/generators/templates/helpers/test_helper.tt +1 -0
  16. data/lib/scaffolding/scaffolding.rb +0 -6
  17. data/lib/scaffolding/templates/page_object.tt +0 -3
  18. data/lib/scaffolding/templates/spec.tt +0 -6
  19. data/lib/scaffolding/templates/steps.tt +0 -3
  20. data/lib/version +1 -1
  21. data/ruby_raider.gemspec +1 -1
  22. data/sig/commands/scaffolding_commands.rbs +1 -1
  23. data/sig/scaffolding/scaffolding.rbs +0 -3
  24. data/spec/integration/content/ci_content_spec.rb +141 -0
  25. data/spec/integration/content/common_content_spec.rb +12 -1
  26. data/spec/integration/content/gemfile_content_spec.rb +38 -0
  27. data/spec/integration/content/helper_content_spec.rb +62 -0
  28. data/spec/integration/content/readme_content_spec.rb +31 -0
  29. data/spec/integration/end_to_end_spec.rb +39 -1
  30. data/spec/integration/scaffolding_e2e_spec.rb +0 -37
  31. data/spec/scaffolding/scaffolding_features_spec.rb +0 -20
  32. data/spec/system/support/system_test_helper.rb +8 -0
  33. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65823e49f5a2bf2e0f338b0f3fa22c9825a665d11d688a2e4a6e29172c7bab36
4
- data.tar.gz: 3acd00fe4a06957f50c559d1c92825cc0d576ff475bb00168e899ae54068f7d5
3
+ metadata.gz: 5141b6656f193315dce72afc9a7096ea48e63eed8a23c348cf38be0978627e90
4
+ data.tar.gz: b47a32013c49843ac2511f4bb0188adfcd50a83294fdbe692f8e483f3215ca67
5
5
  SHA512:
6
- metadata.gz: 6d2954689ece744a1421e0cedf2c34dc03b95cf11486ff8e574c7c376b6338649c5c3dc03d0b91bb2de86c70878b34bbf8b1e7951b94e2017cf4b21a5e14bdbd
7
- data.tar.gz: 752fcf37ecc86bbb60f6cb7e501df42b5721c39d94a05b798d15720eca473e0718d72c88d55d24b67cfd35467f65060c13832b51b48737a390a9aaf59597bf24
6
+ metadata.gz: 4840894d57645404ac69faf2ebe7985e59b5df8e653ec8746fb40d23a45e082b0f2708b1d2cc275f7cfa3ce250a009dea61d2022ed6ca96f6c835ac36ed04bca
7
+ data.tar.gz: f0eee8de1a42d7ff1440ee7d6700c9d6ffa9370fe53a811b2c99ba03147eed8101edeff5a8e9df0849fe25fb5189d5fd34aab9e07b5ee0642d575d46739f487c
data/.rubocop.yml CHANGED
@@ -2,7 +2,7 @@ require:
2
2
  - rubocop-rspec
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 3.1.0
5
+ TargetRubyVersion: 3.2.0
6
6
 
7
7
  # Layout
8
8
  Layout/CaseIndentation:
data/README.md CHANGED
@@ -51,18 +51,30 @@ Ruby Raider is a CLI gem and API backend for scaffolding and generating UI test
51
51
  |--------|------|-------------|
52
52
  | Accessibility | `--accessibility` | Adds axe gem + example accessibility tests |
53
53
 
54
- All generated projects include a **GitHub Actions** CI pipeline out of the box.
54
+ This works on all platforms (Mac OS, Linux and Windows).
55
+
56
+ ## What's Included
57
+
58
+ Every generated project comes with:
55
59
 
56
- ***The web tests run against the [Raider Test Store](https://raider-test-site.onrender.com/).***
60
+ - **Page Object Model** — Base page and component classes with example pages
61
+ - **Test examples** — Working login tests against the [Raider Test Store](https://raider-test-site.onrender.com/)
62
+ - **Allure reporting** — Pre-configured with screenshot capture on failure
63
+ - **Raider reporting** — RSpec projects include [raider_reporter](https://github.com/RaiderHQ/raider_reporter), which writes results to `raider-results/` and uploads runs when `RAIDER_TOKEN` and `RAIDER_ENDPOINT` are set
64
+ - **GitHub Actions CI** — Ready-to-use test pipeline
65
+ - **Rake tasks** — Default, smoke, and regression tasks with tag-based filtering
66
+ - **Retry support** — RSpec retry with configurable retry count via `RETRY_COUNT` env var
67
+ - **Re-run failed tests** — Persistence file for tracking example status
68
+ - **Parallel execution** — parallel_tests and parallel_split_test gems included
69
+ - **Configurable browser** — Chrome/Firefox with customizable arguments, viewport, timeout, and headless mode
70
+ - **Linting** — RuboCop and Reek configs included
57
71
 
58
- ***To run Appium tests, download the example [app](https://github.com/RaiderHQ/raider_test_app) and start the server:***
72
+ For Appium projects, download the example [app](https://github.com/RaiderHQ/raider_test_app) and start the server:
59
73
 
60
74
  ```bash
61
75
  raider u start_appium
62
76
  ```
63
77
 
64
- This works on all platforms (Mac OS, Linux and Windows).
65
-
66
78
  ## Getting Started
67
79
 
68
80
  Install the gem:
@@ -83,7 +95,7 @@ Or skip the menu with parameters:
83
95
  raider new [project_name] -p framework:rspec automation:selenium
84
96
  ```
85
97
 
86
- Add optional features:
98
+ Add accessibility testing:
87
99
 
88
100
  ```bash
89
101
  raider new my_project -p framework:rspec automation:selenium --accessibility
@@ -119,7 +131,6 @@ raider g scaffold [NAME(S)] # Create page + test + steps
119
131
 
120
132
  Options:
121
133
 
122
- * `--uses [PAGES]` — Specify page dependencies
123
134
  * `--path [PATH]` — Custom output path
124
135
 
125
136
  ### Utility Commands
@@ -128,8 +139,9 @@ Options:
128
139
  raider u path [PATH] # Set default paths for scaffolding
129
140
  raider u url [URL] # Set default project URL
130
141
  raider u browser [BROWSER] # Set default browser
131
- raider u browser_options [OPTS] # Set browser options
132
- raider u raid # Run all tests
142
+ raider u browser_options [OPTS] # Set browser arguments (e.g., no-sandbox, headless)
143
+ raider u headless [on/off] # Toggle headless mode
144
+ raider u raid # Run all tests (-p for parallel)
133
145
  raider u timeout [SECONDS] # Set test timeout
134
146
  raider u viewport [DIMENSIONS] # Set viewport size (e.g., 1920x1080)
135
147
  raider u platform [PLATFORM] # Set platform for cross-platform tests
data/RELEASE.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Release Process Documentation
2
2
 
3
+ ## Release Notes
4
+
5
+ ### 3.4.0
6
+
7
+ - Generated RSpec projects with GitHub CI now include a `raider-comment` job that comments Raider test results on pull requests via `raider-reporter comment`. It runs after every test job, only on pull requests, and needs the `RAIDER_TOKEN` secret and `RAIDER_ENDPOINT` variable. Cucumber projects are unchanged.
8
+ - The job needs `contents: read`, `pull-requests: write` and `statuses: write` permissions; it reports a `raider/tests` status, and pull requests from forks are skipped.
9
+ - Generated Gemfiles now require `raider_reporter` `~> 0.3`.
10
+ - Ruby Raider now requires Ruby 3.2.0 or newer.
11
+
12
+ ### 3.3.0
13
+
14
+ - Generated RSpec projects now include `raider_reporter`: results are written to `raider-results/` and uploaded when `RAIDER_TOKEN` and `RAIDER_ENDPOINT` are set. Allure is still produced. Cucumber projects are unchanged.
15
+ - Screenshots (Allure too) are now taken only when an example fails, and are attached to both Allure and Raider.
16
+ - Generated GitHub CI now runs on push (main, master), pull requests and manual dispatch, passes the Raider settings to RSpec runs and uploads `raider-results/` as an artifact.
17
+ - Fixed the generated Gemfile `ruby_raider` pin so it follows the gem's own major.minor version.
18
+
19
+ ---
20
+
3
21
  ## Overview
4
22
 
5
23
  Ruby Raider uses a **fully automated release process**. You only need to run a single command, and everything else happens automatically via GitHub Actions.
@@ -13,11 +13,9 @@ class ScaffoldingCommands < Thor
13
13
  desc 'page [PAGE_NAME]', 'Creates a new page object'
14
14
  option :path, type: :string, required: false,
15
15
  desc: 'The path where your page will be created', aliases: '-p'
16
- option :uses, type: :array, required: false,
17
- desc: 'Dependent pages to require', aliases: '-u'
18
16
 
19
17
  def page(name)
20
- generate_scaffolding(name, 'page', options[:path], uses: options[:uses])
18
+ generate_scaffolding(name, 'page', options[:path])
21
19
  end
22
20
 
23
21
  desc 'feature [NAME]', 'Creates a new feature'
@@ -31,11 +29,9 @@ class ScaffoldingCommands < Thor
31
29
  desc 'spec [SPEC_NAME]', 'Creates a new spec'
32
30
  option :path, type: :string, required: false,
33
31
  desc: 'The path where your spec will be created', aliases: '-p'
34
- option :uses, type: :array, required: false,
35
- desc: 'Dependent pages to require', aliases: '-u'
36
32
 
37
33
  def spec(name)
38
- generate_scaffolding(name, 'spec', options[:path], uses: options[:uses])
34
+ generate_scaffolding(name, 'spec', options[:path])
39
35
  end
40
36
 
41
37
  desc 'helper [HELPER_NAME]', 'Creates a new helper'
@@ -63,8 +59,6 @@ class ScaffoldingCommands < Thor
63
59
  end
64
60
 
65
61
  desc 'scaffold [NAMES...]', 'Generates pages, specs/features, and helpers for one or more names'
66
- option :uses, type: :array, required: false,
67
- desc: 'Dependent pages to require', aliases: '-u'
68
62
 
69
63
  def scaffold(*names)
70
64
  names.each { |name| generate_default_scaffold(name) }
@@ -95,23 +89,21 @@ class ScaffoldingCommands < Thor
95
89
  end
96
90
  end
97
91
 
98
- def generate_scaffolding(name, type, path, uses: nil)
92
+ def generate_scaffolding(name, type, path)
99
93
  path ||= load_config_path(type)
100
94
  scaffolding = Scaffolding.new([name, path])
101
- scaffolding.uses = Array(uses) if uses
102
95
  scaffolding.send("generate_#{type}")
103
96
  end
104
97
 
105
98
  def generate_default_scaffold(name)
106
99
  validate_project!
107
- uses = options[:uses]
108
100
  if Pathname.new('spec').exist? && !Pathname.new('features').exist?
109
- generate_scaffolding(name, 'spec', load_config_path('spec'), uses:)
101
+ generate_scaffolding(name, 'spec', load_config_path('spec'))
110
102
  else
111
103
  generate_scaffolding(name, 'feature', load_config_path('feature'))
112
- generate_scaffolding(name, 'steps', load_config_path('steps'), uses:)
104
+ generate_scaffolding(name, 'steps', load_config_path('steps'))
113
105
  end
114
- generate_scaffolding(name, 'page', load_config_path('page'), uses:)
106
+ generate_scaffolding(name, 'page', load_config_path('page'))
115
107
  end
116
108
  end
117
109
  end
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Given('I am on the home page') do
4
- <% if watir? -%>
5
- browser.goto 'https://raider-test-site.onrender.com/'
6
- <% else -%>
7
- driver.get 'https://raider-test-site.onrender.com/'
8
- <% end -%>
4
+ <%- if watir? -%>
5
+ browser.goto 'https://raider-test-site.onrender.com/'
6
+ <%- else -%>
7
+ driver.get 'https://raider-test-site.onrender.com/'
8
+ <%- end -%>
9
9
  end
10
10
 
11
11
  Then('the page should be accessible') do
12
- <% if watir? -%>
13
- expect(browser.driver).to be_axe_clean
14
- <% else -%>
15
- expect(driver).to be_axe_clean
16
- <% end -%>
12
+ <%- if watir? -%>
13
+ expect(browser.driver).to be_axe_clean
14
+ <%- else -%>
15
+ expect(driver).to be_axe_clean
16
+ <%- end -%>
17
17
  end
@@ -71,6 +71,11 @@ class Generator < Thor::Group
71
71
  args.include?('selenium')
72
72
  end
73
73
 
74
+ def ruby_raider_version_requirement
75
+ major, minor = File.read(File.expand_path('../version', __dir__)).strip.split('.')
76
+ "~> #{major}.#{minor}"
77
+ end
78
+
74
79
  private
75
80
 
76
81
  def _initializer
@@ -1,6 +1,9 @@
1
1
  name: <%- if framework == 'cucumber' -%>Cucumber Tests<%- else -%>Rspec Tests<%- end -%>
2
2
 
3
3
  on:
4
+ push:
5
+ branches: [ main, master ]
6
+ pull_request:
4
7
  workflow_dispatch:
5
8
  inputs:
6
9
  browser:
@@ -37,6 +40,21 @@ jobs:
37
40
  run: <%- if framework == 'cucumber' -%>bundle exec cucumber features --format pretty<%- else -%>bundle exec rspec spec --format documentation<%- end %>
38
41
  env:
39
42
  HEADLESS: true
43
+ <%- unless framework == 'cucumber' -%>
44
+ RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
45
+ RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
46
+ <%- end -%>
47
+
48
+ <%- unless framework == 'cucumber' -%>
49
+ - name: Upload Raider results
50
+ uses: actions/upload-artifact@v4
51
+ if: always()
52
+ with:
53
+ name: raider-results
54
+ path: raider-results/
55
+ if-no-files-found: ignore
56
+
57
+ <%- end -%>
40
58
 
41
59
  - name: Get Allure history
42
60
  uses: actions/checkout@v2
@@ -63,3 +81,24 @@ jobs:
63
81
  PERSONAL_TOKEN: ${{ secrets.GITHUB_TOKEN }}
64
82
  PUBLISH_BRANCH: gh-pages
65
83
  PUBLISH_DIR: allure-history
84
+
85
+ <%- unless framework == 'cucumber' -%>
86
+ raider-comment:
87
+ needs: [build]
88
+ if: always() && github.event_name == 'pull_request'
89
+ runs-on: ubuntu-latest
90
+ permissions:
91
+ contents: read
92
+ pull-requests: write
93
+ statuses: write
94
+ steps:
95
+ - uses: actions/checkout@v4
96
+ - uses: ruby/setup-ruby@v1
97
+ with: { ruby-version: 3.4.0, bundler-cache: true }
98
+ - name: Comment Raider results on the pull request
99
+ run: bundle exec raider-reporter comment
100
+ env:
101
+ RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
102
+ RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
103
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
104
+ <%- end -%>
@@ -2,9 +2,9 @@ name: Appium Tests
2
2
 
3
3
  on:
4
4
  push:
5
- branches: [ main ]
5
+ branches: [ main, master ]
6
6
  pull_request:
7
- branches: [ main ]
7
+ workflow_dispatch:
8
8
 
9
9
  jobs:
10
10
  <%- if ios? || cross_platform? -%>
@@ -52,6 +52,18 @@ jobs:
52
52
  <%- end -%>
53
53
  env:
54
54
  APP_PATH: ${{ github.workspace }}/apps/RaiderTestApp.app
55
+ <%- unless cucumber? -%>
56
+ RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
57
+ RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
58
+
59
+ - name: Upload Raider results
60
+ uses: actions/upload-artifact@v4
61
+ if: always()
62
+ with:
63
+ name: raider-results-ios
64
+ path: raider-results/
65
+ if-no-files-found: ignore
66
+ <%- end -%>
55
67
  <%- end -%>
56
68
 
57
69
  <%- if android? || cross_platform? -%>
@@ -101,4 +113,37 @@ jobs:
101
113
  <%- end -%>
102
114
  env:
103
115
  APP_PATH: ${{ github.workspace }}/apps/app-release.apk
116
+ <%- unless cucumber? -%>
117
+ RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
118
+ RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
119
+
120
+ - name: Upload Raider results
121
+ uses: actions/upload-artifact@v4
122
+ if: always()
123
+ with:
124
+ name: raider-results-android
125
+ path: raider-results/
126
+ if-no-files-found: ignore
127
+ <%- end -%>
128
+ <%- end -%>
129
+
130
+ <%- unless cucumber? -%>
131
+ raider-comment:
132
+ needs: [<%= [('ios-tests' if ios? || cross_platform?), ('android-tests' if android? || cross_platform?)].compact.join(', ') %>]
133
+ if: always() && github.event_name == 'pull_request'
134
+ runs-on: ubuntu-latest
135
+ permissions:
136
+ contents: read
137
+ pull-requests: write
138
+ statuses: write
139
+ steps:
140
+ - uses: actions/checkout@v4
141
+ - uses: ruby/setup-ruby@v1
142
+ with: { ruby-version: 3.4.0, bundler-cache: true }
143
+ - name: Comment Raider results on the pull request
144
+ run: bundle exec raider-reporter comment
145
+ env:
146
+ RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
147
+ RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
148
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
104
149
  <%- end -%>
@@ -20,6 +20,7 @@ gem 'parallel_tests'
20
20
  gem 'rake'
21
21
  gem 'reek'
22
22
  <%- if rspec? -%>
23
+ gem 'raider_reporter', '~> 0.3'
23
24
  gem 'rspec-retry'
24
25
  <%- end -%>
25
26
  gem '<%= framework %>'
@@ -30,7 +31,7 @@ gem 'rubocop'
30
31
  <%- if rspec? -%>
31
32
  gem 'rubocop-rspec'
32
33
  <%- end -%>
33
- gem 'ruby_raider', '~> 1.1.0'
34
+ gem 'ruby_raider', '<%= ruby_raider_version_requirement %>'
34
35
  <%- if selenium_based? %>
35
36
  gem 'selenium-webdriver'
36
37
  <%- end -%>
@@ -1,4 +1,5 @@
1
1
  allure-results
2
2
  <%- if rspec? -%>
3
+ raider-results
3
4
  spec/examples.txt
4
5
  <%- end -%>
@@ -82,6 +82,23 @@ raider g steps [NAME] # Create step definitions
82
82
  raider g scaffold [NAME] # Create page + test + steps
83
83
  ```
84
84
 
85
+ <%- if rspec? -%>
86
+ ## Reporting
87
+
88
+ Every run writes machine-readable results to `raider-results/` (including `run.json`), next to the usual Allure results.
89
+ Allure reports are still produced.
90
+
91
+ To upload runs to Raider, set these environment variables before running the suite:
92
+
93
+ ```bash
94
+ export RAIDER_TOKEN=your-token
95
+ export RAIDER_ENDPOINT=https://your-raider-endpoint
96
+ ```
97
+
98
+ Without `RAIDER_TOKEN`, nothing is uploaded and the suite output is unchanged. Failure screenshots are attached to both
99
+ Allure and Raider. See the [raider_reporter README](https://github.com/RaiderHQ/raider_reporter) for details.
100
+
101
+ <%- end -%>
85
102
  ### Sponsors
86
103
 
87
104
  This project is tested with BrowserStack.
@@ -1,7 +1,7 @@
1
1
  <% if selenium_based? %>
2
- screenshot = driver.save_screenshot("#{temp_folder}/#{example_name}.png")
2
+ screenshot = driver.save_screenshot(screenshot_path)
3
3
  <% elsif watir? %>
4
- screenshot = browser.screenshot.save("#{temp_folder}/#{example_name}.png")
4
+ screenshot = browser.screenshot.save(screenshot_path)
5
5
  <% else %>
6
- screenshot = driver.screenshot("#{temp_folder}/#{example_name}.png")
6
+ screenshot = driver.screenshot(screenshot_path)
7
7
  <% end %>
@@ -5,6 +5,8 @@ require 'axe-rspec'
5
5
  <%- end -%>
6
6
  require 'rspec'
7
7
  require 'rspec/retry'
8
+ require 'digest'
9
+ require 'raider_reporter/rspec'
8
10
  require 'tmpdir'
9
11
  require_relative 'allure_helper'
10
12
  <%- if watir? -%>
@@ -21,7 +23,8 @@ module SpecHelper
21
23
  config.verbose_retry = true
22
24
  config.display_try_failure_messages = true
23
25
  config.default_retry_count = ENV.fetch('RETRY_COUNT', 0).to_i
24
- config.formatter = AllureHelper.formatter
26
+ config.add_formatter(AllureHelper.formatter)
27
+ config.add_formatter(RaiderReporter::RSpec::Formatter)
25
28
  <%- if watir? -%>
26
29
  config.include(BrowserHelper)
27
30
  <%- else -%>
@@ -53,10 +56,12 @@ module SpecHelper
53
56
  example_name = example.description
54
57
  if example.exception
55
58
  @_exception = example.exception
56
- end
57
- Dir.mktmpdir do |temp_folder|
58
- <%= partial('screenshot', strip: true) %>
59
- AllureHelper.add_screenshot(example_name, screenshot)
59
+ Dir.mktmpdir do |temp_folder|
60
+ screenshot_path = "#{temp_folder}/#{example_name}.png"
61
+ <%= partial('screenshot', strip: true) %>
62
+ AllureHelper.add_screenshot(example_name, screenshot)
63
+ RaiderReporter.attach('screenshot', screenshot_path, type: :png)
64
+ end
60
65
  end
61
66
  <%= partial('quit_driver', strip: true) %>
62
67
  end
@@ -74,6 +74,7 @@ module TestHelper
74
74
  <%- end -%>
75
75
  <%- end -%>
76
76
  Dir.mktmpdir do |temp_folder|
77
+ screenshot_path = "#{temp_folder}/#{example_name}.png"
77
78
  <%= partial('screenshot', strip: true) %>
78
79
  <%- if allure_reporter? -%>
79
80
  AllureHelper.add_screenshot(example_name, screenshot)
@@ -11,8 +11,6 @@ class Scaffolding < Thor::Group
11
11
  argument :name, optional: true
12
12
  argument :path, optional: true
13
13
 
14
- attr_writer :uses
15
-
16
14
  def self.source_root
17
15
  "#{File.dirname(__FILE__)}/templates"
18
16
  end
@@ -94,10 +92,6 @@ class Scaffolding < Thor::Group
94
92
  automation_type == 'watir'
95
93
  end
96
94
 
97
- def uses_list
98
- Array(@uses).reject(&:empty?)
99
- end
100
-
101
95
  def default_path(standard_path, file_type)
102
96
  path ? "#{path}/#{normalized_name}#{file_type}" : standard_path
103
97
  end
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../abstract/page'
4
- <%- uses_list.each do |dep| -%>
5
- require_relative '<%= dep %>'
6
- <%- end -%>
7
4
  <% if nested? -%>
8
5
  <% module_parts.each_with_index do |mod, i| -%>
9
6
  <%= ' ' * i %>module <%= mod %>
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../page_objects/pages/<%= normalized_name %>'
4
- <%- uses_list.each do |dep| -%>
5
- require_relative '../page_objects/pages/<%= dep %>'
6
- <%- end -%>
7
4
 
8
5
  describe '<%= page_class_name %>' do
9
6
  <%- if selenium? -%>
@@ -11,9 +8,6 @@ describe '<%= page_class_name %>' do
11
8
  <%- elsif watir? -%>
12
9
  let(:page) { <%= page_class_name %>.new(browser) }
13
10
  <%- end -%>
14
- <%- uses_list.each do |dep| -%>
15
- let(:<%= dep %>) { <%= NameNormalizer.to_page_class(dep) %>.new<%= selenium? ? '(driver)' : '(browser)' %> }
16
- <%- end -%>
17
11
  <%- if project_config['url'] -%>
18
12
 
19
13
  before do
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../page_objects/pages/<%= normalized_name %>'
4
- <%- uses_list.each do |dep| -%>
5
- require_relative '../../page_objects/pages/<%= dep %>'
6
- <%- end -%>
7
4
 
8
5
  Given('I am on the <%= normalized_name.tr("_", " ") %> page') do
9
6
  <%- if selenium? -%>
data/lib/version CHANGED
@@ -1 +1 @@
1
- 3.2.1
1
+ 3.4.0
data/ruby_raider.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.email = 'agustin.pe94@gmail.com'
10
10
  s.homepage = 'https://github.com/RubyRaider/ruby_raider'
11
11
  s.license = 'MIT'
12
- s.required_ruby_version = '>= 3.1.0'
12
+ s.required_ruby_version = '>= 3.2.0'
13
13
  s.files = `git ls-files -z`.split("\x0")
14
14
  s.bindir = 'bin'
15
15
  s.executables << 'raider'
@@ -11,6 +11,6 @@ class ScaffoldingCommands < Thor
11
11
  private
12
12
 
13
13
  def load_config_path: (String type) -> String?
14
- def generate_scaffolding: (String name, String type, String? path, ?uses: Array[String]?) -> void
14
+ def generate_scaffolding: (String name, String type, String? path) -> void
15
15
  def generate_default_scaffold: (String name) -> void
16
16
  end
@@ -2,8 +2,6 @@
2
2
  class Scaffolding < Thor::Group
3
3
  include Thor::Actions
4
4
 
5
- attr_writer uses: Array[String]
6
-
7
5
  def self.source_root: () -> String
8
6
 
9
7
  # Generation methods
@@ -27,6 +25,5 @@ class Scaffolding < Thor::Group
27
25
  def project_config: () -> Hash[String, untyped]
28
26
  def selenium?: () -> bool
29
27
  def watir?: () -> bool
30
- def uses_list: () -> Array[String]
31
28
  def default_path: (String standard_path, String file_type) -> String
32
29
  end
@@ -44,21 +44,162 @@ describe 'CI pipeline content' do
44
44
  end
45
45
  end
46
46
 
47
+ shared_examples 'github triggers' do |project_name, file|
48
+ subject(:pipeline) { read_generated(project_name, ".github/workflows/#{file}") }
49
+
50
+ let(:triggers) { YAML.safe_load(pipeline)[true] }
51
+
52
+ it 'triggers on push to main and master' do
53
+ expect(triggers['push']['branches']).to include('main', 'master')
54
+ end
55
+
56
+ it 'triggers on pull_request' do
57
+ expect(triggers).to have_key('pull_request')
58
+ end
59
+
60
+ it 'triggers on workflow_dispatch' do
61
+ expect(triggers).to have_key('workflow_dispatch')
62
+ end
63
+ end
64
+
65
+ shared_examples 'github raider wiring' do |project_name, file|
66
+ subject(:pipeline) { read_generated(project_name, ".github/workflows/#{file}") }
67
+
68
+ let(:steps) { YAML.safe_load(pipeline)['jobs'].values.flat_map { |job| job['steps'] } }
69
+
70
+ let(:test_steps) do
71
+ steps.select { |step| step['run'].to_s.include?('rspec') || step['with'].to_h['script'].to_s.include?('rspec') }
72
+ end
73
+
74
+ it 'passes Raider settings to every test step' do
75
+ expect(test_steps).not_to be_empty
76
+ test_steps.each do |step|
77
+ expect(step['env']).to include('RAIDER_TOKEN' => '${{ secrets.RAIDER_TOKEN }}',
78
+ 'RAIDER_ENDPOINT' => '${{ vars.RAIDER_ENDPOINT }}')
79
+ end
80
+ end
81
+
82
+ it 'uploads raider-results as an artifact even on failure in every job' do
83
+ uploads = steps.select { |step| step['uses'] == 'actions/upload-artifact@v4' }
84
+ expect(uploads.size).to eq(YAML.safe_load(pipeline)['jobs'].except('raider-comment').size)
85
+ uploads.each do |upload|
86
+ expect(upload['with']['path']).to eq('raider-results/')
87
+ expect(upload['if']).to eq('always()')
88
+ end
89
+ end
90
+ end
91
+
92
+ shared_examples 'github raider-comment job' do |project_name, file, test_jobs|
93
+ subject(:pipeline) { read_generated(project_name, ".github/workflows/#{file}") }
94
+
95
+ let(:jobs) { YAML.safe_load(pipeline)['jobs'] }
96
+ let(:job) { jobs['raider-comment'] }
97
+
98
+ it 'is a valid workflow with exactly the expected jobs' do
99
+ expect(jobs.keys).to match_array(test_jobs + ['raider-comment'])
100
+ end
101
+
102
+ it 'needs every test job' do
103
+ expect(job['needs']).to match_array(test_jobs)
104
+ end
105
+
106
+ it 'runs always, on pull requests only' do
107
+ expect(job['if']).to eq("always() && github.event_name == 'pull_request'")
108
+ expect(job['runs-on']).to eq('ubuntu-latest')
109
+ end
110
+
111
+ it 'has the least permissions required' do
112
+ expect(job['permissions']).to eq('contents' => 'read', 'pull-requests' => 'write', 'statuses' => 'write')
113
+ end
114
+
115
+ it 'checks out, sets up the same Ruby as the test jobs and comments' do
116
+ steps = job['steps']
117
+ expect(steps[0]).to eq('uses' => 'actions/checkout@v4')
118
+ expect(steps[1]['uses']).to eq('ruby/setup-ruby@v1')
119
+ test_ruby = jobs.values_at(*test_jobs).flat_map { |j| j['steps'] }
120
+ .find { |step| step['uses'] == 'ruby/setup-ruby@v1' }['with']['ruby-version']
121
+ expect(steps[1]['with']).to eq('ruby-version' => test_ruby, 'bundler-cache' => true)
122
+ expect(steps[2]).to eq('name' => 'Comment Raider results on the pull request',
123
+ 'run' => 'bundle exec raider-reporter comment',
124
+ 'env' => { 'RAIDER_TOKEN' => '${{ secrets.RAIDER_TOKEN }}',
125
+ 'RAIDER_ENDPOINT' => '${{ vars.RAIDER_ENDPOINT }}',
126
+ 'GITHUB_TOKEN' => '${{ secrets.GITHUB_TOKEN }}' })
127
+ expect(steps.size).to eq(3)
128
+ end
129
+ end
130
+
131
+ shared_examples 'github without raider-comment job' do |project_name, file|
132
+ subject(:pipeline) { read_generated(project_name, ".github/workflows/#{file}") }
133
+
134
+ it 'has no raider-comment job' do
135
+ expect(pipeline).not_to include('raider-comment')
136
+ expect(pipeline).not_to include('raider-reporter')
137
+ end
138
+ end
139
+
140
+ shared_examples 'github without raider wiring' do |project_name, file|
141
+ subject(:pipeline) { read_generated(project_name, ".github/workflows/#{file}") }
142
+
143
+ it 'has no Raider settings or artifact' do
144
+ expect(pipeline).not_to include('RAIDER_')
145
+ expect(pipeline).not_to include('raider-results')
146
+ end
147
+ end
148
+
149
+ shared_examples 'github allure steps' do |project_name|
150
+ subject(:pipeline) { read_generated(project_name, '.github/workflows/test_pipeline.yml') }
151
+
152
+ it 'keeps the Allure steps' do
153
+ expect(pipeline).to include('simple-elf/allure-report-action', 'peaceiris/actions-gh-pages')
154
+ end
155
+ end
156
+
47
157
  context 'with rspec and selenium' do
48
158
  name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
49
159
  include_examples 'valid github pipeline', name
50
160
  include_examples 'github rspec pipeline', name
161
+ include_examples 'github triggers', name, 'test_pipeline.yml'
162
+ include_examples 'github raider wiring', name, 'test_pipeline.yml'
163
+ include_examples 'github raider-comment job', name, 'test_pipeline.yml', %w[build]
164
+ include_examples 'github allure steps', name
51
165
  end
52
166
 
53
167
  context 'with cucumber and selenium' do
54
168
  name = "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}"
55
169
  include_examples 'valid github pipeline', name
56
170
  include_examples 'github cucumber pipeline', name
171
+ include_examples 'github triggers', name, 'test_pipeline.yml'
172
+ include_examples 'github without raider wiring', name, 'test_pipeline.yml'
173
+ include_examples 'github without raider-comment job', name, 'test_pipeline.yml'
174
+ include_examples 'github allure steps', name
57
175
  end
58
176
 
59
177
  context 'with rspec and watir' do
60
178
  name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::WATIR}"
61
179
  include_examples 'valid github pipeline', name
62
180
  include_examples 'github rspec pipeline', name
181
+ include_examples 'github triggers', name, 'test_pipeline.yml'
182
+ include_examples 'github raider wiring', name, 'test_pipeline.yml'
183
+ include_examples 'github raider-comment job', name, 'test_pipeline.yml', %w[build]
184
+ include_examples 'github allure steps', name
185
+ end
186
+
187
+ appium_jobs = { 'android' => %w[android-tests], 'ios' => %w[ios-tests],
188
+ 'cross_platform' => %w[ios-tests android-tests] }
189
+
190
+ appium_jobs.each do |automation, test_jobs|
191
+ context "with rspec and #{automation}" do
192
+ name = "#{FrameworkIndex::RSPEC}_#{automation}"
193
+ include_examples 'github raider-comment job', name, 'appium_pipeline.yml', test_jobs
194
+ include_examples 'github triggers', name, 'appium_pipeline.yml'
195
+ include_examples 'github raider wiring', name, 'appium_pipeline.yml'
196
+ end
197
+
198
+ context "with cucumber and #{automation}" do
199
+ name = "#{FrameworkIndex::CUCUMBER}_#{automation}"
200
+ include_examples 'github triggers', name, 'appium_pipeline.yml'
201
+ include_examples 'github without raider wiring', name, 'appium_pipeline.yml'
202
+ include_examples 'github without raider-comment job', name, 'appium_pipeline.yml'
203
+ end
63
204
  end
64
205
  end
@@ -89,6 +89,10 @@ describe 'Common file content' do
89
89
  it 'uses documentation format' do
90
90
  expect(rspec_file).to include('--format documentation')
91
91
  end
92
+
93
+ it 'leaves the raider formatter to spec_helper, since a command-line --format replaces .rspec formatters' do
94
+ expect(rspec_file).not_to include('RaiderReporter')
95
+ end
92
96
  end
93
97
 
94
98
  shared_examples 'no rspec dotfile' do |project_name|
@@ -109,6 +113,10 @@ describe 'Common file content' do
109
113
  it 'includes spec/examples.txt' do
110
114
  expect(gitignore).to include('spec/examples.txt')
111
115
  end
116
+
117
+ it 'includes raider-results' do
118
+ expect(gitignore).to include('raider-results')
119
+ end
112
120
  end
113
121
 
114
122
  shared_examples 'non-rspec gitignore' do |project_name|
@@ -121,6 +129,10 @@ describe 'Common file content' do
121
129
  it 'does not include spec/examples.txt' do
122
130
  expect(gitignore).not_to include('spec/examples.txt')
123
131
  end
132
+
133
+ it 'does not include raider-results' do
134
+ expect(gitignore).not_to include('raider-results')
135
+ end
124
136
  end
125
137
 
126
138
  # --- Spec helper retry config (C4) ---
@@ -220,5 +232,4 @@ describe 'Common file content' do
220
232
  it_behaves_like 'gemfile without rspec-retry', name
221
233
  it_behaves_like 'cucumber config with retry', name
222
234
  end
223
-
224
235
  end
@@ -119,4 +119,42 @@ describe 'Gemfile content' do
119
119
  include_examples 'contains watir gems', name
120
120
  end
121
121
 
122
+ describe 'raider_reporter and ruby_raider pin' do
123
+ major_minor = File.read('lib/version').strip.split('.').first(2).join('.')
124
+
125
+ AUTOMATION_TYPES.each do |automation|
126
+ context "with rspec and #{automation}" do
127
+ let(:gemfile) { read_generated("#{FrameworkIndex::RSPEC}_#{automation}", 'Gemfile') }
128
+
129
+ it 'includes raider_reporter' do
130
+ expect(gemfile).to include("gem 'raider_reporter', '~> 0.3'")
131
+ end
132
+
133
+ it 'keeps allure gems' do
134
+ expect(gemfile).to include("gem 'allure-rspec', '2.28.0'", "gem 'allure-ruby-commons', '2.28.0'")
135
+ end
136
+
137
+ it 'pins ruby_raider to the generator major.minor' do
138
+ expect(gemfile).to include("gem 'ruby_raider', '~> #{major_minor}'")
139
+ end
140
+ end
141
+
142
+ context "with cucumber and #{automation}" do
143
+ let(:gemfile) { read_generated("#{FrameworkIndex::CUCUMBER}_#{automation}", 'Gemfile') }
144
+
145
+ it 'does not include raider_reporter' do
146
+ expect(gemfile).not_to include('raider_reporter')
147
+ end
148
+
149
+ it 'keeps allure-cucumber' do
150
+ expect(gemfile).to include("gem 'allure-cucumber', '2.28.0'")
151
+ end
152
+
153
+ it 'pins ruby_raider to the generator major.minor' do
154
+ expect(gemfile).to include("gem 'ruby_raider', '~> #{major_minor}'")
155
+ end
156
+ end
157
+ end
158
+ end
159
+
122
160
  end
@@ -109,6 +109,47 @@ describe 'Helper file content' do
109
109
  end
110
110
  end
111
111
 
112
+ shared_examples 'raider reporter spec helper' do |project_name, screenshot_call|
113
+ subject(:helper) { read_generated(project_name, 'helpers/spec_helper.rb') }
114
+
115
+ it 'requires raider_reporter/rspec' do
116
+ expect(helper).to include("require 'raider_reporter/rspec'")
117
+ end
118
+
119
+ it 'requires digest, which allure-ruby-commons uses without requiring' do
120
+ expect(helper).to include("require 'digest'")
121
+ end
122
+
123
+ it 'adds the raider formatter in spec_helper so a command-line --format cannot drop it' do
124
+ expect(helper).to include('config.add_formatter(RaiderReporter::RSpec::Formatter)')
125
+ end
126
+
127
+ it 'does not replace the formatter' do
128
+ expect(helper).not_to match(/config\.formatter\s*=/)
129
+ end
130
+
131
+ it 'adds the allure formatter' do
132
+ expect(helper).to include('config.add_formatter(AllureHelper.formatter)')
133
+ end
134
+
135
+ it 'screenshots only on failure' do
136
+ lines = helper.lines
137
+ start = lines.index { |line| line.include?('if example.exception') }
138
+ expect(start).not_to be_nil
139
+ indent = lines[start][/\A */].size
140
+ body = lines[(start + 1)..].take_while { |line| line.strip.empty? || line[/\A */].size > indent }
141
+ guarded = body.join
142
+
143
+ expect(guarded).to include('AllureHelper.add_screenshot', 'RaiderReporter.attach', screenshot_call)
144
+ expect(lines.select { |line| line.include?('AllureHelper.add_screenshot') }.size).to eq(1)
145
+ expect(lines.select { |line| line.include?(screenshot_call) }.size).to eq(1)
146
+ end
147
+
148
+ it 'attaches the screenshot to raider by path' do
149
+ expect(helper).to include("RaiderReporter.attach('screenshot', screenshot_path, type: :png)")
150
+ end
151
+ end
152
+
112
153
  shared_examples 'selenium spec helper' do |project_name|
113
154
  subject(:helper) { read_generated(project_name, 'helpers/spec_helper.rb') }
114
155
 
@@ -200,4 +241,25 @@ describe 'Helper file content' do
200
241
  name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::IOS}"
201
242
 
202
243
  end
244
+
245
+ # --- Raider reporter wiring (every rspec automation) ---
246
+
247
+ AUTOMATION_TYPES.each do |automation|
248
+ context "with rspec and #{automation} raider reporter wiring" do
249
+ name = "#{FrameworkIndex::RSPEC}_#{automation}"
250
+ screenshot_call = {
251
+ 'selenium' => 'driver.save_screenshot(screenshot_path)',
252
+ 'watir' => 'browser.screenshot.save(screenshot_path)'
253
+ }.fetch(automation, 'driver.screenshot(screenshot_path)')
254
+ it_behaves_like 'raider reporter spec helper', name, screenshot_call
255
+ end
256
+
257
+ context "with cucumber and #{automation}" do
258
+ it 'has no raider reporter wiring' do
259
+ project = "#{FrameworkIndex::CUCUMBER}_#{automation}"
260
+ files = Dir.glob("#{project}/**/*", File::FNM_DOTMATCH).select { |f| File.file?(f) }
261
+ expect(files.select { |f| File.read(f).match?(/raider_reporter|RaiderReporter/) }).to be_empty
262
+ end
263
+ end
264
+ end
203
265
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'content_helper'
4
+
5
+ describe 'Generated Readme content' do
6
+ AUTOMATION_TYPES.each do |automation|
7
+ context "with rspec and #{automation}" do
8
+ subject(:readme) { read_generated("#{FrameworkIndex::RSPEC}_#{automation}", 'Readme.md') }
9
+
10
+ it 'has a Reporting section' do
11
+ expect(readme).to include('## Reporting')
12
+ end
13
+
14
+ it 'documents local results, upload settings and the raider_reporter README' do
15
+ expect(readme).to include('raider-results/', 'RAIDER_TOKEN', 'RAIDER_ENDPOINT',
16
+ 'https://github.com/RaiderHQ/raider_reporter')
17
+ end
18
+
19
+ it 'says Allure is still produced' do
20
+ expect(readme).to match(/Allure/)
21
+ end
22
+ end
23
+
24
+ context "with cucumber and #{automation}" do
25
+ it 'has no Reporting section' do
26
+ readme = read_generated("#{FrameworkIndex::CUCUMBER}_#{automation}", 'Readme.md')
27
+ expect(readme).not_to include('RAIDER_TOKEN')
28
+ end
29
+ end
30
+ end
31
+ end
@@ -3,6 +3,7 @@
3
3
  require_relative 'spec_helper'
4
4
  require 'timeout'
5
5
  require 'open3'
6
+ require 'json'
6
7
 
7
8
  # End-to-end integration tests that verify generated projects actually work
8
9
  # These tests:
@@ -41,9 +42,19 @@ describe 'End-to-End Project Generation and Execution' do
41
42
  result
42
43
  end
43
44
 
45
+ # The generated Gemfile pins ruby_raider to this gem's major.minor, which may not be
46
+ # published yet (a release candidate branch). Resolve it from this checkout instead;
47
+ # the pin itself is covered by the Gemfile content specs.
48
+ def use_local_ruby_raider(project_name)
49
+ gemfile = File.join(project_name, 'Gemfile')
50
+ root = File.expand_path('../..', __dir__)
51
+ File.write(gemfile, File.read(gemfile).sub(/^gem 'ruby_raider'.*$/, "gem 'ruby_raider', path: '#{root}'"))
52
+ end
53
+
44
54
  # Helper to install dependencies
45
55
  def bundle_install(project_name)
46
56
  puts "\n📦 Installing dependencies for #{project_name}..."
57
+ use_local_ruby_raider(project_name)
47
58
  result = run_in_project(project_name, 'bundle install --quiet', timeout: 180)
48
59
 
49
60
  unless result[:success]
@@ -93,6 +104,15 @@ describe 'End-to-End Project Generation and Execution' do
93
104
  expect(bundle_install(project)).to be true
94
105
  end
95
106
 
107
+ it 'resolves raider_reporter 0.3 from RubyGems and ships the raider-reporter executable', :aggregate_failures do
108
+ skip 'Bundle install failed' unless bundle_install(project)
109
+
110
+ expect(File.read(File.join(project, 'Gemfile.lock'))).to match(/^ raider_reporter \(0\.3\.\d+\)$/)
111
+ result = run_in_project(project, 'bundle exec raider-reporter --help', timeout: 60)
112
+ expect(result[:exit_code]).to eq(0), "STDOUT: #{result[:stdout]}\nSTDERR: #{result[:stderr]}"
113
+ expect(result[:stdout] + result[:stderr]).to include('raider-reporter comment')
114
+ end
115
+
96
116
  it 'runs generated RSpec tests successfully', :slow do
97
117
  skip 'Bundle install failed' unless bundle_install(project)
98
118
 
@@ -103,6 +123,25 @@ describe 'End-to-End Project Generation and Execution' do
103
123
  "STDOUT: #{result[:stdout]}\n" \
104
124
  "STDERR: #{result[:stderr]}"
105
125
  end
126
+
127
+ it 'writes raider-results/run.json listing every example without changing the exit status', :aggregate_failures, :slow do
128
+ skip 'Bundle install failed' unless bundle_install(project)
129
+
130
+ FileUtils.rm_rf(File.join(project, 'raider-results'))
131
+ result = run_rspec(project)
132
+ summary = result[:stdout].match(/(\d+) examples?, (\d+) failures?/)
133
+ expect(summary).not_to be_nil, "No RSpec summary line.\nSTDOUT: #{result[:stdout]}\nSTDERR: #{result[:stderr]}"
134
+ examples = summary[1].to_i
135
+ failures = summary[2].to_i
136
+
137
+ run_file = File.join(project, 'raider-results', 'run.json')
138
+ expect(File).to exist(run_file)
139
+ run = JSON.parse(File.read(run_file))
140
+ expect(run['schema_version']).to eq(1)
141
+ expect(run['results'].size).to eq(examples)
142
+ expect(run['results'].count { |r| r['status'] == 'failed' }).to eq(failures)
143
+ expect(result[:exit_code]).to eq(failures.zero? ? 0 : 1)
144
+ end
106
145
  end
107
146
 
108
147
  # Shared example for Cucumber-based projects
@@ -142,7 +181,6 @@ describe 'End-to-End Project Generation and Execution' do
142
181
  describe 'Watir + Cucumber' do
143
182
  include_examples 'executable cucumber project', 'cucumber_watir'
144
183
  end
145
-
146
184
  end
147
185
 
148
186
  # Mobile and Visual frameworks require external services, so we only verify structure
@@ -497,43 +497,6 @@ describe 'Scaffolding E2E' do # rubocop:disable RSpec/DescribeClass
497
497
  end
498
498
  end
499
499
 
500
- # ── Relationships ──────────────────────
501
-
502
- describe 'relationships' do
503
- before do
504
- File.write('page_objects/pages/login.rb', "class LoginPage < Page; end\n")
505
- end
506
-
507
- after do
508
- FileUtils.rm_f('page_objects/pages/dashboard.rb')
509
- FileUtils.rm_f('spec/dashboard_page_spec.rb')
510
- FileUtils.rm_f('features/dashboard.feature')
511
- FileUtils.rm_f('features/step_definitions/dashboard_steps.rb')
512
- FileUtils.rm_f('page_objects/pages/login.rb')
513
- FileUtils.rm_rf('features') unless framework == 'cucumber'
514
- FileUtils.rm_rf('spec') unless framework == 'rspec'
515
- end
516
-
517
- it 'adds require_relative for dependent page' do
518
- scaffold.new.invoke(:page, nil, %w[dashboard --uses login])
519
- content = File.read('page_objects/pages/dashboard.rb')
520
- expect(content).to include("require_relative 'login'")
521
- end
522
-
523
- if style == :spec
524
- it 'adds dependency to spec let declarations' do
525
- scaffold.new.invoke(:spec, nil, %w[dashboard --uses login])
526
- content = File.read('spec/dashboard_page_spec.rb')
527
- expect(content).to include('LoginPage')
528
-
529
- case automation
530
- when 'selenium' then expect(content).to include('LoginPage.new(driver)')
531
- when 'watir' then expect(content).to include('LoginPage.new(browser)')
532
- end
533
- end
534
- end
535
- end
536
-
537
500
  end
538
501
  end
539
502
  end
@@ -93,26 +93,6 @@ RSpec.describe 'Scaffolding features' do
93
93
  end
94
94
  end
95
95
 
96
- # --- Feature 9: Relationships ---
97
-
98
- describe 'relationships (--uses)' do
99
- before do
100
- File.write('page_objects/pages/login.rb', "class LoginPage < Page; end\n")
101
- end
102
-
103
- it 'adds require_relative for dependent pages' do
104
- scaffold.new.invoke(:page, nil, %w[dashboard --uses login])
105
- content = File.read('page_objects/pages/dashboard.rb')
106
- expect(content).to include("require_relative 'login'")
107
- end
108
-
109
- it 'adds uses to spec as let declarations' do
110
- scaffold.new.invoke(:spec, nil, %w[dashboard --uses login])
111
- content = File.read('spec/dashboard_page_spec.rb')
112
- expect(content).to include('LoginPage')
113
- end
114
- end
115
-
116
96
  # --- Feature 1: Batch scaffold ---
117
97
 
118
98
  describe 'batch scaffolding' do
@@ -15,6 +15,7 @@ module SystemTestHelper
15
15
 
16
16
  Bundler.with_unbundled_env do
17
17
  Dir.chdir(project) do
18
+ use_checkout_ruby_raider
18
19
  result = run_command('bundle install --quiet')
19
20
  return result unless result[:success]
20
21
 
@@ -25,6 +26,13 @@ module SystemTestHelper
25
26
 
26
27
  private
27
28
 
29
+ # The generated Gemfile pins ruby_raider to this gem's major.minor, which may not be
30
+ # published yet. Resolve it from this checkout; the pin itself is covered by content specs.
31
+ def use_checkout_ruby_raider(root = File.expand_path('../../..', __dir__))
32
+ gemfile = File.read('Gemfile')
33
+ File.write('Gemfile', gemfile.sub(/^gem 'ruby_raider'.*$/, "gem 'ruby_raider', path: '#{root}'"))
34
+ end
35
+
28
36
  def run_command(command, env: {})
29
37
  stdout, stderr, status = Open3.capture3(env, command)
30
38
  { success: status.success?, stdout:, stderr: }
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_raider
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.1
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Agustin Pequeno
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-03-14 00:00:00.000000000 Z
10
+ date: 2026-10-11 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rake
@@ -309,6 +309,7 @@ files:
309
309
  - spec/integration/content/gemfile_content_spec.rb
310
310
  - spec/integration/content/helper_content_spec.rb
311
311
  - spec/integration/content/page_content_spec.rb
312
+ - spec/integration/content/readme_content_spec.rb
312
313
  - spec/integration/content/syntax_validation_spec.rb
313
314
  - spec/integration/content/test_content_spec.rb
314
315
  - spec/integration/end_to_end_features_spec.rb
@@ -345,7 +346,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
345
346
  requirements:
346
347
  - - ">="
347
348
  - !ruby/object:Gem::Version
348
- version: 3.1.0
349
+ version: 3.2.0
349
350
  required_rubygems_version: !ruby/object:Gem::Requirement
350
351
  requirements:
351
352
  - - ">="