casebook-webrat 0.4.4.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 (76) hide show
  1. data/History.txt +332 -0
  2. data/MIT-LICENSE.txt +19 -0
  3. data/README.rdoc +85 -0
  4. data/Rakefile +156 -0
  5. data/install.rb +1 -0
  6. data/lib/webrat.rb +34 -0
  7. data/lib/webrat/core.rb +14 -0
  8. data/lib/webrat/core/configuration.rb +104 -0
  9. data/lib/webrat/core/elements/area.rb +31 -0
  10. data/lib/webrat/core/elements/element.rb +33 -0
  11. data/lib/webrat/core/elements/field.rb +403 -0
  12. data/lib/webrat/core/elements/form.rb +103 -0
  13. data/lib/webrat/core/elements/label.rb +31 -0
  14. data/lib/webrat/core/elements/link.rb +92 -0
  15. data/lib/webrat/core/elements/select_option.rb +35 -0
  16. data/lib/webrat/core/locators.rb +20 -0
  17. data/lib/webrat/core/locators/area_locator.rb +38 -0
  18. data/lib/webrat/core/locators/button_locator.rb +54 -0
  19. data/lib/webrat/core/locators/field_by_id_locator.rb +37 -0
  20. data/lib/webrat/core/locators/field_labeled_locator.rb +56 -0
  21. data/lib/webrat/core/locators/field_locator.rb +25 -0
  22. data/lib/webrat/core/locators/field_named_locator.rb +41 -0
  23. data/lib/webrat/core/locators/form_locator.rb +19 -0
  24. data/lib/webrat/core/locators/label_locator.rb +34 -0
  25. data/lib/webrat/core/locators/link_locator.rb +66 -0
  26. data/lib/webrat/core/locators/locator.rb +20 -0
  27. data/lib/webrat/core/locators/select_option_locator.rb +59 -0
  28. data/lib/webrat/core/logging.rb +21 -0
  29. data/lib/webrat/core/matchers.rb +4 -0
  30. data/lib/webrat/core/matchers/have_content.rb +73 -0
  31. data/lib/webrat/core/matchers/have_selector.rb +74 -0
  32. data/lib/webrat/core/matchers/have_tag.rb +21 -0
  33. data/lib/webrat/core/matchers/have_xpath.rb +147 -0
  34. data/lib/webrat/core/methods.rb +61 -0
  35. data/lib/webrat/core/mime.rb +29 -0
  36. data/lib/webrat/core/save_and_open_page.rb +50 -0
  37. data/lib/webrat/core/scope.rb +350 -0
  38. data/lib/webrat/core/session.rb +281 -0
  39. data/lib/webrat/core/xml.rb +115 -0
  40. data/lib/webrat/core/xml/hpricot.rb +19 -0
  41. data/lib/webrat/core/xml/nokogiri.rb +76 -0
  42. data/lib/webrat/core/xml/rexml.rb +24 -0
  43. data/lib/webrat/core_extensions/blank.rb +58 -0
  44. data/lib/webrat/core_extensions/deprecate.rb +8 -0
  45. data/lib/webrat/core_extensions/detect_mapped.rb +12 -0
  46. data/lib/webrat/core_extensions/meta_class.rb +6 -0
  47. data/lib/webrat/core_extensions/nil_to_param.rb +5 -0
  48. data/lib/webrat/core_extensions/tcp_socket.rb +27 -0
  49. data/lib/webrat/mechanize.rb +74 -0
  50. data/lib/webrat/merb.rb +9 -0
  51. data/lib/webrat/merb_session.rb +65 -0
  52. data/lib/webrat/rack.rb +24 -0
  53. data/lib/webrat/rails.rb +105 -0
  54. data/lib/webrat/rspec-rails.rb +13 -0
  55. data/lib/webrat/selenium.rb +80 -0
  56. data/lib/webrat/selenium/application_server.rb +71 -0
  57. data/lib/webrat/selenium/location_strategy_javascript/button.js +12 -0
  58. data/lib/webrat/selenium/location_strategy_javascript/label.js +16 -0
  59. data/lib/webrat/selenium/location_strategy_javascript/webrat.js +5 -0
  60. data/lib/webrat/selenium/location_strategy_javascript/webratlink.js +9 -0
  61. data/lib/webrat/selenium/location_strategy_javascript/webratlinkwithin.js +15 -0
  62. data/lib/webrat/selenium/location_strategy_javascript/webratselectwithoption.js +5 -0
  63. data/lib/webrat/selenium/matchers.rb +4 -0
  64. data/lib/webrat/selenium/matchers/have_content.rb +66 -0
  65. data/lib/webrat/selenium/matchers/have_selector.rb +49 -0
  66. data/lib/webrat/selenium/matchers/have_tag.rb +72 -0
  67. data/lib/webrat/selenium/matchers/have_xpath.rb +45 -0
  68. data/lib/webrat/selenium/merb_application_server.rb +48 -0
  69. data/lib/webrat/selenium/rails_application_server.rb +42 -0
  70. data/lib/webrat/selenium/selenium_extensions.js +6 -0
  71. data/lib/webrat/selenium/selenium_rc_server.rb +81 -0
  72. data/lib/webrat/selenium/selenium_session.rb +241 -0
  73. data/lib/webrat/selenium/sinatra_application_server.rb +35 -0
  74. data/lib/webrat/sinatra.rb +44 -0
  75. data/vendor/selenium-server.jar +0 -0
  76. metadata +147 -0
@@ -0,0 +1,80 @@
1
+ require "webrat"
2
+ gem "selenium-client", ">=1.2.14"
3
+ require "selenium/client"
4
+ require "webrat/selenium/selenium_session"
5
+ require "webrat/selenium/matchers"
6
+ require "webrat/core_extensions/tcp_socket"
7
+
8
+ module Webrat
9
+ # To use Webrat's Selenium support, you'll need the selenium-client gem installed.
10
+ # Activate it with (for example, in your <tt>env.rb</tt>):
11
+ #
12
+ # require "webrat"
13
+ #
14
+ # Webrat.configure do |config|
15
+ # config.mode = :selenium
16
+ # end
17
+ #
18
+ # == Dropping down to the selenium-client API
19
+ #
20
+ # If you ever need to do something with Selenium not provided in the Webrat API,
21
+ # you can always drop down to the selenium-client API using the <tt>selenium</tt> method.
22
+ # For example:
23
+ #
24
+ # When "I drag the photo to the left" do
25
+ # selenium.dragdrop("id=photo_123", "+350, 0")
26
+ # end
27
+ #
28
+ # == Choosing the underlying framework to test
29
+ #
30
+ # Webrat assumes you're using rails by default but it can also work with sinatra
31
+ # and merb. To take advantage of this you can use the configuration block to
32
+ # set the application_framework variable.
33
+ # require "webrat"
34
+ #
35
+ # Webrat.configure do |config|
36
+ # config.mode = :selenium
37
+ # config.application_port = 4567
38
+ # config.application_framework = :sinatra # could also be :merb
39
+ # end
40
+ #
41
+ # == Auto-starting of the appserver and java server
42
+ #
43
+ # Webrat will automatically start the Selenium Java server process and an instance
44
+ # of Mongrel when a test is run. The Mongrel will run in the "selenium" environment
45
+ # instead of "test", so ensure you've got that defined, and will run on port
46
+ # Webrat.configuration.application_port.
47
+ #
48
+ # == Waiting
49
+ #
50
+ # In order to make writing Selenium tests as easy as possible, Webrat will automatically
51
+ # wait for the correct elements to exist on the page when trying to manipulate them
52
+ # with methods like <tt>fill_in</tt>, etc. In general, this means you should be able to write
53
+ # your Webrat::Selenium tests ignoring the concurrency issues that can plague in-browser
54
+ # testing, so long as you're using the Webrat API.
55
+ module Selenium
56
+ module Methods
57
+ def response
58
+ webrat_session.response
59
+ end
60
+
61
+ def wait_for(*args, &block)
62
+ webrat_session.wait_for(*args, &block)
63
+ end
64
+
65
+ def save_and_open_screengrab
66
+ webrat_session.save_and_open_screengrab
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ if defined?(ActionController::IntegrationTest)
73
+ module ActionController #:nodoc:
74
+ IntegrationTest.class_eval do
75
+ include Webrat::Methods
76
+ include Webrat::Selenium::Methods
77
+ include Webrat::Selenium::Matchers
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,71 @@
1
+ module Webrat
2
+ module Selenium
3
+
4
+ class ApplicationServer
5
+
6
+ def self.boot
7
+ case Webrat.configuration.application_framework
8
+ when :sinatra
9
+ require "webrat/selenium/sinatra_application_server"
10
+ SinatraApplicationServer.new.boot
11
+ when :merb
12
+ require "webrat/selenium/merb_application_server"
13
+ MerbApplicationServer.new.boot
14
+ when :rails
15
+ require "webrat/selenium/rails_application_server"
16
+ RailsApplicationServer.new.boot
17
+ else
18
+ raise WebratError.new(<<-STR)
19
+ Unknown Webrat application_framework: #{Webrat.configuration.application_framework.inspect}
20
+
21
+ Please ensure you have a Webrat configuration block that specifies an application_framework
22
+ in your test_helper.rb, spec_helper.rb, or env.rb (for Cucumber).
23
+
24
+ For example:
25
+
26
+ Webrat.configure do |config|
27
+ # ...
28
+ config.application_framework = :rails
29
+ end
30
+ STR
31
+ end
32
+ end
33
+
34
+ def boot
35
+ start
36
+ wait
37
+ stop_at_exit
38
+ end
39
+
40
+ def stop_at_exit
41
+ at_exit do
42
+ stop
43
+ end
44
+ end
45
+
46
+ def wait
47
+ $stderr.print "==> Waiting for #{Webrat.configuration.application_framework} application server on port #{Webrat.configuration.application_port}... "
48
+ wait_for_socket
49
+ $stderr.print "Ready!\n"
50
+ end
51
+
52
+ def wait_for_socket
53
+ silence_stream(STDOUT) do
54
+ TCPSocket.wait_for_service_with_timeout \
55
+ :host => Webrat.configuration.application_address,
56
+ :port => Webrat.configuration.application_port.to_i,
57
+ :timeout => 30 # seconds
58
+ end
59
+ rescue SocketError
60
+ fail
61
+ end
62
+
63
+ def prepare_pid_file(file_path, pid_file_name)
64
+ FileUtils.mkdir_p File.expand_path(file_path)
65
+ File.expand_path("#{file_path}/#{pid_file_name}")
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,12 @@
1
+ if (locator == '*') {
2
+ return selenium.browserbot.locationStrategies['xpath'].call(this, "//input[@type='submit']", inDocument, inWindow)
3
+ }
4
+ var inputs = inDocument.getElementsByTagName('input');
5
+ return $A(inputs).find(function(candidate){
6
+ inputType = candidate.getAttribute('type');
7
+ if (inputType == 'submit' || inputType == 'image') {
8
+ var buttonText = $F(candidate);
9
+ return (PatternMatcher.matches(locator, buttonText));
10
+ }
11
+ return false;
12
+ });
@@ -0,0 +1,16 @@
1
+ var allLabels = inDocument.getElementsByTagName("label");
2
+ var candidateLabels = $A(allLabels).select(function(candidateLabel){
3
+ var regExp = new RegExp('^' + locator + '\\b', 'i');
4
+ var labelText = getText(candidateLabel).strip();
5
+ return (labelText.search(regExp) >= 0);
6
+ });
7
+ if (candidateLabels.length == 0) {
8
+ return null;
9
+ }
10
+ candidateLabels = candidateLabels.sortBy(function(s) { return s.length * -1; }); //reverse length sort
11
+ var locatedLabel = candidateLabels.first();
12
+ var labelFor = locatedLabel.getAttribute('for');
13
+ if ((labelFor == null) && (locatedLabel.hasChildNodes())) {
14
+ return locatedLabel.firstChild; //TODO: should find the first form field, not just any node
15
+ }
16
+ return selenium.browserbot.locationStrategies['id'].call(this, labelFor, inDocument, inWindow);
@@ -0,0 +1,5 @@
1
+ var locationStrategies = selenium.browserbot.locationStrategies;
2
+ return locationStrategies['id'].call(this, locator, inDocument, inWindow)
3
+ || locationStrategies['name'].call(this, locator, inDocument, inWindow)
4
+ || locationStrategies['label'].call(this, locator, inDocument, inWindow)
5
+ || null;
@@ -0,0 +1,9 @@
1
+ var links = inDocument.getElementsByTagName('a');
2
+ var candidateLinks = $A(links).select(function(candidateLink) {
3
+ return PatternMatcher.matches(locator, getText(candidateLink));
4
+ });
5
+ if (candidateLinks.length == 0) {
6
+ return null;
7
+ }
8
+ candidateLinks = candidateLinks.sortBy(function(s) { return s.length * -1; }); //reverse length sort
9
+ return candidateLinks.first();
@@ -0,0 +1,15 @@
1
+ var locatorParts = locator.split('|');
2
+ var cssAncestor = locatorParts[0];
3
+ var linkText = locatorParts[1];
4
+ var matchingElements = cssQuery(cssAncestor, inDocument);
5
+ var candidateLinks = matchingElements.collect(function(ancestor){
6
+ var links = ancestor.getElementsByTagName('a');
7
+ return $A(links).select(function(candidateLink) {
8
+ return PatternMatcher.matches(linkText, getText(candidateLink));
9
+ });
10
+ }).flatten().compact();
11
+ if (candidateLinks.length == 0) {
12
+ return null;
13
+ }
14
+ candidateLinks = candidateLinks.sortBy(function(s) { return s.length * -1; }); //reverse length sort
15
+ return candidateLinks.first();
@@ -0,0 +1,5 @@
1
+ var optionElements = inDocument.getElementsByTagName('option');
2
+ var locatedOption = $A(optionElements).find(function(candidate){
3
+ return (PatternMatcher.matches(locator, getText(candidate)));
4
+ });
5
+ return locatedOption ? locatedOption.parentNode : null;
@@ -0,0 +1,4 @@
1
+ require "webrat/selenium/matchers/have_xpath"
2
+ require "webrat/selenium/matchers/have_selector"
3
+ # require "webrat/selenium/matchers/have_tag"
4
+ require "webrat/selenium/matchers/have_content"
@@ -0,0 +1,66 @@
1
+ module Webrat
2
+ module Selenium
3
+ module Matchers
4
+ class HasContent #:nodoc:
5
+ def initialize(content)
6
+ @content = content
7
+ end
8
+
9
+ def matches?(response)
10
+ if @content.is_a?(Regexp)
11
+ text_finder = "regexp:#{@content.source}"
12
+ else
13
+ text_finder = @content
14
+ end
15
+
16
+ response.session.wait_for do
17
+ response.selenium.is_text_present(text_finder)
18
+ end
19
+ rescue Webrat::TimeoutError
20
+ false
21
+ end
22
+
23
+ # ==== Returns
24
+ # String:: The failure message.
25
+ def failure_message
26
+ "expected the following element's content to #{content_message}:\n#{@element}"
27
+ end
28
+
29
+ # ==== Returns
30
+ # String:: The failure message to be displayed in negative matches.
31
+ def negative_failure_message
32
+ "expected the following element's content to not #{content_message}:\n#{@element}"
33
+ end
34
+
35
+ def content_message
36
+ case @content
37
+ when String
38
+ "include \"#{@content}\""
39
+ when Regexp
40
+ "match #{@content.inspect}"
41
+ end
42
+ end
43
+ end
44
+
45
+ # Matches the contents of an HTML document with
46
+ # whatever string is supplied
47
+ def contain(content)
48
+ HasContent.new(content)
49
+ end
50
+
51
+ # Asserts that the body of the response contain
52
+ # the supplied string or regexp
53
+ def assert_contain(content)
54
+ hc = HasContent.new(content)
55
+ assert hc.matches?(response), hc.failure_message
56
+ end
57
+
58
+ # Asserts that the body of the response
59
+ # does not contain the supplied string or regepx
60
+ def assert_not_contain(content)
61
+ hc = HasContent.new(content)
62
+ assert !hc.matches?(response), hc.negative_failure_message
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,49 @@
1
+ module Webrat
2
+ module Selenium
3
+ module Matchers
4
+ class HaveSelector
5
+ def initialize(expected)
6
+ @expected = expected
7
+ end
8
+
9
+ def matches?(response)
10
+ response.session.wait_for do
11
+ response.selenium.is_element_present("css=#{@expected}")
12
+ end
13
+ rescue Webrat::TimeoutError
14
+ false
15
+ end
16
+
17
+ # ==== Returns
18
+ # String:: The failure message.
19
+ def failure_message
20
+ "expected following text to match selector #{@expected}:\n#{@document}"
21
+ end
22
+
23
+ # ==== Returns
24
+ # String:: The failure message to be displayed in negative matches.
25
+ def negative_failure_message
26
+ "expected following text to not match selector #{@expected}:\n#{@document}"
27
+ end
28
+ end
29
+
30
+ def have_selector(content)
31
+ HaveSelector.new(content)
32
+ end
33
+
34
+ # Asserts that the body of the response contains
35
+ # the supplied selector
36
+ def assert_have_selector(expected)
37
+ hs = HaveSelector.new(expected)
38
+ assert hs.matches?(response), hs.failure_message
39
+ end
40
+
41
+ # Asserts that the body of the response
42
+ # does not contain the supplied string or regepx
43
+ def assert_have_no_selector(expected)
44
+ hs = HaveSelector.new(expected)
45
+ assert !hs.matches?(response), hs.negative_failure_message
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,72 @@
1
+ module Webrat
2
+ module Selenium
3
+ module Matchers
4
+
5
+ class HaveTag < HaveSelector #:nodoc:
6
+ # ==== Returns
7
+ # String:: The failure message.
8
+ def failure_message
9
+ "expected following output to contain a #{tag_inspect} tag:\n#{@document}"
10
+ end
11
+
12
+ # ==== Returns
13
+ # String:: The failure message to be displayed in negative matches.
14
+ def negative_failure_message
15
+ "expected following output to omit a #{tag_inspect}:\n#{@document}"
16
+ end
17
+
18
+ def tag_inspect
19
+ options = @expected.last.dup
20
+ content = options.delete(:content)
21
+
22
+ html = "<#{@expected.first}"
23
+ options.each do |k,v|
24
+ html << " #{k}='#{v}'"
25
+ end
26
+
27
+ if content
28
+ html << ">#{content}</#{@expected.first}>"
29
+ else
30
+ html << "/>"
31
+ end
32
+
33
+ html
34
+ end
35
+
36
+ def query
37
+ options = @expected.last.dup
38
+ selector = @expected.first.to_s
39
+
40
+ selector << ":contains('#{options.delete(:content)}')" if options[:content]
41
+
42
+ options.each do |key, value|
43
+ selector << "[#{key}='#{value}']"
44
+ end
45
+
46
+ Nokogiri::CSS.parse(selector).map { |ast| ast.to_xpath }
47
+ end
48
+ end
49
+
50
+ def have_tag(name, attributes = {}, &block)
51
+ HaveTag.new([name, attributes], &block)
52
+ end
53
+
54
+ alias_method :match_tag, :have_tag
55
+
56
+ # Asserts that the body of the response contains
57
+ # the supplied tag with the associated selectors
58
+ def assert_have_tag(name, attributes = {})
59
+ ht = HaveTag.new([name, attributes])
60
+ assert ht.matches?(response), ht.failure_message
61
+ end
62
+
63
+ # Asserts that the body of the response
64
+ # does not contain the supplied string or regepx
65
+ def assert_have_no_tag(name, attributes = {})
66
+ ht = HaveTag.new([name, attributes])
67
+ assert !ht.matches?(response), ht.negative_failure_message
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,45 @@
1
+ module Webrat
2
+ module Selenium
3
+ module Matchers
4
+ class HaveXpath
5
+ def initialize(expected)
6
+ @expected = expected
7
+ end
8
+
9
+ def matches?(response)
10
+ response.session.wait_for do
11
+ response.selenium.is_element_present("xpath=#{@expected}")
12
+ end
13
+ rescue Webrat::TimeoutError
14
+ false
15
+ end
16
+
17
+ # ==== Returns
18
+ # String:: The failure message.
19
+ def failure_message
20
+ "expected following text to match xpath #{@expected}:\n#{@document}"
21
+ end
22
+
23
+ # ==== Returns
24
+ # String:: The failure message to be displayed in negative matches.
25
+ def negative_failure_message
26
+ "expected following text to not match xpath #{@expected}:\n#{@document}"
27
+ end
28
+ end
29
+
30
+ def have_xpath(xpath)
31
+ HaveXpath.new(xpath)
32
+ end
33
+
34
+ def assert_have_xpath(expected)
35
+ hs = HaveXpath.new(expected)
36
+ assert hs.matches?(response), hs.failure_message
37
+ end
38
+
39
+ def assert_have_no_xpath(expected)
40
+ hs = HaveXpath.new(expected)
41
+ assert !hs.matches?(response), hs.negative_failure_message
42
+ end
43
+ end
44
+ end
45
+ end