rspec-core
This skill should be used when the user asks to "write an RSpec test", "create a spec", "use describe blocks", "set up let variables", "use before hooks", "understand RSpec structure", mentions "subject", "context", "it blocks", or needs guidance on RSpec 3.x fundamentals and test structure.
What this skill does
# RSpec Core Fundamentals
RSpec is a behavior-driven development (BDD) testing framework for Ruby. This skill covers the core DSL for structuring and writing specs.
## Example Group Structure
### describe and context
Use `describe` for the thing being tested (class, method, behavior). Use `context` for different scenarios or states:
```ruby
RSpec.describe User do
describe "#full_name" do
context "when user has both names" do
it "returns first and last name" do
user = User.new(first_name: "John", last_name: "Doe")
expect(user.full_name).to eq("John Doe")
end
end
context "when user has no last name" do
it "returns only first name" do
user = User.new(first_name: "John", last_name: nil)
expect(user.full_name).to eq("John")
end
end
end
end
```
**Naming conventions:**
- `describe` with class name: `RSpec.describe User`
- `describe` with method: `describe "#instance_method"` or `describe ".class_method"`
- `context` starts with "when", "with", "without", "given": `context "when logged in"`
### it and specify
Use `it` for individual test cases. The description should complete the sentence "it...":
```ruby
it "returns the user's email" do
expect(user.email).to eq("[email protected]")
end
# For complex descriptions, use specify
specify "the total includes tax and shipping" do
expect(order.total).to eq(110.00)
end
```
**One expectation per example** (generally): Each `it` block should test one behavior. Multiple expectations are acceptable when testing related aspects of a single behavior.
## Subject and Let
### subject
Defines the primary object under test:
```ruby
RSpec.describe User do
subject { User.new(name: "John") }
it { is_expected.to be_valid }
# Named subject for clarity
subject(:user) { User.new(name: "John") }
it "has the correct name" do
expect(user.name).to eq("John")
end
end
```
### let and let!
Use `let` for lazy-evaluated memoized helpers:
```ruby
RSpec.describe Order do
let(:user) { User.create!(name: "John") }
let(:product) { Product.create!(name: "Widget", price: 10) }
let(:order) { Order.new(user: user, product: product) }
it "calculates total correctly" do
expect(order.total).to eq(10)
end
end
```
**let vs let!:**
- `let` - Lazy evaluation, created when first referenced
- `let!` - Eager evaluation, created before each example
```ruby
let(:user) { User.create!(name: "John") } # Created only if referenced
let!(:admin) { User.create!(admin: true) } # Always created before each test
```
**When to use let!:**
- Database records that must exist for callbacks/associations
- Setup that has side effects needed by other code
- When order of creation matters
## Hooks
### before and after
Execute code before or after examples:
```ruby
RSpec.describe User do
before(:each) do # or just `before do`
@user = User.new
end
after(:each) do
# Cleanup after each example
end
before(:all) do # or before(:context)
# Run once before all examples in this group
# Be careful: shared state between examples
end
after(:all) do
# Run once after all examples
end
end
```
**Hook execution order:**
1. `before(:all)` - once per describe/context block
2. `before(:each)` - before every example
3. The example runs
4. `after(:each)` - after every example
5. `after(:all)` - once after all examples
### around
Wrap examples with custom logic:
```ruby
around(:each) do |example|
Timecop.freeze(Time.now) do
example.run
end
end
# Useful for database transactions
around(:each) do |example|
ActiveRecord::Base.transaction do
example.run
raise ActiveRecord::Rollback
end
end
```
## Pending and Skipping
### pending
Mark examples as not yet implemented or temporarily broken:
```ruby
it "sends welcome email" do
pending "email service not implemented"
expect(user.send_welcome_email).to be_truthy
end
# Or mark entire example as pending
pending "calculates complex tax" do
expect(order.tax).to eq(15.00)
end
```
### skip
Skip examples entirely:
```ruby
it "requires external service", skip: "API not available in test" do
# This won't run
end
# Conditional skip
it "runs on CI only", skip: !ENV["CI"] do
# Skipped locally
end
# Skip with xit
xit "not implemented yet" do
# Skipped
end
```
## Metadata and Filtering
Add metadata to examples and filter runs:
```ruby
RSpec.describe User, type: :model do
it "validates email", :slow do
# Tagged with :slow
end
it "processes payment", :integration, timeout: 30 do
# Multiple tags
end
end
# Run filtered specs:
# rspec --tag slow
# rspec --tag ~slow (exclude slow)
# rspec --tag type:model
```
### Focus
Temporarily run only specific examples:
```ruby
fit "only this test runs" do # focus + it
expect(true).to be true
end
fdescribe User do # focus + describe
# Only examples in this block run
end
fcontext "when focused" do # focus + context
end
```
**Important:** Remove focus tags before committing. Configure CI to fail on focus:
```ruby
# spec/spec_helper.rb
RSpec.configure do |config|
config.filter_run_when_matching :focus
config.run_all_when_everything_filtered = true
end
```
## Configuration
### spec_helper.rb vs rails_helper.rb
- `spec_helper.rb` - Pure RSpec configuration, no Rails
- `rails_helper.rb` - Rails-specific setup, requires spec_helper
```ruby
# spec/spec_helper.rb
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.shared_context_metadata_behavior = :apply_to_host_groups
config.filter_run_when_matching :focus
config.example_status_persistence_file_path = "spec/examples.txt"
config.disable_monkey_patching!
config.order = :random
Kernel.srand config.seed
end
```
## Best Practices
### Describe What, Not How
```ruby
# Good - describes behavior
it "returns user's full name" do
expect(user.full_name).to eq("John Doe")
end
# Avoid - describes implementation
it "concatenates first_name and last_name with space" do
expect(user.full_name).to eq("John Doe")
end
```
### Use Descriptive Context Names
```ruby
# Good
context "when user is an admin"
context "with valid attributes"
context "without a password"
# Avoid
context "admin case"
context "valid"
context "test 1"
```
### Prefer let Over Instance Variables
```ruby
# Good
let(:user) { create(:user) }
# Avoid
before { @user = create(:user) }
```
### Keep Examples Independent
Each example should be able to run in isolation. Avoid dependencies between examples.
## Additional Resources
For advanced patterns and detailed examples:
- **`references/hooks-deep-dive.md`** - Comprehensive hook patterns and execution order
Related in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.