rspec-html-matchers 0.8.0 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 95d16513be1c4d695f1c2dec1c2e43bcece4c97f
4
- data.tar.gz: 523b06ab97e4993f5f79334447483c9121cadb7c
2
+ SHA256:
3
+ metadata.gz: 0f037ee7285bbe655173850423adeba9e9825641718cc372e89669a5d02284d0
4
+ data.tar.gz: fc31002e7b48380897520cb09e0e08ee00151311c847b260d75cad9c2fab81f8
5
5
  SHA512:
6
- metadata.gz: 5e49505a8a621e4d7c660827f5450efb92e5d320effadbc93d26a9391ee5a689710d45d4ef78b6339fdf374448820c2a5720a3a71b35c75f9167b67152671253
7
- data.tar.gz: f7dbee862ebefebb529b1f99ad3c79e867ebe5535c8d1d3e79a21f9fc8c0e105cfbf2f4f6b5c5bf35350f715fae351e24b86b9bab986ee5a4cd07a6ca04bf6ba
6
+ metadata.gz: a5b9f1f542091c493c69f402a46d54b6483a2f8c90e65c6fd8f7b038b14bc834cd76f8671e664323b37800f4a3e61afacf08d352963907c0873187521c8355cd
7
+ data.tar.gz: 5dd7980ad29b5ed66f3528366cc13b48199b809a0c025ed713cff6fb2f18f1a9323caa8c3bd6bc9145fea06d86c85c66b8763c560bb46377682c82d0dc7feff6
@@ -1,15 +1,42 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
- unreleased(TODO)
5
- ----------------
4
+ 0.9.2
5
+ -----
6
+
7
+ * fixed have_empty_tag matcher on jruby
8
+ * added ruby 2.7 to build matrix (no official support until stable release though)
9
+ * added ruby 2.6 to build matrix ([#70](https://github.com/kucaahbe/rspec-html-matchers/pull/70))
10
+
11
+ infrastructure/misc:
12
+
13
+ * migrated to travis-ci.com instead of travis-ci.org (thanks [Hamada Takayuki](https://github.com/hamadata) for inspiration: [#70](https://github.com/kucaahbe/rspec-html-matchers/pull/70))
14
+ * refactor travis-ci build setup
15
+ * updated status badges to SVG (thanks to [Olle Jonsson](https://github.com/olleolleolle): [#71](https://github.com/kucaahbe/rspec-html-matchers/pull/71))
16
+
17
+ 0.9.1
18
+ -----
19
+
20
+ * re-added ruby support back to 1.8.7 (supporting same versions as rspec 3)
21
+ * split lib in few files
22
+
23
+ 0.9.0
24
+ -----
25
+
26
+ * fixed `with_tag` nesting (thanks to [randoum](https://github.com/randoum): [#59](https://github.com/kucaahbe/rspec-html-matchers/pull/59))
27
+ * added ~> 2.4 ruby support
28
+ * removed ~> 2 ruby support
29
+
30
+ 0.8.2
31
+ -----
32
+
33
+ * fixed README (thanks to [Rodrigo Castro](https://github.com/roooodcastro))
34
+ * fixed deep nesting (thanks to [Misha Gorodnitzky](https://github.com/misaka))
35
+
36
+ 0.8.1
37
+ -----
6
38
 
7
- * with_tag should raise error when used outside have_tag
8
- * add ability to have_form('/url', 'PUT') or have_form('/url', :PUT)
9
- * inteligent check comments(make sure it is not searching inside comments)
10
- * shouldn't show all markup in error message if it is too big
11
- * order matching
12
- * improve documentation, add more usage examples (look at changelog and code!)
39
+ * Rspec differ fix (thanks to [Misha Gorodnitzky](https://github.com/misaka))
13
40
 
14
41
  0.8.0
15
42
  -----
@@ -57,7 +84,7 @@ unreleased(TODO)
57
84
  0.4.4
58
85
  -----
59
86
 
60
- * options for have_tag now support Regexp (thanks to [Ian C. Anderson](http://github.com/iancanderson))
87
+ * options for have_tag now support Regexp (thanks to [Ian C. Anderson](https://github.com/iancanderson))
61
88
 
62
89
  0.4.3
63
90
  -----
@@ -106,14 +133,14 @@ unreleased(TODO)
106
133
  0.2.2
107
134
  -----
108
135
 
109
- * leading and trailing whitespaces are ignored in tags where they should be ignored(#11, and again thanks to [Simon Schoeters](http://github.com/cimm))
136
+ * leading and trailing whitespaces are ignored in tags where they should be ignored(#11, and again thanks to [Simon Schoeters](https://github.com/cimm))
110
137
  * whitespaces ignoring as browser does in :text matching
111
138
  * have_tag backwards compability(thanks to [Felix Tjandrawibawa](https://github.com/cemeng), #12)
112
139
 
113
140
  0.2.1
114
141
  -----
115
142
 
116
- * make possible use non-string as :text option(#10, thanks for idea to [Simon Schoeters](http://github.com/cimm))
143
+ * make possible use non-string as :text option(#10, thanks for idea to [Simon Schoeters](https://github.com/cimm))
117
144
 
118
145
  0.2.0
119
146
  -----
@@ -132,7 +159,7 @@ unreleased(TODO)
132
159
  0.0.6
133
160
  -----
134
161
 
135
- * allow for single quotes in content matchers (thanks to [Kelly Felkins](http://github.com/kellyfelkins)).
162
+ * allow for single quotes in content matchers (thanks to [Kelly Felkins](https://github.com/kellyfelkins)).
136
163
 
137
164
  0.0.5 (trial-trip)
138
165
  ------------------
data/README.md CHANGED
@@ -1,20 +1,16 @@
1
- rspec-html-matchers
2
- ===================
1
+ # rspec-html-matchers [![Gem Version](https://badge.fury.io/rb/rspec-html-matchers.svg)](https://badge.fury.io/rb/rspec-html-matchers) [![Build Status](https://travis-ci.com/kucaahbe/rspec-html-matchers.svg?branch=master)](https://travis-ci.com/kucaahbe/rspec-html-matchers)
3
2
 
4
3
  [RSpec 3](https://www.relishapp.com/rspec) matchers for testing your html (for [RSpec 2](https://www.relishapp.com/rspec/rspec-core/v/2-99/docs) use 0.5.x version).
5
4
 
6
- [![Gem Version](https://badge.fury.io/rb/rspec-html-matchers.png)](http://badge.fury.io/rb/rspec-html-matchers)
7
- [![Build Status](https://travis-ci.org/kucaahbe/rspec-html-matchers.png)](http://travis-ci.org/kucaahbe/rspec-html-matchers)
8
-
9
5
  Goals
10
6
  -----
11
7
 
12
- * for testing **complicated** html output, for simple matching consider use:
13
- * [assert_select](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/SelectorAssertions.html#method-i-assert_select)
8
+ * designed for testing **complex** html output. If you plan to perform simple matching, consider using:
9
+ * [assert_select](https://api.rubyonrails.org/classes/ActionDispatch/Assertions/SelectorAssertions.html#method-i-assert_select)
14
10
  * [matchers provided out of the box in rspec-rails](https://www.relishapp.com/rspec/rspec-rails/v/2-11/docs/view-specs/view-spec)
15
- * [matchers provided by capybara](http://rdoc.info/github/jnicklas/capybara/Capybara/Node/Matchers)
11
+ * [matchers provided by capybara](https://rdoc.info/github/jnicklas/capybara/Capybara/Node/Matchers)
16
12
  * developer-friendly output in error messages
17
- * built on top of [nokogiri](http://www.nokogiri.org/)
13
+ * built on top of [nokogiri](https://www.nokogiri.org/)
18
14
  * has support for [capybara](https://github.com/jnicklas/capybara), see below
19
15
  * syntax is similar to `have_tag` matcher from rspec-rails 1.x, but with own syntactic sugar
20
16
  * framework agnostic, as input should be `String` (or capybara's page, see below)
@@ -45,7 +41,6 @@ describe "my view spec" do
45
41
  it "has tags" do
46
42
  expect(rendered).to have_tag('div')
47
43
  end
48
-
49
44
  end
50
45
  ```
51
46
 
@@ -55,7 +50,7 @@ Cucumber configuration:
55
50
  World RSpecHtmlMatchers
56
51
  ```
57
52
 
58
- as this gem requires **nokogiri**, here are [instructions for installing it](http://nokogiri.org/tutorials/installing_nokogiri.html).
53
+ as this gem requires **nokogiri**, here are [instructions for installing it](https://nokogiri.org/tutorials/installing_nokogiri.html).
59
54
 
60
55
  Usage
61
56
  -----
@@ -85,7 +80,7 @@ expect(rendered).to have_tag('form', :with => { :action => '/users', :method =>
85
80
  end
86
81
  ```
87
82
 
88
- Example above should be self-descriptive, if not, please refer to the [`have_tag`](http://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers%3Ahave_tag) documentation
83
+ Example above should be self-descriptive, if not, please refer to the [`have_tag`](https://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers%3Ahave_tag) documentation
89
84
 
90
85
  Input can be any html string. Let's take a look at these examples:
91
86
 
@@ -152,7 +147,7 @@ Input can be any html string. Let's take a look at these examples:
152
147
  expect('<p> Some content&nbsphere</p>').to have_tag('p', :text => mymock.text)
153
148
  # or
154
149
  expect('<p> Some content&nbsphere</p>').to have_tag('p') do
155
- with_content mymock.text
150
+ with_text mymock.text
156
151
  end
157
152
 
158
153
  # matching text content as it's seen by user:
@@ -193,7 +188,7 @@ where `page` is an instance of Capybara::Session
193
188
  - with\_date\_field
194
189
 
195
190
  and of course you can use the `without_` matchers,
196
- for more info take a look at [documentation](http://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers)
191
+ for more info take a look at [documentation](https://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers)
197
192
 
198
193
  ### rspec 1 partial backwards compatibility:
199
194
 
@@ -204,7 +199,7 @@ expect(response).to have_tag('div', 'expected content')
204
199
  expect(response).to have_tag('div', /regexp matching expected content/)
205
200
  ```
206
201
 
207
- [RSpec 1 `have_tag` documentation](http://old.rspec.info/rails/writing/views.html)
202
+ [RSpec 1 `have_tag` documentation](https://old.rspec.info/rails/writing/views.html)
208
203
 
209
204
  Matching Tag Attributes
210
205
  -----------------------
@@ -218,7 +213,7 @@ expect(index).to have_tag("img[alt!='']")
218
213
  More info
219
214
  ---------
220
215
 
221
- You can find more on [documentation](http://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers)
216
+ You can find more on [documentation](https://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers)
222
217
 
223
218
  Also, please read [CHANGELOG](https://github.com/kucaahbe/rspec-html-matchers/blob/master/CHANGELOG.md) and [issues](https://github.com/kucaahbe/rspec-html-matchers/issues), might be helpful.
224
219
 
@@ -234,8 +229,8 @@ Contribution
234
229
  Contributors
235
230
  ============
236
231
 
237
- - [Kelly Felkins](http://github.com/kellyfelkins)
238
- - [Ryan Wilcox](http://github.com/rwilcox)
232
+ - [Kelly Felkins](https://github.com/kellyfelkins)
233
+ - [Ryan Wilcox](https://github.com/rwilcox)
239
234
  - [Simon Schoeters](https://github.com/cimm)
240
235
  - [Felix Tjandrawibawa](https://github.com/cemenghttps://github.com/cemeng)
241
236
  - [Szymon Przybył](https://github.com/apocalyptiq)
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Given /^I have following template:$/ do |string|
2
- File.open($INDEX_HTML,'w+') do |file|
4
+ File.open($INDEX_HTML, 'w+') do |file| # rubocop:disable Style/GlobalVars
3
5
  file.write(string)
4
6
  end
5
7
  end
@@ -1,20 +1,38 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # setup rspec matchers
2
4
  require 'rspec/expectations'
3
5
  World(RSpec::Matchers)
4
6
  require 'sinatra/base'
5
7
  require 'capybara/cucumber'
6
8
  require 'rspec-html-matchers'
9
+ require 'webdrivers'
10
+ require 'selenium-webdriver'
7
11
 
8
12
  World RSpecHtmlMatchers
9
13
 
10
- $ASSETS_DIR = File.expand_path('../tmp',__FILE__)
11
- $INDEX_HTML = File.join($ASSETS_DIR,'index.html')
14
+ # rubocop:disable Style/GlobalVars
15
+ $ASSETS_DIR = File.expand_path('../tmp', __FILE__)
16
+ $INDEX_HTML = File.join($ASSETS_DIR, 'index.html')
12
17
 
13
18
  class SimpleApp < Sinatra::Base
14
19
  set :public_folder, $ASSETS_DIR
15
20
  end
16
21
 
17
- Capybara.default_driver = :selenium
22
+ Capybara.register_driver :headless_chrome do |app|
23
+ options = Selenium::WebDriver::Chrome::Options.new
24
+ options.add_argument('--headless')
25
+ options.add_argument('--disable-gpu')
26
+ options.add_argument('--window-size=800,600')
27
+
28
+ Capybara::Selenium::Driver.new(app, :browser => :chrome, :options => options)
29
+ end
30
+
31
+ Capybara.configure do |config|
32
+ config.default_max_wait_time = 15 if config.respond_to? :default_max_wait_time=
33
+ config.default_driver = :headless_chrome
34
+ end
35
+
18
36
  Capybara.app = SimpleApp
19
37
 
20
38
  Before do
@@ -24,3 +42,4 @@ end
24
42
  After do
25
43
  FileUtils.rm_rf $ASSETS_DIR
26
44
  end
45
+ # rubocop:enable Style/GlobalVars
@@ -1,266 +1,30 @@
1
- # frozen_string_literal: true
2
1
  # encoding: UTF-8
3
- require 'rspec'
4
- require 'nokogiri'
2
+ # frozen_string_literal: true
5
3
 
4
+ require 'rspec-html-matchers/nokogiri_regexp_helper'
5
+ require 'rspec-html-matchers/nokogiri_text_helper'
6
+ require 'rspec-html-matchers/have_tag'
7
+
8
+ # RSpec global configuration:
9
+ #
10
+ # RSpec.configure do |config|
11
+ # config.include RSpecHtmlMatchers
12
+ # end
13
+ #
14
+ # RSpec per-test configuration
15
+ #
16
+ # RSpec.describe "my view spec" do
17
+ # include RSpecHtmlMatchers
18
+ #
19
+ # it "has tags" do
20
+ # expect(rendered).to have_tag('div')
21
+ # end
22
+ # end
23
+ #
24
+ # Cucumber configuration:
25
+ #
26
+ # World RSpecHtmlMatchers
6
27
  module RSpecHtmlMatchers
7
-
8
- # @api
9
- # @private
10
- # for nokogiri regexp matching
11
- class NokogiriRegexpHelper
12
- def initialize(regex)
13
- @regex = regex
14
- end
15
-
16
- def regexp node_set
17
- node_set.find_all { |node| node.content =~ @regex }
18
- end
19
- end
20
-
21
- # @api
22
- # @private
23
- class NokogiriTextHelper
24
- NON_BREAKING_SPACE = "\u00a0"
25
-
26
- def initialize text, squeeze_text = false
27
- @text = text
28
- @squeeze_text = squeeze_text
29
- end
30
-
31
- def content node_set
32
- node_set.find_all do |node|
33
- actual_content = node.content.gsub(NON_BREAKING_SPACE, ' ')
34
- actual_content = node.content.strip.squeeze(' ') if @squeeze_text
35
-
36
- actual_content == @text
37
- end
38
- end
39
- end
40
-
41
- # @api
42
- # @private
43
- class HaveTag
44
- attr_reader :failure_message, :failure_message_when_negated
45
- attr_reader :parent_scope, :current_scope
46
-
47
- DESCRIPTIONS = {
48
- :have_at_least_1 => %Q|have at least 1 element matching "%s"|,
49
- :have_n => %Q|have %i element(s) matching "%s"|
50
- }
51
-
52
- MESSAGES = {
53
- :expected_tag => %Q|expected following:\n%s\nto #{DESCRIPTIONS[:have_at_least_1]}, found 0.|,
54
- :unexpected_tag => %Q|expected following:\n%s\nto NOT have element matching "%s", found %s.|,
55
-
56
- :expected_count => %Q|expected following:\n%s\nto #{DESCRIPTIONS[:have_n]}, found %s.|,
57
- :unexpected_count => %Q|expected following:\n%s\nto NOT have %i element(s) matching "%s", but found.|,
58
-
59
- :expected_btw_count => %Q|expected following:\n%s\nto have at least %i and at most %i element(s) matching "%s", found %i.|,
60
- :unexpected_btw_count => %Q|expected following:\n%s\nto NOT have at least %i and at most %i element(s) matching "%s", but found %i.|,
61
-
62
- :expected_at_most => %Q|expected following:\n%s\nto have at most %i element(s) matching "%s", found %i.|,
63
- :unexpected_at_most => %Q|expected following:\n%s\nto NOT have at most %i element(s) matching "%s", but found %i.|,
64
-
65
- :expected_at_least => %Q|expected following:\n%s\nto have at least %i element(s) matching "%s", found %i.|,
66
- :unexpected_at_least => %Q|expected following:\n%s\nto NOT have at least %i element(s) matching "%s", but found %i.|,
67
-
68
- :expected_regexp => %Q|%s regexp expected within "%s" in following template:\n%s|,
69
- :unexpected_regexp => %Q|%s regexp unexpected within "%s" in following template:\n%s\nbut was found.|,
70
-
71
- :expected_text => %Q|"%s" expected within "%s" in following template:\n%s|,
72
- :unexpected_text => %Q|"%s" unexpected within "%s" in following template:\n%s\nbut was found.|,
73
-
74
- :wrong_count_error => %Q|:count with :minimum or :maximum has no sence!|,
75
- :min_max_error => %Q|:minimum should be less than :maximum!|,
76
- :bad_range_error => %Q|Your :count range(%s) has no sence!|,
77
- }
78
-
79
-
80
- def initialize tag, options={}, &block
81
- @tag, @options, @block = tag.to_s, options, block
82
-
83
- if with_attrs = @options.delete(:with)
84
- if classes = with_attrs.delete(:class)
85
- @tag += '.' + classes_to_selector(classes)
86
- end
87
- selector = with_attrs.inject('') do |html_attrs_string, (k, v)|
88
- html_attrs_string += "[#{k}='#{v}']"
89
- html_attrs_string
90
- end
91
- @tag += selector
92
- end
93
-
94
- if without_attrs = @options.delete(:without)
95
- if classes = without_attrs.delete(:class)
96
- @tag += ":not(.#{classes_to_selector(classes)})"
97
- end
98
- end
99
-
100
- validate_options!
101
- set_options
102
- end
103
-
104
- def matches? document, &block
105
- @block = block if block
106
-
107
- document = document.html if defined?(Capybara::Session) && document.is_a?(Capybara::Session)
108
-
109
- case document
110
- when String
111
- @parent_scope = @current_scope = Nokogiri::HTML(document).css(@tag)
112
- @document = document
113
- else
114
- @parent_scope = document.current_scope
115
- @current_scope = begin
116
- document.parent_scope.css(@tag)
117
- # on jruby this produce exception if css was not found:
118
- # undefined method `decorate' for nil:NilClass
119
- rescue NoMethodError
120
- Nokogiri::XML::NodeSet.new(Nokogiri::XML::Document.new)
121
- end
122
- @document = @parent_scope.to_html
123
- end
124
-
125
- if tag_presents? and text_right? and count_right?
126
- @current_scope = @parent_scope
127
- @block.call if @block
128
- true
129
- else
130
- false
131
- end
132
- end
133
-
134
- def description
135
- # TODO should it be more complicated?
136
- if @options.has_key?(:count)
137
- DESCRIPTIONS[:have_n] % [@options[:count],@tag]
138
- else
139
- DESCRIPTIONS[:have_at_least_1] % @tag
140
- end
141
- end
142
-
143
- private
144
-
145
- def classes_to_selector(classes)
146
- case classes
147
- when Array
148
- classes.join('.')
149
- when String
150
- classes.gsub(/\s+/, '.')
151
- end
152
- end
153
-
154
- def tag_presents?
155
- if @current_scope.first
156
- @count = @current_scope.count
157
- @failure_message_when_negated = MESSAGES[:unexpected_tag] % [@document, @tag, @count]
158
- true
159
- else
160
- @failure_message = MESSAGES[:expected_tag] % [@document, @tag]
161
- false
162
- end
163
- end
164
-
165
- def count_right?
166
- case @options[:count]
167
- when Integer
168
- ((@failure_message_when_negated=MESSAGES[:unexpected_count] % [@document,@count,@tag]) && @count == @options[:count]) || (@failure_message=MESSAGES[:expected_count] % [@document,@options[:count],@tag,@count]; false)
169
- when Range
170
- ((@failure_message_when_negated=MESSAGES[:unexpected_btw_count] % [@document,@options[:count].min,@options[:count].max,@tag,@count]) && @options[:count].member?(@count)) || (@failure_message=MESSAGES[:expected_btw_count] % [@document,@options[:count].min,@options[:count].max,@tag,@count]; false)
171
- when nil
172
- if @options[:maximum]
173
- ((@failure_message_when_negated=MESSAGES[:unexpected_at_most] % [@document,@options[:maximum],@tag,@count]) && @count <= @options[:maximum]) || (@failure_message=MESSAGES[:expected_at_most] % [@document,@options[:maximum],@tag,@count]; false)
174
- elsif @options[:minimum]
175
- ((@failure_message_when_negated=MESSAGES[:unexpected_at_least] % [@document,@options[:minimum],@tag,@count]) && @count >= @options[:minimum]) || (@failure_message=MESSAGES[:expected_at_least] % [@document,@options[:minimum],@tag,@count]; false)
176
- else
177
- true
178
- end
179
- end
180
- end
181
-
182
- def text_right?
183
- return true unless @options[:text]
184
-
185
- case text=@options[:text]
186
- when Regexp
187
- new_scope = @current_scope.css(':regexp()',NokogiriRegexpHelper.new(text))
188
- unless new_scope.empty?
189
- @count = new_scope.count
190
- @failure_message_when_negated = MESSAGES[:unexpected_regexp] % [text.inspect,@tag,@document]
191
- true
192
- else
193
- @failure_message = MESSAGES[:expected_regexp] % [text.inspect,@tag,@document]
194
- false
195
- end
196
- else
197
- new_scope = @current_scope.css(':content()', NokogiriTextHelper.new(text, @options[:squeeze_text]))
198
- unless new_scope.empty?
199
- @count = new_scope.count
200
- @failure_message_when_negated = MESSAGES[:unexpected_text] % [text,@tag,@document]
201
- true
202
- else
203
- @failure_message = MESSAGES[:expected_text] % [text,@tag,@document]
204
- false
205
- end
206
- end
207
- end
208
-
209
- protected
210
-
211
- def validate_options!
212
- validate_count_presence!
213
- validate_count_when_set_min_max!
214
- validate_count_when_set_range!
215
- end
216
-
217
- def validate_count_presence!
218
- raise 'wrong :count specified' unless [Range, NilClass].include?(@options[:count].class) or @options[:count].is_a?(Integer)
219
-
220
- [:min, :minimum, :max, :maximum].each do |key|
221
- raise MESSAGES[:wrong_count_error] if @options.has_key?(key) and @options.has_key?(:count)
222
- end
223
- end
224
-
225
- def validate_count_when_set_min_max!
226
- begin
227
- raise MESSAGES[:min_max_error] if @options[:minimum] > @options[:maximum]
228
- rescue NoMethodError # nil > 4
229
- rescue ArgumentError # 2 < nil
230
- end
231
- end
232
-
233
- def validate_count_when_set_range!
234
- begin
235
- begin
236
- raise MESSAGES[:bad_range_error] % [@options[:count].to_s] if count_is_range_but_no_min?
237
- rescue ArgumentError, "comparison of String with" # if @options[:count] == 'a'..'z'
238
- raise MESSAGES[:bad_range_error] % [@options[:count].to_s]
239
- end
240
- rescue TypeError # fix for 1.8.7 for 'rescue ArgumentError, "comparison of String with"' stroke
241
- raise MESSAGES[:bad_range_error] % [@options[:count].to_s]
242
- end
243
- end
244
-
245
- def count_is_range_but_no_min?
246
- @options[:count] && @options[:count].is_a?(Range) &&
247
- (@options[:count].min.nil? or @options[:count].min < 0)
248
- end
249
-
250
- def set_options
251
- @options[:minimum] ||= @options.delete(:min)
252
- @options[:maximum] ||= @options.delete(:max)
253
-
254
- @options[:text] = @options[:text].to_s if @options.has_key?(:text) && !@options[:text].is_a?(Regexp)
255
-
256
- if @options.has_key?(:seen) && !@options[:seen].is_a?(Regexp)
257
- @options[:text] = @options[:seen].to_s
258
- @options[:squeeze_text] = true
259
- end
260
- end
261
-
262
- end
263
-
264
28
  # tag assertion, this is the core of functionality, other matchers are shortcuts to this matcher
265
29
  #
266
30
  # @yield block where you should put with_tag, without_tag and/or other matchers
@@ -295,45 +59,60 @@ module RSpecHtmlMatchers
295
59
  # </html>").to have_tag('body') { with_tag('h1', :text => 'some html document') }
296
60
  # expect('<div class="one two">').to have_tag('div', :with => { :class => ['two', 'one'] })
297
61
  # expect('<div class="one two">').to have_tag('div', :with => { :class => 'two one' })
298
- def have_tag tag, options={}, &block
62
+ def have_tag tag, options = {}, &block
299
63
  # for backwards compatibility with rpecs have tag:
300
- options = { :text => options } if options.kind_of?(String) || options.kind_of?(Regexp)
64
+ options = { :text => options } if options.is_a?(String) || options.is_a?(Regexp)
301
65
  @__current_scope_for_nokogiri_matcher = HaveTag.new(tag, options, &block)
302
66
  end
303
67
 
304
- def have_empty_tag tag, options={}
305
- have_tag(tag, options.merge(text: ""))
68
+ # tests whether tag have any content inside
69
+ #
70
+ # @example
71
+ # expect('<div></div>').to have_empty_tag('div') # success
72
+ # expect('<div>hi</div>').to have_empty_tag('div') # fail
73
+ def have_empty_tag tag, options = {}
74
+ have_tag(tag, options.merge(:blank => true))
306
75
  end
307
76
 
308
77
  def with_text text
309
78
  raise StandardError, 'this matcher should be used inside "have_tag" matcher block' unless defined?(@__current_scope_for_nokogiri_matcher)
310
79
  raise ArgumentError, 'this matcher does not accept block' if block_given?
80
+
311
81
  tag = @__current_scope_for_nokogiri_matcher.instance_variable_get(:@tag)
312
- expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, :text => text)
82
+ within_nested_tag do
83
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, :text => text)
84
+ end
313
85
  end
314
86
 
315
87
  def without_text text
316
88
  raise StandardError, 'this matcher should be used inside "have_tag" matcher block' unless defined?(@__current_scope_for_nokogiri_matcher)
317
89
  raise ArgumentError, 'this matcher does not accept block' if block_given?
90
+
318
91
  tag = @__current_scope_for_nokogiri_matcher.instance_variable_get(:@tag)
319
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, :text => text)
92
+ within_nested_tag do
93
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, :text => text)
94
+ end
320
95
  end
321
- alias :but_without_text :without_text
96
+ alias but_without_text without_text
322
97
 
323
98
  # with_tag matcher
324
99
  # @yield block where you should put other with_tag or without_tag
325
100
  # @see #have_tag
326
101
  # @note this should be used within block of have_tag matcher
327
- def with_tag tag, options={}, &block
328
- expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options, &block)
102
+ def with_tag tag, options = {}, &block
103
+ within_nested_tag do
104
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options, &block)
105
+ end
329
106
  end
330
107
 
331
108
  # without_tag matcher
332
109
  # @yield block where you should put other with_tag or without_tag
333
110
  # @see #have_tag
334
111
  # @note this should be used within block of have_tag matcher
335
- def without_tag tag, options={}, &block
336
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options, &block)
112
+ def without_tag tag, options = {}, &block
113
+ within_nested_tag do
114
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options, &block)
115
+ end
337
116
  end
338
117
 
339
118
  # form assertion
@@ -342,250 +121,275 @@ module RSpecHtmlMatchers
342
121
  # have_tag 'form', :with => { :action => action_url, :method => method ... }
343
122
  # @yield block with with_<field>, see below
344
123
  # @see #have_tag
345
- def have_form action_url, method, options={}, &block
124
+ def have_form action_url, method, options = {}, &block
346
125
  options[:with] ||= {}
347
126
  id = options[:with].delete(:id)
348
- tag = 'form'; tag += '#'+id if id
127
+ tag = 'form'; tag += '#' + id if id
349
128
  options[:with].merge!(:action => action_url)
350
129
  options[:with].merge!(:method => method.to_s)
351
130
  have_tag tag, options, &block
352
131
  end
353
132
 
354
- #@TODO fix code duplications
133
+ # @TODO fix code duplications
355
134
 
356
- def with_hidden_field name, value=nil
357
- options = form_tag_options('hidden',name,value)
135
+ def with_hidden_field name, value = nil
136
+ options = form_tag_options('hidden', name, value)
358
137
  should_have_input(options)
359
138
  end
360
139
 
361
- def without_hidden_field name, value=nil
362
- options = form_tag_options('hidden',name,value)
140
+ def without_hidden_field name, value = nil
141
+ options = form_tag_options('hidden', name, value)
363
142
  should_not_have_input(options)
364
143
  end
365
144
 
366
- def with_text_field name, value=nil
367
- options = form_tag_options('text',name,value)
145
+ def with_text_field name, value = nil
146
+ options = form_tag_options('text', name, value)
368
147
  should_have_input(options)
369
148
  end
370
149
 
371
- def without_text_field name, value=nil
372
- options = form_tag_options('text',name,value)
150
+ def without_text_field name, value = nil
151
+ options = form_tag_options('text', name, value)
373
152
  should_not_have_input(options)
374
153
  end
375
154
 
376
- def with_email_field name, value=nil
377
- options = form_tag_options('email',name,value)
155
+ def with_email_field name, value = nil
156
+ options = form_tag_options('email', name, value)
378
157
  should_have_input(options)
379
158
  end
380
159
 
381
- def without_email_field name, value=nil
382
- options = form_tag_options('email',name,value)
160
+ def without_email_field name, value = nil
161
+ options = form_tag_options('email', name, value)
383
162
  should_not_have_input(options)
384
163
  end
385
164
 
386
- def with_url_field name, value=nil
387
- options = form_tag_options('url',name,value)
165
+ def with_url_field name, value = nil
166
+ options = form_tag_options('url', name, value)
388
167
  should_have_input(options)
389
168
  end
390
169
 
391
- def without_url_field name, value=nil
392
- options = form_tag_options('url',name,value)
170
+ def without_url_field name, value = nil
171
+ options = form_tag_options('url', name, value)
393
172
  should_not_have_input(options)
394
173
  end
395
174
 
396
- def with_number_field name, value=nil
397
- options = form_tag_options('number',name,value)
175
+ def with_number_field name, value = nil
176
+ options = form_tag_options('number', name, value)
398
177
  should_have_input(options)
399
178
  end
400
179
 
401
- def without_number_field name, value=nil
402
- options = form_tag_options('number',name,value)
180
+ def without_number_field name, value = nil
181
+ options = form_tag_options('number', name, value)
403
182
  should_not_have_input(options)
404
183
  end
405
184
 
406
- def with_range_field name, min, max, options={}
407
- options = { :with => { :name => name, :type => 'range', :min => min.to_s, :max => max.to_s }.merge(options.delete(:with)||{}) }
185
+ def with_range_field name, min, max, options = {}
186
+ options = { :with => { :name => name, :type => 'range', :min => min.to_s, :max => max.to_s }.merge(options.delete(:with) || {}) }
408
187
  should_have_input(options)
409
188
  end
410
189
 
411
- def without_range_field name, min=nil, max=nil, options={}
412
- options = { :with => { :name => name, :type => 'range' }.merge(options.delete(:with)||{}) }
190
+ def without_range_field name, min = nil, max = nil, options = {}
191
+ options = { :with => { :name => name, :type => 'range' }.merge(options.delete(:with) || {}) }
413
192
  options[:with].merge!(:min => min.to_s) if min
414
193
  options[:with].merge!(:max => max.to_s) if max
415
194
  should_not_have_input(options)
416
195
  end
417
196
 
418
- DATE_FIELD_TYPES = %w( date month week time datetime datetime-local )
197
+ DATE_FIELD_TYPES = %w[date month week time datetime datetime-local].freeze
419
198
 
420
- def with_date_field date_field_type, name=nil, options={}
199
+ def with_date_field date_field_type, name = nil, options = {}
421
200
  date_field_type = date_field_type.to_s
422
201
  raise "unknown type `#{date_field_type}` for date picker" unless DATE_FIELD_TYPES.include?(date_field_type)
423
- options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with)||{}) }
202
+
203
+ options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with) || {}) }
424
204
  options[:with].merge!(:name => name.to_s) if name
425
205
  should_have_input(options)
426
206
  end
427
207
 
428
- def without_date_field date_field_type, name=nil, options={}
208
+ def without_date_field date_field_type, name = nil, options = {}
429
209
  date_field_type = date_field_type.to_s
430
210
  raise "unknown type `#{date_field_type}` for date picker" unless DATE_FIELD_TYPES.include?(date_field_type)
431
- options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with)||{}) }
211
+
212
+ options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with) || {}) }
432
213
  options[:with].merge!(:name => name.to_s) if name
433
214
  should_not_have_input(options)
434
215
  end
435
216
 
436
- def with_password_field name, value=nil
437
- # TODO add ability to explicitly say that value should be empty
438
- options = form_tag_options('password',name,value)
217
+ def with_password_field name, value = nil
218
+ # TODO: add ability to explicitly say that value should be empty
219
+ options = form_tag_options('password', name, value)
439
220
  should_have_input(options)
440
221
  end
441
222
 
442
- def without_password_field name, value=nil
443
- options = form_tag_options('password',name,value)
223
+ def without_password_field name, value = nil
224
+ options = form_tag_options('password', name, value)
444
225
  should_not_have_input(options)
445
226
  end
446
227
 
447
- def with_file_field name, value=nil
448
- options = form_tag_options('file',name,value)
228
+ def with_file_field name, value = nil
229
+ options = form_tag_options('file', name, value)
449
230
  should_have_input(options)
450
231
  end
451
232
 
452
- def without_file_field name, value=nil
453
- options = form_tag_options('file',name,value)
233
+ def without_file_field name, value = nil
234
+ options = form_tag_options('file', name, value)
454
235
  should_not_have_input(options)
455
236
  end
456
237
 
457
238
  def with_text_area name
458
239
  # TODO, should be: with_text_area name, text=nil
459
- #options = form_tag_options('text',name,value)
240
+ # options = form_tag_options('text',name,value)
460
241
  options = { :with => { :name => name } }
461
- expect(@__current_scope_for_nokogiri_matcher).to have_tag('textarea', options)
242
+ within_nested_tag do
243
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag('textarea', options)
244
+ end
462
245
  end
463
246
 
464
247
  def without_text_area name
465
248
  # TODO, should be: without_text_area name, text=nil
466
- #options = form_tag_options('text',name,value)
249
+ # options = form_tag_options('text',name,value)
467
250
  options = { :with => { :name => name } }
468
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('textarea', options)
251
+ within_nested_tag do
252
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('textarea', options)
253
+ end
469
254
  end
470
255
 
471
- def with_checkbox name, value=nil
472
- options = form_tag_options('checkbox',name,value)
256
+ def with_checkbox name, value = nil
257
+ options = form_tag_options('checkbox', name, value)
473
258
  should_have_input(options)
474
259
  end
475
260
 
476
- def without_checkbox name, value=nil
477
- options = form_tag_options('checkbox',name,value)
261
+ def without_checkbox name, value = nil
262
+ options = form_tag_options('checkbox', name, value)
478
263
  should_not_have_input(options)
479
264
  end
480
265
 
481
266
  def with_radio_button name, value
482
- options = form_tag_options('radio',name,value)
267
+ options = form_tag_options('radio', name, value)
483
268
  should_have_input(options)
484
269
  end
485
270
 
486
271
  def without_radio_button name, value
487
- options = form_tag_options('radio',name,value)
272
+ options = form_tag_options('radio', name, value)
488
273
  should_not_have_input(options)
489
274
  end
490
275
 
491
- def with_select name, options={}, &block
276
+ def with_select name, options = {}, &block
492
277
  options[:with] ||= {}
493
278
  id = options[:with].delete(:id)
494
- tag='select'; tag += '#'+id if id
279
+ tag = 'select'; tag += '#' + id if id
495
280
  options[:with].merge!(:name => name)
496
- expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options, &block)
281
+ within_nested_tag do
282
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options, &block)
283
+ end
497
284
  end
498
285
 
499
- def without_select name, options={}, &block
286
+ def without_select name, options = {}, &block
500
287
  options[:with] ||= {}
501
288
  id = options[:with].delete(:id)
502
- tag='select'; tag += '#'+id if id
289
+ tag = 'select'; tag += '#' + id if id
503
290
  options[:with].merge!(:name => name)
504
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options, &block)
291
+ within_nested_tag do
292
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options, &block)
293
+ end
505
294
  end
506
295
 
507
- def with_option text, value=nil, options={}
296
+ def with_option text, value = nil, options = {}
508
297
  options[:with] ||= {}
509
298
  if value.is_a?(Hash)
510
299
  options.merge!(value)
511
- value=nil
300
+ value = nil
512
301
  end
513
- tag='option'
302
+ tag = 'option'
514
303
  options[:with].merge!(:value => value.to_s) if value
515
- if options[:selected]
516
- options[:with].merge!(:selected => "selected")
517
- end
304
+ options[:with].merge!(:selected => 'selected') if options[:selected]
518
305
  options.delete(:selected)
519
306
  options.merge!(:text => text) if text
520
- expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options)
307
+ within_nested_tag do
308
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options)
309
+ end
521
310
  end
522
311
 
523
- def without_option text, value=nil, options={}
312
+ def without_option text, value = nil, options = {}
524
313
  options[:with] ||= {}
525
314
  if value.is_a?(Hash)
526
315
  options.merge!(value)
527
- value=nil
316
+ value = nil
528
317
  end
529
- tag='option'
318
+ tag = 'option'
530
319
  options[:with].merge!(:value => value.to_s) if value
531
- if options[:selected]
532
- options[:with].merge!(:selected => "selected")
533
- end
320
+ options[:with].merge!(:selected => 'selected') if options[:selected]
534
321
  options.delete(:selected)
535
322
  options.merge!(:text => text) if text
536
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options)
323
+ within_nested_tag do
324
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options)
325
+ end
537
326
  end
538
327
 
539
- def with_button text, value=nil, options={}
328
+ def with_button text, value = nil, options = {}
540
329
  options[:with] ||= {}
541
330
  if value.is_a?(Hash)
542
331
  options.merge!(value)
543
- value=nil
332
+ value = nil
544
333
  end
545
334
  options[:with].merge!(:value => value.to_s) if value
546
335
  options.merge!(:text => text) if text
547
- expect(@__current_scope_for_nokogiri_matcher).to have_tag('button', options)
336
+ within_nested_tag do
337
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag('button', options)
338
+ end
548
339
  end
549
340
 
550
- def without_button text, value=nil, options={}
341
+ def without_button text, value = nil, options = {}
551
342
  options[:with] ||= {}
552
343
  if value.is_a?(Hash)
553
344
  options.merge!(value)
554
- value=nil
345
+ value = nil
555
346
  end
556
347
  options[:with].merge!(:value => value.to_s) if value
557
348
  options.merge!(:text => text) if text
558
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('button', options)
349
+ within_nested_tag do
350
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('button', options)
351
+ end
559
352
  end
560
353
 
561
354
  def with_submit value
562
355
  options = { :with => { :type => 'submit', :value => value } }
563
- #options = form_tag_options('text',name,value)
356
+ # options = form_tag_options('text',name,value)
564
357
  should_have_input(options)
565
358
  end
566
359
 
567
360
  def without_submit value
568
- #options = form_tag_options('text',name,value)
361
+ # options = form_tag_options('text',name,value)
569
362
  options = { :with => { :type => 'submit', :value => value } }
570
363
  should_not_have_input(options)
571
364
  end
572
365
 
573
366
  private
574
367
 
575
- def should_have_input(options)
576
- expect(@__current_scope_for_nokogiri_matcher).to have_tag('input', options)
368
+ def should_have_input options
369
+ within_nested_tag do
370
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag('input', options)
371
+ end
577
372
  end
578
373
 
579
- def should_not_have_input(options)
580
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('input', options)
374
+ def should_not_have_input options
375
+ within_nested_tag do
376
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('input', options)
377
+ end
581
378
  end
582
379
 
583
380
  # form_tag in method name name mean smth. like input, submit, tags that should appear in a form
584
- def form_tag_options form_tag_type, form_tag_name, form_tag_value=nil
381
+ def form_tag_options form_tag_type, form_tag_name, form_tag_value = nil
585
382
  options = { :with => { :name => form_tag_name, :type => form_tag_type } }
586
383
  # .to_s if value is a digit or smth. else, see issue#10
587
384
  options[:with].merge!(:value => form_tag_value.to_s) if form_tag_value
588
- return options
385
+ options
589
386
  end
590
387
 
388
+ def within_nested_tag &block
389
+ raise 'block needed' unless block_given?
390
+
391
+ parent_scope = @__current_scope_for_nokogiri_matcher
392
+ block.call
393
+ @__current_scope_for_nokogiri_matcher = parent_scope
394
+ end
591
395
  end