teamcapybara/capybara · error · Capybara::ExpectationNotMet
Item matched the provided selector
Error message
Item matched the provided selector
What it means
assert_not_matches_selector is the inverse of assert_matches_selector: it raises ExpectationNotMet 'Item matched the provided selector' when the receiver element DOES match the selector plus filters, which the caller expected it not to. Same MatchQuery machinery (_verify_match_result), inverted condition on result.include?(self).
Source
Thrown at lib/capybara/node/matchers.rb:604
# @raise [Capybara::ExpectationNotMet] If the selector does not match
#
def assert_matches_selector(*args, &optional_filter_block)
_verify_match_result(args, optional_filter_block) do |result|
raise Capybara::ExpectationNotMet, 'Item does not match the provided selector' unless result.include? self
end
end
##
#
# Asserts that the current node does not match a given selector.
# Usage is identical to {#assert_matches_selector}.
#
# @param (see #assert_matches_selector)
# @raise [Capybara::ExpectationNotMet] If the selector matches
#
def assert_not_matches_selector(*args, &optional_filter_block)
_verify_match_result(args, optional_filter_block) do |result|
raise Capybara::ExpectationNotMet, 'Item matched the provided selector' if result.include? self
end
end
##
#
# Checks if the current node matches given selector.
#
# @param (see #has_selector?)
# @return [Boolean]
#
def matches_selector?(*args, **options, &optional_filter_block)
make_predicate(options) { assert_matches_selector(*args, options, &optional_filter_block) }
end
##
#
# Checks if the current node matches given XPath expression.
#View on GitHub (pinned to 15b5fdb76e)
Solutions
- Check the element's actual state (el[:class], el.checked?) and adjust the expectation or drive the UI to change it first
- Add wait for state transitions: assert_not_matches_selector('li', '.active', wait: 3) — note match queries reject count options, not wait
- Use exact text if partial matching causes false positives: assert_not_matches_selector('a', text: 'Delete', exact_text: true)
- Confirm you are asserting on the intended element instance (re-find after DOM replacement)
Example fix
# before
row.assert_not_matches_selector('tr', '.selected') # still selected
# after
click_link('Unselect')
row.assert_not_matches_selector('tr', '.selected', wait: 3) Defensive patterns
Strategy: validation
Validate before calling
return if el.matches_selector?('li', '.active') # nothing to assert
el.assert_not_matches_selector('li', '.active') Type guard
def node_free_of?(node, *args, **opts, &block) node.not_matches_selector?(*args, **opts, &block) end
Try / catch
begin
el.assert_not_matches_selector('a', text: 'Delete', exact_text: true, wait: 3)
rescue Capybara::ExpectationNotMet
# node unexpectedly matches — drive UI to clear state, then re-check once
el.assert_not_matches_selector('a', text: 'Delete', exact_text: true, wait: 5)
end Prevention
- Use exact_text: true so partial text matches do not trip the negative assertion
- Perform the state-clearing action before asserting not-matching
- Prefer not_matches_selector? predicate in conditional test flows
When it happens
Trigger: el.assert_not_matches_selector('li') on an element that is an li; assert_not_matches_selector('a', text: 'Delete') where the text matches exactly; asserting not-checked with assert_not_matches_selector('input', checked: true) while the checkbox is indeed checked; verifying an element lost a class ('.active') while the class is still applied.
Common situations: Guard assertions that a node no longer carries a state (active/disabled/selected) that in fact persists, copy changes making text filters match again, class-removal transitions not yet applied at assert time.
Related errors
- Item does not match the provided selector
- result.negative_failure_message
- query.negative_failure_message
- result.failure_message
- query.failure_message
AI-assisted analysis of teamcapybara/capybara@15b5fdb76e (2026-08-21).
Data as JSON: /api/errors/25f4d078b86a922b.
Report an issue: GitHub.