teamcapybara/capybara · error · Capybara::ExpectationNotMet

query.negative_failure_message

Error message

query.negative_failure_message

What it means

Raised by Session#assert_no_current_path (and the have_no_current_path matcher) when the current path or URL STILL equals/matches the given String/Regexp after the wait time expires. It is the negative expectation: Capybara polls until the path stops resolving, and if it never does, raises Capybara::ExpectationNotMet with the query's negative_failure_message.

Source

Thrown at lib/capybara/session/matchers.rb:40

    def assert_current_path(path, **options, &optional_filter_block)
      _verify_current_path(path, optional_filter_block, **options) do |query|
        raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
      end
    end

    ##
    # Asserts that the page doesn't have the given path.
    # By default, if passed a full url this will compare against the full url,
    # if passed a path only the path+query portion will be compared, if passed a regexp
    # the comparison will depend on the :url option
    #
    # @macro current_path_query_params
    # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
    # @return [true]
    #
    def assert_no_current_path(path, **options, &optional_filter_block)
      _verify_current_path(path, optional_filter_block, **options) do |query|
        raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self)
      end
    end

    ##
    # Checks if the page has the given path.
    # By default, if passed a full url this will compare against the full url,
    # if passed a path only the path+query portion will be compared, if passed a regexp
    # the comparison will depend on the :url option
    #
    # @macro current_path_query_params
    # @return [Boolean]
    #
    def has_current_path?(path, **options, &optional_filter_block)
      make_predicate(options) { assert_current_path(path, **options, &optional_filter_block) }
    end

    ##
    # Checks if the page doesn't have the given path.

View on GitHub (pinned to 15b5fdb76e)

Solutions

  1. Make sure the action that navigates away (click_link/click_button) has run before the negative assertion, so the matcher's polling observes the change.
  2. Tighten an over-broad Regexp: assert_no_current_path('/login') or a specific %r{\A/login\z} instead of %r{/}.
  3. Extend the wait for slow redirects: have_no_current_path('/login', wait: 5).
  4. If the path is genuinely expected to stay, invert the assertion to have_current_path and assert on content changes instead.

Example fix

# before
expect(page).to have_no_current_path(%r{/}) # always matches every path -> always raises

# after
expect(page).to have_no_current_path('/login')
Defensive patterns

Strategy: retry

Validate before calling

# Trigger and confirm the navigation first, then assert the negative
click_button 'Log out'
expect(page).to have_selector('.flash', text: 'Signed out')
expect(page).to have_no_current_path('/login')

Type guard

def still_on_path?(expected)
  page.current_path == expected || page.current_path.match?(expected.is_a?(Regexp) ? expected : /\A#{Regexp.escape(expected)}\z/)
end

Try / catch

begin
  expect(page).to have_no_current_path('/login', wait: 2)
rescue Capybara::ExpectationNotMet
  # The navigation never happened; re-trigger it once, then retry the assertion
  click_button 'Log out' if page.has_button?('Log out')
  retry
end

Prevention

When it happens

Trigger: expect(page).to have_no_current_path('/login') after a login-submit that should navigate away, but the page stays on '/login'; page.assert_no_current_path(%r{/}) where the regexp matches every path, so it can never stop matching.

Common situations: Logout or redirect flows where navigation never fires (JS error, prevented submit); overly broad regexps such as %r{/} that match any path; asserting the negative before the navigating action has been performed; single-page apps that change content without changing the path.

Related errors


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