ruby_raider 3.7.0 → 3.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1dcadd35b6861c6b6e789c0c06cdd4b2febd6d0fdd664eb65faff04ddf206856
4
- data.tar.gz: fdc320f7e5c560920318b9d3fd4a46a1aec8ef9bfadd371820f85b5b72ed75e5
3
+ metadata.gz: ed3634de8115662d6148059e139a55f330a07fe9736ac82efbc439a256dd5747
4
+ data.tar.gz: 2c88f2ecb9c18c6f787ac216ef89de3e2dd626c1d1671c990b313d3df29b0e4d
5
5
  SHA512:
6
- metadata.gz: dc8218ab6eff3ebf9b86cde049cc9876ee2528e86adaa60ed2cb954401417df4acdb68cb28a1d948524b87429a6680c0906717ee5fc0117d9adc00c4054b6348
7
- data.tar.gz: '0094141af34fd3154591755d8fb882f6604aca77b8d5a94bd0946c49474fb6b53e91746af5a656b6ac35a62de17881ee93fafc84f0e1f5c03189db32195dfafe'
6
+ metadata.gz: f534bbb7ae8a9ae5870f905376bf1fc6bdc2189729ccb01fd5d76c8a0886255b1693a716e28cebd87d892ce3646b17dfca9a2b887c35349431bae2d47573fc05
7
+ data.tar.gz: 15eba78213eaee9100e1bc9ec5959fa5a8f89843b65fd77259db1571f74684ac01e665ab36a1ff152fb9ec3b8b96090acea9edf3e5d5c7ccd145f5b88c450b67
data/README.md CHANGED
@@ -60,7 +60,7 @@ Every generated project comes with:
60
60
 
61
61
  - **Page Object Model** — Base page and component classes with example pages
62
62
  - **Test examples** — Working login tests against the [Raider Test Store](https://raider-test-site.onrender.com/)
63
- - **Raider reporting** — RSpec and Cucumber 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
63
+ - **Raider reporting** — RSpec and Cucumber 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; generated CI runs the suite through `raider-reporter exec` with `RAIDER_QUARANTINE`, so quarantined tests do not fail the build; an opt-in `raider-gate` job (`RAIDER_GATE=1`) fails CI when the Raider quality gate fails
64
64
  - **GitHub Actions CI** — Ready-to-use test pipeline
65
65
  - **Rake tasks** — Default, smoke, and regression tasks with tag-based filtering
66
66
  - **Retry support** — RSpec retry with configurable retry count via `RETRY_COUNT` env var
@@ -21,16 +21,17 @@ jobs:
21
21
  inputs: { versionSpec: '3.4' }
22
22
  - script: bundle install
23
23
  displayName: Install gems
24
- - script: <%- if cucumber? -%>bundle exec cucumber features/ --format pretty<%- else -%>bundle exec rspec spec/ --format documentation<%- end %>
24
+ - script: <%- if cucumber? -%>bundle exec raider-reporter exec -- bundle exec cucumber features/ --format pretty<%- else -%>bundle exec raider-reporter exec -- bundle exec rspec spec/ --format documentation<%- end %>
25
25
  displayName: Run tests
26
26
  env:
27
27
  RAIDER_TOKEN: $(RAIDER_TOKEN)
28
28
  RAIDER_ENDPOINT: $(RAIDER_ENDPOINT)
29
+ RAIDER_QUARANTINE: 1
29
30
  - task: PublishPipelineArtifact@1
30
31
  condition: always()
31
32
  inputs: { targetPath: raider-results, artifact: raider-results-$(System.JobPositionInPhase)-$(System.JobAttempt) }
32
33
  - job: raider_comment
33
- dependsOn: tests
34
+ dependsOn: [tests, raider_gate]
34
35
  condition: and(always(), eq(variables['Build.Reason'], 'PullRequest'))
35
36
  steps:
36
37
  - task: UseRubyVersion@0
@@ -42,3 +43,16 @@ jobs:
42
43
  RAIDER_TOKEN: $(RAIDER_TOKEN)
43
44
  RAIDER_ENDPOINT: $(RAIDER_ENDPOINT)
44
45
  SYSTEM_ACCESSTOKEN: $(System.AccessToken)
46
+ - job: raider_gate
47
+ dependsOn: tests
48
+ condition: and(always(), eq(variables['RAIDER_GATE'], '1'))
49
+ steps:
50
+ - task: UseRubyVersion@0
51
+ inputs: { versionSpec: '3.4' }
52
+ - script: bundle install
53
+ - script: bundle exec raider-reporter gate
54
+ displayName: Wait for the Raider quality gate
55
+ env:
56
+ RAIDER_TOKEN: $(RAIDER_TOKEN)
57
+ RAIDER_ENDPOINT: $(RAIDER_ENDPOINT)
58
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
@@ -34,11 +34,12 @@ jobs:
34
34
  chrome-version: stable
35
35
 
36
36
  - name: Run tests
37
- run: <%- if framework == 'cucumber' -%>bundle exec cucumber features --format pretty<%- else -%>bundle exec rspec spec --format documentation<%- end %>
37
+ run: <%- if framework == 'cucumber' -%>bundle exec raider-reporter exec -- bundle exec cucumber features --format pretty<%- else -%>bundle exec raider-reporter exec -- bundle exec rspec spec --format documentation<%- end %>
38
38
  env:
39
39
  HEADLESS: true
40
40
  RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
41
41
  RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
42
+ RAIDER_QUARANTINE: "1"
42
43
 
43
44
  - name: Upload Raider results
44
45
  uses: actions/upload-artifact@v4
@@ -49,7 +50,7 @@ jobs:
49
50
  if-no-files-found: ignore
50
51
 
51
52
  raider-comment:
52
- needs: [build]
53
+ needs: [build, raider-gate]
53
54
  if: always() && github.event_name == 'pull_request'
54
55
  runs-on: ubuntu-latest
55
56
  permissions:
@@ -66,3 +67,21 @@ jobs:
66
67
  RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
67
68
  RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
68
69
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70
+
71
+ raider-gate:
72
+ needs: [build]
73
+ if: always() && vars.RAIDER_GATE == '1'
74
+ runs-on: ubuntu-latest
75
+ permissions:
76
+ contents: read
77
+ statuses: write
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+ - uses: ruby/setup-ruby@v1
81
+ with: { ruby-version: 3.4.0, bundler-cache: true }
82
+ - name: Wait for the Raider quality gate
83
+ run: bundle exec raider-reporter gate
84
+ env:
85
+ RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
86
+ RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
87
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -46,14 +46,19 @@ jobs:
46
46
 
47
47
  - name: Run tests
48
48
  <%- if cucumber? -%>
49
- run: bundle exec cucumber features/ --format pretty
49
+ run: bundle exec raider-reporter exec -- bundle exec cucumber features/ --format pretty
50
50
  <%- else -%>
51
- run: bundle exec rspec spec/ --format documentation
51
+ run: bundle exec raider-reporter exec -- bundle exec rspec spec/ --format documentation
52
52
  <%- end -%>
53
53
  env:
54
54
  APP_PATH: ${{ github.workspace }}/apps/RaiderTestApp.app
55
55
  RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
56
56
  RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
57
+ RAIDER_QUARANTINE: "1"
58
+ <%- if cross_platform? -%>
59
+ RAIDER_SHARD_INDEX: "1"
60
+ RAIDER_SHARD_TOTAL: "2"
61
+ <%- end -%>
57
62
 
58
63
  - name: Upload Raider results
59
64
  uses: actions/upload-artifact@v4
@@ -105,14 +110,19 @@ jobs:
105
110
  profile: pixel_8
106
111
  script: |
107
112
  <%- if cucumber? -%>
108
- bundle exec cucumber features/ --format pretty
113
+ bundle exec raider-reporter exec -- bundle exec cucumber features/ --format pretty
109
114
  <%- else -%>
110
- bundle exec rspec spec/ --format documentation
115
+ bundle exec raider-reporter exec -- bundle exec rspec spec/ --format documentation
111
116
  <%- end -%>
112
117
  env:
113
118
  APP_PATH: ${{ github.workspace }}/apps/app-release.apk
114
119
  RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
115
120
  RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
121
+ RAIDER_QUARANTINE: "1"
122
+ <%- if cross_platform? -%>
123
+ RAIDER_SHARD_INDEX: "2"
124
+ RAIDER_SHARD_TOTAL: "2"
125
+ <%- end -%>
116
126
 
117
127
  - name: Upload Raider results
118
128
  uses: actions/upload-artifact@v4
@@ -124,7 +134,7 @@ jobs:
124
134
  <%- end -%>
125
135
 
126
136
  raider-comment:
127
- needs: [<%= [('ios-tests' if ios? || cross_platform?), ('android-tests' if android? || cross_platform?)].compact.join(', ') %>]
137
+ needs: [<%= [('ios-tests' if ios? || cross_platform?), ('android-tests' if android? || cross_platform?)].compact.join(', ') %>, raider-gate]
128
138
  if: always() && github.event_name == 'pull_request'
129
139
  runs-on: ubuntu-latest
130
140
  permissions:
@@ -141,3 +151,21 @@ jobs:
141
151
  RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
142
152
  RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
143
153
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
154
+
155
+ raider-gate:
156
+ needs: [<%= [('ios-tests' if ios? || cross_platform?), ('android-tests' if android? || cross_platform?)].compact.join(', ') %>]
157
+ if: always() && vars.RAIDER_GATE == '1'
158
+ runs-on: ubuntu-latest
159
+ permissions:
160
+ contents: read
161
+ statuses: write
162
+ steps:
163
+ - uses: actions/checkout@v4
164
+ - uses: ruby/setup-ruby@v1
165
+ with: { ruby-version: 3.4.0, bundler-cache: true }
166
+ - name: Wait for the Raider quality gate
167
+ run: bundle exec raider-reporter gate
168
+ env:
169
+ RAIDER_TOKEN: ${{ secrets.RAIDER_TOKEN }}
170
+ RAIDER_ENDPOINT: ${{ vars.RAIDER_ENDPOINT }}
171
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -13,7 +13,7 @@ gem 'parallel_split_test'
13
13
  gem 'parallel_tests'
14
14
  gem 'rake'
15
15
  gem 'reek'
16
- gem 'raider_reporter', '~> 0.7'
16
+ gem 'raider_reporter', '~> 0.9'
17
17
  <%- if rspec? -%>
18
18
  gem 'rspec-retry'
19
19
  <%- end -%>
@@ -108,6 +108,34 @@ Without `RAIDER_TOKEN`, nothing is uploaded and the suite output is unchanged. F
108
108
  report and to Raider. See the [raider_reporter README](https://github.com/RaiderHQ/raider_reporter) for details.
109
109
  <%- end -%>
110
110
 
111
+ <%- unless azure? && mobile? -%>
112
+ ### Quarantine
113
+
114
+ CI runs the suite through `bundle exec raider-reporter exec -- …` with `RAIDER_QUARANTINE` set. Tests quarantined in
115
+ Raider still run and are still reported (as `quarantined`), and a build whose only failures are quarantined stays green.
116
+ Local runs keep quarantine off. To turn it off in CI, remove `RAIDER_QUARANTINE` from the pipeline.
117
+
118
+ <%- end -%>
119
+ <%- unless azure? && mobile? -%>
120
+ ### Quality gate
121
+
122
+ The `<%= azure? ? 'raider_gate' : 'raider-gate' %>` CI job runs `bundle exec raider-reporter gate` after the tests and
123
+ fails the pipeline when the Raider quality gate fails. It is off until you turn it on:
124
+
125
+ - set the CI variable `RAIDER_GATE=1` (<%= azure? ? 'a pipeline variable' : 'a repository variable under Settings → Secrets and variables → Actions → Variables' %>);
126
+ - turn on rules under the project's Gate page in Raider: a minimum pass rate, no new failures against the default
127
+ branch, no new flaky tests;
128
+ - optionally require the `raider/gate` check in branch protection.
129
+
130
+ `raider-reporter gate` exits 1 when the gate fails, naming the failed rules, and 2 when it gets no verdict (timeout,
131
+ Raider unreachable, token rejected, build not found). `RAIDER_GATE_TIMEOUT` sets how long it waits, in seconds
132
+ (default 600). The job stays off by default because a project without `RAIDER_TOKEN`, or a pull request from a fork,
133
+ would exit 2 on every run.
134
+
135
+ Parallel test jobs that upload to one build must each set `RAIDER_SHARD_TOTAL` (the number of jobs) and
136
+ `RAIDER_SHARD_INDEX` (1 to that number), so the gate waits for all of them instead of judging the first one to finish.
137
+
138
+ <%- end -%>
111
139
  <%- if azure? && mobile? -%>
112
140
  ## CI
113
141
 
data/lib/version CHANGED
@@ -1 +1 @@
1
- 3.7.0
1
+ 3.9.0
@@ -27,9 +27,9 @@ describe 'Azure Pipelines content' do
27
27
  let(:yml) { YAML.safe_load(raw) }
28
28
  let(:run_command) do
29
29
  if framework == 'cucumber'
30
- 'bundle exec cucumber features/ --format pretty'
30
+ 'bundle exec raider-reporter exec -- bundle exec cucumber features/ --format pretty'
31
31
  else
32
- 'bundle exec rspec spec/ --format documentation'
32
+ 'bundle exec raider-reporter exec -- bundle exec rspec spec/ --format documentation'
33
33
  end
34
34
  end
35
35
 
@@ -49,20 +49,37 @@ describe 'Azure Pipelines content' do
49
49
 
50
50
  it 'passes exactly the Raider settings to the test step' do
51
51
  step = yml['jobs'][0]['steps'].find { |s| s['script'] == run_command }
52
- expect(step['env']).to eq('RAIDER_TOKEN' => '$(RAIDER_TOKEN)', 'RAIDER_ENDPOINT' => '$(RAIDER_ENDPOINT)')
52
+ expect(step['env']).to eq('RAIDER_TOKEN' => '$(RAIDER_TOKEN)', 'RAIDER_ENDPOINT' => '$(RAIDER_ENDPOINT)',
53
+ 'RAIDER_QUARANTINE' => 1)
53
54
  expect(yml['variables']['HEADLESS']).to eq('true')
54
55
  end
55
56
 
56
- it 'has a raider_comment job for pull requests' do
57
+ it 'has a raider_comment job for pull requests that waits for the gate job but runs even when it is skipped' do
57
58
  comment = yml['jobs'][1]
58
59
  expect(comment['job']).to eq('raider_comment')
59
- expect(comment['dependsOn']).to eq('tests')
60
+ expect(comment['dependsOn']).to eq(%w[tests raider_gate])
60
61
  expect(comment['condition']).to eq("and(always(), eq(variables['Build.Reason'], 'PullRequest'))")
61
62
  last = comment['steps'].last
62
63
  expect(last['script']).to eq('bundle exec raider-reporter comment')
63
64
  expect(last['env']).to include('SYSTEM_ACCESSTOKEN' => '$(System.AccessToken)')
64
65
  end
65
66
 
67
+ it 'has a raider_gate job that runs only when RAIDER_GATE is 1' do
68
+ gate = yml['jobs'][2]
69
+ expect(yml['jobs'].size).to eq(3)
70
+ expect(gate['job']).to eq('raider_gate')
71
+ expect(gate['dependsOn']).to eq('tests')
72
+ expect(gate['condition']).to eq("and(always(), eq(variables['RAIDER_GATE'], '1'))")
73
+ end
74
+
75
+ it 'sets up Ruby in the raider_gate job and runs the gate with the token env' do
76
+ gate = yml['jobs'][2]
77
+ expect(gate['steps'].first).to eq('task' => 'UseRubyVersion@0', 'inputs' => { 'versionSpec' => '3.4' })
78
+ expect(gate['steps'].filter_map { |s| s['script'] }).to eq(['bundle install', 'bundle exec raider-reporter gate'])
79
+ expect(gate['steps'].last['env']).to eq('RAIDER_TOKEN' => '$(RAIDER_TOKEN)', 'RAIDER_ENDPOINT' => '$(RAIDER_ENDPOINT)',
80
+ 'SYSTEM_ACCESSTOKEN' => '$(System.AccessToken)')
81
+ end
82
+
66
83
  it 'has triggers, pool and the self-hosted hint' do
67
84
  expect(yml['trigger']['branches']['include']).to include('main', 'master')
68
85
  expect(yml['pr']['branches']['include']).to include('*')
@@ -83,7 +100,7 @@ describe 'Azure Pipelines content' do
83
100
  readme = read_generated(name, 'Readme.md')
84
101
  expect(readme).to include('## Azure Pipelines', 'RAIDER_TOKEN', 'Contribute to pull requests',
85
102
  'pool: { name: Default }', 'Build validation branch policy',
86
- 'same stage')
103
+ 'same stage', 'raider_gate', 'RAIDER_GATE=1', 'RAIDER_SHARD_TOTAL', 'RAIDER_SHARD_INDEX')
87
104
  expect(readme).not_to match(/GitHub Actions/i)
88
105
  end
89
106
  end
@@ -75,13 +75,24 @@ describe 'CI pipeline content' do
75
75
  expect(test_steps).not_to be_empty
76
76
  test_steps.each do |step|
77
77
  expect(step['env']).to include('RAIDER_TOKEN' => '${{ secrets.RAIDER_TOKEN }}',
78
- 'RAIDER_ENDPOINT' => '${{ vars.RAIDER_ENDPOINT }}')
78
+ 'RAIDER_ENDPOINT' => '${{ vars.RAIDER_ENDPOINT }}',
79
+ 'RAIDER_QUARANTINE' => '1')
80
+ end
81
+ end
82
+
83
+ it 'runs every test command through raider-reporter exec' do
84
+ expect(test_steps).not_to be_empty
85
+ test_steps.each do |step|
86
+ command = step['run'] || step['with']['script']
87
+ wrapped = command.scan(/raider-reporter exec -- bundle exec #{runner}\b/).size
88
+ expect(wrapped).to be_positive
89
+ expect(command.scan(/bundle exec #{runner}\b/).size).to eq(wrapped)
79
90
  end
80
91
  end
81
92
 
82
93
  it 'uploads raider-results as an artifact even on failure in every job' do
83
94
  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)
95
+ expect(uploads.size).to eq(YAML.safe_load(pipeline)['jobs'].except('raider-comment', 'raider-gate').size)
85
96
  uploads.each do |upload|
86
97
  expect(upload['with']['path']).to eq('raider-results/')
87
98
  expect(upload['if']).to eq('always()')
@@ -96,15 +107,16 @@ describe 'CI pipeline content' do
96
107
  let(:job) { jobs['raider-comment'] }
97
108
 
98
109
  it 'is a valid workflow with exactly the expected jobs' do
99
- expect(jobs.keys).to match_array(test_jobs + ['raider-comment'])
110
+ expect(jobs.keys).to match_array(test_jobs + %w[raider-comment raider-gate])
100
111
  end
101
112
 
102
- it 'needs every test job' do
103
- expect(job['needs']).to match_array(test_jobs)
113
+ it 'needs every test job and the gate job, so the comment carries the final gate line' do
114
+ expect(job['needs']).to match_array(test_jobs + %w[raider-gate])
104
115
  end
105
116
 
106
- it 'runs always, on pull requests only' do
117
+ it 'runs always, on pull requests only, so a skipped or failed gate job does not skip it' do
107
118
  expect(job['if']).to eq("always() && github.event_name == 'pull_request'")
119
+ expect(job['if']).to start_with('always()')
108
120
  expect(job['runs-on']).to eq('ubuntu-latest')
109
121
  end
110
122
 
@@ -140,6 +152,62 @@ describe 'CI pipeline content' do
140
152
  end
141
153
  end
142
154
 
155
+ shared_examples 'github raider-gate job' do |project_name, file, test_jobs|
156
+ subject(:pipeline) { read_generated(project_name, ".github/workflows/#{file}") }
157
+
158
+ let(:jobs) { YAML.safe_load(pipeline)['jobs'] }
159
+ let(:gate_job) { jobs['raider-gate'] }
160
+
161
+ it 'needs every test job and runs always when RAIDER_GATE is 1, on push and pull requests' do
162
+ expect(gate_job['needs']).to match_array(test_jobs)
163
+ expect(gate_job['if']).to eq("always() && vars.RAIDER_GATE == '1'")
164
+ expect(gate_job['runs-on']).to eq('ubuntu-latest')
165
+ end
166
+
167
+ it 'can read the code and write statuses only' do
168
+ expect(gate_job['permissions']).to eq('contents' => 'read', 'statuses' => 'write')
169
+ end
170
+
171
+ it 'checks out, sets up the same Ruby as the test jobs and runs the gate' do
172
+ steps = gate_job['steps']
173
+ expect(steps[0]).to eq('uses' => 'actions/checkout@v4')
174
+ test_ruby = jobs.values_at(*test_jobs).flat_map { |j| j['steps'] }
175
+ .find { |step| step['uses'] == 'ruby/setup-ruby@v1' }['with']['ruby-version']
176
+ expect(steps[1]).to eq('uses' => 'ruby/setup-ruby@v1', 'with' => { 'ruby-version' => test_ruby, 'bundler-cache' => true })
177
+ expect(steps[2]).to eq('name' => 'Wait for the Raider quality gate',
178
+ 'run' => 'bundle exec raider-reporter gate',
179
+ 'env' => { 'RAIDER_TOKEN' => '${{ secrets.RAIDER_TOKEN }}',
180
+ 'RAIDER_ENDPOINT' => '${{ vars.RAIDER_ENDPOINT }}',
181
+ 'GITHUB_TOKEN' => '${{ secrets.GITHUB_TOKEN }}' })
182
+ expect(steps.size).to eq(3)
183
+ end
184
+ end
185
+
186
+ shared_examples 'github appium shards' do |project_name, runner, shards|
187
+ subject(:pipeline) { read_generated(project_name, '.github/workflows/appium_pipeline.yml') }
188
+
189
+ let(:jobs) { YAML.safe_load(pipeline)['jobs'] }
190
+
191
+ def test_step(job, runner)
192
+ job['steps'].find { |step| step['run'].to_s.include?(runner) || step['with'].to_h['script'].to_s.include?(runner) }
193
+ end
194
+
195
+ if shards
196
+ it 'gives each platform job its own shard of two, so the gate waits for both' do
197
+ shards.each do |job_name, index|
198
+ expect(test_step(jobs[job_name], runner)['env'])
199
+ .to include('RAIDER_SHARD_INDEX' => index, 'RAIDER_SHARD_TOTAL' => '2')
200
+ end
201
+ end
202
+ else
203
+ it 'sets no shard env for a single platform' do
204
+ jobs.except('raider-comment', 'raider-gate').each_value do |job|
205
+ expect(test_step(job, runner)['env'].keys).not_to include('RAIDER_SHARD_INDEX', 'RAIDER_SHARD_TOTAL')
206
+ end
207
+ end
208
+ end
209
+ end
210
+
143
211
  context 'with rspec and selenium' do
144
212
  name = "#{FrameworkIndex::RSPEC}_#{AutomationIndex::SELENIUM}"
145
213
  include_examples 'valid github pipeline', name
@@ -147,6 +215,7 @@ describe 'CI pipeline content' do
147
215
  include_examples 'github triggers', name, 'test_pipeline.yml'
148
216
  include_examples 'github raider wiring', name, 'test_pipeline.yml'
149
217
  include_examples 'github raider-comment job', name, 'test_pipeline.yml', %w[build]
218
+ include_examples 'github raider-gate job', name, 'test_pipeline.yml', %w[build]
150
219
  include_examples 'github without allure steps', name
151
220
  end
152
221
 
@@ -157,6 +226,7 @@ describe 'CI pipeline content' do
157
226
  include_examples 'github triggers', name, 'test_pipeline.yml'
158
227
  include_examples 'github raider wiring', name, 'test_pipeline.yml', 'cucumber'
159
228
  include_examples 'github raider-comment job', name, 'test_pipeline.yml', %w[build]
229
+ include_examples 'github raider-gate job', name, 'test_pipeline.yml', %w[build]
160
230
  include_examples 'github without allure steps', name
161
231
  end
162
232
 
@@ -167,6 +237,7 @@ describe 'CI pipeline content' do
167
237
  include_examples 'github triggers', name, 'test_pipeline.yml'
168
238
  include_examples 'github raider wiring', name, 'test_pipeline.yml'
169
239
  include_examples 'github raider-comment job', name, 'test_pipeline.yml', %w[build]
240
+ include_examples 'github raider-gate job', name, 'test_pipeline.yml', %w[build]
170
241
  include_examples 'github without allure steps', name
171
242
  end
172
243
 
@@ -177,25 +248,32 @@ describe 'CI pipeline content' do
177
248
  include_examples 'github triggers', name, 'test_pipeline.yml'
178
249
  include_examples 'github raider wiring', name, 'test_pipeline.yml', 'cucumber'
179
250
  include_examples 'github raider-comment job', name, 'test_pipeline.yml', %w[build]
251
+ include_examples 'github raider-gate job', name, 'test_pipeline.yml', %w[build]
180
252
  include_examples 'github without allure steps', name
181
253
  end
182
254
 
183
255
  appium_jobs = { 'android' => %w[android-tests], 'ios' => %w[ios-tests],
184
256
  'cross_platform' => %w[ios-tests android-tests] }
185
257
 
258
+ appium_shards = { 'cross_platform' => { 'ios-tests' => '1', 'android-tests' => '2' } }
259
+
186
260
  appium_jobs.each do |automation, test_jobs|
187
261
  context "with rspec and #{automation}" do
188
262
  name = "#{FrameworkIndex::RSPEC}_#{automation}"
263
+ include_examples 'github appium shards', name, 'rspec', appium_shards[automation]
189
264
  include_examples 'github raider-comment job', name, 'appium_pipeline.yml', test_jobs
265
+ include_examples 'github raider-gate job', name, 'appium_pipeline.yml', test_jobs
190
266
  include_examples 'github triggers', name, 'appium_pipeline.yml'
191
267
  include_examples 'github raider wiring', name, 'appium_pipeline.yml'
192
268
  end
193
269
 
194
270
  context "with cucumber and #{automation}" do
195
271
  name = "#{FrameworkIndex::CUCUMBER}_#{automation}"
272
+ include_examples 'github appium shards', name, 'cucumber', appium_shards[automation]
196
273
  include_examples 'github triggers', name, 'appium_pipeline.yml'
197
274
  include_examples 'github raider wiring', name, 'appium_pipeline.yml', 'cucumber'
198
275
  include_examples 'github raider-comment job', name, 'appium_pipeline.yml', test_jobs
276
+ include_examples 'github raider-gate job', name, 'appium_pipeline.yml', test_jobs
199
277
  end
200
278
  end
201
279
  end
@@ -127,7 +127,7 @@ describe 'Gemfile content' do
127
127
  let(:gemfile) { read_generated("#{FrameworkIndex::RSPEC}_#{automation}", 'Gemfile') }
128
128
 
129
129
  it 'includes raider_reporter' do
130
- expect(gemfile).to include("gem 'raider_reporter', '~> 0.7'")
130
+ expect(gemfile).to include("gem 'raider_reporter', '~> 0.9'")
131
131
  end
132
132
 
133
133
  it 'has no allure gems' do
@@ -143,7 +143,7 @@ describe 'Gemfile content' do
143
143
  let(:gemfile) { read_generated("#{FrameworkIndex::CUCUMBER}_#{automation}", 'Gemfile') }
144
144
 
145
145
  it 'includes raider_reporter' do
146
- expect(gemfile).to include("gem 'raider_reporter', '~> 0.7'")
146
+ expect(gemfile).to include("gem 'raider_reporter', '~> 0.9'")
147
147
  end
148
148
 
149
149
  it 'drops allure-cucumber' do
@@ -16,6 +16,17 @@ describe 'Generated Readme content' do
16
16
  'https://github.com/RaiderHQ/raider_reporter')
17
17
  end
18
18
 
19
+ it 'explains quarantine in CI' do
20
+ expect(readme).to include('### Quarantine', 'RAIDER_QUARANTINE', 'raider-reporter exec')
21
+ end
22
+
23
+ it 'explains the quality gate' do
24
+ expect(readme).to include('### Quality gate', 'RAIDER_GATE=1', 'Gate page', 'raider/gate',
25
+ 'raider-reporter gate', 'raider-gate', 'exits 1 when the gate fails',
26
+ '2 when it gets no verdict', 'RAIDER_GATE_TIMEOUT', 'RAIDER_SHARD_TOTAL',
27
+ 'RAIDER_SHARD_INDEX')
28
+ end
29
+
19
30
  it 'points to the local HTML report' do
20
31
  expect(readme).to include('raider-results/index.html')
21
32
  expect(readme).not_to match(/allure/i)
@@ -34,6 +45,17 @@ describe 'Generated Readme content' do
34
45
  'https://github.com/RaiderHQ/raider_reporter')
35
46
  end
36
47
 
48
+ it 'explains quarantine in CI' do
49
+ expect(readme).to include('### Quarantine', 'RAIDER_QUARANTINE', 'raider-reporter exec')
50
+ end
51
+
52
+ it 'explains the quality gate' do
53
+ expect(readme).to include('### Quality gate', 'RAIDER_GATE=1', 'Gate page', 'raider/gate',
54
+ 'raider-reporter gate', 'raider-gate', 'exits 1 when the gate fails',
55
+ '2 when it gets no verdict', 'RAIDER_GATE_TIMEOUT', 'RAIDER_SHARD_TOTAL',
56
+ 'RAIDER_SHARD_INDEX')
57
+ end
58
+
37
59
  it 'does not mention Allure' do
38
60
  expect(readme).not_to match(/allure/i)
39
61
  end
@@ -18,8 +18,8 @@ describe 'RSpec projects without Allure' do
18
18
  expect(File).not_to exist(File.join(project_name, 'allure-results'))
19
19
  end
20
20
 
21
- it 'pins raider_reporter 0.7' do
22
- expect(read_generated(project_name, 'Gemfile')).to include("gem 'raider_reporter', '~> 0.7'")
21
+ it 'pins raider_reporter 0.9' do
22
+ expect(read_generated(project_name, 'Gemfile')).to include("gem 'raider_reporter', '~> 0.9'")
23
23
  end
24
24
  end
25
25
  end
@@ -104,10 +104,10 @@ describe 'End-to-End Project Generation and Execution' do
104
104
  expect(bundle_install(project)).to be true
105
105
  end
106
106
 
107
- it 'resolves raider_reporter 0.5 from RubyGems and ships the raider-reporter executable', :aggregate_failures do
107
+ it 'resolves raider_reporter 0.9 from RubyGems and ships the raider-reporter executable', :aggregate_failures do
108
108
  skip 'Bundle install failed' unless bundle_install(project)
109
109
 
110
- expect(File.read(File.join(project, 'Gemfile.lock'))).to match(/^ raider_reporter \(0\.5\.\d+\)$/)
110
+ expect(File.read(File.join(project, 'Gemfile.lock'))).to match(/^ raider_reporter \(0\.9\.\d+\)$/)
111
111
  result = run_in_project(project, 'bundle exec raider-reporter --help', timeout: 60)
112
112
  expect(result[:exit_code]).to eq(0), "STDOUT: #{result[:stdout]}\nSTDERR: #{result[:stderr]}"
113
113
  expect(result[:stdout] + result[:stderr]).to include('raider-reporter comment')
@@ -163,11 +163,11 @@ describe 'End-to-End Project Generation and Execution' do
163
163
  "STDERR: #{result[:stderr]}"
164
164
  end
165
165
 
166
- it 'resolves raider_reporter 0.5 from RubyGems and requires its Cucumber plugin', :aggregate_failures do
166
+ it 'resolves raider_reporter 0.9 from RubyGems and requires its Cucumber plugin', :aggregate_failures do
167
167
  skip 'Bundle install failed' unless bundle_install(project)
168
168
 
169
169
  lockfile = File.read(File.join(project, 'Gemfile.lock'))
170
- expect(lockfile).to match(/^ raider_reporter \(0\.5\.\d+\)$/)
170
+ expect(lockfile).to match(/^ raider_reporter \(0\.9\.\d+\)$/)
171
171
  expect(File.read(File.join(project, 'features/support/env.rb'))).to include("require 'raider_reporter/cucumber'")
172
172
  end
173
173
 
@@ -310,12 +310,12 @@ describe 'End-to-End Project Generation and Execution' do
310
310
  describe 'Selenium + RSpec' do
311
311
  let(:project) { generate_azure_project('rspec') }
312
312
 
313
- it 'ships azure-pipelines.yml and resolves raider_reporter 0.5', :aggregate_failures do
313
+ it 'ships azure-pipelines.yml and resolves raider_reporter 0.9', :aggregate_failures do
314
314
  expect(File).to exist(File.join(project, 'azure-pipelines.yml'))
315
315
  expect(File).not_to exist(File.join(project, '.github/workflows'))
316
316
  skip 'Bundle install failed' unless bundle_install(project)
317
317
 
318
- expect(File.read(File.join(project, 'Gemfile.lock'))).to match(/^ raider_reporter \(0\.5\.\d+\)$/)
318
+ expect(File.read(File.join(project, 'Gemfile.lock'))).to match(/^ raider_reporter \(0\.9\.\d+\)$/)
319
319
  end
320
320
 
321
321
  it 'records provider azure_pipelines and an azure_pipelines: build key in run.json', :aggregate_failures, :slow do
@@ -332,11 +332,11 @@ describe 'End-to-End Project Generation and Execution' do
332
332
  describe 'Selenium + Cucumber' do
333
333
  let(:project) { generate_azure_project('cucumber') }
334
334
 
335
- it 'ships azure-pipelines.yml and resolves raider_reporter 0.5', :aggregate_failures do
335
+ it 'ships azure-pipelines.yml and resolves raider_reporter 0.9', :aggregate_failures do
336
336
  expect(File).to exist(File.join(project, 'azure-pipelines.yml'))
337
337
  skip 'Bundle install failed' unless bundle_install(project)
338
338
 
339
- expect(File.read(File.join(project, 'Gemfile.lock'))).to match(/^ raider_reporter \(0\.5\.\d+\)$/)
339
+ expect(File.read(File.join(project, 'Gemfile.lock'))).to match(/^ raider_reporter \(0\.9\.\d+\)$/)
340
340
  end
341
341
 
342
342
  it 'records provider azure_pipelines and an azure_pipelines: build key in run.json', :aggregate_failures, :slow do
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.7.0
4
+ version: 3.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Agustin Pequeno
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
10
+ date: 2026-10-25 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rake
@@ -354,7 +354,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
354
354
  - !ruby/object:Gem::Version
355
355
  version: '0'
356
356
  requirements: []
357
- rubygems_version: 4.0.6
357
+ rubygems_version: 3.6.2
358
358
  specification_version: 4
359
359
  summary: A gem to make setup and start of UI automation projects easier
360
360
  test_files: []