---
title: Avoid Merging RSpec "Focused" Tests
teaser: 'Use RSpec''s Focus filter without fear of accidentally turning CI into a
  single-test false positive.

  '
tags: rspec,testing
author: Stephanie Viccari
published_on: 2023-02-02
---

I enjoy using the [RSpec Focus filter] to run a specific test or subset of
tests. However, I often forget to remove this filter, which leaves the tests in
a "focused" state. On a good day, I notice the issue and remove the filter. On a
bad day, I don't notice the issue and merge my changes, leaving RSpec in a
"focused" state and causing CI to ignore the majority of the test suite.

![Gif of a grey cat, sitting on a window sill in a trance, focused
on something in front of them as a person waves their hand in front of the cat's
eyes, while the cat ignores their hand and continues to stare off into the distance.](https://images.thoughtbot.com/blog-vellum-image-uploads/NjrQ3t8YSEmsYCAYf81N_focused-cat.gif)

Before we restore RSpec's attention, let's review how to use the RSpec Focus
filter.

```rb
# run a specific test by adding the "focus" metadata
it "tells RSpec to run this test and this test only", focus: true do
end

# use the alias `fit`, `fdescribe`, or `fcontext`
fit "tells RSpec to run this test and this test only" do
end
```

To execute focused tests, use either of the following commands:

```
rspec

rspec --tag focus
```

## Option 1: Use RuboCop to Catch Focused Tests

[RuboCop] provides an RSpec extension that checks for focused tests. If your
team already uses RuboCop, follow the [rubocop-rspec] installation instructions
and RuboCop will notify you when a focused test exists.

### Run RuboCop for each Pull Request

Running RuboCop locally is great, but it's still possible that our future self
(or colleagues) will forget to run RuboCop locally and commit a focused test. To
prevent focused tests from being merged, we can include RuboCop as part of
the Pull Request process.

Using GitHub as an example, let's create a GitHub Action to run Rubocop and a
Branch Protection Rule to prevent the Pull Request from being merged.

1. Add a GitHub Action that runs RuboCop:

```yml
# github/workflows/rubocop.yml

name: RuboCop
on:
  pull_request:
    branches:
      - main
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up Ruby
      uses: ruby/setup-ruby@v1
      with:
        bundler-cache: true
    - name: Run Rubocop
      run: bundle exec rubocop
```

2. Add a GitHub Branch Protection Rule

To add a rule, visit "Settings", then "Branches", and then select the option to
add a rule. From here, set the "Branch name pattern" to name of the branch you
wish to protect. For example, if you wish to protect the "main" branch, set the
branch name pattern to "main".

Next, enable the "Require status checks to pass before merging" option. In the
"Search for status checks" field, search for the name of the job (in this
example, the name of the job is "lint"). If you run into any issues, consult the
GitHub documentation: [About branch protection rules].

![Image that shows a GitHub form with the option "Require status checks to pass before merging" selected.](https://images.thoughtbot.com/blog-vellum-image-uploads/hjw1EaI8TqmMZruXUpFK_github-require-status-check-before-merging.png)

Once the GitHub Action and Branch Protection Rule are completed, attempting to
merge a Pull Request that has not successfully passed RuboCop will look like
this:

![Screenshot of a GitHub Pull Request that includes the text "All checks have failed" and the "Merge pull request" button is disabled.](https://images.thoughtbot.com/blog-vellum-image-uploads/m8q7AkJ4QZaYevEtPbwy_github-block-merging-for-failed-status-checks.png)

### Use the RuboCop RSpec Extension in Isolation

If your team uses a tool other than RuboCop, you can still use the
[rubocop-rspec] extension without adding all of RuboCop's opinions. Steps below.

1. Follow the [rubocop-rspec] installation instructions
2. At the root of your project, create a new file named `.rubocop.yml`
3. In the `.rubocop.yml` file, disable default warnings and enable the RSpec
   Focus warning. Your `.rubocop.yml` file will look something like this:

```yml
require: rubocop-rspec

# Turn all Rubocop rules off by default
AllCops:
  DisabledByDefault: true

# Turn on the RSpec/Focus rule
RSpec/Focus:
  Enabled: true
```

## Option 2: Use RSpec to Catch Focused Tests

Another option is to instruct RSpec to raise when a test includes the Focus
metadata. (Thank you to [Marz Drel] for this suggestion.)

```rb
# spec/rails_helper.rb

RSpec.configure do |config|
  if ENV["CI"]
    config.before(:example, :focus) { |example| raise "Focused spec found at
#{example.location}" }
  else
    config.filter_run_when_matching :focus
  end
end
```

If you prefer the RSpec approach, don't forget to include "green tests" as part
of your Pull Request process. ✅

Hooray! Now, using RuboCop or RSpec, we can alert the team when a Focus filter
needs to be removed and ensure all of our tests are hard at work.

![Gif of an orange kitten, sitting on an open laptop and nodding their head, creating the impression that they're reading the content on the screen.](https://images.thoughtbot.com/blog-vellum-image-uploads/hFAqtG1TVuZKtgcjkRRt_busy-cat.gif)

[RSpec Focus filter]: https://relishapp.com/rspec/rspec-core/v/3-10/docs/filtering/filter-run-when-matching
[https://github.com/rubocop/rubocop-rspec]: https://github.com/rubocop/rubocop
[rubocop-rspec]: https://github.com/rubocop/rubocop-rspec
[Rubocop]: https://github.com/rubocop
[Marz Drel]: https://twitter.com/marzdrel/status/1459119991278690305
[About branch protection rules]: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule
