nimboids-capybara 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
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