kbaum-webrat 0.5.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.
- data/.document +4 -0
- data/.gitignore +15 -0
- data/History.txt +406 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.rdoc +85 -0
- data/Rakefile +186 -0
- data/VERSION +1 -0
- data/install.rb +1 -0
- data/lib/webrat.rb +18 -0
- data/lib/webrat/adapters/mechanize.rb +78 -0
- data/lib/webrat/adapters/merb.rb +11 -0
- data/lib/webrat/adapters/rack.rb +25 -0
- data/lib/webrat/adapters/rails.rb +96 -0
- data/lib/webrat/adapters/sinatra.rb +9 -0
- data/lib/webrat/core.rb +13 -0
- data/lib/webrat/core/configuration.rb +96 -0
- data/lib/webrat/core/elements/area.rb +31 -0
- data/lib/webrat/core/elements/element.rb +33 -0
- data/lib/webrat/core/elements/field.rb +487 -0
- data/lib/webrat/core/elements/form.rb +103 -0
- data/lib/webrat/core/elements/label.rb +31 -0
- data/lib/webrat/core/elements/link.rb +93 -0
- data/lib/webrat/core/elements/select_option.rb +48 -0
- data/lib/webrat/core/locators.rb +20 -0
- data/lib/webrat/core/locators/area_locator.rb +38 -0
- data/lib/webrat/core/locators/button_locator.rb +54 -0
- data/lib/webrat/core/locators/field_by_id_locator.rb +37 -0
- data/lib/webrat/core/locators/field_labeled_locator.rb +56 -0
- data/lib/webrat/core/locators/field_locator.rb +25 -0
- data/lib/webrat/core/locators/field_named_locator.rb +41 -0
- data/lib/webrat/core/locators/form_locator.rb +19 -0
- data/lib/webrat/core/locators/label_locator.rb +34 -0
- data/lib/webrat/core/locators/link_locator.rb +74 -0
- data/lib/webrat/core/locators/locator.rb +20 -0
- data/lib/webrat/core/locators/select_option_locator.rb +59 -0
- data/lib/webrat/core/logging.rb +23 -0
- data/lib/webrat/core/matchers.rb +4 -0
- data/lib/webrat/core/matchers/have_content.rb +68 -0
- data/lib/webrat/core/matchers/have_selector.rb +74 -0
- data/lib/webrat/core/matchers/have_tag.rb +21 -0
- data/lib/webrat/core/matchers/have_xpath.rb +122 -0
- data/lib/webrat/core/methods.rb +64 -0
- data/lib/webrat/core/mime.rb +18 -0
- data/lib/webrat/core/save_and_open_page.rb +48 -0
- data/lib/webrat/core/scope.rb +365 -0
- data/lib/webrat/core/session.rb +307 -0
- data/lib/webrat/core/xml.rb +72 -0
- data/lib/webrat/core_extensions/blank.rb +58 -0
- data/lib/webrat/core_extensions/deprecate.rb +8 -0
- data/lib/webrat/core_extensions/detect_mapped.rb +12 -0
- data/lib/webrat/core_extensions/meta_class.rb +6 -0
- data/lib/webrat/core_extensions/nil_to_param.rb +5 -0
- data/lib/webrat/core_extensions/tcp_socket.rb +27 -0
- data/lib/webrat/integrations/merb.rb +10 -0
- data/lib/webrat/integrations/rails.rb +9 -0
- data/lib/webrat/integrations/rspec-rails.rb +10 -0
- data/lib/webrat/integrations/selenium.rb +11 -0
- data/lib/webrat/merb.rb +9 -0
- data/lib/webrat/rspec-rails.rb +2 -0
- data/lib/webrat/selenium.rb +70 -0
- data/lib/webrat/selenium/application_server_factory.rb +40 -0
- data/lib/webrat/selenium/application_servers.rb +5 -0
- data/lib/webrat/selenium/application_servers/base.rb +46 -0
- data/lib/webrat/selenium/application_servers/external.rb +26 -0
- data/lib/webrat/selenium/application_servers/merb.rb +50 -0
- data/lib/webrat/selenium/application_servers/rails.rb +44 -0
- data/lib/webrat/selenium/application_servers/sinatra.rb +37 -0
- data/lib/webrat/selenium/location_strategy_javascript/button.js +19 -0
- data/lib/webrat/selenium/location_strategy_javascript/label.js +24 -0
- data/lib/webrat/selenium/location_strategy_javascript/webrat.js +5 -0
- data/lib/webrat/selenium/location_strategy_javascript/webratlink.js +12 -0
- data/lib/webrat/selenium/location_strategy_javascript/webratlinkwithin.js +15 -0
- data/lib/webrat/selenium/location_strategy_javascript/webratselectwithoption.js +5 -0
- data/lib/webrat/selenium/matchers.rb +4 -0
- data/lib/webrat/selenium/matchers/have_content.rb +66 -0
- data/lib/webrat/selenium/matchers/have_selector.rb +74 -0
- data/lib/webrat/selenium/matchers/have_tag.rb +49 -0
- data/lib/webrat/selenium/matchers/have_xpath.rb +45 -0
- data/lib/webrat/selenium/selenium_extensions.js +6 -0
- data/lib/webrat/selenium/selenium_rc_server.rb +86 -0
- data/lib/webrat/selenium/selenium_session.rb +250 -0
- data/lib/webrat/selenium/silence_stream.rb +18 -0
- data/selenium_rc_server.patch +20 -0
- data/spec/fakes/test_adapter.rb +37 -0
- data/spec/integration/mechanize/Rakefile +7 -0
- data/spec/integration/mechanize/config.ru +2 -0
- data/spec/integration/mechanize/sample_app.rb +20 -0
- data/spec/integration/mechanize/spec/mechanize_spec.rb +22 -0
- data/spec/integration/mechanize/spec/spec_helper.rb +27 -0
- data/spec/integration/merb/.gitignore +21 -0
- data/spec/integration/merb/Rakefile +35 -0
- data/spec/integration/merb/app/controllers/application.rb +2 -0
- data/spec/integration/merb/app/controllers/exceptions.rb +13 -0
- data/spec/integration/merb/app/controllers/testing.rb +27 -0
- data/spec/integration/merb/app/views/exceptions/not_acceptable.html.erb +63 -0
- data/spec/integration/merb/app/views/exceptions/not_found.html.erb +47 -0
- data/spec/integration/merb/app/views/layout/application.html.erb +12 -0
- data/spec/integration/merb/app/views/testing/show_form.html.erb +27 -0
- data/spec/integration/merb/app/views/testing/upload.html.erb +9 -0
- data/spec/integration/merb/config/environments/development.rb +15 -0
- data/spec/integration/merb/config/environments/rake.rb +11 -0
- data/spec/integration/merb/config/environments/test.rb +14 -0
- data/spec/integration/merb/config/init.rb +25 -0
- data/spec/integration/merb/config/rack.rb +11 -0
- data/spec/integration/merb/config/router.rb +34 -0
- data/spec/integration/merb/spec/spec.opts +1 -0
- data/spec/integration/merb/spec/spec_helper.rb +26 -0
- data/spec/integration/merb/spec/webrat_spec.rb +39 -0
- data/spec/integration/merb/tasks/merb.thor/app_script.rb +31 -0
- data/spec/integration/merb/tasks/merb.thor/common.rb +64 -0
- data/spec/integration/merb/tasks/merb.thor/gem_ext.rb +124 -0
- data/spec/integration/merb/tasks/merb.thor/main.thor +150 -0
- data/spec/integration/merb/tasks/merb.thor/ops.rb +93 -0
- data/spec/integration/merb/tasks/merb.thor/utils.rb +40 -0
- data/spec/integration/rack/Rakefile +5 -0
- data/spec/integration/rack/app.rb +89 -0
- data/spec/integration/rack/test/helper.rb +21 -0
- data/spec/integration/rack/test/webrat_rack_test.rb +73 -0
- data/spec/integration/rails/.gitignore +3 -0
- data/spec/integration/rails/Rakefile +30 -0
- data/spec/integration/rails/app/controllers/application.rb +15 -0
- data/spec/integration/rails/app/controllers/buttons_controller.rb +7 -0
- data/spec/integration/rails/app/controllers/fields_controller.rb +4 -0
- data/spec/integration/rails/app/controllers/links_controller.rb +7 -0
- data/spec/integration/rails/app/controllers/webrat_controller.rb +43 -0
- data/spec/integration/rails/app/helpers/buttons_helper.rb +2 -0
- data/spec/integration/rails/app/helpers/fields_helper.rb +2 -0
- data/spec/integration/rails/app/helpers/links_helper.rb +2 -0
- data/spec/integration/rails/app/views/buttons/show.html.erb +11 -0
- data/spec/integration/rails/app/views/fields/show.html.erb +9 -0
- data/spec/integration/rails/app/views/links/show.html.erb +5 -0
- data/spec/integration/rails/app/views/webrat/before_redirect_form.html.erb +4 -0
- data/spec/integration/rails/app/views/webrat/buttons.html.erb +11 -0
- data/spec/integration/rails/app/views/webrat/form.html.erb +28 -0
- data/spec/integration/rails/config/boot.rb +109 -0
- data/spec/integration/rails/config/environment.rb +12 -0
- data/spec/integration/rails/config/environments/development.rb +17 -0
- data/spec/integration/rails/config/environments/selenium.rb +22 -0
- data/spec/integration/rails/config/environments/test.rb +22 -0
- data/spec/integration/rails/config/initializers/inflections.rb +10 -0
- data/spec/integration/rails/config/initializers/mime_types.rb +5 -0
- data/spec/integration/rails/config/initializers/new_rails_defaults.rb +17 -0
- data/spec/integration/rails/config/locales/en.yml +5 -0
- data/spec/integration/rails/config/routes.rb +18 -0
- data/spec/integration/rails/public/404.html +30 -0
- data/spec/integration/rails/public/422.html +30 -0
- data/spec/integration/rails/public/500.html +33 -0
- data/spec/integration/rails/script/about +4 -0
- data/spec/integration/rails/script/console +3 -0
- data/spec/integration/rails/script/dbconsole +3 -0
- data/spec/integration/rails/script/destroy +3 -0
- data/spec/integration/rails/script/generate +3 -0
- data/spec/integration/rails/script/performance/benchmarker +3 -0
- data/spec/integration/rails/script/performance/profiler +3 -0
- data/spec/integration/rails/script/performance/request +3 -0
- data/spec/integration/rails/script/plugin +3 -0
- data/spec/integration/rails/script/process/inspector +3 -0
- data/spec/integration/rails/script/process/reaper +3 -0
- data/spec/integration/rails/script/process/spawner +3 -0
- data/spec/integration/rails/script/runner +3 -0
- data/spec/integration/rails/script/server +3 -0
- data/spec/integration/rails/test/integration/button_click_test.rb +80 -0
- data/spec/integration/rails/test/integration/fill_in_test.rb +24 -0
- data/spec/integration/rails/test/integration/link_click_test.rb +27 -0
- data/spec/integration/rails/test/integration/webrat_test.rb +97 -0
- data/spec/integration/rails/test/test_helper.rb +26 -0
- data/spec/integration/sinatra/Rakefile +5 -0
- data/spec/integration/sinatra/classic_app.rb +64 -0
- data/spec/integration/sinatra/modular_app.rb +16 -0
- data/spec/integration/sinatra/test/classic_app_test.rb +37 -0
- data/spec/integration/sinatra/test/modular_app_test.rb +18 -0
- data/spec/integration/sinatra/test/test_helper.rb +17 -0
- data/spec/private/core/configuration_spec.rb +87 -0
- data/spec/private/core/field_spec.rb +85 -0
- data/spec/private/core/link_spec.rb +24 -0
- data/spec/private/core/session_spec.rb +200 -0
- data/spec/private/mechanize/mechanize_adapter_spec.rb +73 -0
- data/spec/private/nokogiri_spec.rb +77 -0
- data/spec/private/rails/attaches_file_spec.rb +81 -0
- data/spec/private/rails/rails_adapter_spec.rb +110 -0
- data/spec/private/selenium/application_servers/rails_spec.rb +26 -0
- data/spec/public/basic_auth_spec.rb +24 -0
- data/spec/public/check_spec.rb +191 -0
- data/spec/public/choose_spec.rb +118 -0
- data/spec/public/click_area_spec.rb +106 -0
- data/spec/public/click_button_spec.rb +494 -0
- data/spec/public/click_link_spec.rb +511 -0
- data/spec/public/fill_in_spec.rb +224 -0
- data/spec/public/locators/field_by_xpath_spec.rb +19 -0
- data/spec/public/locators/field_labeled_spec.rb +172 -0
- data/spec/public/locators/field_with_id_spec.rb +16 -0
- data/spec/public/matchers/contain_spec.rb +114 -0
- data/spec/public/matchers/have_selector_spec.rb +146 -0
- data/spec/public/matchers/have_tag_spec.rb +39 -0
- data/spec/public/matchers/have_xpath_spec.rb +136 -0
- data/spec/public/reload_spec.rb +10 -0
- data/spec/public/save_and_open_spec.rb +70 -0
- data/spec/public/select_date_spec.rb +112 -0
- data/spec/public/select_datetime_spec.rb +137 -0
- data/spec/public/select_spec.rb +455 -0
- data/spec/public/select_time_spec.rb +100 -0
- data/spec/public/selenium/application_server_factory_spec.rb +49 -0
- data/spec/public/selenium/application_servers/external_spec.rb +12 -0
- data/spec/public/selenium/selenium_session_spec.rb +37 -0
- data/spec/public/set_hidden_field_spec.rb +5 -0
- data/spec/public/submit_form_spec.rb +5 -0
- data/spec/public/visit_spec.rb +58 -0
- data/spec/public/within_spec.rb +177 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +54 -0
- data/vendor/selenium-server.jar +0 -0
- data/webrat.gemspec +356 -0
- metadata +410 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
if (locator == '*') {
|
|
2
|
+
return selenium.browserbot.locationStrategies['xpath'].call(this, "//input[@type='submit']", inDocument, inWindow)
|
|
3
|
+
}
|
|
4
|
+
var buttons = inDocument.getElementsByTagName('button');
|
|
5
|
+
var inputs = inDocument.getElementsByTagName('input');
|
|
6
|
+
var result = $A(inputs).concat($A(buttons)).find(function(candidate){
|
|
7
|
+
var type = candidate.getAttribute('type');
|
|
8
|
+
if (type == 'submit' || type == 'image' || type == 'button') {
|
|
9
|
+
var matches_id = PatternMatcher.matches(locator, candidate.id);
|
|
10
|
+
var matches_value = PatternMatcher.matches(locator, candidate.value);
|
|
11
|
+
var matches_html = PatternMatcher.matches(locator, candidate.innerHTML);
|
|
12
|
+
var matches_alt = PatternMatcher.matches(locator, candidate.alt);
|
|
13
|
+
if (matches_id || matches_value || matches_html || matches_alt) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
});
|
|
19
|
+
return result;
|
|
@@ -0,0 +1,24 @@
|
|
|
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') || locatedLabel.getAttribute('htmlFor');
|
|
13
|
+
if((!labelFor || labelFor == "") && (locatedLabel.hasChildNodes())) {
|
|
14
|
+
var inputTags = locatedLabel.getElementsByTagName("input");
|
|
15
|
+
var textAreaTags = locatedLabel.getElementsByTagName("textarea");
|
|
16
|
+
if(inputTags.length > 0) {
|
|
17
|
+
return inputTags[0];
|
|
18
|
+
} else if(textAreaTags.length > 0) {
|
|
19
|
+
return textAreaTags[0];
|
|
20
|
+
} else {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
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,12 @@
|
|
|
1
|
+
var links = inDocument.getElementsByTagName('a');
|
|
2
|
+
var candidateLinks = $A(links).select(function(candidateLink) {
|
|
3
|
+
var textMatched = PatternMatcher.matches(locator, getText(candidateLink));
|
|
4
|
+
var idMatched = PatternMatcher.matches(locator, candidateLink.id);
|
|
5
|
+
var titleMatched = PatternMatcher.matches(locator, candidateLink.title);
|
|
6
|
+
return textMatched || idMatched || titleMatched;
|
|
7
|
+
});
|
|
8
|
+
if (candidateLinks.length == 0) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
candidateLinks = candidateLinks.sortBy(function(s) { return s.length * -1; }); //reverse length sort
|
|
12
|
+
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,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,74 @@
|
|
|
1
|
+
module Webrat
|
|
2
|
+
module Selenium
|
|
3
|
+
module Matchers
|
|
4
|
+
class HaveSelector
|
|
5
|
+
def initialize(expected, options = {}, &block)
|
|
6
|
+
@expected = expected
|
|
7
|
+
@options = options
|
|
8
|
+
@block = block
|
|
9
|
+
@content = @options.delete(:content)||@options.delete(:text)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def matches?(response)
|
|
13
|
+
response.session.wait_for do
|
|
14
|
+
# if @content
|
|
15
|
+
# @element=response.selenium.get_text("css=#{@expected}")
|
|
16
|
+
# case @content
|
|
17
|
+
# when String
|
|
18
|
+
# @element.include?(@content)
|
|
19
|
+
# when Regexp
|
|
20
|
+
# @element.match(@content)
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# else
|
|
24
|
+
response.selenium.is_element_present(selector)
|
|
25
|
+
# end
|
|
26
|
+
end
|
|
27
|
+
rescue Webrat::TimeoutError
|
|
28
|
+
false
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def selector
|
|
32
|
+
"css=#{@expected}" + ((@content && ":contains('#{@content}')") || '')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# ==== Returns
|
|
36
|
+
# String:: The failure message.
|
|
37
|
+
def failure_message
|
|
38
|
+
"expected following text to match selector #{@expected}:\n#{@document}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# ==== Returns
|
|
42
|
+
# String:: The failure message to be displayed in negative matches.
|
|
43
|
+
def negative_failure_message
|
|
44
|
+
"expected following text to not match selector #{@expected}:\n#{@document}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Matches HTML content against a CSS 3 selector.
|
|
49
|
+
#
|
|
50
|
+
# ==== Parameters
|
|
51
|
+
# expected<String>:: The CSS selector to look for.
|
|
52
|
+
#
|
|
53
|
+
# ==== Returns
|
|
54
|
+
# HaveSelector:: A new have selector matcher.
|
|
55
|
+
def have_selector(name, attributes = {}, &block)
|
|
56
|
+
HaveSelector.new(name, attributes, &block)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Asserts that the body of the response contains
|
|
60
|
+
# the supplied selector
|
|
61
|
+
def assert_have_selector(expected, attributes = {})
|
|
62
|
+
hs = HaveSelector.new(expected, attributes)
|
|
63
|
+
assert hs.matches?(response), hs.failure_message
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Asserts that the body of the response
|
|
67
|
+
# does not contain the supplied string or regepx
|
|
68
|
+
def assert_have_no_selector(expected, attributes = {})
|
|
69
|
+
hs = HaveSelector.new(expected, attributes)
|
|
70
|
+
assert !hs.matches?(response), hs.negative_failure_message
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
|
|
19
|
+
def selector
|
|
20
|
+
attribute_selector=super
|
|
21
|
+
@options.each do |key, value|
|
|
22
|
+
attribute_selector << "[#{key}='#{value}']"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def have_tag(name, attributes = {}, &block)
|
|
28
|
+
HaveTag.new(name, attributes, &block)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
alias_method :match_tag, :have_tag
|
|
32
|
+
|
|
33
|
+
# Asserts that the body of the response contains
|
|
34
|
+
# the supplied tag with the associated selectors
|
|
35
|
+
def assert_have_tag(name, attributes = {})
|
|
36
|
+
ht = HaveTag.new(name, attributes)
|
|
37
|
+
assert ht.matches?(response), ht.failure_message
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Asserts that the body of the response
|
|
41
|
+
# does not contain the supplied string or regepx
|
|
42
|
+
def assert_have_no_tag(name, attributes = {})
|
|
43
|
+
ht = HaveTag.new(name, attributes)
|
|
44
|
+
assert !ht.matches?(response), ht.negative_failure_message
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
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
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
module Webrat
|
|
2
|
+
module Selenium
|
|
3
|
+
|
|
4
|
+
class SeleniumRCServer
|
|
5
|
+
|
|
6
|
+
include Webrat::Selenium::SilenceStream
|
|
7
|
+
|
|
8
|
+
def self.boot
|
|
9
|
+
new.boot
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def boot
|
|
13
|
+
return if selenium_grid?
|
|
14
|
+
|
|
15
|
+
start
|
|
16
|
+
wait
|
|
17
|
+
stop_at_exit
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def start
|
|
21
|
+
silence_stream(STDOUT) do
|
|
22
|
+
remote_control.start :background => true
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def stop_at_exit
|
|
27
|
+
at_exit do
|
|
28
|
+
stop
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def remote_control
|
|
33
|
+
return @remote_control if @remote_control
|
|
34
|
+
|
|
35
|
+
@remote_control = ::Selenium::RemoteControl::RemoteControl.new("0.0.0.0",
|
|
36
|
+
Webrat.configuration.selenium_server_port,
|
|
37
|
+
:timeout => Webrat.configuration.selenium_browser_startup_timeout)
|
|
38
|
+
@remote_control.jar_file = jar_path
|
|
39
|
+
|
|
40
|
+
return @remote_control
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def jar_path
|
|
44
|
+
File.expand_path(__FILE__ + "../../../../../vendor/selenium-server.jar")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def selenium_grid?
|
|
48
|
+
Webrat.configuration.selenium_server_address
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def wait
|
|
52
|
+
$stderr.print "==> Waiting for Selenium RC server on port #{Webrat.configuration.selenium_server_port}... "
|
|
53
|
+
wait_for_socket
|
|
54
|
+
$stderr.print "Ready!\n"
|
|
55
|
+
rescue SocketError
|
|
56
|
+
fail
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def wait_for_socket
|
|
60
|
+
silence_stream(STDOUT) do
|
|
61
|
+
TCPSocket.wait_for_service_with_timeout \
|
|
62
|
+
:host => (Webrat.configuration.selenium_server_address || "0.0.0.0"),
|
|
63
|
+
:port => Webrat.configuration.selenium_server_port,
|
|
64
|
+
:timeout => 15 # seconds
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def fail
|
|
69
|
+
$stderr.puts
|
|
70
|
+
$stderr.puts
|
|
71
|
+
$stderr.puts "==> Failed to boot the Selenium RC server... exiting!"
|
|
72
|
+
exit
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def stop
|
|
76
|
+
silence_stream(STDOUT) do
|
|
77
|
+
::Selenium::RemoteControl::RemoteControl.new("0.0.0.0",
|
|
78
|
+
Webrat.configuration.selenium_server_port,
|
|
79
|
+
:timeout => 5).stop
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
require "webrat/core/save_and_open_page"
|
|
2
|
+
require "webrat/selenium/selenium_rc_server"
|
|
3
|
+
require "webrat/selenium/application_server_factory"
|
|
4
|
+
require "webrat/selenium/application_servers/base"
|
|
5
|
+
|
|
6
|
+
require "selenium"
|
|
7
|
+
|
|
8
|
+
module Webrat
|
|
9
|
+
class TimeoutError < WebratError
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class SeleniumResponse
|
|
13
|
+
attr_reader :body
|
|
14
|
+
attr_reader :session
|
|
15
|
+
|
|
16
|
+
def initialize(session, body)
|
|
17
|
+
@session = session
|
|
18
|
+
@body = body
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def selenium
|
|
22
|
+
session.selenium
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class SeleniumSession
|
|
27
|
+
include Webrat::SaveAndOpenPage
|
|
28
|
+
include Webrat::Selenium::SilenceStream
|
|
29
|
+
|
|
30
|
+
def initialize(*args) # :nodoc:
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def simulate
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def automate
|
|
37
|
+
yield
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def visit(url)
|
|
41
|
+
selenium.open(url)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
webrat_deprecate :visits, :visit
|
|
45
|
+
|
|
46
|
+
def fill_in(field_identifier, options)
|
|
47
|
+
locator = "webrat=#{field_identifier}"
|
|
48
|
+
selenium.wait_for_element locator, :timeout_in_seconds => Webrat.configuration.selenium_response_wait_time
|
|
49
|
+
selenium.type(locator, "#{options[:with]}")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
webrat_deprecate :fills_in, :fill_in
|
|
53
|
+
|
|
54
|
+
def response
|
|
55
|
+
SeleniumResponse.new(self, response_body)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def response_body #:nodoc:
|
|
59
|
+
selenium.get_html_source
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def current_url
|
|
63
|
+
selenium.location
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def click_button(button_text_or_regexp = nil, options = {})
|
|
67
|
+
if button_text_or_regexp.is_a?(Hash) && options == {}
|
|
68
|
+
pattern, options = nil, button_text_or_regexp
|
|
69
|
+
elsif button_text_or_regexp
|
|
70
|
+
pattern = adjust_if_regexp(button_text_or_regexp)
|
|
71
|
+
end
|
|
72
|
+
pattern ||= '*'
|
|
73
|
+
locator = "button=#{pattern}"
|
|
74
|
+
|
|
75
|
+
selenium.wait_for_element locator, :timeout_in_seconds => Webrat.configuration.selenium_response_wait_time
|
|
76
|
+
selenium.click locator
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
webrat_deprecate :clicks_button, :click_button
|
|
80
|
+
|
|
81
|
+
def click_link(link_text_or_regexp, options = {})
|
|
82
|
+
pattern = adjust_if_regexp(link_text_or_regexp)
|
|
83
|
+
locator = "webratlink=#{pattern}"
|
|
84
|
+
selenium.wait_for_element locator, :timeout_in_seconds => Webrat.configuration.selenium_response_wait_time
|
|
85
|
+
selenium.click locator
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
webrat_deprecate :clicks_link, :click_link
|
|
89
|
+
|
|
90
|
+
def click_link_within(selector, link_text, options = {})
|
|
91
|
+
locator = "webratlinkwithin=#{selector}|#{link_text}"
|
|
92
|
+
selenium.wait_for_element locator, :timeout_in_seconds => Webrat.configuration.selenium_response_wait_time
|
|
93
|
+
selenium.click locator
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
webrat_deprecate :clicks_link_within, :click_link_within
|
|
97
|
+
|
|
98
|
+
def select(option_text, options = {})
|
|
99
|
+
id_or_name_or_label = options[:from]
|
|
100
|
+
|
|
101
|
+
if id_or_name_or_label
|
|
102
|
+
select_locator = "webrat=#{id_or_name_or_label}"
|
|
103
|
+
else
|
|
104
|
+
select_locator = "webratselectwithoption=#{option_text}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
selenium.wait_for_element select_locator, :timeout_in_seconds => Webrat.configuration.selenium_response_wait_time
|
|
108
|
+
selenium.select(select_locator, option_text)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
webrat_deprecate :selects, :select
|
|
112
|
+
|
|
113
|
+
def choose(label_text)
|
|
114
|
+
locator = "webrat=#{label_text}"
|
|
115
|
+
selenium.wait_for_element locator, :timeout_in_seconds => Webrat.configuration.selenium_response_wait_time
|
|
116
|
+
selenium.click locator
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
webrat_deprecate :chooses, :choose
|
|
120
|
+
|
|
121
|
+
def check(label_text)
|
|
122
|
+
locator = "webrat=#{label_text}"
|
|
123
|
+
selenium.wait_for_element locator, :timeout_in_seconds => Webrat.configuration.selenium_response_wait_time
|
|
124
|
+
selenium.click locator
|
|
125
|
+
end
|
|
126
|
+
alias_method :uncheck, :check
|
|
127
|
+
|
|
128
|
+
webrat_deprecate :checks, :check
|
|
129
|
+
|
|
130
|
+
def fire_event(field_identifier, event)
|
|
131
|
+
locator = "webrat=#{Regexp.escape(field_identifier)}"
|
|
132
|
+
selenium.fire_event(locator, "#{event}")
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def key_down(field_identifier, key_code)
|
|
136
|
+
locator = "webrat=#{Regexp.escape(field_identifier)}"
|
|
137
|
+
selenium.key_down(locator, key_code)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def key_up(field_identifier, key_code)
|
|
141
|
+
locator = "webrat=#{Regexp.escape(field_identifier)}"
|
|
142
|
+
selenium.key_up(locator, key_code)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def wait_for(params={})
|
|
146
|
+
timeout = params[:timeout] || Webrat.configuration.selenium_response_wait_time
|
|
147
|
+
message = params[:message] || "Timeout exceeded"
|
|
148
|
+
|
|
149
|
+
begin_time = Time.now
|
|
150
|
+
|
|
151
|
+
while (Time.now - begin_time) < timeout
|
|
152
|
+
value = nil
|
|
153
|
+
|
|
154
|
+
begin
|
|
155
|
+
value = yield
|
|
156
|
+
rescue Exception => e
|
|
157
|
+
unless is_ignorable_wait_for_exception?(e)
|
|
158
|
+
raise e
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
return value if value
|
|
163
|
+
|
|
164
|
+
sleep 0.25
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
raise Webrat::TimeoutError.new(message + " (after #{timeout} sec)")
|
|
168
|
+
true
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def selenium
|
|
172
|
+
return $browser if $browser
|
|
173
|
+
setup
|
|
174
|
+
$browser
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
webrat_deprecate :browser, :selenium
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def save_and_open_screengrab
|
|
181
|
+
return unless File.exist?(saved_page_dir)
|
|
182
|
+
|
|
183
|
+
filename = "#{saved_page_dir}/webrat-#{Time.now.to_i}.png"
|
|
184
|
+
|
|
185
|
+
if $browser.chrome_backend?
|
|
186
|
+
$browser.capture_entire_page_screenshot(filename, '')
|
|
187
|
+
else
|
|
188
|
+
$browser.capture_screenshot(filename)
|
|
189
|
+
end
|
|
190
|
+
open_in_browser(filename)
|
|
191
|
+
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
protected
|
|
195
|
+
def is_ignorable_wait_for_exception?(exception) #:nodoc:
|
|
196
|
+
if defined?(::Spec::Expectations::ExpectationNotMetError)
|
|
197
|
+
return true if exception.class == ::Spec::Expectations::ExpectationNotMetError
|
|
198
|
+
end
|
|
199
|
+
return true if [::Selenium::CommandError, Webrat::WebratError].include?(exception.class)
|
|
200
|
+
return false
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def setup #:nodoc:
|
|
204
|
+
Webrat::Selenium::SeleniumRCServer.boot
|
|
205
|
+
Webrat::Selenium::ApplicationServerFactory.app_server_instance.boot
|
|
206
|
+
|
|
207
|
+
create_browser
|
|
208
|
+
$browser.start
|
|
209
|
+
|
|
210
|
+
extend_selenium
|
|
211
|
+
define_location_strategies
|
|
212
|
+
$browser.window_maximize
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def create_browser
|
|
217
|
+
$browser = ::Selenium::Client::Driver.new(Webrat.configuration.selenium_server_address || "localhost",
|
|
218
|
+
Webrat.configuration.selenium_server_port, Webrat.configuration.selenium_browser_key, "http://#{Webrat.configuration.application_address}:#{Webrat.configuration.application_port}")
|
|
219
|
+
$browser.set_speed(0) unless Webrat.configuration.selenium_server_address
|
|
220
|
+
|
|
221
|
+
at_exit do
|
|
222
|
+
silence_stream(STDOUT) do
|
|
223
|
+
$browser.stop
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def adjust_if_regexp(text_or_regexp) #:nodoc:
|
|
229
|
+
if text_or_regexp.is_a?(Regexp)
|
|
230
|
+
"evalregex:#{text_or_regexp.inspect}"
|
|
231
|
+
else
|
|
232
|
+
"evalregex:/#{text_or_regexp}/"
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def extend_selenium #:nodoc:
|
|
237
|
+
extensions_file = File.join(File.dirname(__FILE__), "selenium_extensions.js")
|
|
238
|
+
extenions_js = File.read(extensions_file)
|
|
239
|
+
selenium.get_eval(extenions_js)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def define_location_strategies #:nodoc:
|
|
243
|
+
Dir[File.join(File.dirname(__FILE__), "location_strategy_javascript", "*.js")].sort.each do |file|
|
|
244
|
+
strategy_js = File.read(file)
|
|
245
|
+
strategy_name = File.basename(file, '.js')
|
|
246
|
+
selenium.add_location_strategy(strategy_name, strategy_js)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|