have_table 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +15 -0
- data/lib/have_table/have_table.rb +54 -0
- data/lib/have_table/matchers.rb +7 -0
- data/lib/have_table/row_matcher.rb +30 -0
- data/lib/have_table/row_sequence.rb +69 -0
- data/lib/have_table.rb +9 -0
- data/spec/row_sequence_spec.rb +36 -0
- metadata +69 -0
data/README.rdoc
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
= have_table matcher
|
2
|
+
|
3
|
+
This gem provides a custom matcher for testing tables in an intuitive way.
|
4
|
+
|
5
|
+
eg:
|
6
|
+
|
7
|
+
response.should have_table do
|
8
|
+
with_row do
|
9
|
+
with_cell("Username" => "jsmith")
|
10
|
+
with_cell("First Name" => "John")
|
11
|
+
with_cell("Last Name" => "Smith")
|
12
|
+
with_cell("Email" => "jsmith@email.com")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module HaveTable
|
2
|
+
class HaveTable
|
3
|
+
def matches?(response, &block)
|
4
|
+
@response = response
|
5
|
+
@document = Webrat::XML.document(response)
|
6
|
+
@table_nodes = @document.xpath("//table")
|
7
|
+
if (block_given?)
|
8
|
+
# Asked: have_table { ... }
|
9
|
+
block.bind(self).call
|
10
|
+
return matches_conditions?
|
11
|
+
else
|
12
|
+
# Asked: have_table
|
13
|
+
return @table_nodes.length > 0
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure_message_for_should
|
18
|
+
"expected that #{@response} would have a table"
|
19
|
+
end
|
20
|
+
|
21
|
+
def failure_message_for_should_not
|
22
|
+
"expected that #{@response} would not have a table"
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_row(&block)
|
26
|
+
@table_conditions ||= []
|
27
|
+
|
28
|
+
row_matcher = RowMatcher.new
|
29
|
+
if block_given?
|
30
|
+
block.bind(row_matcher).call
|
31
|
+
end
|
32
|
+
@table_conditions << row_matcher
|
33
|
+
end
|
34
|
+
|
35
|
+
def matches_conditions?
|
36
|
+
any_tables_match = false
|
37
|
+
@table_nodes.each do |table_node|
|
38
|
+
row_sequence = RowSequence.new(table_node)
|
39
|
+
table_matches = true
|
40
|
+
@table_conditions.each do |row_matcher|
|
41
|
+
unless row_matcher.matches?(row_sequence)
|
42
|
+
table_matches = false
|
43
|
+
break
|
44
|
+
end
|
45
|
+
end
|
46
|
+
if table_matches
|
47
|
+
any_tables_match = true
|
48
|
+
break
|
49
|
+
end
|
50
|
+
end
|
51
|
+
return any_tables_match
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module HaveTable
|
2
|
+
class RowMatcher
|
3
|
+
def with_cell(params)
|
4
|
+
@row_conditions ||= {}
|
5
|
+
@row_conditions.merge!(params)
|
6
|
+
end
|
7
|
+
|
8
|
+
def matches?(row_sequence)
|
9
|
+
# Tester called: have_table { with_row }
|
10
|
+
return row_sequence.any? unless @row_conditions
|
11
|
+
|
12
|
+
matches = false
|
13
|
+
row_sequence.each do |row|
|
14
|
+
row_matches = true
|
15
|
+
@row_conditions.each do |key, value|
|
16
|
+
unless row[key] == value
|
17
|
+
row_matches = false
|
18
|
+
break
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
if row_matches
|
23
|
+
matches = true
|
24
|
+
break
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return matches
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module HaveTable
|
2
|
+
class RowSequence
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def initialize(table_node)
|
6
|
+
raise "did not receive a <table> node" unless table_node.name == "table"
|
7
|
+
|
8
|
+
@tr_nodes = table_node.xpath("tr")
|
9
|
+
read_header
|
10
|
+
end
|
11
|
+
|
12
|
+
def each
|
13
|
+
reset
|
14
|
+
while true
|
15
|
+
if is_on_header?
|
16
|
+
next_row
|
17
|
+
next
|
18
|
+
end
|
19
|
+
row = next_row
|
20
|
+
break unless row
|
21
|
+
yield(row)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def reset
|
28
|
+
@index = 0
|
29
|
+
end
|
30
|
+
|
31
|
+
def more?
|
32
|
+
@index < @tr_nodes.length
|
33
|
+
end
|
34
|
+
|
35
|
+
def next_row
|
36
|
+
return nil unless more?
|
37
|
+
td_nodes = next_row_node
|
38
|
+
row_texts = td_nodes.children.map{|node|node.text}
|
39
|
+
Hash[@header.zip(row_texts)]
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_header
|
43
|
+
@index = -1
|
44
|
+
while true
|
45
|
+
@index+= 1
|
46
|
+
if is_on_header?
|
47
|
+
@header = peek_row_node.children.map { |node| node.text }
|
48
|
+
break
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def is_on_header?
|
54
|
+
return false unless more?
|
55
|
+
tag_names = peek_row_node.children.map { |node| node.name }
|
56
|
+
tag_names.length > 0 && !tag_names.detect { |tag_name| tag_name != "th" && tag_name != "text" }
|
57
|
+
end
|
58
|
+
|
59
|
+
def peek_row_node
|
60
|
+
@tr_nodes[@index] if more?
|
61
|
+
end
|
62
|
+
|
63
|
+
def next_row_node
|
64
|
+
rval = peek_row_node
|
65
|
+
@index+= 1
|
66
|
+
rval
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/have_table.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe RowSequence do
|
4
|
+
|
5
|
+
it "should not return the header as the first row" do
|
6
|
+
xml = <<EOT
|
7
|
+
<table>
|
8
|
+
<tr><th>One</th></tr>
|
9
|
+
<tr><td>value</td></tr>
|
10
|
+
</table>
|
11
|
+
EOT
|
12
|
+
table_node = Nokogiri::XML.parse(xml).children.first
|
13
|
+
row_sequence = RowSequence.new(table_node)
|
14
|
+
|
15
|
+
row = row_sequence.first
|
16
|
+
row["One"].should eql("value")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should evalate each once for one row" do
|
20
|
+
xml = <<EOT
|
21
|
+
<table>
|
22
|
+
<tr><th>One</th></tr>
|
23
|
+
<tr><td>value</td></tr>
|
24
|
+
</table>
|
25
|
+
EOT
|
26
|
+
table_node = Nokogiri::XML.parse(xml).children.first
|
27
|
+
row_sequence = RowSequence.new(table_node)
|
28
|
+
|
29
|
+
count = 0
|
30
|
+
row_sequence.each do |row|
|
31
|
+
count+= 1
|
32
|
+
end
|
33
|
+
count.should eql(1)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: have_table
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Paradise
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-05-09 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.9
|
24
|
+
version:
|
25
|
+
description: An RSpec matcher
|
26
|
+
email: adparadise@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README.rdoc
|
33
|
+
files:
|
34
|
+
- lib/have_table/row_sequence.rb
|
35
|
+
- lib/have_table/row_matcher.rb
|
36
|
+
- lib/have_table/matchers.rb
|
37
|
+
- lib/have_table/have_table.rb
|
38
|
+
- lib/have_table.rb
|
39
|
+
- README.rdoc
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://andrewparadise.com/
|
42
|
+
licenses: []
|
43
|
+
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
requirements: []
|
62
|
+
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 1.3.5
|
65
|
+
signing_key:
|
66
|
+
specification_version: 3
|
67
|
+
summary: An RSpec matcher for view-testing tables.
|
68
|
+
test_files:
|
69
|
+
- spec/row_sequence_spec.rb
|