{"record":{"id":"fbe855b8a0e869b8","repo":"teamcapybara/capybara","slug":"result-negative-failure-message","errorCode":null,"errorMessage":"result.negative_failure_message","messagePattern":"result\\.negative_failure_message","errorType":"exception","errorClass":"Capybara::ExpectationNotMet","httpStatus":null,"severity":"error","filePath":"lib/capybara/node/matchers.rb","lineNumber":236,"sourceCode":"      #\n      # Asserts that a given selector is not on the page or a descendant of the current node.\n      # Usage is identical to {#assert_selector}.\n      #\n      # Query options such as `:count`, `:minimum`, `:maximum`, and `:between` are\n      # considered to be an integral part of the selector. This will return\n      # `true`, for example, if a page contains 4 anchors but the query expects 5:\n      #\n      #     page.assert_no_selector('a', minimum: 1) # Found, raises Capybara::ExpectationNotMet\n      #     page.assert_no_selector('a', count: 4)   # Found, raises Capybara::ExpectationNotMet\n      #     page.assert_no_selector('a', count: 5)   # Not Found, returns true\n      #\n      # @param (see #assert_selector)\n      # @raise [Capybara::ExpectationNotMet]      If the selector exists\n      #\n      def assert_no_selector(*args, &optional_filter_block)\n        _verify_selector_result(args, optional_filter_block) do |result, query|\n          if result.matches_count? && (!result.empty? || query.expects_none?)\n            raise Capybara::ExpectationNotMet, result.negative_failure_message\n          end\n        end\n      end\n\n      ##\n      #\n      # Checks if a given XPath expression is on the page or a descendant of the current node.\n      #\n      #     page.has_xpath?('.//p[@id=\"foo\"]')\n      #\n      # By default it will check if the expression occurs at least once,\n      # but a different number can be specified.\n      #\n      #     page.has_xpath?('.//p[@id=\"foo\"]', count: 4)\n      #\n      # This will check if the expression occurs exactly 4 times.\n      #\n      # It also accepts all options that {Capybara::Node::Finders#all} accepts,","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/teamcapybara/capybara/blob/15b5fdb76e972e9623d5af2123ed3755594f9732/lib/capybara/node/matchers.rb#L218-L254","documentation":"assert_no_selector is the negated form of assert_selector: it raises ExpectationNotMet with Result#negative_failure_message ('expected NOT to find <description> ... but found N matches: ...') when the selector still matches the expected number of elements after the wait time. Because count options are part of the selector, it also raises when an expects-none query (e.g. count: 0) is satisfied — the docs show page.assert_no_selector('a', count: 5) passing with zero anchors but count: 0 with zero anchors failing.","triggerScenarios":"page.assert_no_selector('.modal') while the modal is still in the DOM; assert_no_selector('a', minimum: 1) on a page with anchors (docs example); assert_no_selector('flash', text: 'Saved') when the flash message persists; assert_no_selector('tr', count: 5) when there are exactly 5 rows; using count: 0 instead of a plain call on an empty page.","commonSituations":"Elements hidden but not removed from the DOM (modals using display:none — pair with visible: true or assert removal), frontend frameworks keeping nodes mounted, cache/session leftovers, negative assertions run too early before removal animation completes.","solutions":["Wait for actual disappearance: assert_no_selector('.modal', wait: 10) or RSpec expect(page).to have_no_selector('.modal', wait: 10)","If the node stays mounted but hidden, assert on visibility: assert_no_selector('.modal', visible: true)","Remove count options you did not intend (count: 0 flips the semantics); a bare assert_no_selector just means 'matches nothing'","Drive the UI to the state where the element is gone (click close/delete) before the negative assertion"],"exampleFix":"# before\npage.assert_no_selector('.modal')\n\n# after\nclick_button('Close')\npage.assert_no_selector('.modal', wait: 10)\n# if modal is merely hidden, not removed\npage.assert_no_selector('.modal', visible: true, wait: 10)","handlingStrategy":"validation","validationCode":"return unless page.has_selector?('.modal')\npage.assert_no_selector('.modal', wait: 10) # only assert absence while it is expected","typeGuard":"def modal_gone?(page, wait: 5)\n  !page.has_selector?('.modal', wait: wait)\nend","tryCatchPattern":"begin\n  page.assert_no_selector('.modal', wait: 10)\nrescue Capybara::ExpectationNotMet\n  page.execute_script('document.querySelector(\".modal\")&.remove()') # last-resort cleanup in test teardown\n  raise\nend","preventionTips":["Trigger removal actions before negative assertions","Distinguish hidden vs removed: pair visible: true with the right expectation","Never pass count: 0 to assert_no_selector unless you intend the inverted semantics"],"tags":["capybara","assertion","negative-assertion","selector","expectation-not-met"],"backgroundTag":"unexpected-element-present","analyzedSha":"15b5fdb76e972e9623d5af2123ed3755594f9732","analyzedAt":"2026-08-21T16:53:45.588Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}