# frozen_string_literal: true RSpec::Matchers.define :have_table_row do |row| match do |node| @row = row rows_under(node).include? row # Robust check of columns end match_when_negated do |node| @row = row rows_under(node).exclude? row # Robust check of columns end failure_message do |text| "expected to find table row #{@row}, got #{text}" end failure_message_when_negated do |_text| "expected not to find table row #{@row}" end def rows_under(node) node.all('tr').map { |tr| tr.all('th, td').map(&:text) } end end # find("#my-table").should match_table [[...]] RSpec::Matchers.define :match_table do |expected_table| match do |node| rows = node. all("tr"). map { |r| r.all("th,td").map { |c| c.text.strip } } if rows.count == expected_table.count rows.each_with_index do |row, i| expected_row = expected_table[i] if row.count != expected_row.count @failure_message = "row #{i} has #{row.count} columns, expected #{expected_row.count}" break elsif row != expected_row row.each_with_index do |cell, j| next unless cell != expected_row[j] @failure_message = "cell [#{i}, #{j}] has content '#{cell}', " \ "expected '#{expected_row[j]}'" break end break if @failure_message end end else @failure_message = "found table with #{rows.count} rows, expected #{expected_table.count}" end @failure_message.nil? end failure_message do |_text| @failure_message end end