Add table selector with_cols and with_rows expression filters
This commit is contained in:
parent
18c9325fd2
commit
b802c87d8a
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'capybara/selector/xpath_extensions'
|
||||
require 'capybara/selector/selector'
|
||||
|
||||
Capybara::Selector::FilterSet.add(:_field) do
|
||||
node_filter(:checked, :boolean) { |node, value| !(value ^ node.checked?) }
|
||||
node_filter(:unchecked, :boolean) { |node, value| (value ^ node.checked?) }
|
||||
|
@ -454,6 +456,46 @@ Capybara.add_selector(:table, locator_type: [String, Symbol]) do
|
|||
xpath
|
||||
end
|
||||
|
||||
expression_filter(:with_cols, valid_values: [Array]) do |xpath, cols|
|
||||
raise ArgumentError, 'Columns must be specified as hashes' unless cols.all? { |col| col.is_a? Hash }
|
||||
|
||||
col_conditions = cols.map do |col|
|
||||
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.count)]
|
||||
end
|
||||
end.reduce(:&)
|
||||
xpath[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(:&)
|
||||
xpath[rows_conditions]
|
||||
end
|
||||
|
||||
describe_expression_filters do |caption: nil, **|
|
||||
" with caption \"#{caption}\"" if caption
|
||||
end
|
||||
|
@ -472,11 +514,7 @@ Capybara.add_selector(:table_row, locator_type: [Array, Hash]) do
|
|||
end
|
||||
else
|
||||
initial_td = XPath.descendant(:td)[XPath.string.n.is(locator.shift)]
|
||||
tds = locator.reverse.map do |cell|
|
||||
XPath.following_sibling(:td)[XPath.string.n.is(cell)]
|
||||
end.reduce do |xp, cell|
|
||||
xp[cell]
|
||||
end
|
||||
tds = locator.reverse.map { |cell| XPath.following_sibling(:td)[XPath.string.n.is(cell)] }.reduce { |xp, cell| xp[cell] }
|
||||
xpath[initial_td[tds]]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module XPath
|
||||
class Renderer
|
||||
def join(*expressions)
|
||||
expressions.join('/')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -11,20 +11,70 @@ Capybara::SpecHelper.spec '#has_table?' do
|
|||
expect(@session).to have_table(:villain_table)
|
||||
end
|
||||
|
||||
it 'should accept rows with column header hashes' do
|
||||
expect(@session).to have_table('Horizontal Headers', with_rows:
|
||||
[
|
||||
{ 'First Name' => 'Vern', 'Last Name' => 'Konopelski', 'City' => 'Everette' },
|
||||
{ 'First Name' => 'Palmer', 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
|
||||
])
|
||||
end
|
||||
|
||||
it 'should accept rows with partial column header hashses' do
|
||||
expect(@session).to have_table('Horizontal Headers', with_rows:
|
||||
[
|
||||
{ 'First Name' => 'Thomas' },
|
||||
{ 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
|
||||
])
|
||||
end
|
||||
|
||||
it 'should accept rows with array of cell values' do
|
||||
expect(@session).to have_table('Horizontal Headers', with_rows:
|
||||
[
|
||||
%w[Thomas Walpole Oceanside],
|
||||
['Ratke', 'Lawrence', 'East Sorayashire']
|
||||
])
|
||||
end
|
||||
|
||||
it 'should consider order of cells in each row' do
|
||||
expect(@session).not_to have_table('Horizontal Headers', with_rows:
|
||||
[
|
||||
%w[Thomas Walpole Oceanside],
|
||||
['Lawrence', 'Ratke', 'East Sorayashire']
|
||||
])
|
||||
end
|
||||
|
||||
it 'should match with vertical headers' do
|
||||
expect(@session).to have_table('Vertical Headers', with_cols:
|
||||
[
|
||||
{ 'First Name' => 'Thomas' },
|
||||
{ 'First Name' => 'Danilo', 'Last Name' => 'Wilkinson', 'City' => 'Johnsonville' },
|
||||
{ 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
|
||||
])
|
||||
end
|
||||
|
||||
it "should not match with vertical headers if the columns don't match" do
|
||||
expect(@session).not_to have_table('Vertical Headers', with_cols:
|
||||
[
|
||||
{ 'First Name' => 'Thomas' },
|
||||
{ 'First Name' => 'Danilo', 'Last Name' => 'Walpole', 'City' => 'Johnsonville' },
|
||||
{ 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
|
||||
])
|
||||
end
|
||||
|
||||
it 'should be false if the table is not on the page' do
|
||||
expect(@session).not_to have_table('Monkey')
|
||||
end
|
||||
|
||||
it 'should find row by header and cell values' do
|
||||
expect(@session.find(:table, 'Vertical')).to have_selector(:table_row, 'First Name' => 'Thomas', 'Last Name' => 'Walpole')
|
||||
expect(@session.find(:table, 'Vertical')).to have_selector(:table_row, 'Last Name' => 'Walpole')
|
||||
expect(@session.find(:table, 'Vertical')).not_to have_selector(:table_row, 'First Name' => 'Walpole')
|
||||
expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, 'First Name' => 'Thomas', 'Last Name' => 'Walpole')
|
||||
expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, 'Last Name' => 'Walpole')
|
||||
expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, 'First Name' => 'Walpole')
|
||||
end
|
||||
|
||||
it 'should find row by cell values' do
|
||||
expect(@session.find(:table, 'Vertical')).to have_selector(:table_row, %w[Thomas Walpole])
|
||||
expect(@session.find(:table, 'Vertical')).not_to have_selector(:table_row, %w[Walpole Thomas])
|
||||
expect(@session.find(:table, 'Vertical')).not_to have_selector(:table_row, %w[Other])
|
||||
expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, %w[Thomas Walpole])
|
||||
expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, %w[Walpole Thomas])
|
||||
expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, %w[Other])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -41,4 +91,18 @@ Capybara::SpecHelper.spec '#has_no_table?' do
|
|||
it 'should be true if the table is not on the page' do
|
||||
expect(@session).to have_no_table('Monkey')
|
||||
end
|
||||
|
||||
it 'should consider rows' do
|
||||
expect(@session).to have_no_table('Horizontal Headers', with_rows:
|
||||
[
|
||||
{ 'First Name' => 'Thomas', 'City' => 'Los Angeles' }
|
||||
])
|
||||
end
|
||||
|
||||
it 'should consider columns' do
|
||||
expect(@session).to have_no_table('Vertical Headers', with_cols:
|
||||
[
|
||||
{ 'First Name' => 'Joe' }
|
||||
])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,30 +63,68 @@
|
|||
</form>
|
||||
|
||||
<table>
|
||||
<caption>Vertical</caption>
|
||||
<caption>Horizontal Headers</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>City</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Thomas</td>
|
||||
<td>Walpole</td>
|
||||
<td>Oceanside</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Danilo</td>
|
||||
<td>Wilkinson</td>
|
||||
<td>Johnsonville</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Vern</td>
|
||||
<td>Konopelski</td>
|
||||
<td>Everette</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ratke</td>
|
||||
<td>Lawrence</td>
|
||||
<td>East Sorayashire</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Palmer</td>
|
||||
<td>Sawayn</td>
|
||||
<td>West Trinidad</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<caption>Horizontal</caption>
|
||||
<caption>Vertical Headers</caption>
|
||||
<tr>
|
||||
<th>First Name</th>
|
||||
<td>Thomas</td>
|
||||
<td>Danilo</td>
|
||||
<td>Vern</td>
|
||||
<td>Ratke</td>
|
||||
<td>Palmer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Last Name</th>
|
||||
<td>Walpole</td>
|
||||
<td>Wilkinson</td>
|
||||
<td>Konopelski</td>
|
||||
<td>Lawrence</td>
|
||||
<td>Sawayn</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>City</th>
|
||||
<td>Oceanside</td>
|
||||
<td>Johnsonville</td>
|
||||
<td>Everette</td>
|
||||
<td>East Sorayashire</td>
|
||||
<td>West Trinidad</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
Loading…
Reference in New Issue