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
- 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.
- Tighten an over-broad Regexp: assert_no_current_path('/login') or a specific %r{\A/login\z} instead of %r{/}.
- Extend the wait for slow redirects: have_no_current_path('/login', wait: 5).
- 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
- Never assert no_current_path before performing the action that should navigate away.
- Avoid over-broad regexps like %r{/}; they match every path and make the negative assertion unsatisfiable.
- For SPAs that keep the path and swap content, assert on disappearing content (have_no_selector) instead of the path.
- Include a wait budget (wait: n) on negative path assertions in redirect-heavy flows.
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
- query.failure_message
- result.failure_message
- query.failure_message
- res.join(' or ')
- result.negative_failure_message
AI-assisted analysis of teamcapybara/capybara@15b5fdb76e (2026-08-21).
Data as JSON: /api/errors/cb01b63c8a27f573.
Report an issue: GitHub.