pr0d1r2-capybara 0.3.7

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 (87) hide show
  1. data/History.txt +71 -0
  2. data/README.rdoc +388 -0
  3. data/lib/capybara.rb +57 -0
  4. data/lib/capybara/cucumber.rb +32 -0
  5. data/lib/capybara/driver/base.rb +48 -0
  6. data/lib/capybara/driver/celerity_driver.rb +143 -0
  7. data/lib/capybara/driver/culerity_driver.rb +25 -0
  8. data/lib/capybara/driver/rack_test_driver.rb +271 -0
  9. data/lib/capybara/driver/selenium_driver.rb +161 -0
  10. data/lib/capybara/dsl.rb +60 -0
  11. data/lib/capybara/node.rb +60 -0
  12. data/lib/capybara/rails.rb +17 -0
  13. data/lib/capybara/save_and_open_page.rb +33 -0
  14. data/lib/capybara/searchable.rb +54 -0
  15. data/lib/capybara/server.rb +114 -0
  16. data/lib/capybara/session.rb +262 -0
  17. data/lib/capybara/spec/driver.rb +162 -0
  18. data/lib/capybara/spec/fixtures/capybara.jpg +0 -0
  19. data/lib/capybara/spec/fixtures/test_file.txt +1 -0
  20. data/lib/capybara/spec/public/jquery-ui.js +35 -0
  21. data/lib/capybara/spec/public/jquery.js +19 -0
  22. data/lib/capybara/spec/public/test.js +33 -0
  23. data/lib/capybara/spec/session.rb +81 -0
  24. data/lib/capybara/spec/session/all_spec.rb +69 -0
  25. data/lib/capybara/spec/session/attach_file_spec.rb +64 -0
  26. data/lib/capybara/spec/session/check_spec.rb +67 -0
  27. data/lib/capybara/spec/session/choose_spec.rb +26 -0
  28. data/lib/capybara/spec/session/click_button_spec.rb +236 -0
  29. data/lib/capybara/spec/session/click_link_spec.rb +108 -0
  30. data/lib/capybara/spec/session/click_spec.rb +24 -0
  31. data/lib/capybara/spec/session/current_url_spec.rb +8 -0
  32. data/lib/capybara/spec/session/fill_in_spec.rb +108 -0
  33. data/lib/capybara/spec/session/find_button_spec.rb +16 -0
  34. data/lib/capybara/spec/session/find_by_id_spec.rb +16 -0
  35. data/lib/capybara/spec/session/find_field_spec.rb +22 -0
  36. data/lib/capybara/spec/session/find_link_spec.rb +17 -0
  37. data/lib/capybara/spec/session/find_spec.rb +57 -0
  38. data/lib/capybara/spec/session/has_button_spec.rb +32 -0
  39. data/lib/capybara/spec/session/has_content_spec.rb +106 -0
  40. data/lib/capybara/spec/session/has_css_spec.rb +107 -0
  41. data/lib/capybara/spec/session/has_field_spec.rb +96 -0
  42. data/lib/capybara/spec/session/has_link_spec.rb +33 -0
  43. data/lib/capybara/spec/session/has_select_spec.rb +89 -0
  44. data/lib/capybara/spec/session/has_table_spec.rb +96 -0
  45. data/lib/capybara/spec/session/has_xpath_spec.rb +123 -0
  46. data/lib/capybara/spec/session/headers.rb +19 -0
  47. data/lib/capybara/spec/session/javascript.rb +204 -0
  48. data/lib/capybara/spec/session/locate_spec.rb +59 -0
  49. data/lib/capybara/spec/session/select_spec.rb +77 -0
  50. data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
  51. data/lib/capybara/spec/session/unselect_spec.rb +54 -0
  52. data/lib/capybara/spec/session/within_spec.rb +153 -0
  53. data/lib/capybara/spec/test_app.rb +75 -0
  54. data/lib/capybara/spec/views/buttons.erb +4 -0
  55. data/lib/capybara/spec/views/fieldsets.erb +29 -0
  56. data/lib/capybara/spec/views/form.erb +234 -0
  57. data/lib/capybara/spec/views/frame_one.erb +8 -0
  58. data/lib/capybara/spec/views/frame_two.erb +8 -0
  59. data/lib/capybara/spec/views/postback.erb +13 -0
  60. data/lib/capybara/spec/views/tables.erb +122 -0
  61. data/lib/capybara/spec/views/with_html.erb +42 -0
  62. data/lib/capybara/spec/views/with_js.erb +39 -0
  63. data/lib/capybara/spec/views/with_scope.erb +36 -0
  64. data/lib/capybara/spec/views/with_simple_html.erb +1 -0
  65. data/lib/capybara/spec/views/within_frames.erb +10 -0
  66. data/lib/capybara/version.rb +3 -0
  67. data/lib/capybara/wait_until.rb +28 -0
  68. data/lib/capybara/xpath.rb +179 -0
  69. data/spec/capybara_spec.rb +18 -0
  70. data/spec/driver/celerity_driver_spec.rb +16 -0
  71. data/spec/driver/culerity_driver_spec.rb +12 -0
  72. data/spec/driver/rack_test_driver_spec.rb +11 -0
  73. data/spec/driver/remote_culerity_driver_spec.rb +23 -0
  74. data/spec/driver/remote_selenium_driver_spec.rb +18 -0
  75. data/spec/driver/selenium_driver_spec.rb +11 -0
  76. data/spec/dsl_spec.rb +140 -0
  77. data/spec/save_and_open_page_spec.rb +43 -0
  78. data/spec/searchable_spec.rb +66 -0
  79. data/spec/server_spec.rb +53 -0
  80. data/spec/session/celerity_session_spec.rb +27 -0
  81. data/spec/session/culerity_session_spec.rb +25 -0
  82. data/spec/session/rack_test_session_spec.rb +33 -0
  83. data/spec/session/selenium_session_spec.rb +25 -0
  84. data/spec/spec_helper.rb +19 -0
  85. data/spec/wait_until_spec.rb +28 -0
  86. data/spec/xpath_spec.rb +180 -0
  87. metadata +259 -0
@@ -0,0 +1,161 @@
1
+ require 'selenium-webdriver'
2
+
3
+ class Capybara::Driver::Selenium < Capybara::Driver::Base
4
+ class Node < Capybara::Node
5
+ def text
6
+ node.text
7
+ end
8
+
9
+ def [](name)
10
+ if name == :value
11
+ node.value
12
+ else
13
+ node.attribute(name.to_s)
14
+ end
15
+ rescue Selenium::WebDriver::Error::WebDriverError
16
+ nil
17
+ end
18
+
19
+ def value
20
+ if tag_name == "select" and self[:multiple]
21
+ node.find_elements(:xpath, ".//option").select { |n| n.selected? }.map { |n| n.text }
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def set(value)
28
+ if tag_name == 'textarea' or (tag_name == 'input' and %w(text password hidden file).include?(type))
29
+ node.clear
30
+ node.send_keys(value.to_s)
31
+ elsif tag_name == 'input' and type == 'radio'
32
+ node.click
33
+ elsif tag_name == 'input' and type == 'checkbox'
34
+ node.click if node.attribute('checked') != value
35
+ end
36
+ end
37
+
38
+ def select(option)
39
+ option_node = node.find_element(:xpath, ".//option[text()=#{Capybara::XPath.escape(option)}]") || node.find_element(:xpath, ".//option[contains(.,#{Capybara::XPath.escape(option)})]")
40
+ option_node.select
41
+ rescue
42
+ options = node.find_elements(:xpath, "//option").map { |o| "'#{o.text}'" }.join(', ')
43
+ raise Capybara::OptionNotFound, "No such option '#{option}' in this select box. Available options: #{options}"
44
+ end
45
+
46
+ def unselect(option)
47
+ if node['multiple'] != 'multiple'
48
+ raise Capybara::UnselectNotAllowed, "Cannot unselect option '#{option}' from single select box."
49
+ end
50
+
51
+ begin
52
+ option_node = node.find_element(:xpath, ".//option[text()=#{Capybara::XPath.escape(option)}]") || node.find_element(:xpath, ".//option[contains(.,#{Capybara::XPath.escape(option)})]")
53
+ option_node.clear
54
+ rescue
55
+ options = node.find_elements(:xpath, "//option").map { |o| "'#{o.text}'" }.join(', ')
56
+ raise Capybara::OptionNotFound, "No such option '#{option}' in this select box. Available options: #{options}"
57
+ end
58
+ end
59
+
60
+ def click
61
+ node.click
62
+ end
63
+
64
+ def drag_to(element)
65
+ node.drag_and_drop_on(element.node)
66
+ end
67
+
68
+ def tag_name
69
+ node.tag_name
70
+ end
71
+
72
+ def visible?
73
+ begin
74
+ node.displayed? and node.displayed? != "false"
75
+ rescue Selenium::WebDriver::Error::WebDriverError
76
+ # rescues the inevitable "Selenium::WebDriver::Error::WebDriverError: element is obsolete" if you check to see if an element that has been removed from the DOM is visible
77
+ return false
78
+ end
79
+ end
80
+
81
+ def trigger(event)
82
+ end
83
+
84
+ private
85
+
86
+ def all_unfiltered(locator)
87
+ node.find_elements(:xpath, locator).map { |n| self.class.new(driver, n) }
88
+ end
89
+
90
+ def type
91
+ self[:type]
92
+ end
93
+
94
+ end
95
+
96
+ attr_reader :app, :rack_server
97
+
98
+ def self.driver
99
+ unless @driver
100
+ @driver = Selenium::WebDriver.for :firefox
101
+ at_exit do
102
+ @driver.quit
103
+ end
104
+ end
105
+ @driver
106
+ end
107
+
108
+ def initialize(app)
109
+ @app = app
110
+ @rack_server = Capybara::Server.new(@app)
111
+ @rack_server.boot if Capybara.run_server
112
+ end
113
+
114
+ def visit(path)
115
+ browser.navigate.to(url(path))
116
+ end
117
+
118
+ def source
119
+ browser.page_source
120
+ end
121
+
122
+ def body
123
+ browser.page_source
124
+ end
125
+
126
+ def current_url
127
+ browser.current_url
128
+ end
129
+
130
+ def find(selector)
131
+ browser.find_elements(:xpath, selector).map { |node| Node.new(self, node) }
132
+ end
133
+
134
+ def wait?; true; end
135
+
136
+ def evaluate_script(script)
137
+ browser.execute_script "return #{script}"
138
+ end
139
+
140
+ def browser
141
+ self.class.driver
142
+ end
143
+
144
+ def cleanup!
145
+ browser.manage.delete_all_cookies
146
+ end
147
+
148
+ def within_frame(frame_id)
149
+ old_window = browser.window_handle
150
+ browser.switch_to.frame(frame_id)
151
+ yield
152
+ browser.switch_to.window old_window
153
+ end
154
+
155
+ private
156
+
157
+ def url(path)
158
+ rack_server.url(path)
159
+ end
160
+
161
+ end
@@ -0,0 +1,60 @@
1
+ require 'capybara'
2
+
3
+ module Capybara
4
+ class << self
5
+ attr_writer :default_driver, :current_driver, :javascript_driver
6
+
7
+ attr_accessor :app
8
+
9
+ def default_driver
10
+ @default_driver || :rack_test
11
+ end
12
+
13
+ def current_driver
14
+ @current_driver || default_driver
15
+ end
16
+ alias_method :mode, :current_driver
17
+
18
+ def javascript_driver
19
+ @javascript_driver || :selenium
20
+ end
21
+
22
+ def use_default_driver
23
+ @current_driver = nil
24
+ end
25
+
26
+ def current_session
27
+ session_pool["#{current_driver}#{app.object_id}"] ||= Capybara::Session.new(current_driver, app)
28
+ end
29
+
30
+ def current_session?
31
+ session_pool.has_key?("#{current_driver}#{app.object_id}")
32
+ end
33
+
34
+ def reset_sessions!
35
+ session_pool.each { |mode, session| session.cleanup! }
36
+ @session_pool = nil
37
+ end
38
+
39
+ private
40
+
41
+ def session_pool
42
+ @session_pool ||= {}
43
+ end
44
+ end
45
+
46
+ extend(self)
47
+
48
+ def page
49
+ Capybara.current_session
50
+ end
51
+
52
+ Session::DSL_METHODS.each do |method|
53
+ class_eval <<-RUBY, __FILE__, __LINE__+1
54
+ def #{method}(*args, &block)
55
+ page.#{method}(*args, &block)
56
+ end
57
+ RUBY
58
+ end
59
+
60
+ end
@@ -0,0 +1,60 @@
1
+ module Capybara
2
+ class Node
3
+ include Searchable
4
+
5
+ attr_reader :driver, :node
6
+
7
+ def initialize(driver, node)
8
+ @driver = driver
9
+ @node = node
10
+ end
11
+
12
+ def text
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def [](name)
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def value
21
+ self[:value]
22
+ end
23
+
24
+ def set(value)
25
+ raise NotImplementedError
26
+ end
27
+
28
+ def select(option)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def unselect(option)
33
+ raise NotImplementedError
34
+ end
35
+
36
+ def click
37
+ raise NotImplementedError
38
+ end
39
+
40
+ def drag_to(element)
41
+ raise NotImplementedError
42
+ end
43
+
44
+ def tag_name
45
+ raise NotImplementedError
46
+ end
47
+
48
+ def visible?
49
+ raise NotImplementedError
50
+ end
51
+
52
+ def path
53
+ raise NotSupportedByDriverError
54
+ end
55
+
56
+ def trigger(event)
57
+ raise NotSupportedByDriverError
58
+ end
59
+ end
60
+ 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
+ ActionDispatch::Static
8
+ run Rails.application
9
+ else # Rails 2
10
+ use Rails::Rack::Static
11
+ run ActionController::Dispatcher.new
12
+ end
13
+ end
14
+ end.to_app
15
+
16
+ Capybara.asset_root = Rails.root.join('public')
17
+
@@ -0,0 +1,33 @@
1
+ module Capybara
2
+ module SaveAndOpenPage
3
+ extend(self)
4
+
5
+ def save_and_open_page(html)
6
+ name="capybara-#{Time.new.strftime("%Y%m%d%H%M%S")}.html"
7
+
8
+ FileUtils.touch(name) unless File.exist?(name)
9
+
10
+ tempfile = File.new(name,'w')
11
+ tempfile.write(rewrite_css_and_image_references(html))
12
+ tempfile.close
13
+
14
+ open_in_browser(tempfile.path)
15
+ end
16
+
17
+ def open_in_browser(path) # :nodoc
18
+ require "launchy"
19
+ Launchy::Browser.run(path)
20
+ rescue LoadError
21
+ warn "Sorry, you need to install launchy to open pages: `gem install launchy`"
22
+ end
23
+
24
+ def rewrite_css_and_image_references(response_html) # :nodoc:
25
+ return response_html unless Capybara.asset_root
26
+ directories = Dir.new(Capybara.asset_root).entries.inject([]) do |list, name|
27
+ list << name if File.directory?(name) and not name.to_s =~ /^\./
28
+ list
29
+ end
30
+ response_html.gsub(/("|')\/(#{directories.join('|')})/, '\1' + Capybara.asset_root.to_s + '/\2')
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,54 @@
1
+ module Capybara
2
+ module Searchable
3
+ def find(*args)
4
+ all(*args).first
5
+ end
6
+
7
+ def find_field(locator)
8
+ find(:xpath, XPath.field(locator))
9
+ end
10
+ alias_method :field_labeled, :find_field
11
+
12
+ def find_link(locator)
13
+ find(:xpath, XPath.link(locator))
14
+ end
15
+
16
+ def find_button(locator)
17
+ find(:xpath, XPath.button(locator))
18
+ end
19
+
20
+ def find_by_id(id)
21
+ find(:css, "##{id}")
22
+ end
23
+
24
+ def all(*args)
25
+ options = if args.last.is_a?(Hash) then args.pop else {} end
26
+ if args[1].nil?
27
+ kind, locator = Capybara.default_selector, args.first
28
+ else
29
+ kind, locator = args
30
+ end
31
+ locator = XPath.from_css(locator) if kind == :css
32
+
33
+ results = all_unfiltered(locator)
34
+
35
+ if options[:text]
36
+ options[:text] = Regexp.escape(options[:text]) unless options[:text].kind_of?(Regexp)
37
+ results = results.select { |n| n.text.match(options[:text]) }
38
+ end
39
+
40
+ if options[:visible] or Capybara.ignore_hidden_elements
41
+ results = results.select { |n| n.visible? }
42
+ end
43
+
44
+ results
45
+ end
46
+
47
+ private
48
+
49
+ def all_unfiltered(locator)
50
+ raise "Must be overridden"
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,114 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'rack'
4
+
5
+ class Capybara::Server
6
+ class Identify
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ if env["PATH_INFO"] == "/__identify__"
13
+ [200, {}, @app.object_id.to_s]
14
+ else
15
+ @app.call(env)
16
+ end
17
+ end
18
+ end
19
+
20
+ attr_reader :app, :port
21
+
22
+ def initialize(app)
23
+ @app = app
24
+ end
25
+
26
+ def host
27
+ "localhost"
28
+ end
29
+
30
+ def url(path)
31
+ if path =~ /^http/
32
+ path
33
+ else
34
+ (Capybara.app_host || "http://#{host}:#{port}") + path.to_s
35
+ end
36
+ end
37
+
38
+ def responsive?
39
+ is_running_on_port?(port)
40
+ end
41
+
42
+ def handler
43
+ begin
44
+ require 'rack/handler/thin'
45
+ Rack::Handler::Thin
46
+ rescue LoadError
47
+ begin
48
+ require 'rack/handler/mongrel'
49
+ Rack::Handler::Mongrel
50
+ rescue LoadError
51
+ require 'rack/handler/webrick'
52
+ Rack::Handler::WEBrick
53
+ end
54
+ end
55
+ end
56
+
57
+ def boot
58
+ return self unless @app
59
+ find_available_port
60
+ Capybara.log "application has already booted" and return self if responsive?
61
+ Capybara.log "booting Rack applicartion on port #{port}"
62
+
63
+ Thread.new do
64
+ handler.run(Identify.new(@app), :Port => port, :AccessLog => [])
65
+ end
66
+ Capybara.log "checking if application has booted"
67
+
68
+ Capybara::WaitUntil.timeout(10) do
69
+ if responsive?
70
+ Capybara.log("application has booted")
71
+ true
72
+ else
73
+ sleep 0.5
74
+ false
75
+ end
76
+ end
77
+ self
78
+ rescue Timeout::Error
79
+ Capybara.log "Rack application timed out during boot"
80
+ exit
81
+ end
82
+
83
+ private
84
+
85
+ def find_available_port
86
+ @port = 9887
87
+ @port += 1 while is_port_open?(@port) and not is_running_on_port?(@port)
88
+ end
89
+
90
+ def is_running_on_port?(tested_port)
91
+ res = Net::HTTP.start(host, tested_port) { |http| http.get('/__identify__') }
92
+
93
+ if res.is_a?(Net::HTTPSuccess) or res.is_a?(Net::HTTPRedirection)
94
+ return res.body == @app.object_id.to_s
95
+ end
96
+ rescue Errno::ECONNREFUSED, Errno::EBADF
97
+ return false
98
+ end
99
+
100
+ def is_port_open?(tested_port)
101
+ Timeout::timeout(1) do
102
+ begin
103
+ s = TCPSocket.new(host, tested_port)
104
+ s.close
105
+ return true
106
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
107
+ return false
108
+ end
109
+ end
110
+ rescue Timeout::Error
111
+ return false
112
+ end
113
+
114
+ end