rspec
Comprehensive RSpec testing for Ruby and Rails applications. Covers model specs, request specs, system specs, factories, mocks, and TDD workflow. Automatically triggers on RSpec-related keywords and testing scenarios.
What this skill does
# RSpec Testing Skill
Expert guidance for writing comprehensive tests in RSpec for Ruby and Rails applications. This skill provides immediate, actionable testing strategies with deep-dive references for complex scenarios.
## Quick Start
### Basic RSpec Structure
```ruby
# spec/models/user_spec.rb
RSpec.describe User, type: :model do
describe '#full_name' do
it 'returns the first and last name' do
user = User.new(first_name: 'John', last_name: 'Doe')
expect(user.full_name).to eq('John Doe')
end
end
end
```
**Key concepts:**
- `describe`: Groups related tests (classes, methods)
- `context`: Describes specific scenarios
- `it`: Individual test example
- `expect`: Makes assertions using matchers
### Running Tests
```bash
# Run all specs
bundle exec rspec
# Run specific file
bundle exec rspec spec/models/user_spec.rb
# Run specific line
bundle exec rspec spec/models/user_spec.rb:12
# Run with documentation format
bundle exec rspec --format documentation
# Run only failures from last run
bundle exec rspec --only-failures
```
## Core Testing Patterns
### 1. Model Specs
Test business logic, validations, associations, and methods:
```ruby
RSpec.describe Article, type: :model do
# Test validations
describe 'validations' do
it { should validate_presence_of(:title) }
it { should validate_length_of(:title).is_at_most(100) }
end
# Test associations
describe 'associations' do
it { should belong_to(:author) }
it { should have_many(:comments) }
end
# Test instance methods
describe '#published?' do
context 'when publish_date is in the past' do
it 'returns true' do
article = Article.new(publish_date: 1.day.ago)
expect(article.published?).to be true
end
end
context 'when publish_date is in the future' do
it 'returns false' do
article = Article.new(publish_date: 1.day.from_now)
expect(article.published?).to be false
end
end
end
# Test scopes
describe '.recent' do
it 'returns articles from the last 30 days' do
old = create(:article, created_at: 31.days.ago)
recent = create(:article, created_at: 1.day.ago)
expect(Article.recent).to include(recent)
expect(Article.recent).not_to include(old)
end
end
end
```
### 2. Request Specs
Test HTTP requests and responses across the entire stack:
```ruby
RSpec.describe 'Articles API', type: :request do
describe 'GET /articles' do
it 'returns all articles' do
create_list(:article, 3)
get '/articles'
expect(response).to have_http_status(:success)
expect(JSON.parse(response.body).size).to eq(3)
end
end
describe 'POST /articles' do
context 'with valid params' do
it 'creates a new article' do
article_params = { article: { title: 'New Article', body: 'Content' } }
expect {
post '/articles', params: article_params
}.to change(Article, :count).by(1)
expect(response).to have_http_status(:created)
end
end
context 'with invalid params' do
it 'returns errors' do
invalid_params = { article: { title: '' } }
post '/articles', params: invalid_params
expect(response).to have_http_status(:unprocessable_entity)
end
end
end
describe 'authentication' do
it 'requires authentication for create' do
post '/articles', params: { article: { title: 'Test' } }
expect(response).to have_http_status(:unauthorized)
end
it 'allows authenticated users to create' do
user = create(:user)
post '/articles',
params: { article: { title: 'Test' } },
headers: { 'Authorization' => "Bearer #{user.token}" }
expect(response).to have_http_status(:created)
end
end
end
```
### 3. System Specs (End-to-End)
Test user workflows through the browser with Capybara:
```ruby
RSpec.describe 'Article management', type: :system do
before { driven_by(:selenium_chrome_headless) }
scenario 'user creates an article' do
visit new_article_path
fill_in 'Title', with: 'My Article'
fill_in 'Body', with: 'Article content'
click_button 'Create Article'
expect(page).to have_content('Article was successfully created')
expect(page).to have_content('My Article')
end
scenario 'user edits an article' do
article = create(:article, title: 'Original Title')
visit article_path(article)
click_link 'Edit'
fill_in 'Title', with: 'Updated Title'
click_button 'Update Article'
expect(page).to have_content('Updated Title')
expect(page).not_to have_content('Original Title')
end
# Test JavaScript interactions
scenario 'user filters articles', js: true do
create(:article, title: 'Ruby Article', category: 'ruby')
create(:article, title: 'Python Article', category: 'python')
visit articles_path
select 'Ruby', from: 'filter'
expect(page).to have_content('Ruby Article')
expect(page).not_to have_content('Python Article')
end
end
```
## Factory Bot Integration
Use FactoryBot for test data. Define factories in `spec/factories/`, use traits for variations, and prefer `build` over `create` when persistence isn't needed.
See [references/factory_bot.md](references/factory_bot.md) for factory definitions, traits, sequences, associations, and build strategies.
## Essential Matchers
| Category | Examples |
|----------|----------|
| Equality | `eq`, `eql`, `be`, `equal` |
| Truthiness | `be_truthy`, `be_falsy`, `be_nil`, `be_a` |
| Collections | `include`, `contain_exactly`, `match_array` |
| Changes | `change`, `raise_error`, `have_enqueued_job` |
See [references/matchers.md](references/matchers.md) for the complete matcher reference.
## Mocks, Stubs, and Doubles
Use `double` or `instance_double` (preferred — verifies against real class) for test doubles. Stub with `allow(obj).to receive(:method)`, set expectations with `expect(obj).to receive(:method)`, and verify after the fact with spies via `have_received`.
See [references/mocking.md](references/mocking.md) for test doubles, stubbing, message expectations, and spies.
## DRY Testing Techniques
Use `let` (lazy) and `let!` (eager) for test data, `before` hooks for shared setup, `shared_examples` for reusable test groups, and `shared_context` for reusable setup blocks. Prefer `subject` for the object under test.
See [references/core_concepts.md](references/core_concepts.md) for detailed coverage of hooks, let, shared examples, shared contexts, and subject.
## TDD Workflow
### Red-Green-Refactor Cycle
1. **Red**: Write a failing test first
```ruby
describe User do
it 'has a full name' do
user = User.new(first_name: 'John', last_name: 'Doe')
expect(user.full_name).to eq('John Doe')
end
end
# Fails: undefined method `full_name'
```
2. **Green**: Write minimal code to pass
```ruby
class User
def full_name
"#{first_name} #{last_name}"
end
end
# Passes!
```
3. **Refactor**: Improve code while keeping tests green
### Testing Strategy
**Start with system specs** for user-facing features:
- Tests complete workflows
- Highest confidence
- Slowest to run
**Drop to request specs** for API/controller logic:
- Test HTTP interactions
- Faster than system specs
- Cover authentication, authorization, edge cases
**Use model specs** for business logic:
- Test calculations, validations, scopes
- Fast and focused
- Most of your test suite
## Configuration Best Practices
### spec/rails_helper.rb
```ruby
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
abort("Run in production!") if Rails.env.production?
require 'rspec/rails'
# Auto-require support files
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
RSpec.configure do |config|
# Use transactional fixtures
config.use_transactional_fixtures = true
# Infer spec type from file location
config.infer_spec_type_from_filRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.