toothbrush 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c0236cdd0e3cd84517f2172af73e1eb430373dd8
4
+ data.tar.gz: 16bbf613fe9f1b22077041dbba1fc482043d2454
5
+ SHA512:
6
+ metadata.gz: 3e27a550cef69208428161cccb36ef51d6bac05e8fc7631c2efabdbe70cad113aadd9f0f0eaa69db69026552aa629ee737d291c2609e4b0d6601c53724fae6e5
7
+ data.tar.gz: b2ea8d28c73be7673841d675cc6e81de457178b85e8ebbe7ae8548d1f0b54a728afb0f19771e06e4256c8ff83fc7e3dd4be8ca8e9a65b794a7f9b2081597041a
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.4
@@ -1,37 +1,133 @@
1
- module Toothbrush
2
- module Helpers
3
- def ensure_table(table_selector, header_or_content, content = nil)
4
- if content.nil?
5
- return _ensure_table(table_selector, header_or_content)
1
+ require 'rspec/expectations'
2
+ require 'text-table'
3
+
4
+ RSpec::Matchers.define :include_table do |selector, *header_content|
5
+ match do |actual|
6
+ if header_content.count == 2
7
+ expected_header, expected_content = header_content.map(&:clone)
8
+ else
9
+ expected_header, expected_content = nil, header_content[0].clone
10
+ end
11
+
12
+ check_selector = lambda do
13
+ actual.has_selector?(selector)
14
+ end
15
+
16
+ has_thead = lambda do
17
+ actual.has_selector?("#{selector} thead")
18
+ end
19
+
20
+ has_tbody = lambda do
21
+ actual.has_selector?("#{selector} tbody")
22
+ end
23
+
24
+ has_header = lambda do
25
+ has_thead[] || actual.has_selector?("#{selector} tr th")
26
+ end
27
+
28
+ expected_has_header = lambda do
29
+ expected_header && !expected_header.empty?
30
+ end
31
+
32
+ html_table_to_array = lambda do
33
+ if has_thead[]
34
+ header = actual.all("#{selector} thead tr th").map(&:text)
35
+ header = actual.all("#{selector} thead tr td").map(&:text) if header.empty?
36
+ elsif has_header[]
37
+ header = actual.first("#{selector} tr").all('th').map(&:text)
38
+ header = actual.first("#{selector} tr").all('td').map(&:text) if header.empty?
39
+ end
40
+ body_rows = if has_tbody[]
41
+ actual.all("#{selector} tbody tr")
42
+ elsif has_header[]
43
+ actual.all("#{selector} tr")[1..-1]
6
44
  else
7
- header = header_or_content
45
+ actual.all("#{selector} tr")
46
+ end
47
+ body = body_rows.map {|tr| tr.all('td').map(&:text) }
48
+ if header && !header.empty?
49
+ body_size = body.first ? body.first.size : 0
50
+ header << '' while header.size < body_size
51
+ body.unshift(header)
8
52
  end
53
+ body.to_table(first_row_is_head: has_header[]).to_s
54
+ end
55
+
56
+ column_equivalence = {}
9
57
 
10
- content.each_with_index do |row, row_index|
11
- row.each_with_index do |cell, cell_index|
12
- begin
13
- within("#{table_selector} tbody tr:nth-child(#{row_index+1}) td:nth-child(#{cell_index+1})") do
14
- page.should have_content(cell)
15
- end
16
- rescue Capybara::ElementNotFound
17
- within("#{table_selector} tr:nth-child(#{row_index+2}) td:nth-child(#{cell_index+1})") do
18
- page.should have_content(cell)
19
- end
58
+ check_header = lambda do
59
+ return true unless expected_header
60
+
61
+ check_header_content = lambda do |*header_selector|
62
+ columns = {}
63
+ sub_selector = header_selector.empty? ? '' : header_selector[0]
64
+ first_row = actual.all("#{selector} #{sub_selector} tr")[0]
65
+ if first_row
66
+ first_row.
67
+ all("th, td").
68
+ each_with_index {|td, index| columns[td.text] = index }
69
+ expected_header.each_with_index do |title, index|
70
+ column_equivalence[index] = columns[title] if columns.has_key? title
20
71
  end
72
+ expected_header.all? {|title| columns.has_key? title }
73
+ else
74
+ expected_header.empty?
21
75
  end
22
76
  end
77
+
78
+ (has_thead[] && check_header_content.('thead')) ||
79
+ (!has_thead[] && check_header_content[])
23
80
  end
24
81
 
25
- private
82
+ check_content = lambda do
83
+ check_body_content = lambda do |sub_selector_or_flag|
84
+ if sub_selector_or_flag.is_a? Symbol
85
+ sub_selector, exclude_first_line = '', sub_selector_or_flag == :exclude_first_line
86
+ else
87
+ sub_selector, exclude_first_line = sub_selector_or_flag, false
88
+ end
89
+ trs = actual.all("#{selector} #{sub_selector} tr").to_a
90
+ trs.shift if exclude_first_line
91
+ expected_content.map.with_index {|row, row_index|
92
+ tds = trs[row_index].all('td')
93
+ row.map.with_index {|data, col_index|
94
+ tds[column_equivalence[col_index] || col_index].has_content? data
95
+ }.all?
96
+ }.compact.all?
97
+ end
26
98
 
27
- def _ensure_table(selector, content)
28
- content.each_with_index do |row, row_index|
29
- row.each_with_index do |cell_data, cell_index|
30
- within("#{selector} tr:nth-child(#{row_index + 1}) td:nth-child(#{cell_index + 1})") do
31
- page.should have_content cell_data
32
- end
99
+ if has_tbody[]
100
+ check_body_content.('tbody')
101
+ elsif has_header[]
102
+ check_body_content.(:exclude_first_line)
103
+ else
104
+ check_body_content.('')
105
+ end
106
+ end
107
+
108
+ result = check_selector[] && check_header[] && check_content[]
109
+ if !result
110
+ if !check_selector[]
111
+ @message = "expected to have selector '#{selector}'"
112
+ else
113
+ expected_table = expected_content.clone
114
+ if expected_header
115
+ expected_header << '' while expected_header.size < expected_table.first.size
116
+ expected_table.unshift(expected_header)
33
117
  end
118
+ @message = "expected to include table\n%sbut found\n%s" %
119
+ [expected_table.to_table(first_row_is_head: expected_has_header[]),
120
+ html_table_to_array[]]
34
121
  end
35
122
  end
123
+ result
124
+ end
125
+
126
+ class << self
127
+ alias :failure_message :failure_message_for_should
128
+ end unless respond_to? :failure_message
129
+
130
+ failure_message do |actual|
131
+ @message
36
132
  end
37
133
  end
@@ -96,4 +96,7 @@
96
96
  <td>You can't destroy this</td>
97
97
  </tr>
98
98
  </tbody>
99
- </table>
99
+ </table>
100
+
101
+ <table id='nothing-inside'>
102
+ </table>
data/spec/spec_helper.rb CHANGED
@@ -4,6 +4,8 @@ require 'rspec'
4
4
  require 'toothbrush'
5
5
  require 'capybara'
6
6
  require 'capybara/dsl'
7
+ require 'pry-rails'
8
+ require 'text-table'
7
9
 
8
10
  require File.join(File.dirname(__FILE__), 'dummy_app', 'app')
9
11
  Capybara.app = Sinatra::Application
@@ -14,5 +16,4 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
14
16
 
15
17
  RSpec.configure do |config|
16
18
  config.include Capybara::DSL
17
- config.include Toothbrush::Helpers
18
19
  end
@@ -4,12 +4,12 @@ describe "Toothbrush" do
4
4
  before(:each) { visit '/dummy' }
5
5
 
6
6
  it 'talks to the dummy app' do
7
- page.should have_content "Hey, ho, let's go!"
7
+ expect(page).to have_content "Hey, ho, let's go!"
8
8
  end
9
9
 
10
10
  describe 'ensures table content' do
11
11
  it 'correct table' do
12
- ensure_table '#football-clubs-from-rio-de-janeiro-and-their-honors',
12
+ expect(page).to include_table '#football-clubs-from-rio-de-janeiro-and-their-honors',
13
13
  [ 'Club', 'World', 'Libertadores', 'Brasileiro', 'Copa do Brasil', 'Carioca'],
14
14
  [%w( Flamengo 1 1 6 2 32 ),
15
15
  %w( Vasco 0 1 4 1 22 ),
@@ -19,37 +19,171 @@ describe "Toothbrush" do
19
19
 
20
20
  it 'vasco is not a world club champion' do
21
21
  expect {
22
- ensure_table '#football-clubs-from-rio-de-janeiro-and-their-honors',
22
+ expect(page).to include_table '#football-clubs-from-rio-de-janeiro-and-their-honors',
23
23
  [ 'Club', 'World', 'Libertadores', 'Brasileiro', 'Copa do Brasil', 'Carioca'],
24
24
  [%w( Flamengo 1 1 6 2 32 ),
25
25
  %w( Vasco 1 1 4 1 22 ),
26
26
  %w( Fluminense 0 0 3 1 30 ),
27
27
  %w( Botafogo 0 0 1 0 19 )]
28
28
  }.to raise_error(RSpec::Expectations::ExpectationNotMetError,
29
- 'expected #has_content?("1") to return true, got false')
29
+ """expected to include table
30
+ +------------+-------+--------------+------------+----------------+---------+
31
+ | Club | World | Libertadores | Brasileiro | Copa do Brasil | Carioca |
32
+ +------------+-------+--------------+------------+----------------+---------+
33
+ | Flamengo | 1 | 1 | 6 | 2 | 32 |
34
+ | Vasco | 1 | 1 | 4 | 1 | 22 |
35
+ | Fluminense | 0 | 0 | 3 | 1 | 30 |
36
+ | Botafogo | 0 | 0 | 1 | 0 | 19 |
37
+ +------------+-------+--------------+------------+----------------+---------+
38
+ but found
39
+ +------------+-------+--------------+------------+----------------+---------+
40
+ | Club | World | Libertadores | Brasileiro | Copa do Brasil | Carioca |
41
+ +------------+-------+--------------+------------+----------------+---------+
42
+ | Flamengo | 1 | 1 | 6 | 2 | 32 |
43
+ | Vasco | 0 | 1 | 4 | 1 | 22 |
44
+ | Fluminense | 0 | 0 | 3 | 1 | 30 |
45
+ | Botafogo | 0 | 0 | 1 | 0 | 19 |
46
+ +------------+-------+--------------+------------+----------------+---------+
47
+ """)
30
48
  end
31
49
 
32
- it 'supports tables without <thead> and <tbody>' do
33
- ensure_table '#without-thead-tbody',
34
- %w( 1 2),
35
- [%w(3 4),
36
- %w(5 6)]
50
+ describe 'supports tables without <thead> and <tbody>' do
51
+ it 'passing' do
52
+ expect(page).to include_table '#without-thead-tbody',
53
+ %w( 1 2),
54
+ [%w(3 4),
55
+ %w(5 6)]
56
+ end
57
+
58
+ it 'failing' do
59
+ expect {
60
+ expect(page).to include_table '#without-thead-tbody',
61
+ %w( 1 2),
62
+ [%w(3 4),
63
+ %w(5 7)]
64
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError,
65
+ """expected to include table
66
+ +---+---+
67
+ | 1 | 2 |
68
+ +---+---+
69
+ | 3 | 4 |
70
+ | 5 | 7 |
71
+ +---+---+
72
+ but found
73
+ +---+---+
74
+ | 1 | 2 |
75
+ +---+---+
76
+ | 3 | 4 |
77
+ | 5 | 6 |
78
+ +---+---+
79
+ """)
80
+ end
37
81
  end
38
82
 
39
- it 'supports tables without <th>' do
40
- ensure_table '#without-th',
41
- [%w(1 2),
42
- %w(3 4),
43
- %w(5 6)]
83
+ describe 'supports tables without header' do
84
+ it 'passing' do
85
+ expect(page).to include_table '#without-th',
86
+ [%w(1 2),
87
+ %w(3 4),
88
+ %w(5 6)]
89
+ end
90
+
91
+ it 'failing' do
92
+ expect {
93
+ expect(page).to include_table '#without-th',
94
+ [%w(1 2),
95
+ %w(3 4),
96
+ %w(6 6)]
97
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError,
98
+ """expected to include table
99
+ +---+---+
100
+ | 1 | 2 |
101
+ | 3 | 4 |
102
+ | 6 | 6 |
103
+ +---+---+
104
+ but found
105
+ +---+---+
106
+ | 1 | 2 |
107
+ | 3 | 4 |
108
+ | 5 | 6 |
109
+ +---+---+
110
+ """)
111
+ end
112
+ end
113
+
114
+ describe 'supports tables with different <th> and <td> number' do
115
+ it 'passing' do
116
+ expect(page).to include_table '#different-th-td-number',
117
+ ['Name', 'City'],
118
+ [
119
+ ['Americano', 'Campos', 'Destroy'],
120
+ ['Goytacaz', 'Campos', "You can't destroy this"]
121
+ ]
122
+ end
123
+
124
+ it 'failing' do
125
+ expect {
126
+ expect(page).to include_table '#different-th-td-number',
127
+ ['Name', 'Cidade'],
128
+ [
129
+ ['Americano', 'Campos', 'Destroy'],
130
+ ['Goytacaz', 'Campos', "You can't destroy this"]
131
+ ]
132
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError,
133
+ """expected to include table
134
+ +-----------+--------+------------------------+
135
+ | Name | Cidade | |
136
+ +-----------+--------+------------------------+
137
+ | Americano | Campos | Destroy |
138
+ | Goytacaz | Campos | You can't destroy this |
139
+ +-----------+--------+------------------------+
140
+ but found
141
+ +-----------+--------+------------------------+
142
+ | Name | City | |
143
+ +-----------+--------+------------------------+
144
+ | Americano | Campos | Destroy |
145
+ | Goytacaz | Campos | You can't destroy this |
146
+ +-----------+--------+------------------------+
147
+ """)
148
+ end
44
149
  end
45
150
 
46
- it 'supports tables with different <th> and <td> number' do
47
- ensure_table '#different-th-td-number',
48
- ['Name', 'City'],
49
- [
50
- ['Americano', 'Campos', 'Destroy'],
51
- ['Goytacaz', 'Campos', "You can't destroy this"]
52
- ]
151
+ it 'supports partial table' do
152
+ expect(page).to include_table '#football-clubs-from-rio-de-janeiro-and-their-honors',
153
+ %w( Club World ),
154
+ [%w( Flamengo 1 ),
155
+ %w( Vasco 0 ),
156
+ %w( Fluminense 0 ),
157
+ %w( Botafogo 0 )]
53
158
  end
159
+
160
+ it 'does not care about column ordering' do
161
+ expect(page).to include_table '#football-clubs-from-rio-de-janeiro-and-their-honors',
162
+ %w( World Club ),
163
+ [%w( 1 Flamengo ),
164
+ %w( 0 Vasco ),
165
+ %w( 0 Fluminense ),
166
+ %w( 0 Botafogo )]
167
+ end
168
+ end
169
+
170
+ it 'supports table having nothing inside' do
171
+ expect {
172
+ expect(page).to include_table '#nothing-inside',
173
+ ['a'],
174
+ [['b'],
175
+ ['c']]
176
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError,
177
+ """expected to include table
178
+ +---+
179
+ | a |
180
+ +---+
181
+ | b |
182
+ | c |
183
+ +---+
184
+ but found
185
+ ++
186
+ ++
187
+ """)
54
188
  end
55
189
  end
data/toothbrush.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "toothbrush"
8
- s.version = "0.1.3"
8
+ s.version = "0.1.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Rodrigo Manh\u{e3}es"]
@@ -37,7 +37,9 @@ Gem::Specification.new do |s|
37
37
  s.require_paths = ["lib"]
38
38
  s.summary = "Useful stuff for testing with Capybara"
39
39
 
40
- s.add_development_dependency('rspec', '~> 2.0')
40
+ s.add_dependency('text-table')
41
+ s.add_development_dependency('rspec', '>= 2.11.0')
41
42
  s.add_development_dependency('sinatra', '>= 0')
42
43
  s.add_development_dependency('capybara', '>= 1.0')
44
+ s.add_development_dependency('pry-rails')
43
45
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toothbrush
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
5
- prerelease:
4
+ version: 0.1.4
6
5
  platform: ruby
7
6
  authors:
8
7
  - Rodrigo Manhães
@@ -11,54 +10,76 @@ bindir: bin
11
10
  cert_chain: []
12
11
  date: 2013-02-23 00:00:00.000000000 Z
13
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: text-table
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
14
27
  - !ruby/object:Gem::Dependency
15
28
  name: rspec
16
29
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
30
  requirements:
19
- - - ~>
31
+ - - ">="
20
32
  - !ruby/object:Gem::Version
21
- version: '2.0'
33
+ version: 2.11.0
22
34
  type: :development
23
35
  prerelease: false
24
36
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
37
  requirements:
27
- - - ~>
38
+ - - ">="
28
39
  - !ruby/object:Gem::Version
29
- version: '2.0'
40
+ version: 2.11.0
30
41
  - !ruby/object:Gem::Dependency
31
42
  name: sinatra
32
43
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
44
  requirements:
35
- - - ! '>='
45
+ - - ">="
36
46
  - !ruby/object:Gem::Version
37
47
  version: '0'
38
48
  type: :development
39
49
  prerelease: false
40
50
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
51
  requirements:
43
- - - ! '>='
52
+ - - ">="
44
53
  - !ruby/object:Gem::Version
45
54
  version: '0'
46
55
  - !ruby/object:Gem::Dependency
47
56
  name: capybara
48
57
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
58
  requirements:
51
- - - ! '>='
59
+ - - ">="
52
60
  - !ruby/object:Gem::Version
53
61
  version: '1.0'
54
62
  type: :development
55
63
  prerelease: false
56
64
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
65
  requirements:
59
- - - ! '>='
66
+ - - ">="
60
67
  - !ruby/object:Gem::Version
61
68
  version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
62
83
  description: Useful stuff for testing with Capybara
63
84
  email: rmanhaes@gmail.com
64
85
  executables: []
@@ -67,8 +88,8 @@ extra_rdoc_files:
67
88
  - LICENSE.txt
68
89
  - README.rdoc
69
90
  files:
70
- - .document
71
- - .rspec
91
+ - ".document"
92
+ - ".rspec"
72
93
  - Gemfile
73
94
  - LICENSE.txt
74
95
  - README.rdoc
@@ -84,26 +105,25 @@ files:
84
105
  homepage: http://github.com/rodrigomanhaes/toothbrush
85
106
  licenses:
86
107
  - MIT
108
+ metadata: {}
87
109
  post_install_message:
88
110
  rdoc_options: []
89
111
  require_paths:
90
112
  - lib
91
113
  required_ruby_version: !ruby/object:Gem::Requirement
92
- none: false
93
114
  requirements:
94
- - - ! '>='
115
+ - - ">="
95
116
  - !ruby/object:Gem::Version
96
117
  version: '0'
97
118
  required_rubygems_version: !ruby/object:Gem::Requirement
98
- none: false
99
119
  requirements:
100
- - - ! '>='
120
+ - - ">="
101
121
  - !ruby/object:Gem::Version
102
122
  version: '0'
103
123
  requirements: []
104
124
  rubyforge_project:
105
- rubygems_version: 1.8.23
125
+ rubygems_version: 2.2.2
106
126
  signing_key:
107
- specification_version: 3
127
+ specification_version: 4
108
128
  summary: Useful stuff for testing with Capybara
109
129
  test_files: []