walidhalabi-celerity 0.0.6.11

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 (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