nimboids-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 (105) hide show
  1. data/History.txt +289 -0
  2. data/README.rdoc +722 -0
  3. data/lib/capybara.rb +252 -0
  4. data/lib/capybara/cucumber.rb +28 -0
  5. data/lib/capybara/driver/base.rb +64 -0
  6. data/lib/capybara/driver/node.rb +74 -0
  7. data/lib/capybara/dsl.rb +168 -0
  8. data/lib/capybara/node/actions.rb +162 -0
  9. data/lib/capybara/node/base.rb +63 -0
  10. data/lib/capybara/node/document.rb +25 -0
  11. data/lib/capybara/node/element.rb +201 -0
  12. data/lib/capybara/node/finders.rb +197 -0
  13. data/lib/capybara/node/matchers.rb +417 -0
  14. data/lib/capybara/node/simple.rb +132 -0
  15. data/lib/capybara/rack_test/browser.rb +121 -0
  16. data/lib/capybara/rack_test/driver.rb +80 -0
  17. data/lib/capybara/rack_test/form.rb +80 -0
  18. data/lib/capybara/rack_test/node.rb +105 -0
  19. data/lib/capybara/rails.rb +17 -0
  20. data/lib/capybara/rspec.rb +26 -0
  21. data/lib/capybara/rspec/features.rb +22 -0
  22. data/lib/capybara/rspec/matchers.rb +154 -0
  23. data/lib/capybara/selector.rb +89 -0
  24. data/lib/capybara/selenium/driver.rb +163 -0
  25. data/lib/capybara/selenium/node.rb +91 -0
  26. data/lib/capybara/server.rb +90 -0
  27. data/lib/capybara/session.rb +321 -0
  28. data/lib/capybara/spec/driver.rb +301 -0
  29. data/lib/capybara/spec/fixtures/capybara.jpg +3 -0
  30. data/lib/capybara/spec/fixtures/test_file.txt +1 -0
  31. data/lib/capybara/spec/public/test.js +43 -0
  32. data/lib/capybara/spec/session.rb +154 -0
  33. data/lib/capybara/spec/session/all_spec.rb +78 -0
  34. data/lib/capybara/spec/session/attach_file_spec.rb +73 -0
  35. data/lib/capybara/spec/session/check_spec.rb +65 -0
  36. data/lib/capybara/spec/session/choose_spec.rb +26 -0
  37. data/lib/capybara/spec/session/click_button_spec.rb +304 -0
  38. data/lib/capybara/spec/session/click_link_or_button_spec.rb +36 -0
  39. data/lib/capybara/spec/session/click_link_spec.rb +119 -0
  40. data/lib/capybara/spec/session/current_host_spec.rb +68 -0
  41. data/lib/capybara/spec/session/current_url_spec.rb +15 -0
  42. data/lib/capybara/spec/session/fill_in_spec.rb +125 -0
  43. data/lib/capybara/spec/session/find_button_spec.rb +18 -0
  44. data/lib/capybara/spec/session/find_by_id_spec.rb +18 -0
  45. data/lib/capybara/spec/session/find_field_spec.rb +26 -0
  46. data/lib/capybara/spec/session/find_link_spec.rb +19 -0
  47. data/lib/capybara/spec/session/find_spec.rb +149 -0
  48. data/lib/capybara/spec/session/first_spec.rb +105 -0
  49. data/lib/capybara/spec/session/has_button_spec.rb +32 -0
  50. data/lib/capybara/spec/session/has_content_spec.rb +106 -0
  51. data/lib/capybara/spec/session/has_css_spec.rb +243 -0
  52. data/lib/capybara/spec/session/has_field_spec.rb +192 -0
  53. data/lib/capybara/spec/session/has_link_spec.rb +37 -0
  54. data/lib/capybara/spec/session/has_select_spec.rb +129 -0
  55. data/lib/capybara/spec/session/has_selector_spec.rb +129 -0
  56. data/lib/capybara/spec/session/has_table_spec.rb +96 -0
  57. data/lib/capybara/spec/session/has_xpath_spec.rb +123 -0
  58. data/lib/capybara/spec/session/headers.rb +19 -0
  59. data/lib/capybara/spec/session/javascript.rb +289 -0
  60. data/lib/capybara/spec/session/response_code.rb +19 -0
  61. data/lib/capybara/spec/session/select_spec.rb +113 -0
  62. data/lib/capybara/spec/session/text_spec.rb +19 -0
  63. data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
  64. data/lib/capybara/spec/session/unselect_spec.rb +61 -0
  65. data/lib/capybara/spec/session/within_spec.rb +178 -0
  66. data/lib/capybara/spec/test_app.rb +142 -0
  67. data/lib/capybara/spec/views/buttons.erb +4 -0
  68. data/lib/capybara/spec/views/fieldsets.erb +29 -0
  69. data/lib/capybara/spec/views/form.erb +365 -0
  70. data/lib/capybara/spec/views/frame_one.erb +8 -0
  71. data/lib/capybara/spec/views/frame_two.erb +8 -0
  72. data/lib/capybara/spec/views/header_links.erb +7 -0
  73. data/lib/capybara/spec/views/host_links.erb +12 -0
  74. data/lib/capybara/spec/views/popup_one.erb +8 -0
  75. data/lib/capybara/spec/views/popup_two.erb +8 -0
  76. data/lib/capybara/spec/views/postback.erb +13 -0
  77. data/lib/capybara/spec/views/tables.erb +122 -0
  78. data/lib/capybara/spec/views/with_html.erb +78 -0
  79. data/lib/capybara/spec/views/with_html_entities.erb +1 -0
  80. data/lib/capybara/spec/views/with_js.erb +48 -0
  81. data/lib/capybara/spec/views/with_scope.erb +36 -0
  82. data/lib/capybara/spec/views/with_simple_html.erb +1 -0
  83. data/lib/capybara/spec/views/within_frames.erb +10 -0
  84. data/lib/capybara/spec/views/within_popups.erb +25 -0
  85. data/lib/capybara/util/save_and_open_page.rb +44 -0
  86. data/lib/capybara/util/timeout.rb +27 -0
  87. data/lib/capybara/version.rb +3 -0
  88. data/spec/basic_node_spec.rb +77 -0
  89. data/spec/capybara_spec.rb +46 -0
  90. data/spec/driver/rack_test_driver_spec.rb +89 -0
  91. data/spec/driver/selenium_driver_spec.rb +50 -0
  92. data/spec/dsl_spec.rb +253 -0
  93. data/spec/fixtures/selenium_driver_rspec_failure.rb +8 -0
  94. data/spec/fixtures/selenium_driver_rspec_success.rb +8 -0
  95. data/spec/rspec/features_spec.rb +45 -0
  96. data/spec/rspec/matchers_spec.rb +495 -0
  97. data/spec/rspec_spec.rb +53 -0
  98. data/spec/save_and_open_page_spec.rb +155 -0
  99. data/spec/server_spec.rb +89 -0
  100. data/spec/session/rack_test_session_spec.rb +55 -0
  101. data/spec/session/selenium_session_spec.rb +26 -0
  102. data/spec/spec_helper.rb +30 -0
  103. data/spec/string_spec.rb +77 -0
  104. data/spec/timeout_spec.rb +28 -0
  105. metadata +346 -0
@@ -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,154 @@
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
+ if normalized.failure_message
20
+ normalized.failure_message.call(@actual, normalized)
21
+ else
22
+ "expected #{selector_name} to return something"
23
+ end
24
+ end
25
+
26
+ def failure_message_for_should_not
27
+ "expected #{selector_name} not to return anything"
28
+ end
29
+
30
+ def description
31
+ "has #{selector_name}"
32
+ end
33
+
34
+ def selector_name
35
+ name = "#{normalized.name} #{normalized.locator.inspect}"
36
+ name << " with text #{normalized.options[:text].inspect}" if normalized.options[:text]
37
+ name
38
+ end
39
+
40
+ def wrap(actual)
41
+ if actual.respond_to?("has_selector?")
42
+ actual
43
+ else
44
+ Capybara.string(actual.to_s)
45
+ end
46
+ end
47
+
48
+ def normalized
49
+ @normalized ||= Capybara::Selector.normalize(*@args)
50
+ end
51
+ end
52
+
53
+ class HaveMatcher
54
+ attr_reader :name, :locator, :options, :failure_message, :actual
55
+
56
+ def initialize(name, locator, options={}, &block)
57
+ @name = name
58
+ @locator = locator
59
+ @options = options
60
+ @failure_message = block
61
+ end
62
+
63
+ def arguments
64
+ if options.empty? then [locator] else [locator, options] end
65
+ end
66
+
67
+ def matches?(actual)
68
+ @actual = wrap(actual)
69
+ @actual.send(:"has_#{name}?", *arguments)
70
+ end
71
+
72
+ def does_not_match?(actual)
73
+ @actual = wrap(actual)
74
+ @actual.send(:"has_no_#{name}?", *arguments)
75
+ end
76
+
77
+ def failure_message_for_should
78
+ if failure_message
79
+ failure_message.call(actual, self)
80
+ else
81
+ "expected #{selector_name} to return something"
82
+ end
83
+ end
84
+
85
+ def failure_message_for_should_not
86
+ "expected #{selector_name} not to return anything"
87
+ end
88
+
89
+ def description
90
+ "has #{selector_name}"
91
+ end
92
+
93
+ def selector_name
94
+ selector_name = "#{name} #{locator.inspect}"
95
+ selector_name << " with text #{options[:text].inspect}" if options[:text]
96
+ selector_name
97
+ end
98
+
99
+ def wrap(actual)
100
+ if actual.respond_to?("has_selector?")
101
+ actual
102
+ else
103
+ Capybara.string(actual.to_s)
104
+ end
105
+ end
106
+ end
107
+
108
+ def have_selector(*args)
109
+ HaveSelector.new(*args)
110
+ end
111
+
112
+ def have_xpath(xpath, options={})
113
+ HaveMatcher.new(:xpath, xpath, options)
114
+ end
115
+
116
+ def have_css(css, options={})
117
+ HaveMatcher.new(:css, css, options)
118
+ end
119
+
120
+ def have_content(text)
121
+ HaveMatcher.new(:content, text.to_s) do |page, matcher|
122
+ %(expected there to be content #{matcher.locator.inspect} in #{page.text.inspect})
123
+ end
124
+ end
125
+
126
+ def have_link(locator, options={})
127
+ HaveMatcher.new(:link, locator, options)
128
+ end
129
+
130
+ def have_button(locator)
131
+ HaveMatcher.new(:button, locator)
132
+ end
133
+
134
+ def have_field(locator, options={})
135
+ HaveMatcher.new(:field, locator, options)
136
+ end
137
+
138
+ def have_checked_field(locator)
139
+ HaveMatcher.new(:checked_field, locator)
140
+ end
141
+
142
+ def have_unchecked_field(locator)
143
+ HaveMatcher.new(:unchecked_field, locator)
144
+ end
145
+
146
+ def have_select(locator, options={})
147
+ HaveMatcher.new(:select, locator, options)
148
+ end
149
+
150
+ def have_table(locator, options={})
151
+ HaveMatcher.new(:table, locator, options)
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,89 @@
1
+ module Capybara
2
+ class Selector
3
+ attr_reader :name
4
+
5
+ class Normalized
6
+ attr_accessor :selector, :locator, :options, :xpaths
7
+
8
+ def failure_message; selector.failure_message; end
9
+ def name; selector.name; end
10
+ end
11
+
12
+ class << self
13
+ def all
14
+ @selectors ||= {}
15
+ end
16
+
17
+ def add(name, &block)
18
+ all[name.to_sym] = Capybara::Selector.new(name.to_sym, &block)
19
+ end
20
+
21
+ def remove(name)
22
+ all.delete(name.to_sym)
23
+ end
24
+
25
+ def normalize(*args)
26
+ normalized = Normalized.new
27
+ normalized.options = if args.last.is_a?(Hash) then args.pop else {} end
28
+
29
+ if args[1]
30
+ normalized.selector = all[args[0]]
31
+ normalized.locator = args[1]
32
+ else
33
+ normalized.selector = all.values.find { |s| s.match?(args[0]) }
34
+ normalized.locator = args[0]
35
+ end
36
+ normalized.selector ||= all[Capybara.default_selector]
37
+
38
+ xpath = normalized.selector.call(normalized.locator)
39
+ if xpath.respond_to?(:to_xpaths)
40
+ normalized.xpaths = xpath.to_xpaths
41
+ else
42
+ normalized.xpaths = [xpath.to_s].flatten
43
+ end
44
+ normalized
45
+ end
46
+ end
47
+
48
+ def initialize(name, &block)
49
+ @name = name
50
+ instance_eval(&block)
51
+ end
52
+
53
+ def xpath(&block)
54
+ @xpath = block if block
55
+ @xpath
56
+ end
57
+
58
+ def match(&block)
59
+ @match = block if block
60
+ @match
61
+ end
62
+
63
+ def failure_message(&block)
64
+ @failure_message = block if block
65
+ @failure_message
66
+ end
67
+
68
+ def call(locator)
69
+ @xpath.call(locator)
70
+ end
71
+
72
+ def match?(locator)
73
+ @match and @match.call(locator)
74
+ end
75
+ end
76
+ end
77
+
78
+ Capybara.add_selector(:xpath) do
79
+ xpath { |xpath| xpath }
80
+ end
81
+
82
+ Capybara.add_selector(:css) do
83
+ xpath { |css| XPath.css(css) }
84
+ end
85
+
86
+ Capybara.add_selector(:id) do
87
+ xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
88
+ match { |value| value.is_a?(Symbol) }
89
+ end
@@ -0,0 +1,163 @@
1
+ require 'selenium-webdriver'
2
+
3
+ class Capybara::Selenium::Driver < Capybara::Driver::Base
4
+ DEFAULT_OPTIONS = {
5
+ :resynchronize => false,
6
+ :resynchronization_timeout => 10,
7
+ :browser => :firefox
8
+ }
9
+ SPECIAL_OPTIONS = [:browser, :resynchronize, :resynchronization_timeout]
10
+
11
+ attr_reader :app, :rack_server, :options
12
+
13
+ def browser
14
+ unless @browser
15
+ @browser = Selenium::WebDriver.for(options[:browser], options.reject { |key,val| SPECIAL_OPTIONS.include?(key) })
16
+
17
+ main = Process.pid
18
+ at_exit do
19
+ # Store the exit status of the test run since it goes away after calling the at_exit proc...
20
+ @exit_status = $!.status if $!.is_a?(SystemExit)
21
+ quit if Process.pid == main
22
+ exit @exit_status if @exit_status # Force exit with stored status
23
+ end
24
+ end
25
+ @browser
26
+ end
27
+
28
+ def initialize(app, options={})
29
+ @app = app
30
+ @options = DEFAULT_OPTIONS.merge(options)
31
+ @rack_server = Capybara::Server.new(@app)
32
+ @rack_server.boot if Capybara.run_server
33
+ end
34
+
35
+ def visit(path)
36
+ browser.navigate.to(url(path))
37
+ end
38
+
39
+ def source
40
+ browser.page_source
41
+ end
42
+
43
+ def body
44
+ browser.page_source
45
+ end
46
+
47
+ def current_url
48
+ browser.current_url
49
+ end
50
+
51
+ def find(selector)
52
+ browser.find_elements(:xpath, selector).map { |node| Capybara::Selenium::Node.new(self, node) }
53
+ end
54
+
55
+ def wait?; true; end
56
+
57
+ def resynchronize
58
+ if options[:resynchronize]
59
+ load_wait_for_ajax_support
60
+ yield
61
+ Capybara.timeout(options[:resynchronization_timeout], self, "failed to resynchronize, ajax request timed out") do
62
+ evaluate_script("!window.capybaraRequestsOutstanding")
63
+ end
64
+ else
65
+ yield
66
+ end
67
+ end
68
+
69
+ def execute_script(script)
70
+ browser.execute_script script
71
+ end
72
+
73
+ def evaluate_script(script)
74
+ browser.execute_script "return #{script}"
75
+ end
76
+
77
+ def reset!
78
+ # Use instance variable directly so we avoid starting the browser just to reset the session
79
+ if @browser
80
+ begin
81
+ @browser.manage.delete_all_cookies
82
+ rescue Selenium::WebDriver::Error::UnhandledError => e
83
+ # delete_all_cookies fails when we've previously gone
84
+ # to about:blank, so we rescue this error and do nothing
85
+ # instead.
86
+ end
87
+ @browser.navigate.to('about:blank')
88
+ end
89
+ end
90
+
91
+ def within_frame(frame_id)
92
+ old_window = browser.window_handle
93
+ browser.switch_to.frame(frame_id)
94
+ yield
95
+ browser.switch_to.window old_window
96
+ end
97
+
98
+ def find_window( selector )
99
+ original_handle = browser.window_handle
100
+ browser.window_handles.each do |handle|
101
+ browser.switch_to.window handle
102
+ if( selector == browser.execute_script("return window.name") ||
103
+ browser.title.include?(selector) ||
104
+ browser.current_url.include?(selector) ||
105
+ (selector == handle) )
106
+ browser.switch_to.window original_handle
107
+ return handle
108
+ end
109
+ end
110
+ raise Capybara::ElementNotFound, "Could not find a window identified by #{selector}"
111
+ end
112
+
113
+ def within_window(selector, &blk)
114
+ handle = find_window( selector )
115
+ browser.switch_to.window(handle, &blk)
116
+ end
117
+
118
+ def quit
119
+ @browser.quit
120
+ rescue Errno::ECONNREFUSED
121
+ # Browser must have already gone
122
+ end
123
+
124
+ def invalid_element_errors
125
+ [Selenium::WebDriver::Error::ObsoleteElementError]
126
+ end
127
+
128
+ private
129
+
130
+ def load_wait_for_ajax_support
131
+ browser.execute_script <<-JS
132
+ window.capybaraRequestsOutstanding = 0;
133
+ (function() { // Overriding XMLHttpRequest
134
+ var oldXHR = window.XMLHttpRequest;
135
+
136
+ function newXHR() {
137
+ var realXHR = new oldXHR();
138
+
139
+ window.capybaraRequestsOutstanding++;
140
+ realXHR.addEventListener("readystatechange", function() {
141
+ if( realXHR.readyState == 4 ) {
142
+ setTimeout( function() {
143
+ window.capybaraRequestsOutstanding--;
144
+ if(window.capybaraRequestsOutstanding < 0) {
145
+ window.capybaraRequestsOutstanding = 0;
146
+ }
147
+ }, 500 );
148
+ }
149
+ }, false);
150
+
151
+ return realXHR;
152
+ }
153
+
154
+ window.XMLHttpRequest = newXHR;
155
+ })();
156
+ JS
157
+ end
158
+
159
+ def url(path)
160
+ rack_server.url(path)
161
+ end
162
+
163
+ end