claude-os/templates/skill-library/testing/rspec/skill.md
Bob Roberts a744080e65 feat: Add Skills Library and Session Insights (v2.3)
## Skills Library
- Browse and install 36+ community skills from Anthropic & Superpowers
- Local skill templates (Rails, React, testing)
- Create custom project-specific skills
- Beautiful UI with search and filtering
- /claude-os-skills command for CLI management

## Session Insights
- Parse Claude Code native .jsonl session files
- Extract patterns, decisions, blockers automatically
- Track tool usage and file changes
- Session summary generation for LLM processing

## Documentation
- Updated README with v2.3 features
- Updated API_REFERENCE with new endpoints
- Added SKILLS_GUIDE.md and SESSIONS_GUIDE.md
- Updated GitHub Pages (docs/index.html)
- Reorganized docs (internal_docs for private)

## Bug Fixes
- Fixed httpx client closure in community skill install
- Fixed frontend request format for skill install

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 12:56:49 -06:00

221 lines
5.2 KiB
Markdown

# RSpec Testing Patterns
## Purpose
Provides comprehensive RSpec testing patterns for Ruby/Rails applications:
- Unit testing conventions
- Integration testing patterns
- Factory Bot best practices
- Mocking and stubbing
- Test organization
## Test Structure
```ruby
# spec/services/user_registration_service_spec.rb
RSpec.describe UserRegistrationService do
describe '#call' do
subject(:service) { described_class.new(params) }
context 'with valid params' do
let(:params) { { name: 'Test', email: 'test@example.com', password: 'password123' } }
it 'creates a user' do
expect { service.call }.to change(User, :count).by(1)
end
it 'returns success' do
result = service.call
expect(result).to be_success
expect(result.user).to be_persisted
end
it 'sends welcome email' do
expect { service.call }
.to have_enqueued_mail(UserMailer, :welcome)
end
end
context 'with existing email' do
let(:params) { { name: 'Test', email: existing_user.email, password: 'password123' } }
let(:existing_user) { create(:user) }
it 'does not create a user' do
expect { service.call }.not_to change(User, :count)
end
it 'returns failure' do
result = service.call
expect(result).not_to be_success
expect(result.error).to include('Email already exists')
end
end
end
end
```
## Factory Bot Patterns
```ruby
# spec/factories/users.rb
FactoryBot.define do
factory :user do
sequence(:email) { |n| "user#{n}@example.com" }
name { Faker::Name.name }
password { 'password123' }
trait :admin do
role { :admin }
end
trait :with_posts do
transient do
posts_count { 3 }
end
after(:create) do |user, evaluator|
create_list(:post, evaluator.posts_count, user: user)
end
end
end
end
# Usage:
create(:user) # Basic user
create(:user, :admin) # Admin user
create(:user, :with_posts) # User with 3 posts
create(:user, :with_posts, posts_count: 5) # User with 5 posts
```
## Request Specs (API Testing)
```ruby
# spec/requests/api/v1/users_spec.rb
RSpec.describe 'Api::V1::Users', type: :request do
describe 'GET /api/v1/users' do
let!(:users) { create_list(:user, 3) }
before { get '/api/v1/users', headers: auth_headers }
it 'returns users' do
expect(response).to have_http_status(:ok)
expect(json_response['data'].size).to eq(3)
end
end
describe 'POST /api/v1/users' do
let(:valid_params) do
{
user: {
name: 'New User',
email: 'new@example.com',
password: 'password123'
}
}
end
context 'with valid params' do
it 'creates user' do
expect {
post '/api/v1/users', params: valid_params, headers: auth_headers
}.to change(User, :count).by(1)
expect(response).to have_http_status(:created)
end
end
end
end
```
## Model Specs
```ruby
# spec/models/user_spec.rb
RSpec.describe User, type: :model do
describe 'validations' do
subject { build(:user) }
it { is_expected.to validate_presence_of(:email) }
it { is_expected.to validate_uniqueness_of(:email).case_insensitive }
it { is_expected.to validate_presence_of(:name) }
end
describe 'associations' do
it { is_expected.to have_many(:posts).dependent(:destroy) }
it { is_expected.to have_many(:comments) }
it { is_expected.to belong_to(:organization).optional }
end
describe 'scopes' do
describe '.active' do
let!(:active_user) { create(:user, active: true) }
let!(:inactive_user) { create(:user, active: false) }
it 'returns only active users' do
expect(User.active).to contain_exactly(active_user)
end
end
end
describe '#full_name' do
let(:user) { build(:user, first_name: 'John', last_name: 'Doe') }
it 'returns combined name' do
expect(user.full_name).to eq('John Doe')
end
end
end
```
## Shared Examples
```ruby
# spec/support/shared_examples/authenticatable.rb
RSpec.shared_examples 'authenticatable' do
context 'without authentication' do
let(:auth_headers) { {} }
it 'returns unauthorized' do
subject
expect(response).to have_http_status(:unauthorized)
end
end
end
# Usage in specs:
describe 'GET /api/v1/users' do
subject { get '/api/v1/users', headers: auth_headers }
it_behaves_like 'authenticatable'
end
```
## Test Helpers
```ruby
# spec/support/request_helpers.rb
module RequestHelpers
def json_response
JSON.parse(response.body)
end
def auth_headers
user = create(:user)
{ 'Authorization' => "Bearer #{user.generate_token}" }
end
end
RSpec.configure do |config|
config.include RequestHelpers, type: :request
end
```
## Key Principles
1. **One assertion per test** - Keep tests focused
2. **Use `let` and `let!`** - Lazy vs eager loading
3. **Use `subject`** - Name what you're testing
4. **Use `described_class`** - Reference class being tested
5. **Use traits** - Compose variations cleanly
6. **Avoid database when possible** - Use `build` over `create`
7. **Use `aggregate_failures`** - Group related assertions