RSpec::Matchers.define :have_flash_message do |message| match do |node| @message, @node = message, node # Ignore leading and trailing whitespace. Later versions of Capybara have :exact_text option. # The :exact option is not supported in has_selector?. message_substring_regex = substring_match_regex(message) node.has_selector?(".flash", text: message_substring_regex, visible: false) end failure_message do |_actual| "expected to find flash message ##{@message}" end match_when_negated do |node| @message, @node = message, node # Ignore leading and trailing whitespace. Later versions of Capybara have :exact_text option. # The :exact option is not supported in has_selector?. message_substring_regex = substring_match_regex(message) node.has_no_selector?(".flash", text: message_substring_regex, visible: false) end failure_message_when_negated do |_actual| "expected not to find flash message ##{@message}" end def substring_match_regex(text) /\A\s*#{Regexp.escape(text)}\s*\Z/ end end