Back to list
bastos

rspec-rails

by bastos

Bastos' Claude Code Ruby Plugin Marketplace

0🍴 0📅 Jan 24, 2026

SKILL.md


name: RSpec Rails description: This skill should be used when the user asks about "request specs", "system specs", "model specs", "controller specs", "mailer specs", "feature specs", "Capybara", "rspec-rails", or needs guidance on testing Rails applications with RSpec. version: 1.0.0

RSpec Rails

rspec-rails integrates RSpec with Rails, providing specialized spec types for each Rails component.

Spec Types

Spec TypeLocationPurpose
Modelspec/models/ActiveRecord models, validations, associations
Requestspec/requests/HTTP requests, full controller + routing
Systemspec/system/Browser-based end-to-end tests
Mailerspec/mailers/Email content and delivery
Jobspec/jobs/Background job behavior
Viewspec/views/View rendering (less common)
Helperspec/helpers/View helper methods
Routingspec/routing/Route resolution
Controllerspec/controllers/Deprecated - use request specs

Model Specs

Test ActiveRecord models, validations, associations, and scopes:

# spec/models/user_spec.rb
RSpec.describe User, type: :model do
  describe "validations" do
    it { is_expected.to validate_presence_of(:email) }
    it { is_expected.to validate_uniqueness_of(:email).case_insensitive }
    it { is_expected.to validate_length_of(:password).is_at_least(8) }
  end

  describe "associations" do
    it { is_expected.to have_many(:posts).dependent(:destroy) }
    it { is_expected.to belong_to(:organization).optional }
    it { is_expected.to have_one(:profile) }
  end

  describe "#full_name" do
    it "returns first and last name" do
      user = build(:user, first_name: "John", last_name: "Doe")
      expect(user.full_name).to eq("John Doe")
    end
  end

  describe ".active" do
    it "returns only active users" do
      active = create(:user, active: true)
      inactive = create(:user, active: false)

      expect(User.active).to include(active)
      expect(User.active).not_to include(inactive)
    end
  end
end

Shoulda Matchers

Add to Gemfile for one-liner validations:

# Gemfile
group :test do
  gem "shoulda-matchers"
end

# spec/rails_helper.rb
Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end

Request Specs

Test HTTP endpoints (preferred over controller specs):

# spec/requests/users_spec.rb
RSpec.describe "Users", type: :request do
  describe "GET /users" do
    it "returns a list of users" do
      create_list(:user, 3)

      get users_path

      expect(response).to have_http_status(:ok)
      expect(response.parsed_body.size).to eq(3)
    end
  end

  describe "POST /users" do
    context "with valid params" do
      it "creates a user" do
        user_params = { user: { email: "new@example.com", password: "password123" } }

        expect {
          post users_path, params: user_params
        }.to change(User, :count).by(1)

        expect(response).to redirect_to(user_path(User.last))
      end
    end

    context "with invalid params" do
      it "returns unprocessable entity" do
        post users_path, params: { user: { email: "" } }

        expect(response).to have_http_status(:unprocessable_entity)
      end
    end
  end

  describe "with authentication" do
    let(:user) { create(:user) }

    it "allows access to authenticated users" do
      sign_in user  # Devise helper

      get dashboard_path

      expect(response).to have_http_status(:ok)
    end

    it "redirects unauthenticated users" do
      get dashboard_path

      expect(response).to redirect_to(login_path)
    end
  end
end

JSON API Testing

RSpec.describe "API::Users", type: :request do
  describe "GET /api/users/:id" do
    it "returns user as JSON" do
      user = create(:user)

      get api_user_path(user), headers: { "Accept" => "application/json" }

      expect(response).to have_http_status(:ok)
      expect(response.content_type).to include("application/json")

      json = response.parsed_body
      expect(json["email"]).to eq(user.email)
    end
  end

  describe "POST /api/users" do
    it "creates user with JSON params" do
      headers = {
        "Content-Type" => "application/json",
        "Accept" => "application/json"
      }

      post api_users_path,
        params: { email: "test@example.com" }.to_json,
        headers: headers

      expect(response).to have_http_status(:created)
    end
  end
end

System Specs

Browser-based tests using Capybara:

# spec/system/user_registration_spec.rb
RSpec.describe "User Registration", type: :system do
  before do
    driven_by(:rack_test)  # Fast, no JS
    # driven_by(:selenium_chrome_headless)  # With JS
  end

  it "allows new user to register" do
    visit new_user_registration_path

    fill_in "Email", with: "newuser@example.com"
    fill_in "Password", with: "password123"
    fill_in "Password confirmation", with: "password123"
    click_button "Sign up"

    expect(page).to have_content("Welcome!")
    expect(page).to have_current_path(dashboard_path)
  end

  it "shows validation errors" do
    visit new_user_registration_path

    fill_in "Email", with: ""
    click_button "Sign up"

    expect(page).to have_content("Email can't be blank")
  end
end

JavaScript Testing

RSpec.describe "Dynamic Form", type: :system, js: true do
  before do
    driven_by(:selenium_chrome_headless)
  end

  it "adds items dynamically" do
    visit new_order_path

    click_button "Add Item"

    within "#items" do
      expect(page).to have_selector(".item", count: 1)
    end
  end

  it "filters results without page reload" do
    create(:product, name: "Widget")
    create(:product, name: "Gadget")

    visit products_path

    fill_in "Search", with: "Wid"

    expect(page).to have_content("Widget")
    expect(page).not_to have_content("Gadget")
  end
end

Capybara Matchers

# Content
expect(page).to have_content("Welcome")
expect(page).to have_text("Hello", exact: true)
expect(page).not_to have_content("Error")

# Elements
expect(page).to have_selector("div.alert")
expect(page).to have_css(".user-list li", count: 3)
expect(page).to have_xpath("//table/tr")

# Forms
expect(page).to have_field("Email")
expect(page).to have_button("Submit")
expect(page).to have_checked_field("Remember me")

# Links
expect(page).to have_link("Home", href: root_path)

# Current URL
expect(page).to have_current_path(dashboard_path)

Mailer Specs

# spec/mailers/user_mailer_spec.rb
RSpec.describe UserMailer, type: :mailer do
  describe "#welcome" do
    let(:user) { create(:user, email: "test@example.com") }
    let(:mail) { described_class.welcome(user) }

    it "renders the headers" do
      expect(mail.subject).to eq("Welcome to Our App!")
      expect(mail.to).to eq(["test@example.com"])
      expect(mail.from).to eq(["noreply@example.com"])
    end

    it "renders the body" do
      expect(mail.body.encoded).to include("Hello")
      expect(mail.body.encoded).to include(user.first_name)
    end

    it "includes unsubscribe link" do
      expect(mail.body.encoded).to include(unsubscribe_url)
    end
  end
end

Testing Email Delivery

RSpec.describe UserRegistration do
  it "sends welcome email" do
    expect {
      described_class.call(user_params)
    }.to change { ActionMailer::Base.deliveries.count }.by(1)
  end

  it "enqueues welcome email" do
    expect {
      described_class.call(user_params)
    }.to have_enqueued_mail(UserMailer, :welcome)
  end
end

Job Specs

# spec/jobs/send_newsletter_job_spec.rb
RSpec.describe SendNewsletterJob, type: :job do
  describe "#perform" do
    it "sends newsletter to all subscribers" do
      subscribers = create_list(:user, 3, subscribed: true)
      newsletter = create(:newsletter)

      expect {
        described_class.perform_now(newsletter.id)
      }.to change { ActionMailer::Base.deliveries.count }.by(3)
    end
  end

  describe "enqueuing" do
    it "enqueues job" do
      expect {
        described_class.perform_later(1)
      }.to have_enqueued_job(described_class).with(1)
    end

    it "enqueues to correct queue" do
      expect {
        described_class.perform_later(1)
      }.to have_enqueued_job.on_queue("mailers")
    end
  end
end

Rails Helper

# spec/rails_helper.rb
require "spec_helper"
ENV["RAILS_ENV"] ||= "test"
require_relative "../config/environment"
abort("Production!") if Rails.env.production?
require "rspec/rails"

Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }

RSpec.configure do |config|
  config.fixture_paths = [Rails.root.join("spec/fixtures")]
  config.use_transactional_fixtures = true
  config.infer_spec_type_from_file_location!
  config.filter_rails_from_backtrace!
end

Additional Resources

Reference Files

  • references/system-spec-patterns.md - Advanced Capybara patterns
  • references/request-spec-patterns.md - API testing patterns

Example Files

  • examples/full_request_spec.rb - Complete request spec example
  • examples/system_spec_with_js.rb - JavaScript testing example

Score

Total Score

65/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon