Skip to content
Merged
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
79 changes: 67 additions & 12 deletions .github/workflows/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,26 @@ on: [ push, pull_request ]

jobs:
test:
name: 'Tests'
name: 'Tests (Group ${{ matrix.ci_node_index }})'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ci_node_total: [6]
ci_node_index: [0, 1, 2, 3, 4, 5]

env:
# prevent unnecessary log output -- https://bundler.io/man/bundle-config.1.html
BUNDLE_IGNORE_FUNDING_REQUESTS: true
BUNDLE_IGNORE_MESSAGES: true
RAILS_ENV: test
PARALLEL_TEST_PROCESSORS: ${{ matrix.ci_node_total }}
services:
postgres:
image: postgres:17
ports: ["5432:5432"]
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test
options: >-
--health-cmd pg_isready
--health-interval 10s
Expand All @@ -34,20 +40,69 @@ jobs:
# .ruby-version provides the Ruby version implicitly.
bundler-cache: true

- name: Setup test database
- name: Setup test databases
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test
RAILS_ENV: test
run:
bundle exec rake db:create db:migrate
DATABASE_URL: postgres://postgres:postgres@localhost:5432
run: |
bundle exec rake parallel:setup

- name: Run tests
- name: Run tests in parallel
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test
RAILS_ENV: test
run: bundle exec rake spec
DATABASE_URL: postgres://postgres:postgres@localhost:5432
CI_NODE_INDEX: ${{ matrix.ci_node_index }}
run: |
bundle exec parallel_rspec spec/ \
-n ${{ matrix.ci_node_total }} \
--only-group ${{ matrix.ci_node_index }}

- name: Preserve coverage results
run: |
# Copy resultset immediately after tests complete to prevent deletion
cp coverage/.resultset.json coverage/resultset-${{ matrix.ci_node_index }}.json

- name: Upload coverage artifacts
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.ci_node_index }}
path: coverage/resultset-${{ matrix.ci_node_index }}.json
retention-days: 1

coverage:
name: 'Report Coverage'
runs-on: ubuntu-latest
needs: test
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true

- name: Download all coverage artifacts
uses: actions/download-artifact@v4
with:
path: coverage-results

- name: Merge coverage results
run: |
mkdir -p coverage
bundle exec ruby -e '
require "json"
require "simplecov"

resultsets = {}
Dir["coverage-results/coverage-*/resultset-*.json"].each do |file|
data = JSON.parse(File.read(file))
resultsets.merge!(data)
end

File.write("coverage/.resultset.json", JSON.generate(resultsets))
'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nicely done!


- name: Report to Coveralls
continue-on-error: true # Don't fail the build if Coveralls fails to upload.
continue-on-error: true
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.github_token }}
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ group :development, :test do
gem 'faker'
gem 'irb' # LOCKED: Added because of byebug
gem 'launchy'
gem 'parallel_tests'
gem 'pry-rails'
gem 'pry-byebug'
gem 'pry-remote'
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ GEM
json
yaml
parallel (1.27.0)
parallel_tests (5.5.0)
parallel
parser (3.3.10.1)
ast (~> 2.4.1)
racc
Expand Down Expand Up @@ -651,6 +653,7 @@ DEPENDENCIES
omniauth-github
omniauth-rails_csrf_protection
pagy (~> 43.2)
parallel_tests
pg
pickadate-rails
premailer-rails
Expand Down
2 changes: 1 addition & 1 deletion config/database.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ development: &default

test:
<<: *default
database: planner_test
database: planner_test<%= ENV['TEST_ENV_NUMBER'] %>
pool: 5
6 changes: 6 additions & 0 deletions config/puma.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@
pidfile ENV["PIDFILE"] if ENV["PIDFILE"]
worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
environment ENV.fetch("RAILS_ENV") { "development" }

# Silence Puma output in test environment
if ENV.fetch("RAILS_ENV", "development") == "test"
quiet
end

preload_app!
# "worker" is the Puma term, not a background job.
on_worker_boot do
Expand Down
4 changes: 2 additions & 2 deletions spec/features/admin/manage_workshop_attendances_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
expect(page).to have_content('1 are attending as students')
expect(page).to_not have_selector('i.fa-magic')

find('span', text: 'Select a member to RSVP', visible: true).click
find('li', text: "#{other_invitation.member.full_name} (#{other_invitation.role})", visible: true).click
# Use the select_from_chosen helper to select the member
select_from_chosen("#{other_invitation.member.full_name} (#{other_invitation.role})", from: 'workshop_invitations')

expect(page).to have_content('2 are attending as students')

Expand Down
5 changes: 5 additions & 0 deletions spec/features/member_feedback_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
context 'Submitting a feedback request' do
scenario 'I can see success page with message and link to homepage when valid data is given', js: true do
visit feedback_path(valid_token)

# Wait for Chosen dropdowns to initialize
expect(page).to have_css('#feedback_coach_id_chosen')
expect(page).to have_css('#feedback_tutorial_id_chosen')

within('.rating') { all('li').at(3).click }
select_from_chosen(coach.full_name, from: 'feedback_coach_id')
select_from_chosen(@tutorial.title, from: 'feedback_tutorial_id')
Expand Down
15 changes: 15 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ def self.branch_coverage?

SimpleCov.start do
add_filter 'spec/'

# Support parallel test execution
# In CI: Use CI_NODE_INDEX (0, 1, 2, 3) set by GitHub Actions matrix
# Locally: Use TEST_ENV_NUMBER ('', '2', '3', '4') set by parallel_tests
if ENV['CI_NODE_INDEX']
command_name "RSpec-#{ENV['CI_NODE_INDEX']}"
use_merging true
merge_timeout 3600
elsif ENV.key?('TEST_ENV_NUMBER')
# TEST_ENV_NUMBER is '' for first process, '2', '3', etc. for others
suffix = ENV['TEST_ENV_NUMBER'].empty? ? '1' : ENV['TEST_ENV_NUMBER']
command_name "RSpec-#{suffix}"
use_merging true
merge_timeout 3600
end
end

ENV['RAILS_ENV'] ||= 'test'
Expand Down
4 changes: 4 additions & 0 deletions spec/support/capybara.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@
end

Capybara.javascript_driver = :chrome
Capybara.default_max_wait_time = 5

# Silence Capybara server output
Capybara.server = :puma, { Silent: true }
20 changes: 12 additions & 8 deletions spec/support/select_from_chosen.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@ module SelectFromChosen
def select_from_chosen(item_text, options)
# Find the native <select>
field = find_field(options[:from], :visible => false)
field_id = field[:id]

# Open the Chosen dialog
find("##{field[:id]}_chosen").click
# Find the option value we need to select
option = field.all('option', visible: false).find { |opt| opt.text == item_text }
raise "Option '#{item_text}' not found in select '#{options[:from]}'" unless option
option_value = option.value

# On the search input, type the string we're looking for and press Enter
within field.sibling('.chosen-container') do
input = find("input").native
input.send_keys(item_text)
input.send_key(:return)
end
# Use JavaScript to set the value and trigger Chosen update
page.execute_script <<-JS
$('##{field_id}').val('#{option_value}').trigger('chosen:updated').trigger('change');
JS

# Verify it was set
expect(page).to have_select(field_id, selected: item_text, visible: false)
end
end