capybara 0.1

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 (43) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +42 -0
  3. data/README.rdoc +208 -0
  4. data/Rakefile +33 -0
  5. data/examples/webcat.rb +36 -0
  6. data/lib/capybara.rb +30 -0
  7. data/lib/capybara/core_ext/tcp_socket.rb +26 -0
  8. data/lib/capybara/cucumber.rb +32 -0
  9. data/lib/capybara/driver/culerity_driver.rb +83 -0
  10. data/lib/capybara/driver/firewatir_driver.rb +66 -0
  11. data/lib/capybara/driver/rack_test_driver.rb +151 -0
  12. data/lib/capybara/driver/safariwatir_driver.rb +67 -0
  13. data/lib/capybara/driver/selenium_driver.rb +93 -0
  14. data/lib/capybara/dsl.rb +58 -0
  15. data/lib/capybara/node.rb +36 -0
  16. data/lib/capybara/rails.rb +11 -0
  17. data/lib/capybara/save_and_open_page.rb +25 -0
  18. data/lib/capybara/server.rb +53 -0
  19. data/lib/capybara/session.rb +190 -0
  20. data/script/console +10 -0
  21. data/script/destroy +14 -0
  22. data/script/generate +14 -0
  23. data/spec/driver/culerity_driver_spec.rb +10 -0
  24. data/spec/driver/firewatir_driver_spec.rb +10 -0
  25. data/spec/driver/rack_test_driver_spec.rb +9 -0
  26. data/spec/driver/safariwarit_driver_spec.rb +10 -0
  27. data/spec/driver/selenium_driver_spec.rb +10 -0
  28. data/spec/drivers_spec.rb +72 -0
  29. data/spec/dsl_spec.rb +139 -0
  30. data/spec/fixtures/test_file.txt +1 -0
  31. data/spec/public/jquery.js +19 -0
  32. data/spec/session/culerity_session_spec.rb +23 -0
  33. data/spec/session/rack_test_session_spec.rb +23 -0
  34. data/spec/session/selenium_session_spec.rb +23 -0
  35. data/spec/session_spec.rb +611 -0
  36. data/spec/spec_helper.rb +10 -0
  37. data/spec/test_app.rb +67 -0
  38. data/spec/views/form.erb +117 -0
  39. data/spec/views/with_html.erb +19 -0
  40. data/spec/views/with_js.erb +20 -0
  41. data/spec/views/with_scope.erb +36 -0
  42. data/spec/views/with_simple_html.erb +1 -0
  43. metadata +164 -0
@@ -0,0 +1,66 @@
1
+ require 'watir'
2
+ Watir::Browser.default = "firefox"
3
+
4
+ class Capybara::Driver::FireWatir
5
+ class Node < Struct.new(:node)
6
+ def text
7
+ node.text
8
+ end
9
+
10
+ def attribute(name)
11
+ value = if name.to_sym == :class
12
+ node.class_name
13
+ else
14
+ node.send(name.to_sym)
15
+ end
16
+ return value if value and not value.empty?
17
+ end
18
+
19
+ def click
20
+ node.click
21
+ end
22
+
23
+ def tag_name
24
+ # FIXME: this might be the dumbest way ever of getting the tag name
25
+ # there has to be something better...
26
+ node.to_xml[/^\s*<([a-z0-9\-\:]+)/, 1]
27
+ end
28
+ end
29
+
30
+ attr_reader :app, :rack_server
31
+
32
+ def initialize(app)
33
+ @app = app
34
+ @rack_server = Capybara::Server.new(@app)
35
+ @rack_server.boot
36
+ end
37
+
38
+ def visit(path)
39
+ browser.goto(url(path))
40
+ end
41
+
42
+ def body
43
+ browser.html
44
+ end
45
+
46
+ def find(selector)
47
+ browser.elements_by_xpath(selector).map { |node| Node.new(node) }
48
+ end
49
+
50
+ private
51
+
52
+ def url(path)
53
+ rack_server.url(path)
54
+ end
55
+
56
+ def browser
57
+ unless @_browser
58
+ @_browser = Watir::Browser.new
59
+ at_exit do
60
+ @_browser.exit
61
+ end
62
+ end
63
+ @_browser
64
+ end
65
+
66
+ end
@@ -0,0 +1,151 @@
1
+ require 'rack/test'
2
+ require 'nokogiri'
3
+
4
+ class Capybara::Driver::RackTest
5
+ class Node < Capybara::Node
6
+ def text
7
+ node.text
8
+ end
9
+
10
+ def [](name)
11
+ value = node[name.to_s]
12
+ return value.to_s if value
13
+ end
14
+
15
+ def set(value)
16
+ if tag_name == 'input' and %w(text password hidden file).include?(type)
17
+ node['value'] = value.to_s
18
+ elsif tag_name == 'input' and type == 'radio'
19
+ driver.html.xpath("//input[@name='#{self[:name]}']").each { |node| node.remove_attribute("checked") }
20
+ node['checked'] = 'checked'
21
+ elsif tag_name == 'input' and type == 'checkbox'
22
+ if value
23
+ node['checked'] = 'checked'
24
+ else
25
+ node.remove_attribute('checked')
26
+ end
27
+ elsif tag_name == "textarea"
28
+ node.content = value.to_s
29
+ end
30
+ end
31
+
32
+ def select(option)
33
+ node.xpath(".//option").each { |node| node.remove_attribute("selected") }
34
+ node.xpath(".//option[contains(.,'#{option}')]").first["selected"] = 'selected'
35
+ end
36
+
37
+ def click
38
+ if tag_name == 'a'
39
+ driver.visit(self[:href])
40
+ elsif tag_name == 'input' and %w(submit image).include?(type)
41
+ Form.new(driver, form).submit(self)
42
+ end
43
+ end
44
+
45
+ def tag_name
46
+ node.node_name
47
+ end
48
+
49
+ private
50
+
51
+ def type
52
+ self[:type]
53
+ end
54
+
55
+ def form
56
+ node.ancestors('form').first
57
+ end
58
+ end
59
+
60
+ class Form < Node
61
+ def params(button)
62
+ params = []
63
+ params += node.xpath(".//input[@type='text']", ".//input[@type='hidden']", ".//input[@type='password']").inject([]) do |agg, input|
64
+ agg << [input['name'].to_s, input['value'].to_s]
65
+ agg
66
+ end
67
+ params += node.xpath(".//textarea").inject([]) do |agg, textarea|
68
+ agg << [textarea['name'].to_s, textarea.text.to_s]
69
+ agg
70
+ end
71
+ params += node.xpath(".//input[@type='radio']").inject([]) do |agg, input|
72
+ agg << [input['name'].to_s, input['value'].to_s] if input['checked']
73
+ agg
74
+ end
75
+ params += node.xpath(".//input[@type='checkbox']").inject([]) do |agg, input|
76
+ agg << [input['name'].to_s, input['value'].to_s] if input['checked']
77
+ agg
78
+ end
79
+ params += node.xpath(".//select").inject([]) do |agg, select|
80
+ option = select.xpath(".//option[@selected]").first
81
+ option ||= select.xpath('.//option').first
82
+ agg << [select['name'].to_s, (option['value'] || option.text).to_s] if option
83
+ agg
84
+ end
85
+ params += node.xpath(".//input[@type='file']").inject([]) do |agg, input|
86
+ if multipart?
87
+ agg << [input['name'].to_s, Rack::Test::UploadedFile.new(input['value'].to_s)]
88
+ else
89
+ agg << [input['name'].to_s, File.basename(input['value'].to_s)]
90
+ end
91
+ agg
92
+ end
93
+ params.push [button[:name], button[:value]] if button[:name]
94
+ if multipart?
95
+ params.inject({}) { |agg, (key, value)| agg[key] = value; agg }
96
+ else
97
+ params.map { |key, value| "#{key}=#{value}" }.join('&')
98
+ end
99
+ end
100
+
101
+ def submit(button)
102
+ if post?
103
+ driver.submit(node['action'].to_s, params(button))
104
+ else
105
+ driver.visit(node['action'].to_s.split('?').first + '?' + params(button))
106
+ end
107
+ end
108
+
109
+ def multipart?
110
+ self[:enctype] == "multipart/form-data"
111
+ end
112
+
113
+ def post?
114
+ self[:method] =~ /post/i
115
+ end
116
+ end
117
+
118
+ include ::Rack::Test::Methods
119
+ attr_reader :app, :html, :body
120
+
121
+ alias_method :response, :last_response
122
+ alias_method :request, :last_request
123
+
124
+ def initialize(app)
125
+ @app = app
126
+ end
127
+
128
+ def visit(path)
129
+ get(path)
130
+ follow_redirect! while response.redirect?
131
+ cache_body
132
+ end
133
+
134
+ def submit(path, attributes)
135
+ post(path, attributes)
136
+ follow_redirect! while response.redirect?
137
+ cache_body
138
+ end
139
+
140
+ def find(selector)
141
+ html.xpath(selector).map { |node| Node.new(self, node) }
142
+ end
143
+
144
+ private
145
+
146
+ def cache_body
147
+ @body = response.body
148
+ @html = Nokogiri::HTML(body)
149
+ end
150
+
151
+ end
@@ -0,0 +1,67 @@
1
+ require 'safariwatir'
2
+
3
+ class Capybara::Driver::SafariWatir
4
+ class Node < Struct.new(:node)
5
+ def text
6
+ node.text
7
+ end
8
+
9
+ def attribute(name)
10
+ value = if name.to_sym == :class
11
+ node.class_name
12
+ else
13
+ node.send(name.to_sym)
14
+ end
15
+ return value if value and not value.empty?
16
+ end
17
+
18
+ def click
19
+ node.click
20
+ end
21
+
22
+ def tag_name
23
+ # FIXME: this might be the dumbest way ever of getting the tag name
24
+ # there has to be something better...
25
+ node.to_xml[/^\s*<([a-z0-9\-\:]+)/, 1]
26
+ end
27
+ end
28
+
29
+ attr_reader :app, :rack_server
30
+
31
+ def initialize(app)
32
+ @app = app
33
+ @rack_server = Capybara::Server.new(@app)
34
+ @rack_server.boot
35
+ end
36
+
37
+ def visit(path)
38
+ browser.goto(url(path))
39
+ end
40
+
41
+ def body
42
+ browser.html
43
+ end
44
+
45
+ def find(selector)
46
+ foo = Struct.new(:what).new
47
+ foo.what = selector
48
+ browser.send(:scripter).operate_by_xpath(foo){}.map { |node| Node.new(node) }
49
+ end
50
+
51
+ private
52
+
53
+ def url(path)
54
+ rack_server.url(path)
55
+ end
56
+
57
+ def browser
58
+ unless @_browser
59
+ @_browser = Watir::Safari.new
60
+ at_exit do
61
+ @_browser.exit
62
+ end
63
+ end
64
+ @_browser
65
+ end
66
+
67
+ end
@@ -0,0 +1,93 @@
1
+ require 'selenium-webdriver'
2
+
3
+ class Capybara::Driver::Selenium
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)
14
+ end
15
+ rescue Selenium::WebDriver::Error::WebDriverError
16
+ nil
17
+ end
18
+
19
+ def set(value)
20
+ if tag_name == 'input' and %w(text password hidden file).include?(type)
21
+ node.clear
22
+ node.send_keys(value.to_s)
23
+ elsif tag_name == 'input' and type == 'radio'
24
+ node.select
25
+ elsif tag_name == 'input' and type == 'checkbox'
26
+ node.toggle
27
+ elsif tag_name == "textarea"
28
+ node.clear
29
+ node.send_keys(value.to_s)
30
+ end
31
+ end
32
+
33
+ def select(option)
34
+ node.find_element(:xpath, ".//option[contains(.,'#{option}')]").select
35
+ end
36
+
37
+ def click
38
+ node.click
39
+ end
40
+
41
+ def tag_name
42
+ node.tag_name
43
+ end
44
+
45
+ private
46
+
47
+ def type
48
+ self[:type]
49
+ end
50
+
51
+ end
52
+
53
+ attr_reader :app, :rack_server
54
+
55
+ def self.driver
56
+ unless @driver
57
+ @driver = Selenium::WebDriver.for :firefox
58
+ at_exit do
59
+ @driver.quit
60
+ end
61
+ end
62
+ @driver
63
+ end
64
+
65
+ def initialize(app)
66
+ @app = app
67
+ @rack_server = Capybara::Server.new(@app)
68
+ @rack_server.boot
69
+ end
70
+
71
+ def visit(path)
72
+ driver.navigate.to(url(path))
73
+ end
74
+
75
+ def body
76
+ driver.page_source
77
+ end
78
+
79
+ def find(selector)
80
+ driver.find_elements(:xpath, selector).map { |node| Node.new(self, node) }
81
+ end
82
+
83
+ private
84
+
85
+ def url(path)
86
+ rack_server.url(path)
87
+ end
88
+
89
+ def driver
90
+ self.class.driver
91
+ end
92
+
93
+ end
@@ -0,0 +1,58 @@
1
+ module Capybara
2
+ class << self
3
+ attr_writer :default_driver, :current_driver, :javascript_driver
4
+
5
+ attr_accessor :app
6
+
7
+ def default_driver
8
+ @default_driver || :rack_test
9
+ end
10
+
11
+ def current_driver
12
+ @current_driver || default_driver
13
+ end
14
+ alias_method :mode, :current_driver
15
+
16
+ def javascript_driver
17
+ @javascript_driver || :selenium
18
+ end
19
+
20
+ def use_default_driver
21
+ @current_driver = nil
22
+ end
23
+
24
+ def current_session
25
+ session_pool["#{current_driver}#{app.object_id}"] ||= Capybara::Session.new(current_driver, app)
26
+ end
27
+
28
+ def reset_sessions!
29
+ @session_pool = nil
30
+ end
31
+
32
+ private
33
+
34
+ def session_pool
35
+ @session_pool ||= {}
36
+ end
37
+ end
38
+
39
+ extend(self)
40
+
41
+ def page
42
+ Capybara.current_session
43
+ end
44
+
45
+ SESSION_METHODS = [
46
+ :visit, :body, :click_link, :click_button, :fill_in, :choose, :has_xpath?, :has_css?,
47
+ :check, :uncheck, :attach_file, :select, :has_content?, :within, :save_and_open_page,
48
+ :find_field, :find_link, :find_button, :field_labeled
49
+ ]
50
+ SESSION_METHODS.each do |method|
51
+ class_eval <<-RUBY, __FILE__, __LINE__+1
52
+ def #{method}(*args, &block)
53
+ page.#{method}(*args, &block)
54
+ end
55
+ RUBY
56
+ end
57
+
58
+ end
@@ -0,0 +1,36 @@
1
+ class Capybara::Node
2
+ attr_reader :driver, :node
3
+
4
+ def initialize(driver, node)
5
+ @driver = driver
6
+ @node = node
7
+ end
8
+
9
+ def text
10
+ raise "Not implemented"
11
+ end
12
+
13
+ def [](name)
14
+ raise "Not implemented"
15
+ end
16
+
17
+ def value
18
+ self[:value]
19
+ end
20
+
21
+ def set(value)
22
+ raise "Not implemented"
23
+ end
24
+
25
+ def select(option)
26
+ raise "Not implemented"
27
+ end
28
+
29
+ def click
30
+ raise "Not implemented"
31
+ end
32
+
33
+ def tag_name
34
+ raise "Not implemented"
35
+ end
36
+ end