bbc-capybara 1.1.2

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.
Files changed (107) hide show
  1. data/History.txt +325 -0
  2. data/License.txt +22 -0
  3. data/README.md +815 -0
  4. data/lib/capybara.rb +368 -0
  5. data/lib/capybara/cucumber.rb +25 -0
  6. data/lib/capybara/driver/base.rb +64 -0
  7. data/lib/capybara/driver/node.rb +74 -0
  8. data/lib/capybara/dsl.rb +50 -0
  9. data/lib/capybara/node/actions.rb +146 -0
  10. data/lib/capybara/node/base.rb +63 -0
  11. data/lib/capybara/node/document.rb +25 -0
  12. data/lib/capybara/node/element.rb +201 -0
  13. data/lib/capybara/node/finders.rb +154 -0
  14. data/lib/capybara/node/matchers.rb +442 -0
  15. data/lib/capybara/node/simple.rb +132 -0
  16. data/lib/capybara/query.rb +63 -0
  17. data/lib/capybara/rack_test/browser.rb +126 -0
  18. data/lib/capybara/rack_test/driver.rb +80 -0
  19. data/lib/capybara/rack_test/form.rb +80 -0
  20. data/lib/capybara/rack_test/node.rb +121 -0
  21. data/lib/capybara/rails.rb +17 -0
  22. data/lib/capybara/rspec.rb +26 -0
  23. data/lib/capybara/rspec/features.rb +22 -0
  24. data/lib/capybara/rspec/matchers.rb +152 -0
  25. data/lib/capybara/selector.rb +156 -0
  26. data/lib/capybara/selenium/driver.rb +169 -0
  27. data/lib/capybara/selenium/node.rb +91 -0
  28. data/lib/capybara/server.rb +87 -0
  29. data/lib/capybara/session.rb +322 -0
  30. data/lib/capybara/spec/driver.rb +329 -0
  31. data/lib/capybara/spec/fixtures/capybara.jpg +3 -0
  32. data/lib/capybara/spec/fixtures/test_file.txt +1 -0
  33. data/lib/capybara/spec/public/jquery-ui.js +791 -0
  34. data/lib/capybara/spec/public/jquery.js +9046 -0
  35. data/lib/capybara/spec/public/test.js +43 -0
  36. data/lib/capybara/spec/session.rb +148 -0
  37. data/lib/capybara/spec/session/all_spec.rb +78 -0
  38. data/lib/capybara/spec/session/attach_file_spec.rb +76 -0
  39. data/lib/capybara/spec/session/check_spec.rb +68 -0
  40. data/lib/capybara/spec/session/choose_spec.rb +29 -0
  41. data/lib/capybara/spec/session/click_button_spec.rb +305 -0
  42. data/lib/capybara/spec/session/click_link_or_button_spec.rb +37 -0
  43. data/lib/capybara/spec/session/click_link_spec.rb +120 -0
  44. data/lib/capybara/spec/session/current_url_spec.rb +83 -0
  45. data/lib/capybara/spec/session/fill_in_spec.rb +127 -0
  46. data/lib/capybara/spec/session/find_button_spec.rb +18 -0
  47. data/lib/capybara/spec/session/find_by_id_spec.rb +18 -0
  48. data/lib/capybara/spec/session/find_field_spec.rb +26 -0
  49. data/lib/capybara/spec/session/find_link_spec.rb +19 -0
  50. data/lib/capybara/spec/session/find_spec.rb +168 -0
  51. data/lib/capybara/spec/session/first_spec.rb +105 -0
  52. data/lib/capybara/spec/session/has_button_spec.rb +32 -0
  53. data/lib/capybara/spec/session/has_css_spec.rb +243 -0
  54. data/lib/capybara/spec/session/has_field_spec.rb +192 -0
  55. data/lib/capybara/spec/session/has_link_spec.rb +37 -0
  56. data/lib/capybara/spec/session/has_select_spec.rb +129 -0
  57. data/lib/capybara/spec/session/has_selector_spec.rb +129 -0
  58. data/lib/capybara/spec/session/has_table_spec.rb +34 -0
  59. data/lib/capybara/spec/session/has_text_spec.rb +138 -0
  60. data/lib/capybara/spec/session/has_xpath_spec.rb +123 -0
  61. data/lib/capybara/spec/session/headers.rb +19 -0
  62. data/lib/capybara/spec/session/javascript.rb +312 -0
  63. data/lib/capybara/spec/session/response_code.rb +19 -0
  64. data/lib/capybara/spec/session/select_spec.rb +119 -0
  65. data/lib/capybara/spec/session/text_spec.rb +24 -0
  66. data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
  67. data/lib/capybara/spec/session/unselect_spec.rb +67 -0
  68. data/lib/capybara/spec/session/within_spec.rb +178 -0
  69. data/lib/capybara/spec/test_app.rb +156 -0
  70. data/lib/capybara/spec/views/buttons.erb +4 -0
  71. data/lib/capybara/spec/views/fieldsets.erb +29 -0
  72. data/lib/capybara/spec/views/form.erb +366 -0
  73. data/lib/capybara/spec/views/frame_one.erb +8 -0
  74. data/lib/capybara/spec/views/frame_two.erb +8 -0
  75. data/lib/capybara/spec/views/header_links.erb +7 -0
  76. data/lib/capybara/spec/views/host_links.erb +12 -0
  77. data/lib/capybara/spec/views/popup_one.erb +8 -0
  78. data/lib/capybara/spec/views/popup_two.erb +8 -0
  79. data/lib/capybara/spec/views/postback.erb +13 -0
  80. data/lib/capybara/spec/views/tables.erb +62 -0
  81. data/lib/capybara/spec/views/with_html.erb +75 -0
  82. data/lib/capybara/spec/views/with_html_entities.erb +1 -0
  83. data/lib/capybara/spec/views/with_js.erb +53 -0
  84. data/lib/capybara/spec/views/with_scope.erb +36 -0
  85. data/lib/capybara/spec/views/with_simple_html.erb +1 -0
  86. data/lib/capybara/spec/views/within_frames.erb +10 -0
  87. data/lib/capybara/spec/views/within_popups.erb +25 -0
  88. data/lib/capybara/util/save_and_open_page.rb +45 -0
  89. data/lib/capybara/util/timeout.rb +27 -0
  90. data/lib/capybara/version.rb +3 -0
  91. data/spec/basic_node_spec.rb +89 -0
  92. data/spec/capybara_spec.rb +46 -0
  93. data/spec/driver/rack_test_driver_spec.rb +90 -0
  94. data/spec/driver/selenium_driver_spec.rb +55 -0
  95. data/spec/dsl_spec.rb +255 -0
  96. data/spec/fixtures/selenium_driver_rspec_failure.rb +8 -0
  97. data/spec/fixtures/selenium_driver_rspec_success.rb +8 -0
  98. data/spec/rspec/features_spec.rb +43 -0
  99. data/spec/rspec/matchers_spec.rb +564 -0
  100. data/spec/rspec_spec.rb +51 -0
  101. data/spec/save_and_open_page_spec.rb +155 -0
  102. data/spec/server_spec.rb +74 -0
  103. data/spec/session/rack_test_session_spec.rb +61 -0
  104. data/spec/session/selenium_session_spec.rb +26 -0
  105. data/spec/spec_helper.rb +31 -0
  106. data/spec/timeout_spec.rb +28 -0
  107. metadata +297 -0
@@ -0,0 +1,121 @@
1
+ class Capybara::RackTest::Node < Capybara::Driver::Node
2
+ def text
3
+ unnormalized_text.strip.gsub(/\s+/, ' ')
4
+ end
5
+
6
+ def [](name)
7
+ string_node[name]
8
+ end
9
+
10
+ def value
11
+ string_node.value
12
+ end
13
+
14
+ def set(value)
15
+ if tag_name == 'input' and type == 'radio'
16
+ other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name).equals(self[:name])] }.to_s
17
+ driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") }
18
+ native['checked'] = 'checked'
19
+ elsif tag_name == 'input' and type == 'checkbox'
20
+ if value && !native['checked']
21
+ native['checked'] = 'checked'
22
+ elsif !value && native['checked']
23
+ native.remove_attribute('checked')
24
+ end
25
+ elsif tag_name == 'input'
26
+ if (type == 'text' || type == 'password') && self[:maxlength] &&
27
+ !self[:maxlength].empty?
28
+ # Browser behavior for maxlength="0" is inconsistent, so we stick with
29
+ # Firefox, allowing no input
30
+ value = value[0...self[:maxlength].to_i]
31
+ end
32
+ native['value'] = value.to_s
33
+ elsif tag_name == "textarea"
34
+ native.content = value.to_s
35
+ end
36
+ end
37
+
38
+ def select_option
39
+ if select_node['multiple'] != 'multiple'
40
+ select_node.find(".//option[@selected]").each { |node| node.native.remove_attribute("selected") }
41
+ end
42
+ native["selected"] = 'selected'
43
+ end
44
+
45
+ def unselect_option
46
+ if select_node['multiple'] != 'multiple'
47
+ raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
48
+ end
49
+ native.remove_attribute('selected')
50
+ end
51
+
52
+ def click
53
+ if tag_name == 'a'
54
+ method = self["data-method"] if driver.options[:respect_data_method]
55
+ method ||= :get
56
+ driver.follow(method, self[:href].to_s)
57
+ elsif (tag_name == 'input' and %w(submit image).include?(type)) or
58
+ ((tag_name == 'button') and type.nil? or type == "submit")
59
+ Capybara::RackTest::Form.new(driver, form).submit(self)
60
+ end
61
+ end
62
+
63
+ def tag_name
64
+ native.node_name
65
+ end
66
+
67
+ def visible?
68
+ string_node.visible?
69
+ end
70
+
71
+ def checked?
72
+ string_node.checked?
73
+ end
74
+
75
+ def selected?
76
+ string_node.selected?
77
+ end
78
+
79
+ def path
80
+ native.path
81
+ end
82
+
83
+ def find(locator)
84
+ native.xpath(locator).map { |n| self.class.new(driver, n) }
85
+ end
86
+
87
+ protected
88
+
89
+ def unnormalized_text
90
+ if !visible?
91
+ ''
92
+ elsif native.text?
93
+ native.text
94
+ elsif native.element?
95
+ native.children.map do |child|
96
+ Capybara::RackTest::Node.new(driver, child).unnormalized_text
97
+ end.join
98
+ else
99
+ ''
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def string_node
106
+ @string_node ||= Capybara::Node::Simple.new(native)
107
+ end
108
+
109
+ # a reference to the select node if this is an option node
110
+ def select_node
111
+ find('./ancestor::select').first
112
+ end
113
+
114
+ def type
115
+ native[:type]
116
+ end
117
+
118
+ def form
119
+ native.ancestors('form').first
120
+ end
121
+ end
@@ -0,0 +1,17 @@
1
+ require 'capybara'
2
+ require 'capybara/dsl'
3
+
4
+ Capybara.app = Rack::Builder.new do
5
+ map "/" do
6
+ if Rails.version.to_f >= 3.0
7
+ run Rails.application
8
+ else # Rails 2
9
+ use Rails::Rack::Static
10
+ run ActionController::Dispatcher.new
11
+ end
12
+ end
13
+ end.to_app
14
+
15
+ Capybara.asset_root = Rails.root.join('public')
16
+ Capybara.save_and_open_page_path = Rails.root.join('tmp/capybara')
17
+
@@ -0,0 +1,26 @@
1
+ require 'capybara'
2
+ require 'capybara/dsl'
3
+ require 'rspec/core'
4
+ require 'capybara/rspec/matchers'
5
+ require 'capybara/rspec/features'
6
+
7
+ RSpec.configure do |config|
8
+ config.include Capybara::DSL, :type => :request
9
+ config.include Capybara::DSL, :type => :acceptance
10
+ config.include Capybara::RSpecMatchers, :type => :request
11
+ config.include Capybara::RSpecMatchers, :type => :acceptance
12
+ # The before and after blocks must run instantaneously, because Capybara
13
+ # might not actually be used in all examples where it's included.
14
+ config.after do
15
+ if self.class.include?(Capybara::DSL)
16
+ Capybara.reset_sessions!
17
+ Capybara.use_default_driver
18
+ end
19
+ end
20
+ config.before do
21
+ if self.class.include?(Capybara::DSL)
22
+ Capybara.current_driver = Capybara.javascript_driver if example.metadata[:js]
23
+ Capybara.current_driver = example.metadata[:driver] if example.metadata[:driver]
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ module Capybara
2
+ module Features
3
+ def self.included(base)
4
+ base.instance_eval do
5
+ alias :background :before
6
+ alias :scenario :it
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ def self.feature(*args, &block)
13
+ options = if args.last.is_a?(Hash) then args.pop else {} end
14
+ options[:capybara_feature] = true
15
+ options[:type] = :request
16
+ options[:caller] ||= caller
17
+ args.push(options)
18
+
19
+ describe(*args, &block)
20
+ end
21
+
22
+ RSpec.configuration.include Capybara::Features, :capybara_feature => true
@@ -0,0 +1,152 @@
1
+ module Capybara
2
+ module RSpecMatchers
3
+ class HaveSelector
4
+ def initialize(*args)
5
+ @args = args
6
+ end
7
+
8
+ def matches?(actual)
9
+ @actual = wrap(actual)
10
+ @actual.has_selector?(*@args)
11
+ end
12
+
13
+ def does_not_match?(actual)
14
+ @actual = wrap(actual)
15
+ @actual.has_no_selector?(*@args)
16
+ end
17
+
18
+ def failure_message_for_should
19
+ query.failure_message(:assert, @actual)
20
+ end
21
+
22
+ def failure_message_for_should_not
23
+ query.negative_failure_message(:assert, @actual)
24
+ end
25
+
26
+ def description
27
+ "has #{query.description}"
28
+ end
29
+
30
+ def wrap(actual)
31
+ if actual.respond_to?("has_selector?")
32
+ actual
33
+ else
34
+ Capybara.string(actual.to_s)
35
+ end
36
+ end
37
+
38
+ def query
39
+ @query ||= Capybara::Query.new(*@args)
40
+ end
41
+ end
42
+
43
+ class HaveMatcher
44
+ attr_reader :name, :locator, :options, :failure_message, :actual
45
+
46
+ def initialize(name, locator, options={}, &block)
47
+ @name = name
48
+ @locator = locator
49
+ @options = options
50
+ @failure_message = block
51
+ end
52
+
53
+ def arguments
54
+ if options.empty? then [locator] else [locator, options] end
55
+ end
56
+
57
+ def matches?(actual)
58
+ @actual = wrap(actual)
59
+ @actual.send(:"has_#{name}?", *arguments)
60
+ end
61
+
62
+ def does_not_match?(actual)
63
+ @actual = wrap(actual)
64
+ @actual.send(:"has_no_#{name}?", *arguments)
65
+ end
66
+
67
+ def failure_message_for_should
68
+ if failure_message
69
+ failure_message.call(actual, self)
70
+ elsif(@options[:count])
71
+ "expected #{selector_name} to be returned #{@options[:count]} times"
72
+ else
73
+ "expected #{selector_name} to return something"
74
+ end
75
+ end
76
+
77
+ def failure_message_for_should_not
78
+ "expected #{selector_name} not to return anything"
79
+ end
80
+
81
+ def description
82
+ "has #{selector_name}"
83
+ end
84
+
85
+ def selector_name
86
+ selector_name = "#{name} #{locator.inspect}"
87
+ selector_name << " with text #{options[:text].inspect}" if options[:text]
88
+ selector_name
89
+ end
90
+
91
+ def wrap(actual)
92
+ if actual.respond_to?("has_selector?")
93
+ actual
94
+ else
95
+ Capybara.string(actual.to_s)
96
+ end
97
+ end
98
+ end
99
+
100
+ def have_selector(*args)
101
+ HaveSelector.new(*args)
102
+ end
103
+
104
+ def have_xpath(xpath, options={})
105
+ HaveMatcher.new(:xpath, xpath, options)
106
+ end
107
+
108
+ def have_css(css, options={})
109
+ HaveMatcher.new(:css, css, options)
110
+ end
111
+
112
+ def have_content(text)
113
+ HaveMatcher.new(:content, text.to_s) do |page, matcher|
114
+ %(expected there to be content #{matcher.locator.inspect} in #{page.text.inspect})
115
+ end
116
+ end
117
+
118
+ def have_text(text)
119
+ HaveMatcher.new(:text, text.to_s) do |page, matcher|
120
+ %(expected there to be text #{matcher.locator.inspect} in #{page.text.inspect})
121
+ end
122
+ end
123
+
124
+ def have_link(locator, options={})
125
+ HaveMatcher.new(:link, locator, options)
126
+ end
127
+
128
+ def have_button(locator)
129
+ HaveMatcher.new(:button, locator)
130
+ end
131
+
132
+ def have_field(locator, options={})
133
+ HaveMatcher.new(:field, locator, options)
134
+ end
135
+
136
+ def have_checked_field(locator)
137
+ HaveMatcher.new(:checked_field, locator)
138
+ end
139
+
140
+ def have_unchecked_field(locator)
141
+ HaveMatcher.new(:unchecked_field, locator)
142
+ end
143
+
144
+ def have_select(locator, options={})
145
+ HaveMatcher.new(:select, locator, options)
146
+ end
147
+
148
+ def have_table(locator, options={})
149
+ HaveMatcher.new(:table, locator, options)
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,156 @@
1
+ module Capybara
2
+ class Selector
3
+ attr_reader :name, :custom_filters
4
+
5
+
6
+ class << self
7
+ def all
8
+ @selectors ||= {}
9
+ end
10
+
11
+ def add(name, &block)
12
+ all[name.to_sym] = Capybara::Selector.new(name.to_sym, &block)
13
+ end
14
+
15
+ def remove(name)
16
+ all.delete(name.to_sym)
17
+ end
18
+ end
19
+
20
+ def initialize(name, &block)
21
+ @name = name
22
+ @custom_filters = {}
23
+ @match = nil
24
+ @failure_message = nil
25
+ instance_eval(&block)
26
+ end
27
+
28
+ def xpath(&block)
29
+ @xpath = block if block
30
+ @xpath
31
+ end
32
+
33
+ # Same as xpath, but wrap in XPath.css().
34
+ def css(&block)
35
+ if block
36
+ @xpath = xpath { |*args| XPath.css(block.call(*args)) }
37
+ end
38
+ @xpath
39
+ end
40
+
41
+ def match(&block)
42
+ @match = block if block
43
+ @match
44
+ end
45
+
46
+ def failure_message(&block)
47
+ @failure_message = block if block
48
+ @failure_message
49
+ end
50
+
51
+ def call(locator)
52
+ @xpath.call(locator)
53
+ end
54
+
55
+ def match?(locator)
56
+ @match and @match.call(locator)
57
+ end
58
+
59
+ def filter(name, &block)
60
+ @custom_filters[name] = block
61
+ end
62
+ end
63
+ end
64
+
65
+ Capybara.add_selector(:xpath) do
66
+ xpath { |xpath| xpath }
67
+ end
68
+
69
+ Capybara.add_selector(:css) do
70
+ css { |css| css }
71
+ end
72
+
73
+ Capybara.add_selector(:id) do
74
+ xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
75
+ match { |value| value.is_a?(Symbol) }
76
+ end
77
+
78
+ Capybara.add_selector(:field) do
79
+ xpath { |locator| XPath::HTML.field(locator) }
80
+ filter(:checked) { |node, value| not(value ^ node.checked?) }
81
+ filter(:unchecked) { |node, value| (value ^ node.checked?) }
82
+ filter(:with) { |node, with| node.value == with }
83
+ end
84
+
85
+ Capybara.add_selector(:fieldset) do
86
+ xpath { |locator| XPath::HTML.fieldset(locator) }
87
+ end
88
+
89
+ Capybara.add_selector(:link_or_button) do
90
+ xpath { |locator| XPath::HTML.link_or_button(locator) }
91
+ failure_message { |node, selector| "no link or button '#{selector.locator}' found" }
92
+ end
93
+
94
+ Capybara.add_selector(:link) do
95
+ xpath { |locator| XPath::HTML.link(locator) }
96
+ failure_message { |node, selector| "no link with title, id or text '#{selector.locator}' found" }
97
+ filter(:href) do |node, href|
98
+ node.first(:xpath, XPath.axis(:self)[XPath.attr(:href).equals(href)])
99
+ end
100
+ end
101
+
102
+ Capybara.add_selector(:button) do
103
+ xpath { |locator| XPath::HTML.button(locator) }
104
+ failure_message { |node, selector| "no button with value or id or text '#{selector.locator}' found" }
105
+ end
106
+
107
+ Capybara.add_selector(:fillable_field) do
108
+ xpath { |locator| XPath::HTML.fillable_field(locator) }
109
+ failure_message { |node, selector| "no text field, text area or password field with id, name, or label '#{selector.locator}' found" }
110
+ end
111
+
112
+ Capybara.add_selector(:radio_button) do
113
+ xpath { |locator| XPath::HTML.radio_button(locator) }
114
+ failure_message { |node, selector| "no radio button with id, name, or label '#{selector.locator}' found" }
115
+ filter(:checked) { |node, value| not(value ^ node.checked?) }
116
+ filter(:unchecked) { |node, value| (value ^ node.checked?) }
117
+ end
118
+
119
+ Capybara.add_selector(:checkbox) do
120
+ xpath { |locator| XPath::HTML.checkbox(locator) }
121
+ failure_message { |node, selector| "no checkbox with id, name, or label '#{selector.locator}' found" }
122
+ filter(:checked) { |node, value| not(value ^ node.checked?) }
123
+ filter(:unchecked) { |node, value| (value ^ node.checked?) }
124
+ end
125
+
126
+ Capybara.add_selector(:select) do
127
+ xpath { |locator| XPath::HTML.select(locator) }
128
+ failure_message { |node, selector| "no select box with id, name, or label '#{selector.locator}' found" }
129
+ filter(:options) { |node, options| options.all? { |option| node.first(:option, option) } }
130
+ filter(:selected) do |node, selected|
131
+ actual = node.all(:xpath, './/option').select { |option| option.selected? }.map { |option| option.text }
132
+ ([selected].flatten - actual).empty?
133
+ end
134
+ end
135
+
136
+ Capybara.add_selector(:option) do
137
+ xpath { |locator| XPath::HTML.option(locator) }
138
+ failure_message do |node, selector|
139
+ "no option with text '#{selector.locator}'".tap do |message|
140
+ message << " in the select box" if node.tag_name == 'select'
141
+ end
142
+ end
143
+ end
144
+
145
+ Capybara.add_selector(:file_field) do
146
+ xpath { |locator| XPath::HTML.file_field(locator) }
147
+ failure_message { |node, selector| "no file field with id, name, or label '#{selector.locator}' found" }
148
+ end
149
+
150
+ Capybara.add_selector(:content) do
151
+ xpath { |content| XPath::HTML.content(content) }
152
+ end
153
+
154
+ Capybara.add_selector(:table) do
155
+ xpath { |locator| XPath::HTML.table(locator) }
156
+ end