walidhalabi-celerity 0.0.6.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/History.txt +75 -0
  2. data/License.txt +621 -0
  3. data/README.txt +73 -0
  4. data/Rakefile +12 -0
  5. data/lib/celerity.rb +74 -0
  6. data/lib/celerity/browser.rb +811 -0
  7. data/lib/celerity/clickable_element.rb +69 -0
  8. data/lib/celerity/collections.rb +156 -0
  9. data/lib/celerity/container.rb +788 -0
  10. data/lib/celerity/default_viewer.rb +10 -0
  11. data/lib/celerity/disabled_element.rb +40 -0
  12. data/lib/celerity/element.rb +313 -0
  13. data/lib/celerity/element_collection.rb +107 -0
  14. data/lib/celerity/element_locator.rb +170 -0
  15. data/lib/celerity/elements/button.rb +43 -0
  16. data/lib/celerity/elements/file_field.rb +25 -0
  17. data/lib/celerity/elements/form.rb +23 -0
  18. data/lib/celerity/elements/frame.rb +75 -0
  19. data/lib/celerity/elements/image.rb +76 -0
  20. data/lib/celerity/elements/label.rb +11 -0
  21. data/lib/celerity/elements/link.rb +30 -0
  22. data/lib/celerity/elements/meta.rb +6 -0
  23. data/lib/celerity/elements/non_control_elements.rb +106 -0
  24. data/lib/celerity/elements/option.rb +32 -0
  25. data/lib/celerity/elements/radio_check.rb +115 -0
  26. data/lib/celerity/elements/select_list.rb +121 -0
  27. data/lib/celerity/elements/table.rb +144 -0
  28. data/lib/celerity/elements/table_cell.rb +29 -0
  29. data/lib/celerity/elements/table_elements.rb +42 -0
  30. data/lib/celerity/elements/table_row.rb +48 -0
  31. data/lib/celerity/elements/text_field.rb +169 -0
  32. data/lib/celerity/exception.rb +77 -0
  33. data/lib/celerity/htmlunit.rb +61 -0
  34. data/lib/celerity/htmlunit/commons-codec-1.3.jar +0 -0
  35. data/lib/celerity/htmlunit/commons-collections-3.2.1.jar +0 -0
  36. data/lib/celerity/htmlunit/commons-httpclient-3.1.jar +0 -0
  37. data/lib/celerity/htmlunit/commons-io-1.4.jar +0 -0
  38. data/lib/celerity/htmlunit/commons-lang-2.4.jar +0 -0
  39. data/lib/celerity/htmlunit/commons-logging-1.1.1.jar +0 -0
  40. data/lib/celerity/htmlunit/cssparser-0.9.5.jar +0 -0
  41. data/lib/celerity/htmlunit/htmlunit-2.6-SNAPSHOT.jar +0 -0
  42. data/lib/celerity/htmlunit/htmlunit-core-js-2.5.jar +0 -0
  43. data/lib/celerity/htmlunit/nekohtml-1.9.13-20090507.082850-2.jar +0 -0
  44. data/lib/celerity/htmlunit/sac-1.3.jar +0 -0
  45. data/lib/celerity/htmlunit/serializer-2.7.1.jar +0 -0
  46. data/lib/celerity/htmlunit/xalan-2.7.1.jar +0 -0
  47. data/lib/celerity/htmlunit/xercesImpl-2.8.1.jar +0 -0
  48. data/lib/celerity/htmlunit/xml-apis-1.3.04.jar +0 -0
  49. data/lib/celerity/identifier.rb +11 -0
  50. data/lib/celerity/input_element.rb +25 -0
  51. data/lib/celerity/listener.rb +141 -0
  52. data/lib/celerity/resources/no_viewer.png +0 -0
  53. data/lib/celerity/short_inspect.rb +20 -0
  54. data/lib/celerity/util.rb +91 -0
  55. data/lib/celerity/version.rb +10 -0
  56. data/lib/celerity/watir_compatibility.rb +84 -0
  57. data/tasks/jar.rake +57 -0
  58. data/tasks/rdoc.rake +4 -0
  59. metadata +130 -0
@@ -0,0 +1,170 @@
1
+ module Celerity
2
+
3
+ #
4
+ # Used internally to locate elements on the page.
5
+ #
6
+
7
+ class ElementLocator
8
+ include Celerity::Exception
9
+ attr_accessor :idents
10
+
11
+
12
+ def initialize(container, element_class)
13
+ container.assert_exists
14
+
15
+ @container = container
16
+ @object = container.object
17
+ @element_class = element_class
18
+ @attributes = @element_class::ATTRIBUTES # could check for 'strict' here?
19
+ @idents = @element_class::TAGS
20
+ @tags = @idents.map { |e| e.tag.downcase }
21
+ end
22
+
23
+ def find_by_conditions(conditions) # TODO: refactor without performance hit
24
+ return nil unless @object # probably means we're on a TextPage (content-type is "text/plain")
25
+
26
+ @condition_idents = []
27
+ attributes = Hash.new { |h, k| h[k] = [] }
28
+ index = 0 # by default, return the first matching element
29
+ text = nil
30
+
31
+ conditions.each do |how, what|
32
+ case how
33
+ when :object
34
+ unless what.is_a?(HtmlUnit::Html::HtmlElement) || what.nil?
35
+ raise ArgumentError, "expected an HtmlUnit::Html::HtmlElement subclass, got #{what.inspect}:#{what.class}"
36
+ end
37
+ return what
38
+ when :xpath
39
+ return find_by_xpath(what)
40
+ when :label
41
+ return find_by_label(what) unless @attributes.include?(:label)
42
+ when :class_name
43
+ how = :class
44
+ when :url
45
+ how = :href
46
+ when :caption
47
+ how = :text
48
+ end
49
+
50
+ if how == :id && conditions.size == 1
51
+ return find_by_id(what)
52
+ elsif @attributes.include?(how = how.to_sym)
53
+ attributes[how] << what
54
+ elsif how == :index
55
+ index = what.to_i - Celerity.index_offset
56
+ elsif how == :text
57
+ text = what
58
+ else
59
+ raise MissingWayOfFindingObjectException, "No how #{how.inspect}"
60
+ end
61
+ end
62
+
63
+ @idents.each do |ident|
64
+ merged = attributes.merge(ident.attributes) { |key, v1, v2| v1 | v2 }
65
+ id = Identifier.new(ident.tag, merged)
66
+ id.text = ident.text || text # «original» identifier takes precedence for :text
67
+ @condition_idents << id
68
+ end
69
+
70
+ if index == 0
71
+ element_by_idents(@condition_idents)
72
+ else
73
+ elements_by_idents(@condition_idents)[index]
74
+ end
75
+
76
+ rescue HtmlUnit::ElementNotFoundException
77
+ nil # for rcov
78
+ end
79
+
80
+ def find_by_id(what)
81
+ case what
82
+ when Regexp
83
+ elements_by_tag_names.find { |elem| elem.getId =~ what }
84
+ when String
85
+ obj = @object.getElementById(what)
86
+ return obj if @tags.include?(obj.getTagName)
87
+
88
+ $stderr.puts "warning: multiple elements with identical id? (#{what.inspect})" if $VERBOSE
89
+ elements_by_tag_names.find { |elem| elem.getId == what }
90
+ else
91
+ raise TypeError, "expected String or Regexp, got #{what.inspect}:#{what.class}"
92
+ end
93
+ end
94
+
95
+ def find_by_xpath(what)
96
+ what = ".#{what}" if what[0].chr == "/"
97
+ @object.getByXPath(what).to_a.first
98
+ end
99
+
100
+ def find_by_label(what)
101
+ obj = elements_by_tag_names(%w[label]).find { |e| matches?(e.asText, what) }
102
+
103
+ return nil unless obj && (ref = obj.getReferencedElement)
104
+ return ref if @tags.include?(ref.getTagName)
105
+
106
+ find_by_id obj.getForAttribute
107
+ end
108
+
109
+ def elements_by_idents(idents = @idents)
110
+ get_by_idents(:select, idents)
111
+ end
112
+
113
+ def element_by_idents(idents = @idents)
114
+ get_by_idents(:find, idents)
115
+ end
116
+
117
+ private
118
+
119
+ def get_by_idents(meth, idents)
120
+ with_nullpointer_retry do
121
+ @object.getAllHtmlChildElements.send(meth) do |e|
122
+ next unless @tags.include?(e.getTagName)
123
+ idents.any? { |id| element_matches_ident?(e, id) }
124
+ end
125
+ end
126
+ end
127
+
128
+ def element_matches_ident?(element, ident)
129
+ return false unless ident.tag == element.getTagName
130
+
131
+ attr_result = ident.attributes.all? do |key, values|
132
+ values.any? { |val| matches?(element.getAttribute(key.to_s), val) }
133
+ end
134
+
135
+ if ident.text
136
+ attr_result && matches?(element.asText.strip, ident.text)
137
+ else
138
+ attr_result
139
+ end
140
+ end
141
+
142
+ def elements_by_tag_names(tags = @tags)
143
+ with_nullpointer_retry do
144
+ # HtmlUnit's getHtmlElementsByTagNames won't get elements in the correct
145
+ # order (making :index fail), so we're using getAllHtmlChildElements instead.
146
+ @object.getAllHtmlChildElements.select do |elem|
147
+ tags.include?(elem.getTagName)
148
+ end
149
+ end
150
+ end
151
+
152
+ # HtmlUnit throws NPEs sometimes when we're locating elements
153
+ # Retry seems to work fine.
154
+ def with_nullpointer_retry(max_retries = 3)
155
+ tries = 0
156
+ yield
157
+ rescue java.lang.NullPointerException => e
158
+ raise e if tries >= max_retries
159
+
160
+ tries += 1
161
+ $stderr.puts "warning: celerity caught #{e} - retry ##{tries}"
162
+ retry
163
+ end
164
+
165
+ def matches?(string, what)
166
+ Regexp === what ? string.strip =~ what : string == what.to_s
167
+ end
168
+
169
+ end # ElementLocator
170
+ end # Celerity
@@ -0,0 +1,43 @@
1
+ module Celerity
2
+
3
+ #
4
+ # Input: Button
5
+ #
6
+ # Class representing button elements
7
+ #
8
+
9
+ class Button < InputElement
10
+ TAGS = [ Identifier.new('button'),
11
+ Identifier.new('input', :type => %w[submit reset image button]) ]
12
+
13
+ # Attribute list is a little weird due to this class covering both <button>
14
+ # and <input type="submit|reset|image|button" />
15
+ ATTRIBUTES = BASE_ATTRIBUTES | [:type, :disabled, :tabindex, :accesskey, :onfocus, :onblur] | [:src, :usemap, :ismap]
16
+ DEFAULT_HOW = :value
17
+
18
+ #
19
+ # @api private
20
+ #
21
+
22
+ def locate
23
+ # We want the :value attribute to point to the inner HTML for <button> elements,
24
+ # and to the value attribute for <input type="button"> elements.
25
+
26
+ if (val = @conditions[:value])
27
+ button_ident = Identifier.new('button')
28
+ button_ident.text = val
29
+ input_ident = Identifier.new('input', :type => %w[submit reset image button], :value => [val])
30
+
31
+ locator = ElementLocator.new(@container, self.class)
32
+ locator.idents = [button_ident, input_ident]
33
+
34
+ conditions = @conditions.dup
35
+ conditions.delete(:value)
36
+ @object = locator.find_by_conditions(conditions)
37
+ else
38
+ super
39
+ end
40
+ end
41
+
42
+ end # Button
43
+ end # Celerity
@@ -0,0 +1,25 @@
1
+ module Celerity
2
+
3
+ #
4
+ # For fields that accept file uploads
5
+ #
6
+
7
+ class FileField < InputElement
8
+ TAGS = [ Identifier.new('input', :type => %w[file]) ]
9
+ DEFAULT_HOW = :name
10
+
11
+ #
12
+ # Set the file field to the given path
13
+ #
14
+
15
+ def set(path)
16
+ assert_exists
17
+ path = path.to_s
18
+ @container.update_page @object.setValueAttribute(path)
19
+ unless @object.getContentType
20
+ @object.setContentType(Celerity::Util.content_type_for(path))
21
+ end
22
+ end
23
+
24
+ end # FileField
25
+ end # Celerity
@@ -0,0 +1,23 @@
1
+ module Celerity
2
+ class Form < Element
3
+ include Container
4
+
5
+ TAGS = [Identifier.new('form')]
6
+
7
+ # HTML 4.01 Transitional DTD
8
+ ATTRIBUTES = BASE_ATTRIBUTES | [:action, :method, :enctype, :accept, :name, :onsubmit, :onreset, :target, :'accept-charset']
9
+ DEFAULT_HOW = :name
10
+
11
+ #
12
+ # Submits the form.
13
+ #
14
+ # This method should be avoided - invoke the user interface element that triggers the submit instead.
15
+ #
16
+
17
+ def submit
18
+ assert_exists
19
+ @container.update_page @object.submit(nil)
20
+ end
21
+
22
+ end # Form
23
+ end # Celerity
@@ -0,0 +1,75 @@
1
+ module Celerity
2
+ class Frame < Element
3
+ include Container
4
+ attr_accessor :page
5
+
6
+ TAGS = [Identifier.new('frame'), Identifier.new('iframe')]
7
+ ATTRIBUTES = BASE_ATTRIBUTES | [:longdesc, :name, :src, :frameborder, :marginwidth, :marginheight, :noresize, :scrolling]
8
+ DEFAULT_HOW = :name
9
+
10
+ #
11
+ # Override the default locate to handle frame and inline frames.
12
+ # @api private
13
+ #
14
+
15
+ def locate
16
+ super
17
+ if @object
18
+ @inline_frame_object = @object.getEnclosedWindow.getFrameElement
19
+ self.page = @object.getEnclosedPage
20
+ if (frame = self.page.getDocumentElement)
21
+ @object = frame
22
+ end
23
+ end
24
+ end
25
+
26
+ #
27
+ # Override assert_exists to raise UnknownFrameException (for Watir compatibility)
28
+ # @api private
29
+ #
30
+
31
+ def assert_exists
32
+ locate
33
+ unless @object
34
+ raise UnknownFrameException, "unable to locate frame, using #{identifier_string}"
35
+ end
36
+ end
37
+
38
+ #
39
+ # Executes the given JavaScript string in this frame. (Celerity only)
40
+ #
41
+
42
+ def execute_script(source)
43
+ assert_exists
44
+ @page.executeJavaScript(source.to_s).getJavaScriptResult
45
+ end
46
+
47
+ #
48
+ # Updates the brwoser page with the page from this frame's top window.
49
+ # Used internally.
50
+ #
51
+ # @api private
52
+ #
53
+
54
+ def update_page(value)
55
+ @browser.page = value.getEnclosingWindow.getTopWindow.getEnclosedPage
56
+ end
57
+
58
+ def to_s
59
+ assert_exists
60
+ create_string(@inline_frame_object)
61
+ end
62
+
63
+ def method_missing(meth, *args, &blk)
64
+ meth = selector_to_attribute(meth)
65
+ if self.class::ATTRIBUTES.include?(meth)
66
+ assert_exists
67
+ @inline_frame_object.getAttribute(meth.to_s)
68
+ else
69
+ Log.warn "Element\#method_missing calling super with #{meth.inspect}"
70
+ super
71
+ end
72
+ end
73
+
74
+ end # Frame
75
+ end # Celerity
@@ -0,0 +1,76 @@
1
+ module Celerity
2
+
3
+ class Image < Element
4
+ include ClickableElement
5
+
6
+ TAGS = [ Identifier.new('img') ]
7
+
8
+ ATTRIBUTES = BASE_ATTRIBUTES | [:src, :alt, :longdesc, :name, :height, :width, :usemap, :ismap, :align, :border, :hspace, :vspace]
9
+ DEFAULT_HOW = :src
10
+
11
+ #
12
+ # returns the file created date of the image
13
+ #
14
+
15
+ def file_created_date
16
+ assert_exists
17
+ web_response = @object.getWebResponse(true)
18
+ Time.parse(web_response.getResponseHeaderValue("Last-Modified").to_s)
19
+ end
20
+
21
+ #
22
+ # returns the file size of the image in bytes
23
+ #
24
+
25
+ def file_size
26
+ assert_exists
27
+ web_response = @object.getWebResponse(true)
28
+ web_response.getContentAsBytes.length
29
+ end
30
+
31
+ #
32
+ # returns the width in pixels of the image, as a string
33
+ #
34
+
35
+ def width
36
+ assert_exists
37
+ @object.getWidth
38
+ end
39
+
40
+ #
41
+ # returns the height in pixels of the image, as a string
42
+ #
43
+
44
+ def height
45
+ assert_exists
46
+ @object.getHeight
47
+ end
48
+
49
+ #
50
+ # returns true if the image is loaded
51
+ #
52
+
53
+ def loaded?
54
+ assert_exists
55
+ begin
56
+ @object.getImageReader
57
+ true
58
+ rescue
59
+ false
60
+ end
61
+ end
62
+
63
+ #
64
+ # Saves the image to the given file
65
+ #
66
+
67
+ def save(filename)
68
+ assert_exists
69
+ image_reader = @object.getImageReader
70
+ file = java.io.File.new(filename)
71
+ buffered_image = image_reader.read(0);
72
+ javax.imageio.ImageIO.write(buffered_image, image_reader.getFormatName(), file);
73
+ end
74
+
75
+ end # Image
76
+ end # Celerity
@@ -0,0 +1,11 @@
1
+ module Celerity
2
+
3
+ class Label < Element
4
+ include ClickableElement
5
+
6
+ TAGS = [ Identifier.new('label') ]
7
+ ATTRIBUTES = BASE_ATTRIBUTES | [:for, :accesskey, :onfocus, :onblur]
8
+ DEFAULT_HOW = :text
9
+ end
10
+
11
+ end
@@ -0,0 +1,30 @@
1
+ module Celerity
2
+ class Link < Element
3
+ include ClickableElement
4
+
5
+ TAGS = [ Identifier.new('a') ]
6
+ ATTRIBUTES = BASE_ATTRIBUTES | [:charset, :type, :name, :href, :hreflang,
7
+ :target, :rel, :rev, :accesskey, :shape,
8
+ :coords, :tabindex, :onfocus, :onblur]
9
+ DEFAULT_HOW = :href
10
+
11
+ #
12
+ # Returns the absolute URL for this link (Celerity-specific)
13
+ #
14
+ # (Watir/IE does this for href(), but we don't want that.)
15
+ #
16
+
17
+ def absolute_url
18
+ assert_exists
19
+ href = @object.getAttribute('href')
20
+
21
+ unless href.empty? || URI.parse(href).absolute?
22
+ href = URI.join(browser.url, href).to_s
23
+ end
24
+
25
+ href
26
+ end
27
+
28
+
29
+ end # Link
30
+ end # Celerity