david-capybara 0.3.8

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 (88) hide show
  1. data/History.txt +87 -0
  2. data/README.rdoc +389 -0
  3. data/lib/capybara.rb +52 -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 +272 -0
  9. data/lib/capybara/driver/selenium_driver.rb +156 -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/canvas.jpg +0 -0
  21. data/lib/capybara/spec/public/jquery-ui.js +35 -0
  22. data/lib/capybara/spec/public/jquery.js +19 -0
  23. data/lib/capybara/spec/public/test.js +33 -0
  24. data/lib/capybara/spec/session.rb +81 -0
  25. data/lib/capybara/spec/session/all_spec.rb +69 -0
  26. data/lib/capybara/spec/session/attach_file_spec.rb +64 -0
  27. data/lib/capybara/spec/session/check_spec.rb +67 -0
  28. data/lib/capybara/spec/session/choose_spec.rb +26 -0
  29. data/lib/capybara/spec/session/click_button_spec.rb +236 -0
  30. data/lib/capybara/spec/session/click_link_spec.rb +118 -0
  31. data/lib/capybara/spec/session/click_spec.rb +24 -0
  32. data/lib/capybara/spec/session/current_url_spec.rb +8 -0
  33. data/lib/capybara/spec/session/fill_in_spec.rb +108 -0
  34. data/lib/capybara/spec/session/find_button_spec.rb +16 -0
  35. data/lib/capybara/spec/session/find_by_id_spec.rb +16 -0
  36. data/lib/capybara/spec/session/find_field_spec.rb +22 -0
  37. data/lib/capybara/spec/session/find_link_spec.rb +17 -0
  38. data/lib/capybara/spec/session/find_spec.rb +57 -0
  39. data/lib/capybara/spec/session/has_button_spec.rb +32 -0
  40. data/lib/capybara/spec/session/has_content_spec.rb +106 -0
  41. data/lib/capybara/spec/session/has_css_spec.rb +107 -0
  42. data/lib/capybara/spec/session/has_field_spec.rb +96 -0
  43. data/lib/capybara/spec/session/has_link_spec.rb +33 -0
  44. data/lib/capybara/spec/session/has_select_spec.rb +89 -0
  45. data/lib/capybara/spec/session/has_table_spec.rb +96 -0
  46. data/lib/capybara/spec/session/has_xpath_spec.rb +123 -0
  47. data/lib/capybara/spec/session/headers.rb +19 -0
  48. data/lib/capybara/spec/session/javascript.rb +204 -0
  49. data/lib/capybara/spec/session/locate_spec.rb +59 -0
  50. data/lib/capybara/spec/session/select_spec.rb +83 -0
  51. data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
  52. data/lib/capybara/spec/session/unselect_spec.rb +54 -0
  53. data/lib/capybara/spec/session/within_spec.rb +153 -0
  54. data/lib/capybara/spec/test_app.rb +75 -0
  55. data/lib/capybara/spec/views/buttons.erb +4 -0
  56. data/lib/capybara/spec/views/fieldsets.erb +29 -0
  57. data/lib/capybara/spec/views/form.erb +235 -0
  58. data/lib/capybara/spec/views/frame_one.erb +8 -0
  59. data/lib/capybara/spec/views/frame_two.erb +8 -0
  60. data/lib/capybara/spec/views/postback.erb +13 -0
  61. data/lib/capybara/spec/views/tables.erb +122 -0
  62. data/lib/capybara/spec/views/with_html.erb +46 -0
  63. data/lib/capybara/spec/views/with_js.erb +39 -0
  64. data/lib/capybara/spec/views/with_scope.erb +36 -0
  65. data/lib/capybara/spec/views/with_simple_html.erb +1 -0
  66. data/lib/capybara/spec/views/within_frames.erb +10 -0
  67. data/lib/capybara/version.rb +3 -0
  68. data/lib/capybara/wait_until.rb +28 -0
  69. data/lib/capybara/xpath.rb +180 -0
  70. data/spec/capybara_spec.rb +18 -0
  71. data/spec/driver/celerity_driver_spec.rb +16 -0
  72. data/spec/driver/culerity_driver_spec.rb +12 -0
  73. data/spec/driver/rack_test_driver_spec.rb +17 -0
  74. data/spec/driver/remote_culerity_driver_spec.rb +23 -0
  75. data/spec/driver/remote_selenium_driver_spec.rb +18 -0
  76. data/spec/driver/selenium_driver_spec.rb +11 -0
  77. data/spec/dsl_spec.rb +140 -0
  78. data/spec/save_and_open_page_spec.rb +43 -0
  79. data/spec/searchable_spec.rb +66 -0
  80. data/spec/server_spec.rb +53 -0
  81. data/spec/session/celerity_session_spec.rb +27 -0
  82. data/spec/session/culerity_session_spec.rb +25 -0
  83. data/spec/session/rack_test_session_spec.rb +33 -0
  84. data/spec/session/selenium_session_spec.rb +25 -0
  85. data/spec/spec_helper.rb +19 -0
  86. data/spec/wait_until_spec.rb +28 -0
  87. data/spec/xpath_spec.rb +180 -0
  88. metadata +260 -0
@@ -0,0 +1,156 @@
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[normalize-space(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[normalize-space(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
+ node.displayed? and node.displayed? != "false"
74
+ end
75
+
76
+ def trigger(event)
77
+ end
78
+
79
+ private
80
+
81
+ def all_unfiltered(locator)
82
+ node.find_elements(:xpath, locator).map { |n| self.class.new(driver, n) }
83
+ end
84
+
85
+ def type
86
+ self[:type]
87
+ end
88
+
89
+ end
90
+
91
+ attr_reader :app, :rack_server
92
+
93
+ def self.driver
94
+ unless @driver
95
+ @driver = Selenium::WebDriver.for :firefox
96
+ at_exit do
97
+ @driver.quit
98
+ end
99
+ end
100
+ @driver
101
+ end
102
+
103
+ def initialize(app)
104
+ @app = app
105
+ @rack_server = Capybara::Server.new(@app)
106
+ @rack_server.boot if Capybara.run_server
107
+ end
108
+
109
+ def visit(path)
110
+ browser.navigate.to(url(path))
111
+ end
112
+
113
+ def source
114
+ browser.page_source
115
+ end
116
+
117
+ def body
118
+ browser.page_source
119
+ end
120
+
121
+ def current_url
122
+ browser.current_url
123
+ end
124
+
125
+ def find(selector)
126
+ browser.find_elements(:xpath, selector).map { |node| Node.new(self, node) }
127
+ end
128
+
129
+ def wait?; true; end
130
+
131
+ def evaluate_script(script)
132
+ browser.execute_script "return #{script}"
133
+ end
134
+
135
+ def browser
136
+ self.class.driver
137
+ end
138
+
139
+ def cleanup!
140
+ browser.manage.delete_all_cookies
141
+ end
142
+
143
+ def within_frame(frame_id)
144
+ old_window = browser.window_handle
145
+ browser.switch_to.frame(frame_id)
146
+ yield
147
+ browser.switch_to.window old_window
148
+ end
149
+
150
+ private
151
+
152
+ def url(path)
153
+ rack_server.url(path)
154
+ end
155
+
156
+ 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