Refactor :table selector filters

This commit is contained in:
Thomas Walpole 2019-03-19 11:39:34 -07:00
parent 5bc3f445ae
commit 5e133126c3
3 changed files with 75 additions and 75 deletions

View File

@ -459,101 +459,93 @@ Capybara.add_selector(:table, locator_type: [String, Symbol]) do
expression_filter(:with_cols, valid_values: [Array]) do |xpath, cols|
col_conditions = cols.map do |col|
if col.is_a? Hash
col.reduce(nil) do |xp, (header, cell)|
header_xp = XPath.descendant(:th)[XPath.string.n.is(header)]
cell_xp = XPath.descendant(:tr)[header_xp].descendant(:td)
next cell_xp[XPath.string.n.is(cell)] unless xp
table_ancestor = XPath.ancestor(:table)[1]
xp = XPath::Expression.new(:join, table_ancestor, xp)
cell_xp[XPath.string.n.is(cell) & XPath.position.equals(xp.preceding_sibling(:td).count.plus(1))]
col.reduce(nil) do |xp, (header, cell_str)|
header = XPath.descendant(:th)[XPath.string.n.is(header)]
td = XPath.descendant(:tr)[header].descendant(:td)
cell_condition = XPath.string.n.is(cell_str)
cell_condition &= prev_col_position?(XPath.ancestor(:table)[1].join(xp)) if xp
td[cell_condition]
end
else
cells_xp = col.reduce(nil) do |xp, cell|
cell_conditions = [XPath.string.n.is(cell)]
if xp
prev_row_xp = XPath::Expression.new(:join, XPath.ancestor(:tr)[1].preceding_sibling(:tr), xp)
cell_conditions << XPath.position.equals(prev_row_xp.preceding_sibling(:td).count.plus(1))
cells_xp = col.reduce(nil) do |prev_cell, cell_str|
cell_condition = XPath.string.n.is(cell_str)
if prev_cell
prev_cell = XPath.ancestor(:tr)[1].preceding_sibling(:tr).join(prev_cell)
cell_condition &= prev_col_position?(prev_cell)
end
XPath.descendant(:td)[cell_conditions.reduce :&]
XPath.descendant(:td)[cell_condition]
end
XPath::Expression.new(:join, XPath.descendant(:tr), cells_xp)
XPath.descendant(:tr).join(cells_xp)
end
end.reduce(:&)
xpath[col_conditions]
end
expression_filter(:cols, valid_values: [Array]) do |xpath, cols|
raise ArgumentError, ":cols must be an Array of Arrays" unless cols.all? { |col| col.is_a? Array }
raise ArgumentError, ':cols must be an Array of Arrays' unless cols.all? { |col| col.is_a? Array }
rows = cols.transpose
xpath = xpath[XPath.descendant(:tbody).descendant(:tr).count.equals(rows.size) | (XPath.descendant(:tr).count.equals(rows.size) & ~XPath.descendant(:tbody))]
col_conditions = rows.map do |row|
row_conditions = row.map do |cell|
XPath.self(:td)[XPath.string.n.is(cell)]
end
row_conditions = row_conditions.reverse.reduce do |cond, cell|
cell[XPath.following_sibling[cond]]
end
row_xpath = XPath.descendant(:tr)[XPath.descendant(:td)[row_conditions]]
row_xpath[XPath.descendant(:td).count.equals(row.size)]
end.reduce(:&)
xpath[col_conditions]
col_conditions = rows.map { |row| match_row(row, match_size: true) }.reduce(:&)
xpath[match_row_count(rows.size)][col_conditions]
end
expression_filter(:with_rows, valid_values: [Array]) do |xpath, rows|
rows_conditions = rows.map do |row|
if row.is_a? Hash
row_conditions = row.map do |header, cell|
header_xp = XPath.ancestor(:table)[1].descendant(:tr)[1].descendant(:th)[XPath.string.n.is(header)]
XPath.descendant(:td)[
XPath.string.n.is(cell) & XPath.position.equals(header_xp.preceding_sibling.count.plus(1))
]
end.reduce(:&)
XPath.descendant(:tr)[row_conditions]
else
row_conditions = row.map do |cell|
XPath.self(:td)[XPath.string.n.is(cell)]
end
row_conditions = row_conditions.reverse.reduce do |cond, cell|
cell[XPath.following_sibling[cond]]
end
XPath.descendant(:tr)[XPath.descendant(:td)[row_conditions]]
end
end.reduce(:&)
rows_conditions = rows.map { |row| match_row(row) }.reduce(:&)
xpath[rows_conditions]
end
expression_filter(:rows, valid_values: [Array]) do |xpath, rows|
xpath = xpath[XPath.descendant(:tbody).descendant(:tr).count.equals(rows.size) | (XPath.descendant(:tr).count.equals(rows.size) & ~XPath.descendant(:tbody))]
rows_conditions = rows.map do |row|
row_xpath = if row.is_a? Hash
row_conditions = row.map do |header, cell|
header_xp = XPath.ancestor(:table)[1].descendant(:tr)[1].descendant(:th)[XPath.string.n.is(header)]
XPath.descendant(:td)[
XPath.string.n.is(cell) & XPath.position.equals(header_xp.preceding_sibling.count.plus(1))
]
end.reduce(:&)
XPath.descendant(:tr)[row_conditions]
else
row_conditions = row.map do |cell|
XPath.self(:td)[XPath.string.n.is(cell)]
end
row_conditions = row_conditions.reverse.reduce do |cond, cell|
cell[XPath.following_sibling[cond]]
end
XPath.descendant(:tr)[XPath.descendant(:td)[row_conditions]]
end
row_xpath[XPath.descendant(:td).count.equals(row.size)]
end.reduce(:&)
xpath[rows_conditions]
rows_conditions = rows.map { |row| match_row(row, match_size: true) }.reduce(:&)
xpath[match_row_count(rows.size)][rows_conditions]
end
describe_expression_filters do |caption: nil, **|
" with caption \"#{caption}\"" if caption
end
def prev_col_position?(cell)
XPath.position.equals(cell_position(cell))
end
def cell_position(cell)
cell.preceding_sibling(:td).count.plus(1)
end
def match_row(row, match_size: false)
xp = XPath.descendant(:tr)[
if row.is_a? Hash
row_match_cells_to_headers(row)
else
XPath.descendant(:td)[row_match_ordered_cells(row)]
end
]
xp = xp[XPath.descendant(:td).count.equals(row.size)] if match_size
xp
end
def match_row_count(size)
XPath.descendant(:tbody).descendant(:tr).count.equals(size) | (XPath.descendant(:tr).count.equals(size) & ~XPath.descendant(:tbody))
end
def row_match_cells_to_headers(row)
row.map do |header, cell|
header_xp = XPath.ancestor(:table)[1].descendant(:tr)[1].descendant(:th)[XPath.string.n.is(header)]
XPath.descendant(:td)[
XPath.string.n.is(cell) & XPath.position.equals(header_xp.preceding_sibling.count.plus(1))
]
end.reduce(:&)
end
def row_match_ordered_cells(row)
row_conditions = row.map do |cell|
XPath.self(:td)[XPath.string.n.is(cell)]
end
row_conditions.reverse.reduce do |cond, cell|
cell[XPath.following_sibling[cond]]
end
end
end
Capybara.add_selector(:table_row, locator_type: [Array, Hash]) do

View File

@ -7,3 +7,11 @@ module XPath
end
end
end
module XPath
module DSL
def join(*expressions)
XPath::Expression.new(:join, *[self, expressions].flatten)
end
end
end

View File

@ -49,8 +49,8 @@ Capybara::SpecHelper.spec '#has_table?' do
%w[Thomas Walpole Oceanside],
%w[Danilo Wilkinson Johnsonville],
%w[Vern Konopelski Everette],
["Ratke", "Lawrence", "East Sorayashire"],
["Palmer", "Sawayn", "West Trinidad"]
['Ratke', 'Lawrence', 'East Sorayashire'],
['Palmer', 'Sawayn', 'West Trinidad']
])
end
@ -84,8 +84,8 @@ Capybara::SpecHelper.spec '#has_table?' do
%w[Thomas Walpole Oceanside],
%w[Danilo Wilkinson Johnsonville],
%w[Vern Konopelski Everette],
["Ratke", "Lawrence", "East Sorayashire"],
["Palmer", "Sawayn", "West Trinidad"]
['Ratke', 'Lawrence', 'East Sorayashire'],
['Palmer', 'Sawayn', 'West Trinidad']
])
end