teamcapybara/capybara · error · Capybara::ExpectationNotMet

result.failure_message

Error message

result.failure_message

What it means

Node::Finders#all raises Capybara::ExpectationNotMet (message built by Result#failure_message: 'expected to find <description> ... but there were no matches' or 'found N matches: ...') when the number of resolved elements does not satisfy the count options after waiting. `all` injects minimum: 1 unless you pass :count, :minimum or :between, so even finding zero plain elements can raise. It retries inside synchronize(query.wait) until the deadline before giving up.

Solutions

  1. Verify the actual count first (page.all('li').size) and align the count option with reality
  2. Raise the wait: page.all('li', count: 3, wait: 5) or Capybara.default_max_wait_time = 5
  3. Relax the constraint to minimum:/between: when exact count is brittle (e.g. between: 2..4)
  4. If items are filtered out by :text/:visible, remove or correct the filter so intended items count

Example fix

# before
page.all('li.item', count: 3)

# after
page.all('li.item', count: 3, wait: 5)
# or tolerate async loading
page.all('li.item', minimum: 3, wait: 5)
Defensive patterns

Strategy: retry

Validate before calling

expected = 3
found = page.all('li.item', wait: 5).size
page.all('li.item', count: expected) if found == expected

Try / catch

begin
  page.all('li.item', count: 3, wait: 5)
rescue Capybara::ExpectationNotMet => e
  puts "actual: #{page.all('li.item').size} — #{e.message}"
  raise
end

Prevention

When it happens

Trigger: page.all('li', count: 3) when the list has 2 or 4 items; page.all('.item', minimum: 5) on a partially rendered list; page.all('td') inside a table that has not rendered yet within default_max_wait_time. Note the rescue in the source: when only the implicit minimum: 1 applies and too many elements were found (Result#compare_count == 1), `all` silently returns an empty Result instead of raising.

Common situations: Async/paged content still loading when the count is taken; wrong expectation of item count after filtering; slow CI making the built-in wait too short; mixed-content lists where some items match filters (:text, :visible) and others do not — the failure message lists 'Also found ... which matched the selector but not all filters'.

Related errors


AI-assisted analysis of teamcapybara/capybara@15b5fdb76e (2026-08-21). Data as JSON: /api/errors/d73d54cc80a6b440. Report an issue: GitHub.

Appendix: source

Thrown at lib/capybara/node/finders.rb:267

      #   When `true` allows elements to be reloaded if they become stale. This is an advanced behavior and should only be used
      #   if you fully understand the potential ramifications. The results can be confusing on dynamic pages. Defaults to `false`
      # @overload all([kind = Capybara.default_selector], locator = nil, **options)
      # @overload all([kind = Capybara.default_selector], locator = nil, **options, &filter_block)
      #   @yieldparam element [Capybara::Node::Element]  The element being considered for inclusion in the results
      #   @yieldreturn [Boolean]                     Should the element be considered in the results?
      # @return [Capybara::Result]                   A collection of found elements
      # @raise [Capybara::ExpectationNotMet]         The number of elements found doesn't match the specified conditions
      def all(*args, allow_reload: false, **options, &optional_filter_block)
        minimum_specified = options_include_minimum?(options)
        options = { minimum: 1 }.merge(options) unless minimum_specified
        options[:session_options] = session_options
        query = Capybara::Queries::SelectorQuery.new(*args, **options, &optional_filter_block)
        result = nil
        begin
          synchronize(query.wait) do
            result = query.resolve_for(self)
            result.allow_reload! if allow_reload
            raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?

            result
          end
        rescue Capybara::ExpectationNotMet
          raise if minimum_specified || (result.compare_count == 1)

          Result.new([], nil)
        end
      end
      alias_method :find_all, :all

      ##
      #
      # Find the first element on the page matching the given selector
      # and options. By default {#first} will wait up to {Capybara.configure default_max_wait_time}
      # seconds for matching elements to appear and then raise an error if no matching
      # element is found, or `nil` if the provided count options allow for empty results.
      #

View on GitHub (pinned to 15b5fdb76e)