pr0d1r2-capybara 0.3.7

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