test-unit-capybara 1.0.0 → 1.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/Gemfile ADDED
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8; mode: ruby -*-
2
+ #
3
+ # Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ gem "test-unit", ">= 2.4.4"
20
+ gem "capybara", ">= 1.1.3"
21
+ gem "json"
22
+
23
+ group :development, :test do
24
+ gem "rake"
25
+ gem "jeweler"
26
+ gem "yard"
27
+ gem "packnga"
28
+ gem "test-unit-notify"
29
+ end
@@ -0,0 +1,87 @@
1
+ h1. test-unit-capybara
2
+
3
+ "Web site":http://test-unit.rubyforge.org/#test-unit-capybara
4
+
5
+ h2. Description
6
+
7
+ test-unit-capybara is a Capybara adapter for test-unit 2. You can get "Capybara":https://rubygems.org/gems/capybara integrated Test::Unit::TestCase. It also provides useful assertions for Capybara.
8
+
9
+ h2. Install
10
+
11
+ <pre>
12
+ % sudo gem install test-unit-capybara
13
+ </pre>
14
+
15
+ h2. Usage
16
+
17
+ <pre>
18
+ require 'test/unit/capybara'
19
+
20
+ class MyRackApplication
21
+ def call(env)
22
+ html = <<-HTML
23
+ <html>
24
+ <head>
25
+ <title>Welcome! - my site</title>
26
+ </head>
27
+ <body>
28
+ <h1>Welcome!</h1>
29
+ <div class="header">
30
+ <p>No navigation.</p>
31
+ </div>
32
+ </body>
33
+ </html>
34
+ HTML
35
+ [200, {"Content-Type" => "text/html"}, [html]]
36
+ end
37
+ end
38
+
39
+ class TestMyRackApplication < Test::Unit::TestCase
40
+ include Capybara::DSL
41
+
42
+ def setup
43
+ Capybara.app = MyRackApplication.new
44
+ end
45
+
46
+ def test_title
47
+ visit("/")
48
+ within("h1") do
49
+ assert_equal("Welcome!", text)
50
+ end
51
+ end
52
+
53
+ def test_no_sidebar
54
+ visit("/")
55
+ within("body") do
56
+ assert_not_find(".sidebar")
57
+ end
58
+ end
59
+
60
+ def test_header_content
61
+ visit("/")
62
+ within(".header") do
63
+ find("ol.navi")
64
+ # This fails with the following message:
65
+ #
66
+ # <"ol.navi">(:css) expected to find a element in
67
+ # <<div class="header">
68
+ # <p>No navigation.</p>
69
+ # </div>>
70
+ #
71
+ # This messages shows the current context. You don't need to
72
+ # entire HTML. You just see the current context moved by "within".
73
+ # It helps you debug a problem without save_and_open_page.
74
+ end
75
+ end
76
+ end
77
+ </pre>
78
+
79
+ h2. License
80
+
81
+ LGPLv2.1 or later.
82
+
83
+ (Kouhei Sutou has a right to change the license including contributed patches.)
84
+
85
+ h2. Authors
86
+
87
+ * Kouhei Sutou
data/Rakefile CHANGED
@@ -1,33 +1,81 @@
1
1
  # -*- ruby -*-
2
+ #
3
+ # Copyright (C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2
18
 
3
- require 'pathname'
19
+ require './lib/test/unit/capybara/version'
4
20
 
5
- base_dir = Pathname(__FILE__).dirname.expand_path
6
- test_unit_dir = (base_dir.parent + "test-unit").expand_path
7
- test_unit_lib_dir = test_unit_dir + "lib"
8
- lib_dir = base_dir + "lib"
21
+ require 'rubygems'
22
+ require 'rubygems/package_task'
23
+ require 'yard'
24
+ require 'jeweler'
25
+ require 'packnga'
9
26
 
10
- $LOAD_PATH.unshift(test_unit_lib_dir.to_s)
11
- $LOAD_PATH.unshift(lib_dir.to_s)
27
+ def cleanup_white_space(entry)
28
+ entry.gsub(/(\A\n+|\n+\z)/, '') + "\n"
29
+ end
12
30
 
13
- require 'test/unit/capybara'
31
+ ENV["VERSION"] ||= Test::Unit::Capybara::VERSION
32
+ version = ENV["VERSION"].dup
33
+ spec = nil
34
+ Jeweler::Tasks.new do |_spec|
35
+ spec = _spec
36
+ spec.name = "test-unit-capybara"
37
+ spec.version = version
38
+ spec.rubyforge_project = "test-unit"
39
+ spec.homepage = "http://test-unit.rubyforge.org/#test-unit-capybara"
40
+ spec.authors = ["Kouhei Sutou"]
41
+ spec.email = ["kou@clear-code.com"]
42
+ entries = File.read("README.textile").split(/^h2\.\s(.*)$/)
43
+ description = cleanup_white_space(entries[entries.index("Description") + 1])
44
+ spec.summary, spec.description, = description.split(/\n\n+/, 3)
45
+ spec.license = "LGPLv2 or later"
46
+ spec.files = FileList["lib/**/*.rb",
47
+ "bin/*",
48
+ "doc/text/*",
49
+ "README.textile",
50
+ "COPYING",
51
+ "Rakefile",
52
+ "Gemfile"]
53
+ spec.test_files = FileList["test/**/*.rb"]
54
+ end
14
55
 
15
- require 'rubygems'
16
- require 'hoe'
56
+ Rake::Task["release"].prerequisites.clear
57
+ Jeweler::RubygemsDotOrgTasks.new do
58
+ end
17
59
 
18
- Test::Unit.run = true
60
+ Gem::PackageTask.new(spec) do |pkg|
61
+ pkg.need_tar_gz = true
62
+ end
19
63
 
20
- version = Test::Unit::Capybara::VERSION
21
- ENV["VERSION"] = version
22
- Hoe.spec('test-unit-capybara') do
23
- self.version = version
24
- self.rubyforge_name = "test-unit"
64
+ document_task = Packnga::DocumentTask.new(spec) do
65
+ end
25
66
 
26
- developer('Kouhei Sutou', 'kou@clear-code.com')
67
+ Packnga::ReleaseTask.new(spec) do |task|
68
+ end
27
69
 
28
- extra_deps << ["test-unit", ">= 2.1.2"]
29
- extra_deps << ["capybara"]
70
+ # XXX: Workaround. This should be fixed in packnga.
71
+ task :htaccess do
72
+ htaccess = "doc/html/test-unit-capybara/.htaccess"
73
+ htaccess_content = File.read(htaccess)
74
+ File.open(htaccess, "w") do |htaccess_file|
75
+ htaccess_file.print(htaccess_content.gsub(/#test-unit-capybara/, ""))
76
+ end
30
77
  end
78
+ task "release:reference:publish" => :htaccess
31
79
 
32
80
  desc "Tag the current revision."
33
81
  task :tag do
@@ -0,0 +1,15 @@
1
+ h1. News
2
+
3
+ h2(#1-0-1). 1.0.1 - 2012-01-16
4
+
5
+ A Capybara integration improvement release.
6
+
7
+ h3. Improvments
8
+
9
+ * Added {Test::Unit::Capybara::Assertions#assert_all}.
10
+ * Added {Test::Unit::Capybara::Assertions#assert_not_find}.
11
+ * Supported Capybara::ElementNotFound as a failure.
12
+
13
+ h2(#1-0-0). 1.0.0 - 2011-05-01
14
+
15
+ The first release!!!
@@ -1,25 +1,37 @@
1
- #--
1
+ # -*- ruby -*-
2
2
  #
3
- # Author:: Kouhei Sutou
4
- # Copyright::
5
- # * Copyright (c) 2011 Kouhei Sutou <kou@clear-code.com>
6
- # License:: LGPLv2+
3
+ # Copyright (C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ require "test/unit/capybara/version"
7
20
 
8
21
  require 'capybara'
9
22
  require 'capybara/dsl'
23
+ require "json"
10
24
  require 'test/unit'
11
25
 
12
26
  module Test::Unit
13
27
  module Capybara
14
- VERSION = "1.0.0"
15
-
16
28
  module Adapter
17
29
  class << self
18
30
  def included(mod)
19
31
  mod.module_eval do
20
32
  setup :before => :prepend
21
33
  def setup_capybara
22
- return unless self.class.include?(::Capybara)
34
+ return unless self.class.include?(::Capybara::DSL)
23
35
  extend(Assertions)
24
36
  if self[:js]
25
37
  ::Capybara.current_driver = ::Capybara.javascript_driver
@@ -30,7 +42,7 @@ module Test::Unit
30
42
 
31
43
  teardown :after => :append
32
44
  def teardown_capybara
33
- return unless self.class.include?(::Capybara)
45
+ return unless self.class.include?(::Capybara::DSL)
34
46
  ::Capybara.reset_sessions!
35
47
  ::Capybara.use_default_driver
36
48
  end
@@ -39,33 +51,443 @@ module Test::Unit
39
51
  end
40
52
  end
41
53
 
54
+ # @private
55
+ class ElementNotFound < ::Capybara::ElementNotFound
56
+ attr_reader :node, :query
57
+ def initialize(node, query)
58
+ @node = node
59
+ @query = query
60
+ super(@query.failure_message(:find, @node))
61
+ end
62
+ end
63
+
64
+ # @private
65
+ module FindError
66
+ class << self
67
+ def included(base)
68
+ base.module_eval do
69
+ alias_method :raise_find_error_original, :raise_find_error
70
+ alias_method :raise_find_error, :raise_find_error_for_test_unit
71
+ end
72
+ end
73
+ end
74
+
75
+ def raise_find_error_for_test_unit(*args)
76
+ query = ::Capybara::Query.new(*args)
77
+ raise ElementNotFound.new(self, query)
78
+ end
79
+ end
80
+
81
+ # @private
82
+ class ::Capybara::Node::Base
83
+ include FindError
84
+ end
85
+
86
+ # @private
87
+ module ElementNotFoundHandler
88
+ class << self
89
+ def included(base)
90
+ base.exception_handler(:handle_capybara_element_not_found)
91
+ end
92
+ end
93
+
94
+ private
95
+ def handle_capybara_element_not_found(exception)
96
+ return false unless exception.is_a?(ElementNotFound)
97
+ return false unless respond_to?(:flunk_find)
98
+ query = exception.query
99
+ begin
100
+ flunk_find(exception.node,
101
+ :kind => query.selector.name,
102
+ :locator => query.locator)
103
+ rescue AssertionFailedError => assertion_failed_error
104
+ assertion_failed_error.backtrace.replace(exception.backtrace)
105
+ handle_exception(assertion_failed_error)
106
+ end
107
+ end
108
+ end
109
+
110
+ # @private
111
+ class NodeInspector
112
+ Inspector = ::Test::Unit::Assertions::AssertionMessage::Inspector
113
+ Inspector.register_inspector_class(self)
114
+
115
+ class << self
116
+ def target?(object)
117
+ object.is_a?(::Capybara::Node::Base)
118
+ end
119
+
120
+ def source(node)
121
+ if node.base.respond_to?(:source)
122
+ node.base.source
123
+ else
124
+ node.base.native.to_s
125
+ end
126
+ end
127
+ end
128
+
129
+ def initialize(node, inspected_objects)
130
+ @node = node
131
+ @inspected_objects = inspected_objects
132
+ end
133
+
134
+ def inspect
135
+ @node.inspect.gsub(/>\z/, " #{self.class.source(@node)}>")
136
+ end
137
+
138
+ def pretty_print(q)
139
+ q.text(@node.inspect.gsub(/>\z/, ""))
140
+ q.breakable
141
+ q.text("#{self.class.source(@node)}>")
142
+ end
143
+ end
144
+
42
145
  module Assertions
43
- def assert_body(expected, options={})
146
+ # @private
147
+ AssertionMessage = ::Test::Unit::Assertions::AssertionMessage
148
+
149
+ # Passes if @expected@ == @source@. @source@ is a
150
+ # method provided by Capybara::DSL.
151
+ #
152
+ # @source@ may be parsed depended on response
153
+ # Content-Type before comparing. Here are parsed
154
+ # Content-Types:
155
+ #
156
+ # - @"application/json"@ := It's parsed by @JSON.parse@.
157
+ #
158
+ # @param [Object] expected the expected body
159
+ # content. The actual body may be parsed. It
160
+ # depends on @:content_type@ option.
161
+ #
162
+ # @option options [String] :content_type (nil)
163
+ # the expected Content-Type. If this value is @nil@,
164
+ # Content-Type will not be compared.
165
+ #
166
+ # This value can be specified by abbreviated. Here
167
+ # are abbreviations:
168
+ #
169
+ # - @:json@ := @"application/json"@
170
+ #
171
+ # @yield [expected_response, actual_response] the
172
+ # optional compared responses normalizer.
173
+ # @yieldparam [Hash] expected_response the expected
174
+ # response constructed in the method.
175
+ # @yieldparam [Hash] actual_response the actual
176
+ # response constructed in the method.
177
+ # @yieldreturn [expected_response, actual_response] the
178
+ # normalized compared responses.
179
+ #
180
+ # @example Pass case
181
+ # # Actual response:
182
+ # # Content-Type: application/json
183
+ # # Body: {"status": true}
184
+ # assert_body({"status" => true}, :content_type => :json)
185
+ #
186
+ # @example Failure case
187
+ # # Actual response:
188
+ # # Content-Type: text/html
189
+ # # Body: <html><body>Hello</body></html>
190
+ # assert_body("<html><body>World</body></html>")
191
+ def assert_body(expected, options={}, &block)
44
192
  content_type = options[:content_type]
45
- case content_type
46
- when :json
47
- assert_equal({
48
- :content_type => "application/json",
49
- :body => expected,
50
- },
51
- {
52
- :content_type => page.response_headers["Content-Type"],
53
- :body => JSON.parse(body),
54
- })
193
+ actual_response = {
194
+ :content_type => page_content_type,
195
+ :body => parsed_page_body,
196
+ }
197
+ expected_response = {:body => expected}
198
+ if content_type
199
+ expected_response[:content_type] = normalize_content_type(content_type)
200
+ else
201
+ actual_response.delete(:content_type)
202
+ end
203
+ if block_given?
204
+ expected_response, actual_response = yield(expected_response,
205
+ actual_response)
206
+ end
207
+ assert_equal(expected_response, actual_response)
208
+ end
209
+
210
+ # @param [...] args (see {::Capybara::Node::Finders#all})
211
+ # @return [Array<::Capybara::Element>] The found elements.
212
+ #
213
+ # @see Capybara::Node::Finders#all
214
+ #
215
+ # @overload assert_all(*args)
216
+ # Passes if the selector finds one or more elements
217
+ # from the current node.
218
+ #
219
+ # @example Pass case
220
+ # # Actual response:
221
+ # # <html>
222
+ # # <body>
223
+ # # <h1>Hello</h1>
224
+ # # <h2>Yay!</h2>
225
+ # # <div class="section">
226
+ # # <h2>World</h2>
227
+ # # </div>
228
+ # # </body>
229
+ # # </html>
230
+ # h2_elements = assert_page_all("h2")
231
+ # p h2_elements
232
+ # # => [#<Capybara::Element tag="h2" path="/html/body/h2">,
233
+ # # #<Capybara::Element tag="h2" path="/html/body/div/h2">]
234
+ #
235
+ # @example Failure case
236
+ # # Actual response:
237
+ # # <html>
238
+ # # <body>
239
+ # # <h1>Hello</h1>
240
+ # # <h2>Yay!</h2>
241
+ # # <div class="section">
242
+ # # <h2>World</h2>
243
+ # # </div>
244
+ # # </body>
245
+ # # </html>
246
+ # assert_page_all("h3")
247
+ #
248
+ # @overload assert_all(node, *args)
249
+ # Passes if the selector finds one or more elements
250
+ # from @node@.
251
+ #
252
+ # @param [::Capybara::Node::Base] node The target node.
253
+ #
254
+ # @example Pass case (simple)
255
+ # # Actual response:
256
+ # # <html>
257
+ # # <body>
258
+ # # <h1>Hello</h1>
259
+ # # <h2>Yay!</h2>
260
+ # # <div class="section">
261
+ # # <h2>World</h2>
262
+ # # </div>
263
+ # # </body>
264
+ # # </html>
265
+ # section = assert_find("div.section")
266
+ # p section
267
+ # # => #<Capybara::Element tag="h2" path="/html/body/div">
268
+ # h2_elements = assert_all(section, "h2")
269
+ # p h2_elements
270
+ # # => [#<Capybara::Element tag="h2" path="/html/body/div/h2">]
271
+ def assert_all(*args)
272
+ node = nil
273
+ node = args.shift if args[0].is_a?(::Capybara::Node::Base)
274
+ args = normalize_page_finder_arguments(args)
275
+ format = <<-EOT
276
+ <?>(?) expected to find one or more elements in
277
+ <?>
278
+ EOT
279
+ current_context = node || page.send(:current_node)
280
+ current_context_source = node_source(current_context)
281
+ source_in_message = AssertionMessage.literal(current_context_source)
282
+ full_message = build_message(args[:message],
283
+ format,
284
+ args[:locator],
285
+ args[:kind],
286
+ source_in_message)
287
+ if node
288
+ elements = node.all(*args[:finder_arguments])
289
+ else
290
+ elements = all(*args[:finder_arguments])
291
+ end
292
+ assert_block(full_message) do
293
+ not elements.empty?
294
+ end
295
+ elements
296
+ end
297
+
298
+ # @param [...] args (see {::Capybara::Node::Finders#find})
299
+ #
300
+ # @see ::Capybara::Node::Finders#find
301
+ #
302
+ # @overload assert_not_find(*args, &block)
303
+ # Passes if the selector doesn't find any elements
304
+ # from the current node.
305
+ #
306
+ # @example Pass case
307
+ # # Actual response:
308
+ # # <html>
309
+ # # <body>
310
+ # # <h1>Hello</h1>
311
+ # # <h2>Yay!</h2>
312
+ # # <div class="section">
313
+ # # <h2>World</h2>
314
+ # # </div>
315
+ # # </body>
316
+ # # </html>
317
+ # assert_not_find("h3")
318
+ #
319
+ # @example Failure case
320
+ # # Actual response:
321
+ # # <html>
322
+ # # <body>
323
+ # # <h1>Hello</h1>
324
+ # # <h2>Yay!</h2>
325
+ # # <div class="section">
326
+ # # <h2>World</h2>
327
+ # # </div>
328
+ # # </body>
329
+ # # </html>
330
+ # assert_not_find("h1")
331
+ #
332
+ # @overload assert_not_find(node, *args, &block)
333
+ # Passes if the selector doesn't find any element from @node@.
334
+ #
335
+ # @param [::Capybara::Node::Base] node The target node.
336
+ #
337
+ # @example Pass case
338
+ # # Actual response:
339
+ # # <html>
340
+ # # <body>
341
+ # # <h1>Hello</h1>
342
+ # # <h2>Yay!</h2>
343
+ # # <div class="section">
344
+ # # <h2>World</h2>
345
+ # # </div>
346
+ # # </body>
347
+ # # </html>
348
+ # section = assert_find("section")
349
+ # p section
350
+ # # => #<Capybara::Element tag="h2" path="/html/body/div">
351
+ # assert_not_find(section, "h1")
352
+ #
353
+ # @example Failure case
354
+ # # Actual response:
355
+ # # <html>
356
+ # # <body>
357
+ # # <h1>Hello</h1>
358
+ # # <h2>Yay!</h2>
359
+ # # <div class="section">
360
+ # # <h2>World</h2>
361
+ # # </div>
362
+ # # </body>
363
+ # # </html>
364
+ # section = assert_find("section")
365
+ # p section
366
+ # # => #<Capybara::Element tag="h2" path="/html/body/div">
367
+ # assert_not_find(section, "h2")
368
+ def assert_not_find(*args, &block)
369
+ node = nil
370
+ node = args.shift if args[0].is_a?(::Capybara::Node::Base)
371
+ args = normalize_page_finder_arguments(args)
372
+ if node
373
+ element = node.first(*args[:finder_arguments])
374
+ else
375
+ element = first(*args[:finder_arguments])
376
+ end
377
+ format = <<-EOT
378
+ <?>(?) expected to not find a element but was
379
+ <?> in
380
+ <?>
381
+ EOT
382
+ element_source = nil
383
+ element_source = node_source(element) if element
384
+ current_context = node || page.send(:current_node)
385
+ current_context_source = node_source(current_context)
386
+ source_in_message = AssertionMessage.literal(current_context_source)
387
+ full_message = build_message(args[:message],
388
+ format,
389
+ args[:locator],
390
+ args[:kind],
391
+ AssertionMessage.literal(element_source),
392
+ source_in_message)
393
+ assert_block(full_message) do
394
+ element.nil?
395
+ end
396
+ end
397
+
398
+ # Fails always with {::Capybara::Node::Element} is not
399
+ # found message.
400
+ #
401
+ # @param [::Capybara::Node::Element] base_node The
402
+ # node used as search target.
403
+ # @option options [String] :message The user custom
404
+ # message added to failure message.
405
+ # @option options [String] :locator The query used to
406
+ # find a node.
407
+ #
408
+ # It should be specified for useful failure message.
409
+ # @option options [String] :kind The kind of query.
410
+ #
411
+ # It should be specified for useful failure message.
412
+ def flunk_find(base_node, options={})
413
+ format = <<-EOT
414
+ <?>(?) expected to find a element in
415
+ <?>
416
+ EOT
417
+ base_html = AssertionMessage.literal(node_source(base_node))
418
+ full_message = build_message(options[:message],
419
+ format,
420
+ options[:locator],
421
+ options[:kind],
422
+ base_html)
423
+ assert_block(full_message) do
424
+ false
425
+ end
426
+ end
427
+
428
+ private
429
+ def page_content_type
430
+ page.response_headers["Content-Type"]
431
+ end
432
+
433
+ def parsed_page_body
434
+ case page_content_type
435
+ when "application/json"
436
+ ::JSON.parse(source)
437
+ else
438
+ source
439
+ end
440
+ end
441
+
442
+ def normalize_page_finder_arguments(args)
443
+ args = args.dup
444
+ options = {}
445
+ options = args.pop if args.last.is_a?(Hash)
446
+ if args.size == 1
447
+ locator = args[0]
448
+ if locator[0, 1] == "/"
449
+ kind = :xpath
450
+ args.unshift(kind)
451
+ else
452
+ kind = ::Capybara.default_selector
453
+ end
55
454
  else
56
- format = "unsupported content type: <?>\n" +
57
- "expected: <?>\n" +
58
- " options: <?>"
59
- arguments = [content_type, expected, options]
60
- assert_block(build_message(nil, format, *arguments)) do
61
- false
455
+ kind, locator, = args
456
+ end
457
+ args << options
458
+
459
+ {
460
+ :kind => kind,
461
+ :locator => locator,
462
+ :message => options.delete(:message),
463
+ :finder_arguments => args,
464
+ }
465
+ end
466
+
467
+ def node_source(node)
468
+ if node
469
+ if node.base.respond_to?(:source)
470
+ node.base.source
471
+ else
472
+ node.base.native.to_s
62
473
  end
474
+ else
475
+ source
63
476
  end
64
477
  end
478
+
479
+ # @private
480
+ CONTENT_TYPE_SHORTCUTS = {
481
+ :json => "application/json",
482
+ }
483
+ def normalize_content_type(content_type)
484
+ CONTENT_TYPE_SHORTCUTS[content_type] || content_type
485
+ end
65
486
  end
66
487
  end
67
488
 
68
489
  class TestCase
69
490
  include Capybara::Adapter
491
+ include Capybara::ElementNotFoundHandler
70
492
  end
71
493
  end