adding html unit spike

This commit is contained in:
Ben Mabey 2008-09-15 12:03:42 -06:00
parent 7c46a6fed0
commit 0800f79428
21 changed files with 464 additions and 0 deletions

View File

@ -0,0 +1,41 @@
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
module RubyHtmlUnit
Jars = Dir[File.dirname(__FILE__) + '/ruby_html_unit/htmlunit/*.jar']
end
if RUBY_PLATFORM =~ /java/
require 'java'
RubyHtmlUnit::Jars.each { |jar| require(jar) }
module HtmlUnit
include_package 'com.gargoylesoftware.htmlunit'
end
JavaString = java.lang.String
else
raise "RubyHtmlUnit only works on JRuby at the moment."
end
Dir[File.join(File.dirname(__FILE__), "ruby_html_unit", "*.rb")].each do |file|
require File.expand_path(file)
end
# Deal with the test server
if `uname`.chomp == "Darwin"
TEST_SERVER_PORT = '3001'
if `ps ax`.match(/^\s*(\d*).*-e test -p #{TEST_SERVER_PORT}/)
puts "A test server was found running on port #{TEST_SERVER_PORT} (PID #{$1})"
else
puts "A test server was not found running (looking for -e test -p #{TEST_SERVER_PORT})"
puts "Please start a new test server using the command below:"
puts
command_string = "ruby #{RAILS_ROOT}/script/server -e test -p #{TEST_SERVER_PORT}"
puts command_string
exit
end
end

View File

@ -0,0 +1,13 @@
module RubyHtmlUnit
class AlertHandler
def handleAlert(html_unit_page, alert_message)
alert_messages << alert_message
end
def alert_messages
@alert_messages ||= []
end
end
end

View File

@ -0,0 +1,119 @@
module RubyHtmlUnit
class Element
def initialize(element, page)
@html_unit_element = element
@page = page
end
def elem_type
@html_unit_element.node_name
end
def id_attribute
@html_unit_element.id_attribute
end
def matches_text?(text)
@html_unit_element.as_text =~ text_as_regexp(text)
end
def matches_attribute?(attribute, text)
@html_unit_element.get_attribute(attribute) =~ text_as_regexp(text)
end
def ancestors
current_element = self
[].tap do |ancs|
while current_element.parent && current_element.elem_type != 'html'
ancs << current_element
current_element = current_element.parent
end
end
end
def label_matches?(label_text)
ancestors.each do |anc|
return true if anc.elem_type == 'label' && anc.matches_text?(label_text)
end
if id_attribute.blank?
return nil
else
label_tag = @page.elements_by_xpath("//label[@for='#{id_attribute}']").first
return label_tag if label_tag && label_tag.matches_text?(label_text)
end
end
def click
@html_unit_element.click
end
def fill_in_with(value)
clear
type_string(value)
end
def clear
case @html_unit_element.getTagName
when 'textarea' then @html_unit_element.setText('')
when 'input' then @html_unit_element.setValueAttribute('')
end
end
def select(option_text)
@html_unit_element.getOptions.select { |e| e.asText =~ text_as_regexp(option_text) }.each do |option|
option.click
#@container.update_page(option.click)
end
end
def set(value = true)
@html_unit_element.setChecked(value)
#value ? @html_unit_element.click : @html_unit_element.setChecked(value)
end
def includes_option?(option_text)
!!@html_unit_element.getByXPath("//option").detect {|opt| opt.as_text =~ text_as_regexp(option_text) }
end
def to_s
@html_unit_element.as_text
end
def hidden?
!!ancestors.detect { |elem| elem.style =~ /display\s*:[\s'"]*none/ }
end
def visible?
!hidden?
end
def parent
@html_unit_element.respond_to?(:parent_node) ? Element.new(@html_unit_element.parent_node, @page) : nil
end
def class_name
@html_unit_element.class_attribute
end
def method_missing(name, *args)
return @html_unit_element.send("#{name}_attribute") if @html_unit_element.respond_to?("#{name}_attribute")
super
end
protected
def type_string(value)
last_page = nil
JavaString.new(value.to_java_bytes, @html_unit_element.getPage.getPageEncoding).toCharArray.each do |char|
last_page = @html_unit_element.type(char)
end
last_page
end
def text_as_regexp(text)
Regexp.new(Regexp.escape(text), true)
end
end
end

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,114 @@
module RubyHtmlUnit
class Page
SAVED_PAGE_DIR = File.expand_path('.')
def initialize(html_unit_page)
@html_unit_page = html_unit_page
end
def body
@html_unit_page.getWebResponse.getContentAsString || ''
end
alias_method :html_document, :body
def find_link(text)
matching_links = elements_by_tag_name('a').select{|e| e.matches_text?(text)}
if matching_links.any?
matching_links.sort_by { |l| l.to_s.length }.first
else
flunk("Could not find link with text #{text.inspect}")
end
end
def find_button(text = nil)
buttons = []
field_type_xpaths = %w( //button //input[@type='submit'] //input[@type='reset'] //input[@type='image'] //input[@type='button'] )
field_type_xpaths.each do |xpath_expr|
buttons += elements_by_xpath(xpath_expr)
end
return buttons.first if text.nil?
matching_buttons = buttons.select{|b| b.matches_attribute?('value', text) }
if matching_buttons.any?
matching_buttons.sort_by { |b| b.to_s.length }.first
else
flunk("Could not find button with text #{text.inspect}")
end
end
def find_field(id_or_name_or_label, field_type)
field_type_xpaths = case field_type
when :text then %w( //input[@type='text'] //input[@type='hidden'] //textarea )
when :select then %w( //select )
when :radio then %w( //input[@type='radio'] )
when :checkbox then %w( //input[@type='checkbox'] )
end
field_type_xpaths.each do |xpath_expr|
elements_by_xpath(xpath_expr).each do |possible_field|
return possible_field if possible_field.id_attribute == id_or_name_or_label ||
possible_field.name == id_or_name_or_label ||
possible_field.label_matches?(id_or_name_or_label)
end
end
flunk("Could not find #{field_type_xpaths.inspect}: #{id_or_name_or_label.inspect}")
end
def find_select_list_with_option(option_text, id_or_name_or_label = nil)
if id_or_name_or_label
select_tag = find_field(id_or_name_or_label, :select)
return select_tag if select_tag && select_tag.includes_option?(option_text)
else
elements_by_xpath("//select").each do |sel|
if sel.includes_option?(option_text)
return sel
end
end
end
nil
end
def elements_by_tag_name(tag_name)
node_list = @html_unit_page.getElementsByTagName(tag_name)
list_len = node_list.length
[].tap do |array|
0.upto(list_len-1) { |i| array << Element.new(node_list.item(i), self)}
end
end
def elements_by_xpath(xpath_expression)
@html_unit_page.getByXPath(xpath_expression).to_a.map{ |e| Element.new(e, self) }
end
def save_and_open
return unless File.exist?(SAVED_PAGE_DIR)
filename = "#{SAVED_PAGE_DIR}/webrat-#{Time.now.to_i}.html"
File.open(filename, "w") do |f|
f.write rewrite_css_and_image_references(body)
end
open_in_browser(filename)
end
def rewrite_css_and_image_references(response_html) # :nodoc
response_html.gsub(%r<"/(stylesheets|images)>, Session.rewrite_url('"/\1'))
end
def open_in_browser(path) # :nodoc
`open #{path}`
end
def flunk(message)
raise message
end
end
end

View File

@ -0,0 +1,24 @@
module RubyHtmlUnit
class Response
def initialize(html_unit_response)
@html_unit_response = html_unit_response
end
def success?
@html_unit_response.status_code / 100 == 2
end
def content_type
@html_unit_response.content_type
end
def body
@html_unit_response.getContentAsString || ''
end
alias_method :text, :body
end
end

View File

@ -0,0 +1,26 @@
class Spec::Story::Runner::ScenarioRunner
def initialize
@listeners = []
end
end
module RubyHtmlUnit
class RspecStory
include ::Spec::Matchers
include ::Spec::Rails::Matchers
def current_session
@current_session ||= Session.new
end
def method_missing(name, *args)
if current_session.respond_to?(name)
current_session.send(name, *args)
else
super
end
end
end
end

View File

@ -0,0 +1,127 @@
module RubyHtmlUnit
class Session
attr_accessor :response, :current_page, :alert_handler
include ActionController::UrlWriter
include ActionController::Assertions
include Test::Unit::Assertions
class << self
def rewrite_url(url)
if url =~ %r{^(/.*)} || url =~ %r{^https?://www.example.com(/.*)}
append_to_root_url($1)
else
url
end
end
def append_to_root_url(path)
path = "/#{path}" unless path =~ /^\//
"http://localhost:#{TEST_SERVER_PORT}#{path}"
end
end
def initialize()
#java.lang.System.getProperties.put("org.apache.commons.logging.simplelog.defaultlog", opts[:log_level] ? opts[:log_level].to_s : "warn")
java.lang.System.getProperties.put("org.apache.commons.logging.simplelog.defaultlog", "warn")
browser = ::HtmlUnit::BrowserVersion::FIREFOX_2
@webclient = ::HtmlUnit::WebClient.new(browser)
@webclient.setThrowExceptionOnScriptError(false) #unless opts[:javascript_exceptions]
@webclient.setThrowExceptionOnFailingStatusCode(false) #unless opts[:status_code_exceptions]
@webclient.setCssEnabled(false) #unless opts[:css]
@webclient.setUseInsecureSSL(true) #if opts[:secure_ssl]
@alert_handler = AlertHandler.new
@webclient.setAlertHandler(@alert_handler)
@response = nil
@current_page = nil
end
def visits(url)
update_page(@webclient.getPage(Session.rewrite_url(url)))
end
def clicks_link(text)
link = @current_page.find_link(text)
update_page(link.click)
end
def clicks_button(text = nil)
button = @current_page.find_button(text)
update_page(button.click)
end
def fills_in(id_or_name_or_label, options = {})
field = @current_page.find_field(id_or_name_or_label, :text)
update_page(field.fill_in_with(options[:with]))
end
def selects(option_text, options = {})
id_or_name_or_label = options[:from]
select_tag = @current_page.find_select_list_with_option(option_text, id_or_name_or_label)
flunk("Could not find option #{option_text.inspect}") if select_tag.nil?
select_tag.select(option_text)
end
def chooses(label)
field = @current_page.find_field(label, :radio)
update_page(field.set)
end
def checks(id_or_name_or_label)
field = @current_page.find_field(id_or_name_or_label, :checkbox)
update_page(field.set(true))
end
def unchecks(id_or_name_or_label)
field = @current_page.find_field(id_or_name_or_label, :checkbox)
update_page(field.set(false))
end
def get_element(dom_id)
@current_page.elements_by_xpath("//*[@id='#{dom_id}']").first
end
alias_method :get_element_by_id, :get_element
def wait_for_result(wait_type)
# No support for different types of waiting right now
sleep(0.5)
# if wait_type == :ajax
# wait_for_ajax
# elsif wait_type == :effects
# wait_for_effects
# else
# wait_for_page_to_load
# end
end
def update_page(html_unit_page)
@current_page = Page.new(html_unit_page)
@response = Response.new(html_unit_page.getWebResponse)
end
def save_and_open_page
@current_page.save_and_open
end
def respond_to?(method)
super || @current_page.respond_to?(method)
end
def method_missing(name, *args)
if @current_page.respond_to?(name)
@current_page.send(name, *args)
else
super
end
end
end
end