name: rails:test description: | This skill should be used when the user wants to write, scaffold, or improve tests in a Ruby on Rails application. Covers RSpec organization, FactoryBot patterns, request/model/service specs, VCR setup for HTTP stubbing, and test-driven development workflows. Activates on: "write tests", "add specs", "rspec", "factory bot", "test this", "spec for", "scaffold test", "write spec", "missing tests", "test coverage", "VCR cassette", "stub http", "testing strategy", "TDD", "test driven", "rails test", "how to test", "scrivere test", "aggiungere spec".
Rails Testing Skill
Scaffold and write tests for Rails applications using RSpec, FactoryBot, shoulda-matchers, and VCR. Follows project conventions for test organization and patterns.
Reference files: Consult reference/patterns.md for complete RSpec examples, FactoryBot patterns, and VCR configuration.
Tools Used
- Read: Examine source code to understand what needs testing
- Grep/Glob: Find existing specs, factories, and test helpers
- Write/Edit: Create or update spec files and factories
Workflow
Step 1: Detect Project Conventions
Before writing any test, discover the project's testing setup:
- Test framework: Check
Gemfileforrspec-railsvsminitest - Factory library:
factory_bot_rails(standard) orfabrication - HTTP stubbing:
vcr+webmock, orwebmockalone - Matchers:
shoulda-matchers,rspec-its - Test runner:
bin/rspecwrapper or plainbundle exec rspec - Support files: Read
spec/support/for shared contexts, custom matchers, and helpers - Rails helper: Check
spec/rails_helper.rbfor included modules and configuration
Also check the project's CLAUDE.md for testing conventions.
Step 2: Determine What to Test
Based on the user's request, identify:
| Source Code | Spec Type | Spec Location |
|---|---|---|
app/models/ |
Model spec | spec/models/ |
app/services/ |
Service spec | spec/services/ |
app/controllers/api/ |
Request spec | spec/api/ or spec/requests/ |
app/graphql/mutations/ |
GraphQL spec | spec/graphql/mutations/ |
app/graphql/queries/ |
GraphQL spec | spec/graphql/queries/ |
app/jobs/ |
Job spec | spec/jobs/ |
app/policies/ |
Policy spec | spec/policies/ |
app/controllers/ |
Request spec | spec/requests/ |
Read the source file to understand:
- Public methods to test
- Edge cases and error paths
- External dependencies to mock
- Associations and validations (for models)
Step 3: Check for Existing Specs and Factories
Existing spec: Search for a spec file matching the source:
Glob: spec/**/*<model_name>*_spec.rbExisting factory: Search for the factory:
Glob: spec/factories/*<model_name>*.rbRelated specs: Find specs that test similar patterns in the project to match style:
Glob: spec/<type>/*_spec.rb (read 1-2 examples)
If a spec exists, read it first and add to it rather than creating a new file.
Step 4: Create or Update Factory
If the model doesn't have a factory yet, create one:
- Place in
spec/factories/<plural_model_name>.rb - Include:
- Required attributes with sensible defaults
sequencefor unique fieldsassociationfor belongs_totraitblocks for variations (states, roles, edge cases)
Follow the project's existing factory style. See reference/patterns.md for examples.
Step 5: Write the Spec
Write the spec following these principles:
Structure:
- Use
describefor the class/method being tested - Use
contextfor different scenarios ("when valid", "when unauthorized") - Use
itwith descriptive strings (notit { should ... }for complex behavior) - One assertion per example where practical
For model specs:
- Associations with shoulda-matchers:
it { is_expected.to belong_to(:user) } - Validations with shoulda-matchers:
it { is_expected.to validate_presence_of(:name) } - Scopes: test return values
- Instance methods: test behavior with different inputs
- State machines: test transitions and guards
For service specs:
- Instantiate with
described_class.new(args) - Test the public interface (usually
.callor the primary method) - Mock external dependencies (HTTP, email, etc.)
- Test success and failure paths
- Test side effects (database changes, jobs enqueued, emails sent)
For request specs:
- Test HTTP status codes
- Test response body structure
- Test authentication/authorization
- Test error responses (422, 404, 403)
- Use
letfor setup, avoidbeforeblocks whenletsuffices
For job specs:
- Test
performdirectly - Test enqueue behavior if relevant
- Test idempotency for critical jobs
- Mock external services
Step 6: Handle External Dependencies
When the code under test makes HTTP calls:
Check for VCR: If the project uses VCR, record cassettes:
it "fetches data", :vcr do result = service.call expect(result).to be_success endCassettes are stored in
spec/cassettes/(orspec/fixtures/vcr_cassettes/)If no VCR: Use webmock stubs:
stub_request(:get, "https://api.example.com/data") .to_return(status: 200, body: { result: "ok" }.to_json)For Sidekiq jobs: Use
have_enqueued_sidekiq_jobor test inline withSidekiq::Testing.inline!For email: Use
ActionMailer::Base.deliveriesorhave_enqueued_mail
Step 7: Run and Verify
After writing the spec:
Run the specific spec:
bundle exec rspec spec/path/to/new_spec.rbCheck for failures and fix:
- Missing factories -> create them
- Database state issues -> check
let/let!ordering - Flaky time-dependent tests -> use
travel_toorfreeze_time
Run RuboCop on the spec:
bundle exec rubocop spec/path/to/new_spec.rbSuggest next steps:
- "Want me to add more edge case tests?"
- "Should I check test coverage for this module?"
- "Want me to write specs for related files?"
Error Handling
| Situation | Action |
|---|---|
| No RSpec in project | Check for Minitest, suggest setup if neither exists |
| Factory not found | Create it based on model schema (db/schema.rb) |
| VCR cassette expired | Suggest re-recording with VCR_RECORD=all bundle exec rspec spec/path |
| Database schema mismatch | Suggest RAILS_ENV=test rails db:drop db:create db:schema:load |
| Flaky test (time-dependent) | Use travel_to(Time.zone.parse("2024-01-15 10:00")) block |
| Missing test database | Suggest RAILS_ENV=test rails db:prepare |
Reference Files
reference/patterns.md— Complete RSpec examples for models, services, requests, jobs, and policies with FactoryBot and VCR patterns