Skip to content

Testing

MedTracker uses RSpec, Capybara, and Playwright. Application tests run against PostgreSQL 18.

Prepare the test environment

Run the preflight before coding work:

task test:preflight

If it reports a missing image, build the test image before retrying. Use task test:rebuild only when you need a destructive database reset.

Run tests

Always run tests through task:

task test

Run a targeted spec path:

task test TEST_FILE=spec/models/user_spec.rb

The full suite includes browser and non-browser examples. A focused command can target a file, directory, or line accepted by RSpec.

Test environments

  • Docker test environment: task test and task test:* tasks
  • Local CI-like environment: task local:* tasks

Useful local commands:

task local:test
task playwright
task local:test:all
task local:clean

task playwright is the canonical local Playwright entrypoint. It runs the browser-backed system tests through the repo's Taskfile wrapper.

For a manual screen-reader and keyboard pass over those journeys, use the manual accessibility smoke-test checklist.

TDD workflow

MedTracker follows Red-Green-Refactor:

  1. Write a failing test first.
  2. Make the smallest change that passes.
  3. Refactor while keeping tests green.

Browser coverage

Browser examples use the browser tag and usually live under spec/system/ or spec/features/. Run all browser examples with task playwright, or pass a specific file:

task playwright TEST_FILE=spec/system/dashboard_spec.rb

CI runs non-browser specs in two parallel file shards and browser examples in two parallel example shards. Both use scripts/ci/shard.mjs. Historical timing files are optional balancing hints: new specs need no timing entry, missing or invalid durations use the mean of available timings, and without a timing file items receive equal weights. Each non-browser file stays intact in one shard.

The coverage job combines both non-browser results and enforces the unchanged coverage thresholds. It fails if either result is missing or duplicated. Failure screenshots, HTML and coverage results are uploaded as CI artefacts.

RSpec tests application behaviour. CI script tests live in scripts/ci/tests/ and run with Node's built-in test runner through task ci:test, without Rails, a database, Docker or an npm install. task ci:check runs workflow lint, script syntax checks and these tests in the CI Workflow Check job.

task ci:coverage:test checks coverage collation with a standalone Ruby script in the tools container, without loading Rails or RSpec. The coverage job runs the same script before checking the application results.

Linting

Run RuboCop through Taskfile:

task rubocop
task rubocop AUTOCORRECT=true

Coverage

CI enables SimpleCov for the non-browser suite. The build requires at least 90% line coverage and 75% branch coverage. The API group also requires 90% branch coverage. These limits are defined in .simplecov and must not be lowered without a recorded reason.

Focused local runs do not enforce the coverage gate unless COVERAGE=true.

Mutation testing

Mutant checks whether selected specs detect changes to application code. Start the test services, then choose a subject:

task test:up
task mutation SUBJECT=MedicationFriendlyName
task mutation SUBJECT='GlobalSearch::ResultBuilder*'

Use task mutation:since to check subjects changed since origin/main. Pass REF=HEAD~3 to compare with another Git reference. The CI mutation job is advisory while its signal is evaluated.

Mutant uses its open-source mode. It does not need a licence token. See config/mutant.yml for the current exclusions and their reasons.

Test data

  • Fixtures live in spec/fixtures/.
  • Development seeding loads fixture-style data through db/seeds.rb.
  • Test fixture users use the password password.