Updated: Rule of thumbs against flaky specs

Posted . Visible to the public. Auto-destruct in 60 days

Added additional rules of thumb highlighting common causes of test flakiness.

Changes

  • +Here are a few common patterns that will probably lead to flaky specs. If you notice them in your specs, please make sure that you have not introduced a flaky spec.
  • +
  • +## Using RSpec matchers
  • +
  • One rule of thumb I try to follow in capybara tests is using capybara matchers and not plain rspec matchers.
  • One example:
  • ```ruby
  • visit(some_page)
  • text_field = find('.textfield')
  • expect(text_field['value']).to match /pattern/
  • ```
  • This can work, but is too brittle and flaky. `match` will not retry or synchronize the value of `text_field`.
  • The equivalent code with a capybara matcher:
  • ```ruby
  • visit(some_page)
  • expect(page).to have_field('.textfield', with: /pattern/)
  • ```
  • -`have_field` will retry for and synchronize the text_field.
  • +`have_field` will retry for and synchronize the text_field.
  • +
  • +## Using `.limit(N)`
  • +
  • +If your asserting a list of records that is somehow limited via a `.limit` clause, make sure your order is deterministic, otherwise you'll receive different records in different runs. For example:
  • +
  • +```ruby
  • +# User(id bigint, ends_on: Date)
  • +User.order(:ends_on).limit(5) # Bad, because the order is not deterministic if a lot of users end on the same date
  • +
  • +User.order(:ends_on, :id).limit(5) # Better, because it takes the id into account in such a case
  • +```
  • +
  • +## Using an external ui component library
  • +
  • +If you're using an external UI component library, you've probably introduced a lot of flakyness to your spec. UI Components often introduce autoplay features, animations, take longer to initialize, are lazy loaded etc. Make sure you have a safe way to assert against the most glaring issues in your component. Often times, there's a good `aria-*` selector you can assert against. E.g.
  • +
  • +```ruby
  • +expect(page).to have_selector('.modal[aria-hidden="false"]') # wait for the modal
  • +expect(page).to have_css("[data-datepicker-loaded='true']") # make sure the datepicker is loaded before interacting with it
  • +```
  • +
Niklas Hä.
License
Source code in this card is licensed under the MIT License.
Posted by Niklas Hä. to makandra dev (2025-07-04 10:04)