Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ jobs:
build-and-test:
runs-on: ubuntu-latest

# GitHub-hosted ubuntu-latest runners have 4 vCPUs; split the suite across
# 4 parallel_tests processes (each with its own database) to cut wall time.
env:
PARALLEL_TEST_PROCESSORS: 4

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: PARALLEL_TEST_PROCESSORS=4 matches the 4 vCPUs on ubuntu-latest. Running 4 headless Chrome system specs concurrently is the main flakiness risk to watch — if CI gets flaky, dropping to 3 or sharding system specs into their own job is the lever.

services:
mysql:
image: mysql:8.0
Expand All @@ -54,9 +59,9 @@ jobs:
node-version: 22
- run: npm ci

- name: Setup database
- name: Setup databases
run: |
bundle exec rake db:create db:schema:load
bundle exec rake parallel:create parallel:load_schema
env:
RAILS_ENV: test
# AWS credentials
Expand All @@ -71,7 +76,7 @@ jobs:
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}

- name: Run tests and publish results
run: bundle exec rspec --format progress --format json --out tmp/rspec_results.json
run: bundle exec parallel_rspec spec/
env:
RAILS_ENV: test
# AWS credentials
Expand All @@ -91,4 +96,4 @@ jobs:
if: always()
with:
name: rspec-results
path: tmp/rspec_results.json
path: tmp/rspec_results/
2 changes: 1 addition & 1 deletion .github/workflows/sanity-check-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
- name: Run RSpec (SimpleCov JSON + summary via at_exit)
env:
RAILS_ENV: test
CI: "true"
COVERAGE: "true"
run: bundle exec rspec

- name: Generate coverage badge
Expand Down
13 changes: 11 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,16 @@ Custom colors defined in `app/frontend/stylesheets/application.tailwind.css`:
### Configuration

- **rails_helper.rb**: Loads RSpec Rails, FactoryBot, Shoulda Matchers, ActionPolicy, Devise test helpers, ActiveStorage validation matchers. Transactional fixtures enabled. ActiveJob uses `:test` adapter.
- **spec_helper.rb**: SimpleCov with branch coverage (minimum 20%), random test ordering, profile of 10 slowest examples.
- **spec_helper.rb**: Random test ordering, profile of 10 slowest examples. SimpleCov (branch coverage, minimum 20%) runs only when `COVERAGE=true` (set by the coverage-badge workflow on `main`), not on every run. Under `CI=true`, each parallel process writes its own JSON results file to `tmp/rspec_results/` keyed on `TEST_ENV_NUMBER`.

### Running in parallel

The suite runs across multiple processes via [`parallel_tests`](https://github.com/grosser/parallel_tests), each with its own database (`awbw_test`, `awbw_test2`, … — the `TEST_ENV_NUMBER` suffix is appended in `config/database.yml`):

```
bundle exec rake parallel:create parallel:load_schema # one-time per schema change
bundle exec parallel_rspec spec/ # run the whole suite in parallel
```

### Support Files

Expand Down Expand Up @@ -359,7 +368,7 @@ bundle exec bundle-audit check --update
### ci.yml

1. **scan_ruby**: Brakeman security analysis + bundler-audit
2. **build-and-test**: MySQL 8.0 service, Ruby + Node 22 setup, `npm ci`, schema load, `bundle exec rspec`
2. **build-and-test**: MySQL 8.0 service, Ruby + Node 22 setup, `npm ci`, `parallel:create parallel:load_schema`, then `parallel_rspec spec/` across 4 processes (`PARALLEL_TEST_PROCESSORS=4`)

### rubocop.yml

Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ group :development, :test do
gem "pry-coolline"
gem "pry-rails"
gem "rspec-rails"
gem "parallel_tests"
gem "simplecov", require: false
gem "simplecov_json_formatter", require: false
gem "selenium-webdriver"
Expand Down
4 changes: 4 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,8 @@ GEM
orm_adapter (0.5.0)
ostruct (0.6.3)
parallel (1.27.0)
parallel_tests (5.7.0)
parallel
parser (3.3.10.1)
ast (~> 2.4.1)
racc
Expand Down Expand Up @@ -803,6 +805,7 @@ DEPENDENCIES
opentelemetry-instrumentation-all
opentelemetry-sdk
ostruct
parallel_tests
pay (~> 11.4)
positioning (~> 0.4.7)
premailer-rails
Expand Down Expand Up @@ -1019,6 +1022,7 @@ CHECKSUMS
orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
parallel_tests (5.7.0) sha256=3f1762c46ca2c223b8af8ef877217f9d76974e191bfa934f2580b58bcf1d005c
parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
pay (11.4.3) sha256=f3d50b1a900ab0a7bfe9ba9fda631b2f5faf0c95236dd3d2afa9effc9bfb15e8
polyglot (0.3.5) sha256=59d66ef5e3c166431c39cb8b7c1d02af419051352f27912f6a43981b3def16af
Expand Down
4 changes: 3 additions & 1 deletion config/database.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ development:
# Do not set this db to the same as development or production.
test:
<<: *base
database: awbw_test<%= "_#{workspace_port}" if workspace_port %>
# TEST_ENV_NUMBER is set by parallel_tests to give each parallel process its
# own database (blank for the first process, "2", "3", ... for the rest).
database: awbw_test<%= "_#{workspace_port}" if workspace_port %><%= ENV['TEST_ENV_NUMBER'] %>

staging:
primary: &primary_staging
Expand Down
14 changes: 13 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
require "active_storage_validations/matchers"

if ENV["CI"]
if ENV["COVERAGE"]

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: SimpleCov is now gated on COVERAGE (set only by the badge workflow on main) instead of CI. This keeps branch-coverage overhead off PR runs and sidesteps the per-process minimum_coverage check + .resultset.json merge that parallel execution would otherwise break. Trade-off: PRs lose the 20% coverage gate.

require "simplecov"
require "simplecov_json_formatter"
SimpleCov.formatter =
Expand All @@ -42,6 +42,18 @@
end
end

# Under parallel_tests in CI, a single shared --out file would be clobbered by
# each process. Give every process its own results file, keyed on the
# TEST_ENV_NUMBER that parallel_tests assigns (blank for the first process).
if ENV["CI"]
require "fileutils"
FileUtils.mkdir_p("tmp/rspec_results")
RSpec.configure do |config|
config.add_formatter "progress"
config.add_formatter "json", "tmp/rspec_results/results#{ENV['TEST_ENV_NUMBER']}.json"
end
end

RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
Expand Down
Loading