Created
May 4, 2018 18:51
-
-
Save mcmire/2c09ae3adba0bd8fa1f9ad65daef513a to your computer and use it in GitHub Desktop.
Table matchers for RSpec
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module FeatureSpecs | |
def have_row(expected_row) | |
HaveRowMatcher.new(self, expected_row) | |
end | |
class HaveRowMatcher | |
def initialize(context, expected_row) | |
@context = context | |
@expected_row = expected_row | |
end | |
def description | |
"should have row containing #{expected_row}" | |
end | |
def matches?(element) | |
@element = element | |
table = Table.new(context, element) | |
@actual_rows = | |
if expected_row.is_a?(Hash) | |
table.to_array_of_hashes | |
else | |
table.to_array_of_arrays | |
end | |
@actual_rows.include?(expected_row) | |
end | |
def failure_message | |
"Expected table to have row containing:\n" + | |
expected_row.pretty_inspect + "\n" + | |
"Full table:\n" + | |
actual_rows.pretty_inspect | |
end | |
def failure_message_when_negated | |
"Did not expect table to have row containing:\n" + | |
expected_row.pretty_inspect | |
end | |
protected | |
attr_reader :context, :expected_row, :element, :actual_rows | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative "../mixins/wait_for" | |
module FeatureSpecs | |
def have_table(selector, content:) | |
HaveTableMatcher.new(selector, content: content) | |
end | |
class HaveTableMatcher | |
include WaitFor | |
def initialize(selector, content:) | |
@selector = selector | |
@expected_content = content | |
end | |
def matches?(parent_element) | |
@element = parent_element.find(selector) | |
@table = Table.new(element) | |
wait_for("table to have content") do | |
actual_content == expected_content | |
end | |
rescue FeatureSpecs::WaitedTooLongError | |
false | |
end | |
def failure_message | |
"Expected to see table with content:" + "\n\n" + | |
expected_content.pretty_inspect + "\n\n" + | |
"However, the table contained:" + "\n\n" + | |
actual_content.pretty_inspect + "\n\n" + | |
"Diff:" + "\n" + | |
differ.diff(actual_content, expected_content) | |
end | |
private | |
attr_reader :selector, :expected_content, :element, :table | |
def actual_content | |
if expected_content[0].is_a?(Hash) | |
table.to_array_of_hashes | |
else | |
table.to_array_of_arrays | |
end | |
end | |
def differ | |
@_differ ||= RSpec::Support::Differ.new | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module FeatureSpecs | |
class Table | |
def initialize(element) | |
@element = element | |
end | |
def find_body_row!(&block) | |
if row_element = find_body_row(&block) | |
row_element | |
else | |
raise "Couldn't find row element!" | |
end | |
end | |
def find_body_row(&block) | |
if row = body_rows.detect(&block) | |
row.element | |
end | |
end | |
def to_array_of_arrays | |
header_and_body_rows.map(&:to_array) | |
end | |
def to_array_of_hashes | |
body_rows.map(&:to_hash) | |
end | |
private | |
attr_reader :element | |
def header_and_body_rows | |
[header_row] + body_rows | |
end | |
def body_rows | |
@_body_rows ||= trs[1..-1].map { |tr| BodyTableRow.new(header_row, tr) } | |
end | |
def header_row | |
@_header_row ||= TableRow.new(trs[0]) | |
end | |
def trs | |
@_trs ||= element.all('tr') | |
end | |
end | |
class TableRow | |
attr_reader :element | |
def initialize(element) | |
@element = element | |
end | |
def [](index) | |
to_array[index] | |
end | |
def to_array | |
@_to_array ||= cells.map { |cell| cell.text.strip.squish } | |
end | |
private | |
def cells | |
@_cells ||= element.all('th, td') | |
end | |
end | |
class BodyTableRow < TableRow | |
def initialize(header_row, element) | |
super(element) | |
@header_row = header_row | |
end | |
def [](key) | |
if key.is_a?(String) | |
to_hash[key] | |
else | |
to_array[key] | |
end | |
end | |
def to_hash | |
@_to_hash ||= header_row.to_array.zip(to_array).to_h | |
end | |
private | |
attr_reader :header_row | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module FeatureSpecs | |
WaitedTooLongError = Class.new(Timeout::Error) | |
module WaitFor | |
def wait_for(condition_description) | |
Timeout.timeout(Capybara.default_max_wait_time) do | |
begin | |
sleep(0.1) | |
value = yield | |
end until value | |
value | |
end | |
rescue Timeout::Error | |
raise WaitedTooLongError.new( | |
"Timed out while waiting for #{condition_description}" | |
) | |
end | |
end | |
include WaitFor | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment