### RSpec Configuration File Setup Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This snippet shows the recommended setup for RSpec configuration files. It includes examples for the global '.rspec' file and the project-specific '.rspec-local' file. These files control RSpec's behavior, such as enabling color output and specifying helper files to require. ```shell # .rspec --color --require spec_helper # .rspec-local --profile 2 ``` -------------------------------- ### RSpec Example Description Length Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates concise RSpec example descriptions, contrasting 'bad' verbose examples with 'good' shorter, self-documenting ones. ```ruby # bad it 'rewrites "should not return something" as "does not return something"' do # ... end # good it 'rewrites "should not return something"' do expect(rewrite('should not return something')).to eq 'does not return something' end # good - self-documenting specify do expect(rewrite('should not return something')).to eq 'does not return something' end ``` -------------------------------- ### RSpec: Simplify Hook Definitions Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec snippet illustrates the simplification of hook definitions by omitting the default `:each`/`:example` scope for `before`/`after`/`around` blocks. It promotes cleaner and more concise test setup. ```ruby # good describe '#summary' do before do # ... end # ... end ``` -------------------------------- ### Install Rouge Gem for Syntax Highlighting Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Shell command to install the 'rouge' gem, which provides syntax highlighting capabilities for generated documents. This is often used with documentation generators like Asciidoctor. ```shell gem install rouge ``` -------------------------------- ### RSpec: Single Expectation per Example Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec code showcases the practice of having a single expectation per example for improved clarity and maintainability. It contrasts with multiple expectations, highlighting the trade-off with context initialization. ```ruby # good - one expectation per example describe ArticlesController do #... describe 'GET new' do it 'assigns a new article' do get :new expect(assigns[:article]).to be_a(Article) end it 'renders the new article template' do get :new expect(response).to render_template :new end end end ``` -------------------------------- ### RSpec: Basic Example Group Structure Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates a standard RSpec `describe` block with multiple `it` examples. This structure is fundamental for organizing tests related to a specific class or module. ```ruby describe '#summary' do let(:item) { double('something') } it 'returns the summary' do # ... end it 'does something else' do # ... end it 'does another thing' do # ... end end ``` -------------------------------- ### RSpec Example Description Refactoring Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Shows how to refactor 'bad' example descriptions that end with a conditional into 'good' examples by wrapping them in a `context` block. ```ruby # bad it 'returns the display name if it is present' do # ... end # good context 'when display name is present' do it 'returns the display name' do # ... end end # This encourages the addition of negative test cases that might have # been overlooked context 'when display name is not present' do it 'returns nil' do # ... end end ``` -------------------------------- ### RSpec: Aggregated Failures in Examples Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec snippet demonstrates how to use the `:aggregate_failures` tag to group multiple expectations within a single example. This approach reduces setup overhead while providing detailed failure reports. ```ruby # good - multiple expectations with aggregated failures describe ArticlesController do #... describe 'GET new', :aggregate_failures do it 'assigns new article and renders the new article template' do get :new expect(assigns[:article]).to be_a(Article) expect(response).to render_template :new end end # ... end ``` -------------------------------- ### RSpec: Using `it_behaves_like` for Resource Tests Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec snippet demonstrates the use of `it_behaves_like` to include shared examples for common resource behaviors like listability, pagination, searchability, and filtering. ```ruby describe 'GET /devices' do let(:resource) { FactoryBot.create(:device, created_from: user) } it_behaves_like 'a listable resource' it_behaves_like 'a paginable resource' it_behaves_like 'a searchable resource' it_behaves_like 'a filterable list' end ``` -------------------------------- ### RSpec: Using `let` for Reusable Data Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Shows how to use `let` and `let!` for defining data that is reused across multiple examples within an RSpec group. `let!` is useful for ensuring variables are defined even if not explicitly referenced in all examples. ```ruby let(:tree) { Tree.new(1 => 2, 2 => 3, 2 => 6, 3 => 4, 4 => 5, 5 => 6) } it 'finds shortest path' do expect(dijkstra.shortest_path(tree, from: 1, to: 6)).to eq([1, 2, 6]) end it 'finds longest path' do expect(dijkstra.longest_path(tree, from: 1, to: 6)).to eq([1, 2, 3, 4, 5, 6]) end ``` -------------------------------- ### RSpec: Using `context` for Clarity Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates how to use `context` blocks to organize RSpec tests and make them more readable. `context` is effective for grouping examples based on specific conditions or scenarios. ```ruby # good context 'when logged in' do it { is_expected.to respond_with 200 } end context 'when logged out' do it { is_expected.to respond_with 401 } end ``` -------------------------------- ### Generate PDF and HTML Documentation with Asciidoctor Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Commands to generate PDF and HTML versions of documentation using Asciidoctor. Asciidoctor PDF is used for PDF generation, while the standard Asciidoctor command handles HTML conversion. Requires Asciidoctor to be installed. ```shell # Generates README.pdf asciidoctor-pdf -a allow-uri-read README.adoc # Generates README.html asciidoctor README.adoc ``` -------------------------------- ### RSpec 'it' vs 'specify' Usage Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Illustrates the correct usage of `it` and `specify` in RSpec tests. `specify` is recommended for examples without descriptions or when the docstring reads better with `specify`, while `it` is preferred for examples with descriptions or single-line examples. ```ruby # bad it do # ... end specify 'it sends an email' do # ... end specify { is_expected.to be_truthy } it '#do_something is deprecated' do ... end # good specify do # ... end it 'sends an email' do # ... end it { is_expected.to be_truthy } specify '#do_something is deprecated' do ... end ``` -------------------------------- ### Organize RSpec Tests with `context` Blocks Source: https://context7.com/rubocop/rspec-style-guide/llms.txt Leverages `context` blocks to organize tests based on different conditions or states, promoting clear and well-structured test suites. This allows for grouping related examples that share a common setup or scenario. ```ruby describe Article do subject(:attributes) { article.attributes } let(:article) { FactoryBot.create(:article) } context 'when display name is present' do before do article.display_name = 'something' end it { is_expected.to include(display_name: article.display_name) } end context 'when display name is not present' do before do article.display_name = nil end it { is_expected.not_to include(:display_name) } end end ``` -------------------------------- ### Refactor RSpec Tests with Shared Examples Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec example demonstrates refactoring repetitive test logic into shared examples to improve readability and reduce duplication. It shows how to use `shared_examples` and `include_examples` to DRY up tests. ```ruby describe 'GET /articles' do let(:article) { FactoryBot.create(:article, owner: owner) } before { page.driver.get '/articles' } shared_examples 'shows articles' do it 'shows all related articles' do expect(page.status_code).to be(200) contains_resource resource end end context 'when user is the owner' do let(:user) { owner } include_examples 'shows articles' end context 'when user is an admin' do let(:user) { FactoryBot.create(:user, :admin) } include_examples 'shows articles' end end ``` -------------------------------- ### RSpec Example Description Tense and Person Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Contrasts 'bad' RSpec example descriptions using 'should' with 'good' examples that use the third-person present tense. ```ruby # bad it 'should return the summary' do # ... end # good it 'returns the summary' do # ... end ``` -------------------------------- ### RSpec: Group 'let' and 'subject' Separately from 'before'/'after' Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Ruby RSpec code demonstrating how to group 'let' and 'subject' declarations separately from 'before' and 'after' blocks. This improves readability by clearly segmenting setup definitions from execution hooks. ```ruby # bad describe Article do subject { FactoryBot.create(:some_article) } let(:user) { FactoryBot.create(:user) } before do # ... end after do # ... end describe '#summary' do # ... end end # good describe Article do subject { FactoryBot.create(:some_article) } let(:user) { FactoryBot.create(:user) } before do # ... end after do # ... end describe '#summary' do # ... end end ``` -------------------------------- ### RSpec Context and Subject Initialization Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates proper use of RSpec contexts and subject initialization to improve test clarity and avoid stubbing the object under test. It shows how to correctly set up subjects and avoid common pitfalls. ```ruby describe Article do context 'when there is an author' do subject(:article) { FactoryBot.create(:article, author: user) } it 'shows other articles by the same author' do expect(article.related_stories).to include(story1, story2) end end context 'when the author is anonymous' do subject(:article) { FactoryBot.create(:article, author: nil) } it 'matches stories by title' do expect(article.related_stories).to include(story3, story4) end end end ``` ```ruby describe 'Article' do subject(:article) { Article.new } it 'indicates that the author is unknown' do allow(article).to receive(:author).and_return(nil) expect(article.description).to include('by an unknown author') end end describe 'Article' do subject(:article) { Article.new(author: nil) } it 'indicates that the author is unknown' do expect(article.description).to include('by an unknown author') end end describe 'Article' do subject(:presenter) { ArticlePresenter.new(article) } let(:article) { Article.new } it 'indicates that the author is unknown' do allow(article).to receive(:author).and_return(nil) expect(presenter.description).to include('by an unknown author') end end ``` -------------------------------- ### Simplify JSON Response Expectations in RSpec Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates how to simplify JSON response assertions in RSpec tests. The 'good' example uses the `include_json` matcher for more readable and concise checks compared to manual parsing and assertion. ```ruby it 'returns JSON with temperature in Celsius' do json = JSON.parse(response.body).with_indifferent_access expect(json[:celsius]).to eq 30 end it 'returns JSON with temperature in Fahrenheit' do json = JSON.parse(response.body).with_indifferent_access expect(json[:fahrenheit]).to eq 86 end ``` ```ruby it 'returns JSON with temperature in Celsius' do expect(response).to include_json(celsius: 30) end it 'returns JSON with temperature in Fahrenheit' do expect(response).to include_json(fahrenheit: 86) end ``` -------------------------------- ### RSpec: Order of `subject`, `let`, and Hooks Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Defines the recommended order for declaring `subject`, `let!`/`let` variables, and `before`/`after` hooks within an RSpec example group. Adhering to this order enhances test clarity. ```ruby # good describe Article do subject { FactoryBot.create(:some_article) } let(:user) { FactoryBot.create(:user) } before do # ... end after do # ... end describe '#summary' do # ... end end ``` -------------------------------- ### Reuse RSpec Code with Shared Examples Source: https://context7.com/rubocop/rspec-style-guide/llms.txt Utilizes shared examples (`shared_examples`) to eliminate duplication when multiple contexts need to verify the same behavior. This promotes DRY principles and ensures consistent testing of common functionality across different scenarios. ```ruby describe 'GET /articles' do let(:article) { FactoryBot.create(:article, owner: owner) } before { page.driver.get '/articles' } shared_examples 'shows articles' do it 'shows all related articles' do expect(page.status_code).to be(200) contains_resource resource end end context 'when user is the owner' do let(:user) { owner } include_examples 'shows articles' end context 'when user is an admin' do let(:user) { FactoryBot.create(:user, :admin) } include_examples 'shows articles' end end ``` -------------------------------- ### Efficiently Load Test Data with FactoryBot Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates creating specific test data using FactoryBot, aligning with the principle of loading only necessary data for tests. This improves test performance and clarity. ```ruby subject(:article) { FactoryBot.create(:article) } RSpec.describe User do describe ".top" do subject { described_class.top(2) } before { FactoryBot.create_list(:user, 3) } it { is_expected.to have(2).items } end end ``` -------------------------------- ### RSpec Method Description Conventions Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Shows the correct way to describe methods in RSpec using '.' for class methods and '#' for instance methods, compared to 'bad' less specific descriptions. ```ruby # bad describe 'the authenticate method for User' do # ... end describe 'if the user is an admin' do # ... end # good describe '.authenticate' do # ... end describe '#admin?' do # ... end ``` -------------------------------- ### RSpec Controller Spec: POST create Action Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec controller specification tests the 'POST create' action for ArticlesController. It mocks the Article model, stubs its methods, and tests for new article creation, saving, and redirection. The example focuses on the controller's responsibilities, not model persistence. Dependencies include RSpec and Rails controller testing utilities. ```ruby describe ArticlesController do let(:article) { double(Article) } describe 'POST create' do before { allow(Article).to receive(:new).and_return(article) } it 'creates a new article with the given attributes' do expect(Article).to receive(:new).with(title: 'The New Article Title').and_return(article) post :create, message: { title: 'The New Article Title' } end it 'saves the article' do expect(article).to receive(:save) post :create end it 'redirects to the Articles index' do allow(article).to receive(:save) post :create expect(response).to redirect_to(action: 'index') end end end ``` -------------------------------- ### RSpec: Empty Line After 'let', 'subject', 'before', 'after' Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Ruby RSpec code showing the correct placement of an empty line after 'let', 'subject', and 'before'/'after' blocks. This separation aids in distinguishing setup code from the actual test descriptions or logic. ```ruby # bad describe Article do subject { FactoryBot.create(:some_article) } describe '#summary' do # ... end end # good describe Article do subject { FactoryBot.create(:some_article) } describe '#summary' do # ... end end ``` -------------------------------- ### Refactor `any_instance_of` Usage in RSpec Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Illustrates how to refactor tests that use `allow_any_instance_of` or `expect_any_instance_of`. The 'good' example demonstrates stubbing directly on the instance instead of using `any_instance_of`, which improves clarity and avoids ambiguity. ```ruby it 'has a name' do allow_any_instance_of(User).to receive(:name).and_return('Tweedledee') expect(account.name).to eq 'Tweedledee' end ``` ```ruby let(:account) { Account.new(user) } it 'has a name' do allow(user).to receive(:name).and_return('Tweedledee') expect(account.name).to eq 'Tweedledee' end ``` -------------------------------- ### RSpec Example: Change Assertion Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates how to use the `change` matcher in RSpec to assert that a block of code modifies a specific object or value. ```ruby it 'changes something to a new value' do expect { do_something }.to change(something).to(new_value) end ``` -------------------------------- ### Define Shared Test Data with `let` in RSpec Source: https://context7.com/rubocop/rspec-style-guide/llms.txt Uses the `let` helper to define memoized test data that is lazily evaluated and shared across multiple examples within an example group. This improves test readability and reduces repetition when the same data is needed for multiple assertions. ```ruby describe Article do let(:tree) { Tree.new(1 => 2, 2 => 3, 2 => 6, 3 => 4, 4 => 5, 5 => 6) } it 'finds shortest path' do expect(dijkstra.shortest_path(tree, from: 1, to: 6)).to eq([1, 2, 6]) end it 'finds longest path' do expect(dijkstra.longest_path(tree, from: 1, to: 6)).to eq([1, 2, 3, 4, 5, 6]) end end ``` -------------------------------- ### Avoiding Implicit Block Expectations in RSpec Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Highlights the practice of avoiding implicit block expectations in RSpec. The example shows a 'bad' pattern that relies on implicit expectation and suggests a clearer alternative. ```ruby # bad subject { -> { do_something } } it { is_expected.to change(something).to(new_value) } ``` -------------------------------- ### RSpec Context Description Styles Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Illustrates the difference between 'bad' and 'good' practices for describing RSpec contexts, emphasizing readability and sentence structure. ```ruby # bad - 'Summary user logged in no display name shows a placeholder' describe 'Summary' do context 'user logged in' do context 'no display name' do it 'shows a placeholder' do end end end # good - 'Summary when the user is logged in when the display name is blank shows a placeholder' describe 'Summary' do context 'when the user is logged in' do context 'when the display name is blank' do it 'shows a placeholder' do end end end end ``` -------------------------------- ### RSpec Model Spec: Avoiding Duplication with Let Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec model specification demonstrates how to avoid duplication in model tests by using the `let` keyword to define the Article object. This ensures the article object is created once for all examples within the describe block. Dependencies include RSpec and FactoryBot. ```ruby describe Article do let(:article) { FactoryBot.create(:article) } end ``` -------------------------------- ### RSpec: Leading `subject` Declaration Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Illustrates the correct placement of the `subject` declaration within an RSpec example group. The `subject` should be the first declaration to improve readability and maintainability. ```ruby # good describe Article do subject { FactoryBot.create(:some_article) } let(:user) { FactoryBot.create(:user) } before do # ... end describe '#summary' do # ... end end ``` -------------------------------- ### RSpec Model Spec: Testing Validations (Bad Example) Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This is a 'bad' example of an RSpec model specification for testing validations. It shows how not to test validations by directly checking `be_valid` instead of the specific error on an attribute. A better approach would be to check `model.errors[:attribute].size`. Dependencies include RSpec. ```ruby describe '#title' do it 'is required' do article.title = nil expect(article).to_not be_valid end end ``` -------------------------------- ### RSpec Model Spec: Checking Model Validity Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec model specification adds an example to ensure that an Article model created with FactoryBot is valid. It uses `expect(article).to be_valid` to verify the model's validity. Dependencies include RSpec and FactoryBot. ```ruby describe Article do it 'is valid with valid attributes' do expect(article).to be_valid end end ``` -------------------------------- ### RSpec Factories with Factory Bot Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Recommends using Factory Bot for creating test data in integration tests, discouraging the use of `ModelName.create` or fixtures. This promotes maintainability and reduces the risk of brittle tests. ```ruby # bad subject(:article) do Article.create( title: 'Piccolina', author: 'John Archer', published_at: '17 August 2172', approved: true ) end ``` -------------------------------- ### RSpec: Use `:context` for Hook Scope Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec example demonstrates the correct usage of the `:context` scope for `before`/`after` hooks, replacing the ambiguous `:all` scope. It aims to improve clarity and avoid potential state leakage issues. ```ruby # good describe '#summary' do before(:context) do # ... end # ... end ``` -------------------------------- ### RSpec Assertion Syntax: expect vs should Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates the preferred RSpec assertion syntax using `expect`, contrasting it with the older `should` syntax. ```ruby # bad it 'creates a resource' do response.should respond_with_content_type(:json) end # good it 'creates a resource' do expect(response).to respond_with_content_type(:json) end ``` -------------------------------- ### RSpec: Single Empty Line Between Example Groups Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Ruby RSpec code illustrating the correct placement of empty lines between 'feature', 'context', or 'describe' blocks. A single empty line should separate these groups, but no empty line should follow the last group within a parent block. ```ruby # bad describe Article do describe '#summary' do context 'when there is a summary' do # ... end context 'when there is no summary' do # ... end end describe '#comments' do # ... end end # good describe Article do describe '#summary' do context 'when there is a summary' do # ... end context 'when there is no summary' do # ... end end describe '#comments' do # ... end end ``` -------------------------------- ### Declaring Constants Safely in RSpec Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Explains how to manage constants within RSpec examples to avoid global namespace pollution. It shows the 'bad' practice of direct declaration and the 'good' practices of stubbing constants or using anonymous classes. ```ruby # bad describe SomeClass do CONSTANT_HERE = 'I leak into global namespace' end # good describe SomeClass do before do stub_const('CONSTANT_HERE', 'I only exist during this example') end end # bad describe SomeClass do class FooClass < described_class def double_that some_base_method * 2 end end it { expect(FooClass.new.double_that).to eq(4) } end # good - anonymous class, no constant needs to be defined describe SomeClass do let(:foo_class) do Class.new(described_class) do def double_that some_base_method * 2 end end end it { expect(foo_class.new.double_that).to eq(4) } end # good - constant is stubbed describe SomeClass do before do foo_class = Class.new(described_class) do def do_something end end stub_const('FooClass', foo_class) end it { expect(FooClass.new.double_that).to eq(4) } end ``` -------------------------------- ### RSpec Controller Spec: POST create with Contexts Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec controller specification demonstrates the use of 'context' for testing different behaviors of the 'POST create' action in ArticlesController. It covers scenarios where the article saves successfully or fails to save, testing flash messages, redirects, and template re-renders. Dependencies include RSpec and Rails controller testing utilities. ```ruby describe ArticlesController do let(:article) { double(Article) } describe 'POST create' do before { allow(Article).to receive(:new).and_return(article) } it 'creates a new article with the given attributes' do expect(Article).to receive(:new).with(title: 'The New Article Title').and_return(article) post :create, article: { title: 'The New Article Title' } end it 'saves the article' do expect(article).to receive(:save) post :create end context 'when the article saves successfully' do before do allow(article).to receive(:save).and_return(true) end it 'sets a flash[:notice] message' do post :create expect(flash[:notice]).to eq('The article was saved successfully.') end it 'redirects to the Articles index' do post :create expect(response).to redirect_to(action: 'index') end end context 'when the article fails to save' do before do allow(article).to receive(:save).and_return(false) end it 'assigns @article' do post :create expect(assigns[:article]).to eq(article) end it "re-renders the 'new' template" do post :create expect(response).to render_template('new') end end end end ``` -------------------------------- ### Using Shoulda Matchers for Model Validations in RSpec Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Shows the benefit of using the Shoulda Matchers library for simplifying model validation tests. The 'good' example uses `validate_presence_of` for a more declarative and readable test compared to manually checking errors. ```ruby describe '#title' do it 'is required' do article.title = nil article.valid? expect(article.errors[:title]) .to contain_exactly('Article has no title') not end end ``` ```ruby describe '#title' do it 'is required' do expect(article).to validate_presence_of(:title) .with_message('Article has no title') end end ``` -------------------------------- ### RSpec: Use `subject` for Repetitive Tests Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec example illustrates the effective use of the `subject` keyword to reduce repetition when multiple tests relate to the same object or value. It improves code conciseness and readability. ```ruby # good subject(:equipment) { hero.equipment } it { expect(equipment).to be_heavy } it { expect(equipment).to include 'sword' } ``` -------------------------------- ### Define and Use Custom Matchers in RSpec Source: https://context7.com/rubocop/rspec-style-guide/llms.txt Shows how to create custom RSpec matchers to encapsulate complex or frequently used assertions, improving test readability. The example defines a matcher `include_json` for checking JSON response content and then demonstrates its usage in controller tests. ```ruby # Define a custom matcher RSpec::Matchers.define :include_json do |expected| match do |actual| json = JSON.parse(actual.body).with_indifferent_access expected.all? { |key, value| json[key] == value } end end # Use the custom matcher describe WeatherController do it 'returns JSON with temperature in Celsius' do expect(response).to include_json(celsius: 30) end it 'returns JSON with temperature in Fahrenheit' do expect(response).to include_json(fahrenheit: 86) end end ``` -------------------------------- ### Handling Time in RSpec with Timecop Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Shows the recommended approach for managing time-based tests in RSpec using the Timecop gem. It contrasts the preferred Timecop method with the less desirable direct stubbing of `Time.now`. ```ruby describe InvoiceReminder do subject(:time_with_offset) { described_class.new.get_offset_time } # bad it 'offsets the time 2 days into the future' do current_time = Time.now allow(Time).to receive(:now).and_return(current_time) expect(time_with_offset).to eq(current_time + 2.days) end # good it 'offsets the time 2 days into the future' do Timecop.freeze(Time.now) do expect(time_with_offset).to eq 2.days.from_now end end end ``` -------------------------------- ### RSpec Predicate Matcher Usage Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Illustrates the use of RSpec's predicate matchers for cleaner assertions, showing 'bad' manual boolean checks versus 'good' direct predicate matching. ```ruby describe Article do subject(:article) { FactoryBot.create(:article) } # bad it 'is published' do expect(article.published?).to be true end # good it 'is published' do expect(article).to be_published end # even better it { is_expected.to be_published } end ``` -------------------------------- ### RSpec: Named Subjects in Different Contexts Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec example highlights the importance of using distinct names for `subject` when its attributes are redefined in different contexts. This practice improves test clarity by making it evident which subject is being tested. ```ruby # Example demonstrating named subjects in different contexts # (Actual code would follow, showing different subject names) # describe User do # context 'when admin' do # subject(:admin_user) { FactoryBot.create(:user, :admin) } # it { expect(admin_user).to be_admin } # end # # context 'when regular user' do # subject(:regular_user) { FactoryBot.create(:user) } # it { expect(regular_user).not_to be_admin } # end # end ``` -------------------------------- ### RSpec Model Spec: FactoryBot Creation and Persistence Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec model specification tests the creation and persistence of an Article model using FactoryBot. It ensures the created object is an instance of Article and is persisted in the database. Dependencies include RSpec and FactoryBot. ```ruby describe Article do subject(:article) { FactoryBot.create(:article) } it { is_expected.to be_an Article } it { is_expected.to be_persisted } end ``` -------------------------------- ### RSpec 'be' Matcher Usage Guidelines Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Explains when to avoid the generic `be` matcher and recommends using `be_truthy`, `be_nil`, or type-specific matchers for clarity. ```ruby # bad it 'has author' do expect(article.author).to be end # good it 'has author' do expect(article.author).to be_truthy # same as the original expect(article.author).not_to be_nil # `be` is often used to check for non-nil value expect(article.author).to be_an(Author) # explicit check for the type of the value end ``` -------------------------------- ### RSpec View Spec: Stubbing Helper Methods Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Explains how to stub helper methods within RSpec view specs when a view relies on them. The example shows how to stub the `formatted_date` helper method on the `template` object to control its behavior during the test. ```ruby # app/helpers/articles_helper.rb class ArticlesHelper def formatted_date(date) # ... end end ``` ```ruby # app/views/articles/show.html.erb <%= 'Published at: #{formatted_date(@article.published_at)}' %> ``` ```ruby # spec/views/articles/show.html.erb_spec.rb describe 'articles/show.html.erb' do let(:article) { Article.new(published_at: Time.current) } before do assign(:article, article) allow(template).to receive(:formatted_date) { '2023-10-27' } end it 'displays the formatted publication date' do render expect(rendered).to include('Published at: 2023-10-27') end end ``` -------------------------------- ### RSpec: Avoid Empty Lines After 'describe', 'context', 'feature' Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Ruby RSpec code demonstrating the incorrect and correct way to format empty lines after 'describe', 'context', or 'feature' blocks. The guideline is to not leave empty lines immediately following these block starters to maintain code density and readability. ```ruby # bad describe Article do describe '#summary' do context 'when there is a summary' do it 'returns the summary' do # ... end end end end # good describe Article do describe '#summary' do context 'when there is a summary' do it 'returns the summary' do # ... end end end end ``` -------------------------------- ### Specify Object Under Test with `subject` in RSpec Source: https://context7.com/rubocop/rspec-style-guide/llms.txt Employs the named `subject` helper to reduce repetition when multiple tests reference the same object under test. This approach enhances clarity by explicitly defining the primary object being tested in each example group. ```ruby describe Article do subject(:article) { FactoryBot.create(:article) } it 'is not published on creation' do expect(article).not_to be_published end it 'has a valid factory' do expect(article).to be_valid end end ``` -------------------------------- ### RSpec Avoiding Incidental State Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Contrasts tests that rely on incidental state with tests that use RSpec's change matcher. The 'good' example uses `change` to directly assert the expected modification, making the test more robust and less prone to errors caused by shared state. ```ruby # bad it 'publishes the article' do article.publish # Creating another shared Article test object above would cause this # test to break expect(Article.count).to eq(2) end # good it 'publishes the article' do expect { article.publish }.to change(Article, :count).by(1) end ``` -------------------------------- ### RSpec View Spec: Rendering and Form Actions Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates how to write RSpec view specs in Rails, focusing on rendering a view and asserting the presence and attributes of a form element. It uses `assign` to mock instance variables and Capybara selectors to inspect the rendered HTML. ```ruby describe 'articles/edit.html.erb' do it 'renders the form for a new article creation' do assign(:article, double(Article).as_null_object) render expect(rendered).to have_selector('form', method: 'post', action: articles_path ) do |form| expect(form).to have_selector('input', type: 'submit') end end end ``` -------------------------------- ### RSpec Built-in Matcher for String Inclusion Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Shows the advantage of using built-in RSpec matchers like `include` for string assertions, comparing it to manual string inclusion checks. ```ruby # bad it 'includes a title' do expect(article.title.include?('a lengthy title')).to be true end # good it 'includes a title' do expect(article.title).to include 'a lengthy title' end ``` -------------------------------- ### Stubbing Time with Timecop in RSpec Source: https://context7.com/rubocop/rspec-style-guide/llms.txt Demonstrates how to use the Timecop gem to control time within tests, making time-dependent logic predictable. Instead of directly stubbing `Time` or `Date`, Timecop provides a cleaner way to freeze or travel through time. The example checks if a method correctly calculates a future time. ```ruby describe InvoiceReminder do subject(:time_with_offset) { described_class.new.get_offset_time } it 'offsets the time 2 days into the future' do Timecop.freeze(Time.now) do expect(time_with_offset).to eq 2.days.from_now end end end ``` -------------------------------- ### Test Model Validations with RSpec Source: https://context7.com/rubocop/rspec-style-guide/llms.txt Tests that model validations are correctly implemented. It checks for required attributes and uniqueness constraints. Ensure FactoryBot is available for building model instances. ```ruby describe Article do let(:article) { FactoryBot.build(:article) } describe '#title' do it 'is required' do article.title = nil article.valid? expect(article.errors[:title].size).to eq(1) end end describe '#name' do it 'is unique' do FactoryBot.create(:article, name: 'Unique Name') another_article = FactoryBot.build(:article, name: 'Unique Name') another_article.valid? expect(another_article.errors[:name].size).to eq(1) end end end ``` -------------------------------- ### Using Verifying Doubles in RSpec Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Illustrates the use of verifying doubles (instance_double, object_double, class_double) in RSpec for more robust testing. Verifying doubles ensure methods exist and are called with correct arguments, reducing test fragility. ```ruby # good - verifying instance double article = instance_double('Article') allow(article).to receive(:author).and_return(nil) presenter = described_class.new(article) expect(presenter.title).to include('by an unknown author') # good - verifying object double article = object_double(Article.new, valid?: true) expect(article.save).to be true # good - verifying partial double allow(Article).to receive(:find).with(5).and_return(article) # good - verifying class double notifier = class_double('Notifier') expect(notifier).to receive(:notify).with('suspended as') ``` -------------------------------- ### View Testing with Assign in RSpec Source: https://context7.com/rubocop/rspec-style-guide/llms.txt Tests the rendering of ERB views by assigning instance variables and asserting on the generated HTML. It uses `assign` to set up view context and `rendered` to inspect the output. This snippet specifically tests an article edit form. ```ruby describe 'articles/edit.html.erb' do it 'renders the form for article editing' do assign(:article, double(Article).as_null_object) render expect(rendered).to have_selector('form', method: 'post', action: articles_path ) do |form| expect(form).to have_selector('input', type: 'submit') end end end ``` -------------------------------- ### RSpec: Preferring `let` over Instance Variables Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Recommends using `let` definitions instead of instance variables in RSpec tests. This practice leads to cleaner code and avoids potential issues associated with instance variable scope. ```ruby # good let(:name) { 'John Wayne' } it 'reverses a name' do expect(reverser.reverse(name)).to eq('enyaW nhoJ') end ``` -------------------------------- ### RSpec View Spec: Displaying Formatted Date Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec view specification tests the display of a formatted article publishing date. It mocks an Article object, assigns it to the template, stubs a helper method for date formatting, renders the template, and asserts the expected content is present. Dependencies include RSpec and Rails view testing utilities. ```ruby describe 'articles/show.html.erb' do it 'displays the formatted date of article publishing' do article = double(Article, published_at: Date.new(2012, 01, 01)) assign(:article, article) allow(template).to_receive(:formatted_date).with(article.published_at).and_return('01.01.2012') render expect(rendered).to have_content('Published at: 01.01.2012') end end ``` -------------------------------- ### RSpec Mailer Expectations for Subscription Registration Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc This RSpec snippet demonstrates how to test mailers, specifically for a successful registration email. It mocks the subscriber model and sets expectations for the email's subject, sender, recipient, and content. The test verifies that the email is correctly formatted and contains personalized information. ```ruby describe SubscriberMailer do let(:subscriber) { double(Subscription, email: 'johndoe@test.com', name: 'John Doe') } describe 'successful registration email' do subject(:email) { SubscriptionMailer.successful_registration_email(subscriber) } it { is_expected.to have_attributes(subject: 'Successful Registration!', from: ['infor@your_site.com'], to: [subscriber.email]) } it 'contains the subscriber name' do expect(email.body.encoded).to match(subscriber.name) end end end ``` -------------------------------- ### Generate Test Data with FactoryBot in RSpec Source: https://context7.com/rubocop/rspec-style-guide/llms.txt Demonstrates the use of FactoryBot to create test data objects with valid attributes, avoiding brittle manual object construction. This practice ensures tests use realistic and well-formed data, leading to more reliable test outcomes. ```ruby describe Article do # Use FactoryBot for integration tests subject(:article) { FactoryBot.create(:article) } it { is_expected.to be_an Article } it { is_expected.to be_persisted } context 'with multiple articles' do before { FactoryBot.create_list(:article, 3) } it 'retrieves top articles' do expect(Article.top(2)).to have(2).items end end end ``` -------------------------------- ### RSpec: `context` Cases with Opposite Negatives Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Emphasizes the importance of including opposite negative cases for `context` blocks to ensure comprehensive test coverage. This practice helps identify potential issues and refactoring needs. ```ruby # good describe '#attributes' do subject(:attributes) { article.attributes } let(:article) { FactoryBot.create(:article) } context 'when display name is present' do before do article.display_name = 'something' end it { is_expected.to include(display_name: article.display_name) } end context 'when display name is not present' do before do article.display_name = nil end it { is_expected.not_to include(:display_name) } end end ``` -------------------------------- ### Implement Strict Mocking with Verifying Doubles in RSpec Source: https://context7.com/rubocop/rspec-style-guide/llms.txt Applies verifying doubles (`instance_double`) for stricter mocking, which fails if methods don't exist or are called with incorrect arguments. This enhances test robustness by ensuring mocks accurately reflect the expected interface of the double. ```ruby describe ArticlePresenter do it 'handles articles with unknown authors' do # Verifying instance double ensures 'author' method exists on Article article = instance_double('Article') allow(article).to receive(:author).and_return(nil) presenter = described_class.new(article) expect(presenter.title).to include('by an unknown author') end end ``` -------------------------------- ### Capybara Negative Selectors in RSpec View Specs Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Highlights the preference for using Capybara's negative selectors (e.g., `have_no_selector`) over combining `expect` with `to_not`. This approach leads to more readable and idiomatic Capybara assertions. ```ruby # bad expect(page).to_not have_selector('input', type: 'submit') expect(page).to_not have_xpath('tr') # good expect(page).to have_no_selector('input', type: 'submit') expect(page).to have_no_xpath('tr') ``` -------------------------------- ### Stubbing HTTP Requests in RSpec with WebMock Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates how to stub external HTTP requests within RSpec tests using the `webmock` gem. This prevents tests from making actual network calls, ensuring reliability and speed. ```ruby context 'with unauthorized access' do let(:uri) { 'http://api.lelylan.com/types' } before { stub_request(:get, uri).to_return(status: 401, body: fixture('401.json')) } it 'returns access denied' do page.driver.get uri expect(page).to have_content 'Access denied' end end ``` -------------------------------- ### RSpec Avoiding Iterators for Test Generation Source: https://github.com/rubocop/rspec-style-guide/blob/master/README.adoc Demonstrates why using iterators to generate RSpec tests is discouraged. It shows that breaking down tests into individual `describe` blocks for each case improves maintainability and makes it easier for developers to manage their changes. ```ruby # bad [:new, :show, :index].each do |action| it 'returns 200' do get action expect(response).to be_ok end end # good - more verbose, but better for the future development describe 'GET new' do it 'returns 200' do get :new expect(response).to be_ok end end describe 'GET show' do it 'returns 200' do get :show expect(response).to be_ok end end describe 'GET index' do it 'returns 200' do get :index expect(response).to be_ok end end ```