jarib-celerity 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/History.txt +42 -0
  2. data/License.txt +621 -0
  3. data/README.txt +64 -0
  4. data/Rakefile +12 -0
  5. data/lib/celerity.rb +59 -0
  6. data/lib/celerity/browser.rb +410 -0
  7. data/lib/celerity/clickable_element.rb +26 -0
  8. data/lib/celerity/collections.rb +148 -0
  9. data/lib/celerity/container.rb +488 -0
  10. data/lib/celerity/default_viewer.rb +10 -0
  11. data/lib/celerity/disabled_element.rb +27 -0
  12. data/lib/celerity/element.rb +241 -0
  13. data/lib/celerity/element_collections.rb +68 -0
  14. data/lib/celerity/element_locator.rb +167 -0
  15. data/lib/celerity/elements/button.rb +34 -0
  16. data/lib/celerity/elements/file_field.rb +17 -0
  17. data/lib/celerity/elements/form.rb +16 -0
  18. data/lib/celerity/elements/frame.rb +53 -0
  19. data/lib/celerity/elements/image.rb +57 -0
  20. data/lib/celerity/elements/label.rb +9 -0
  21. data/lib/celerity/elements/link.rb +12 -0
  22. data/lib/celerity/elements/meta.rb +6 -0
  23. data/lib/celerity/elements/non_control_elements.rb +93 -0
  24. data/lib/celerity/elements/option.rb +18 -0
  25. data/lib/celerity/elements/radio_check.rb +85 -0
  26. data/lib/celerity/elements/select_list.rb +81 -0
  27. data/lib/celerity/elements/table.rb +117 -0
  28. data/lib/celerity/elements/table_cell.rb +28 -0
  29. data/lib/celerity/elements/table_elements.rb +41 -0
  30. data/lib/celerity/elements/table_row.rb +36 -0
  31. data/lib/celerity/elements/text_field.rb +127 -0
  32. data/lib/celerity/exception.rb +40 -0
  33. data/lib/celerity/extra/method_generator.rb +158 -0
  34. data/lib/celerity/htmlunit.rb +41 -0
  35. data/lib/celerity/htmlunit/commons-codec-1.3.jar +0 -0
  36. data/lib/celerity/htmlunit/commons-collections-3.2.1.jar +0 -0
  37. data/lib/celerity/htmlunit/commons-httpclient-3.1.jar +0 -0
  38. data/lib/celerity/htmlunit/commons-io-1.4.jar +0 -0
  39. data/lib/celerity/htmlunit/commons-lang-2.4.jar +0 -0
  40. data/lib/celerity/htmlunit/commons-logging-1.1.1.jar +0 -0
  41. data/lib/celerity/htmlunit/cssparser-0.9.5.jar +0 -0
  42. data/lib/celerity/htmlunit/htmlunit-2.4-SNAPSHOT.jar +0 -0
  43. data/lib/celerity/htmlunit/htmlunit-core-js-2.4-SNAPSHOT.jar +0 -0
  44. data/lib/celerity/htmlunit/nekohtml-1.9.10-20081209.100757-4.jar +0 -0
  45. data/lib/celerity/htmlunit/sac-1.3.jar +0 -0
  46. data/lib/celerity/htmlunit/serializer-2.7.1.jar +0 -0
  47. data/lib/celerity/htmlunit/xalan-2.7.1.jar +0 -0
  48. data/lib/celerity/htmlunit/xercesImpl-2.8.1.jar +0 -0
  49. data/lib/celerity/htmlunit/xml-apis-1.3.04.jar +0 -0
  50. data/lib/celerity/identifier.rb +11 -0
  51. data/lib/celerity/input_element.rb +25 -0
  52. data/lib/celerity/listener.rb +106 -0
  53. data/lib/celerity/resources/no_viewer.png +0 -0
  54. data/lib/celerity/util.rb +79 -0
  55. data/lib/celerity/version.rb +9 -0
  56. data/lib/celerity/watir_compatibility.rb +85 -0
  57. data/tasks/benchmark.rake +4 -0
  58. data/tasks/deployment.rake +43 -0
  59. data/tasks/environment.rake +7 -0
  60. data/tasks/fix.rake +25 -0
  61. data/tasks/jar.rake +57 -0
  62. data/tasks/rdoc.rake +4 -0
  63. data/tasks/rspec.rake +30 -0
  64. data/tasks/simple_ci.rake +94 -0
  65. data/tasks/snapshot.rake +26 -0
  66. data/tasks/specserver.rake +21 -0
  67. data/tasks/website.rake +17 -0
  68. data/tasks/yard.rake +5 -0
  69. metadata +129 -0
@@ -0,0 +1,117 @@
1
+ module Celerity
2
+
3
+ class Table < Element
4
+ include Enumerable
5
+ include Container
6
+
7
+ TAGS = [ Identifier.new('table') ]
8
+ ATTRIBUTES = BASE_ATTRIBUTES | [:summary, :width, :border, :frame, :rules,
9
+ :cellspacing, :cellpadding, :align, :bgcolor]
10
+ DEFAULT_HOW = :id
11
+
12
+ def locate
13
+ super
14
+ if @object # cant call assert_exists here, as an exists? method call will fail
15
+ @rows = @object.getRows
16
+ @cells = []
17
+ @rows.each do |row|
18
+ row.getCells.each do |c|
19
+ @cells << c
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ # @return [Celerity::TableRows]
26
+ def rows
27
+ assert_exists
28
+ TableRows.new(self, :object, @rows)
29
+ end
30
+
31
+ # @return [Celerity::TableCells]
32
+ def cells
33
+ assert_exists
34
+ TableCells.new(self, :object, @cells)
35
+ end
36
+
37
+ # Iterates through each row in the table.
38
+ # @yieldparam [Celerity::TableRow] row A row.
39
+ def each
40
+ assert_exists
41
+ @rows.each { |row| yield TableRow.new(self, :object, row) }
42
+ end
43
+
44
+ # Returns the TableRow at the given index (1-indexed).
45
+ #
46
+ # browser.table(:foo, 'bar')[1] # => #<TableRow...>
47
+ # browser.table(:foo, 'bar').child_row[1] # => #<TableRow...>
48
+ #
49
+ # @param [Fixnum] index The index of the wanted row, 1-indexed.
50
+ # @raise [Celerity::Exception::UnknownRowException]
51
+ # @return [Celerity::TableRow]
52
+ def child_row(index)
53
+ assert_exists
54
+
55
+ if (index - INDEX_OFFSET) >= @rows.length
56
+ raise UnknownRowException, "Unable to locate a row at index #{index}"
57
+ end
58
+
59
+ TableRow.new(self, :object, @rows[index - INDEX_OFFSET])
60
+ end
61
+ alias_method :[], :child_row
62
+
63
+ # Returns the TableCell at the given index (1-indexed).
64
+ #
65
+ # In a 10-column row, table.child_cell[11] will return the first cell on the second row.
66
+ #
67
+ # @param [Fixnum] index The index of the wanted cell, 1-indexed.
68
+ # @raise [Celerity::Exception::UnknownCellException]
69
+ # @return [Celerity::TableCell]
70
+ def child_cell(index)
71
+ assert_exists
72
+
73
+ if (index - INDEX_OFFSET) >= @cells.length
74
+ raise UnknownCellException, "Unable to locate a cell at index #{index}"
75
+ end
76
+ TableCell.new(self, :object, @cells[index - INDEX_OFFSET])
77
+ end
78
+
79
+ # The number of rows in the table
80
+ # @return [Fixnum]
81
+ def row_count
82
+ assert_exists
83
+ @object.getRowCount
84
+ end
85
+
86
+ # Returns the number of columns on the row at the given index. (1-indexed)
87
+ # Default is the number of columns on the first row
88
+ # @param [Fixnum] index An index, 1-indexed (optional).
89
+ # @return [Fixnum]
90
+ def column_count(index = INDEX_OFFSET)
91
+ assert_exists
92
+ @object.getRow(index - INDEX_OFFSET).getCells.length
93
+ end
94
+
95
+ # Returns the text of each cell in the the table as a two-dimensional array.
96
+ # @return [Array<Array<String>>]
97
+ def to_a
98
+ assert_exists
99
+ # @object.getRows.map do |table_row|
100
+ # table_row.getCells.map { |td| td.asText.strip }
101
+ # end
102
+ rows.map do |table_row|
103
+ table_row.map { |td| td.text }
104
+ end
105
+ end
106
+
107
+ def column_values(column_number)
108
+ (1..row_count).map { |index| self[index][column_number].text }
109
+ end
110
+
111
+ def row_values(row_number)
112
+ (1..column_count(row_number)).map { |index| self[row_number][index].text }
113
+ end
114
+
115
+ end
116
+
117
+ end
@@ -0,0 +1,28 @@
1
+ module Celerity
2
+
3
+ class TableCell < Element
4
+ include Celerity::Exception
5
+ include Container
6
+
7
+ TAGS = [ Identifier.new('td') ]
8
+ ATTRIBUTES = BASE_ATTRIBUTES | CELLHALIGN_ATTRIBUTES |
9
+ CELLVALIGN_ATTRIBUTES | [:abbr, :axis, :headers, :scope, :rowspan, :colspan]
10
+
11
+ DEFAULT_HOW = :id
12
+
13
+ alias_method :to_s, :text # why?
14
+
15
+ def colspan
16
+ assert_exists
17
+ attribute_value = @object.getAttributeValue('colspan').to_i
18
+ attribute_value > 0 ? attribute_value : 1
19
+ end
20
+
21
+ end
22
+
23
+ # needs code review regarding attributes/correctness of this
24
+ class Th < TableCell
25
+ TAGS = [ Identifier.new('th')]
26
+ end
27
+
28
+ end
@@ -0,0 +1,41 @@
1
+ module Celerity
2
+ class TableElement < Element
3
+ include Enumerable
4
+
5
+ ATTRIBUTES = BASE_ATTRIBUTES | CELLHALIGN_ATTRIBUTES | CELLVALIGN_ATTRIBUTES
6
+ DEFAULT_HOW = :id
7
+
8
+ def locate
9
+ super
10
+ @rows = @object.getRows if @object
11
+ end
12
+
13
+ def [](index)
14
+ assert_exists
15
+ TableRow.new(self, :object, @rows[index - INDEX_OFFSET])
16
+ end
17
+
18
+ def length
19
+ assert_exists
20
+ @object.getRows.length
21
+ end
22
+
23
+ def each
24
+ assert_exists
25
+ @rows.each { |row| yield TableRow.new(self, :object, row) }
26
+ end
27
+ end
28
+
29
+ class TableBody < TableElement
30
+ TAGS = [ Identifier.new('tbody') ]
31
+ end
32
+
33
+ class TableFooter < TableElement
34
+ TAGS = [ Identifier.new('tfoot') ]
35
+ end
36
+
37
+ class TableHeader < TableElement
38
+ TAGS = [ Identifier.new('thead') ]
39
+ end
40
+
41
+ end
@@ -0,0 +1,36 @@
1
+ module Celerity
2
+ class TableRow < Element
3
+ include Enumerable
4
+
5
+ TAGS = [ Identifier.new('tr') ]
6
+ DEFAULT_HOW = :id
7
+
8
+ def locate
9
+ super
10
+ @cells = @object.getCells if @object
11
+ end
12
+
13
+ # Yields each TableCell in this row cell to the given block.
14
+ def each
15
+ assert_exists
16
+ @cells.each { |cell| yield TableCell.new(self, :object, cell) }
17
+ end
18
+
19
+ def child_cell(index)
20
+ assert_exists
21
+
22
+ if (index - INDEX_OFFSET) >= @cells.length
23
+ raise UnknownCellException, "Unable to locate a cell at index #{index}"
24
+ end
25
+
26
+ TableCell.new(self, :object, @cells[index - INDEX_OFFSET])
27
+ end
28
+ alias_method :[], :child_cell
29
+
30
+ def column_count
31
+ assert_exists
32
+ @cells.length
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,127 @@
1
+ module Celerity
2
+ #
3
+ # Class representing text field elements
4
+ #
5
+ # This class is the main class for Text Fields
6
+ # Normally a user would not need to create this object as it is returned by the Watir::Container#text_field method
7
+ class TextField < InputElement
8
+ NON_TEXT_TYPES = %w[file radio checkbox submit reset image button hidden]
9
+ TAGS = [ Identifier.new('textarea'),
10
+ Identifier.new('input', :type => ["text", "password", /^(?!(#{ Regexp.union(*NON_TEXT_TYPES) })$)/]) ]
11
+ DEFAULT_HOW = :name
12
+
13
+ # Clear the text field.
14
+ def clear
15
+ assert_exists
16
+ insert_string ''
17
+ end
18
+
19
+ # Set the text field to the given value.
20
+ # This ensures execution of JavaScript events (onkeypress etc.), but is slower than +value=+
21
+ def set(value)
22
+ assert_enabled
23
+ assert_not_readonly
24
+ clear
25
+ type_string(value.to_s)
26
+ end
27
+
28
+ # This directly sets the text field to the given value, skipping exectuion of JavaScript events.
29
+ # Use +set+ if you want to run events on text fields.
30
+ def value=(value)
31
+ assert_enabled
32
+ assert_not_readonly
33
+ clear
34
+
35
+ insert_string value.to_s
36
+
37
+ value
38
+ end
39
+
40
+ # Returns the text in the text field.
41
+ def value
42
+ assert_exists
43
+ case @object.getTagName
44
+ when 'textarea'
45
+ @object.getText
46
+ when 'input'
47
+ @object.getValueAttribute
48
+ end
49
+ end
50
+ alias_method :get_contents, :value
51
+
52
+ # Append the given value to the text in the text field.
53
+ def append(value)
54
+ assert_enabled
55
+ assert_not_readonly
56
+ type_string(value)
57
+ end
58
+
59
+ def type
60
+ assert_exists
61
+ type = @object.getAttributeValue('type')
62
+
63
+ if NON_TEXT_TYPES.include?(type)
64
+ type
65
+ else
66
+ 'text'
67
+ end
68
+ end
69
+
70
+ # This bascially just moves the text to the other text field using TextField#append
71
+ # Should check if the HtmlUnit API supports some kind of dragging.
72
+ def drag_contents_to(how, what)
73
+ assert_exists # assert_enabled?
74
+ val = self.value
75
+ self.value = ''
76
+ @container.text_field(how, what).append(val)
77
+ end
78
+
79
+ def contains_text(expected_text)
80
+ assert_exists
81
+
82
+ case expected_text
83
+ when Regexp
84
+ value() =~ expected_text
85
+ when String
86
+ value().index(expected_text)
87
+ else
88
+ raise TypeError, "expected String or Regexp, got #{expected_text.inspect}:#{expected_text.class}"
89
+ end
90
+ end
91
+
92
+ # A boolean version of TextField#contains_text
93
+ # @param [String, Regexp] expected_text The text to look for.
94
+ # @return [boolean]
95
+ def verify_contains(expected)
96
+ # assert_exists called by contains_text
97
+ !!contains_text(expected)
98
+ end
99
+
100
+ private
101
+
102
+ def type_string(value)
103
+ java.lang.String.new(value.to_java_bytes, @container.page.getPageEncoding).toCharArray.each do |char|
104
+ @container.update_page @object.type(char)
105
+ end
106
+ end
107
+
108
+ def insert_string(value)
109
+ case @object.getTagName
110
+ when 'textarea'
111
+ @object.setText(value)
112
+ when 'input'
113
+ @object.setValueAttribute(value)
114
+ else
115
+ raise "unknown tag name #{@object.getTagName.inspect} for #{self.class}"
116
+ end
117
+ end
118
+ end
119
+
120
+ # this class can be used to access hidden field objects
121
+ # Normally a user would not need to create this object as it is returned by the Celerity::Container#hidden method
122
+ class Hidden < TextField
123
+ TAGS = [ Identifier.new('input', :type => %w[hidden]) ]
124
+ DEFAULT_HOW = :name
125
+ end
126
+
127
+ end
@@ -0,0 +1,40 @@
1
+ module Celerity
2
+ module Exception
3
+
4
+ # Superclass for all Celerity exceptions.
5
+ class CelerityException < StandardError; end
6
+
7
+ # This exception is thrown if an attempt is made to access an object that doesn't exist
8
+ class UnknownObjectException < CelerityException; end
9
+
10
+ # This exception is thrown if an attempt is made to access an object that is in a disabled state
11
+ class ObjectDisabledException < CelerityException; end
12
+
13
+ # This exception is thrown if an attempt is made to access a frame that cannot be found
14
+ class UnknownFrameException < CelerityException; end
15
+
16
+ # This exception is thrown if an attempt is made to access a form that cannot be found
17
+ class UnknownFormException < CelerityException; end
18
+
19
+ # This exception is thrown if an attempt is made to access an object that is in a read-only state
20
+ class ObjectReadOnlyException < CelerityException; end
21
+
22
+ # This exception is thrown if an attempt is made to access an object when the specified value cannot be found
23
+ class NoValueFoundException < CelerityException; end
24
+
25
+ # This exception gets raised if the how argument is wrong.
26
+ class MissingWayOfFindingObjectException < CelerityException; end
27
+
28
+ # This exception is raised if an attempt is made to access a table row that doesn't exist
29
+ class UnknownRowException < CelerityException; end
30
+
31
+ # This exception is raised if an attempt is made to access a table cell that doesn't exist
32
+ class UnknownCellException < CelerityException; end
33
+
34
+ # This exception is thrown if an http error, such as a 404, 500 etc is encountered while navigating
35
+ class NavigationException < CelerityException; end
36
+
37
+ # This exception is thrown if an unexpected content type is returned by the server.
38
+ class UnexpectedPageException < CelerityException; end
39
+ end
40
+ end
@@ -0,0 +1,158 @@
1
+ require "rubygems"
2
+ require "uri"
3
+ require "active_support"
4
+
5
+ #--
6
+ # http://api.rubyonrails.com/classes/Inflector.html#M001621
7
+ #++
8
+ class String # :nodoc:
9
+ def underscore
10
+ gsub(/::/, '/').
11
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
12
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
13
+ tr("-", "_").
14
+ downcase
15
+ end
16
+ end
17
+
18
+ module Celerity
19
+ # Experimental - generate a method definition for accessing elements on the current page.
20
+ class MethodGenerator
21
+
22
+ ELEMENTS = %w[text_field select_list radio checkbox button].map { |e| e.to_sym }
23
+ BUGGY_ELEMENTS = %w[radio checkbox].map { |e| e.to_sym }
24
+
25
+ def initialize(ie, opts = {})
26
+ @ie = ie
27
+ @opts = opts
28
+ @browser = @opts[:browser] || '@ie'
29
+
30
+ @docs = " # Fills in the page at #{@ie.url}\n #\n"
31
+ @docs << " # Parameters:\n #\n"
32
+ @doc_elements = []
33
+
34
+ @method = " def #{@opts[:method_name] || 'generated_method'}(opts = {})\n\n"
35
+ end
36
+
37
+ def parse
38
+ ELEMENTS.each do |elem|
39
+ @method << " # buggy!\n" if BUGGY_ELEMENTS.include?(elem)
40
+ add_elements(elem)
41
+ end
42
+ add_elements(:link) if @opts[:include_links]
43
+ @method << " end\n\n"
44
+
45
+ # fix docs
46
+ max = @doc_elements.map { |symbol, _| symbol.to_s.size }.max
47
+ @doc_elements.each do |sym, desc|
48
+ @docs << " # #{sym.to_s.ljust(max)} => #{desc}\n"
49
+ end
50
+ @docs << " #\n"*2
51
+ @docs + @method
52
+ end
53
+
54
+ private
55
+
56
+ def add_elements(symbol)
57
+ symbol = symbol.to_sym
58
+ symbol_pluralized = symbol.to_s.pluralize.to_sym
59
+ @ie.send(symbol_pluralized).each_with_index do |elem, idx|
60
+ self.send("add_#{symbol}".to_sym, elem, idx)
61
+ end
62
+
63
+ @method << "\n"
64
+ end
65
+
66
+ def add_text_field(elem, idx)
67
+ how, what = find_identifier(elem) || [:index, (idx + 1).to_s]
68
+ @method << " #{@browser}.text_field(#{how.inspect}, #{what.inspect}).value = "
69
+ symbol = (how == :index) ? ":text_field_#{what.underscore}" : ":#{what.underscore}"
70
+ @method << "opts[#{symbol}]\n"
71
+ @doc_elements << [symbol, "value for text field #{what.inspect}"]
72
+ end
73
+
74
+ def add_select_list(elem, idx)
75
+ how, what = find_identifier(elem) || [:index, (idx + 1).to_s]
76
+ @method << " #{@browser}.select_list(#{how.inspect}, #{what.inspect}).select("
77
+ symbol = (how == :index) ? ":select_list_#{what.underscore}" : ":#{what.underscore}"
78
+ @method << "opts[#{symbol}])\n"
79
+ @doc_elements << [symbol, "option to select for select list #{what.inspect}"]
80
+ end
81
+
82
+ def add_radio(elem, idx)
83
+ how, what = find_identifier(elem) || [:index, (idx + 1).to_s]
84
+ @method << " #{@browser}.radio(#{how.inspect}, #{what.inspect}, "
85
+
86
+ if (value = elem.value).empty?
87
+ symbol = (how == :index) ? ":radio_#{what.underscore}" : ":#{what.underscore}"
88
+ else
89
+ symbol = ":#{what.underscore}_#{value.underscore}"
90
+ @method << "#{value.inspect}).set if opts[#{symbol}]\n"
91
+ end
92
+
93
+ @doc_elements << [symbol, "set the radio with id/value #{what.inspect}"]
94
+ end
95
+
96
+ def add_checkbox(elem, idx)
97
+ how, what = find_identifier(elem) || [:index, (idx + 1).to_s]
98
+ @method << " #{@browser}.checkbox(#{how.inspect}, #{what.inspect}, "
99
+ symbol = (how == :index) ? ":checkbox_#{what.underscore}" : ":#{what.underscore}"
100
+ @method << "#{elem.value.inspect}).set if opts[#{symbol}]\n"
101
+
102
+ @doc_elements << [symbol, "set the checkbox with id/value #{what.inspect}"]
103
+ end
104
+
105
+ def add_button(elem, idx)
106
+ how, what = find_identifier(elem) || [:index, (idx + 1).to_s]
107
+ @method << " #{@browser}.button(#{how.inspect}, #{what.inspect}).click\n"
108
+ end
109
+
110
+ def add_link(elem, idx)
111
+ if (href = elem.href) =~ /javascript/
112
+ how, what = :index, (idx + 1).to_s
113
+ else
114
+ how = :url
115
+
116
+ begin
117
+ uri = URI.parse(href)
118
+ what = Regexp.new(Regexp.escape(uri.to_s.sub(/.*#{uri.host}\//, '')))
119
+ rescue URI::InvalidURIError
120
+ what = href
121
+ end
122
+ end
123
+ @method << " #{@browser}.link(#{how.inspect}, #{what.inspect}).click\n"
124
+ end
125
+
126
+ def find_identifier(element)
127
+ # could use ATTRIBUTES if they were 'weighted' somehow?
128
+ attrs = element.class::ATTRIBUTES
129
+ [:id, :name].each do |attribute|
130
+ return [attribute, element.send(attribute)] if attrs.include?(attribute) && !element.send(attribute).empty?
131
+ end
132
+ nil
133
+ end
134
+
135
+ end # MethodGenerator
136
+
137
+ class Browser
138
+ # Experimental - generate a method definition for accessing elements on the current page
139
+ # Not loaded by default - need to require 'celerity/extra/method_generator'
140
+ def generate_method(opts = {})
141
+ MethodGenerator.new(self, opts).parse
142
+ end
143
+ end # Browser
144
+
145
+ end # Celerity
146
+
147
+
148
+
149
+ # if __FILE__ == $0
150
+ # require File.dirname(__FILE__) + "/../spec/spec_helper"
151
+ # $stdout.sync = true
152
+ # @ie = Browser.new
153
+ # @ie.goto(TEST_HOST + "/forms_with_input_elements.html")
154
+ #
155
+ # puts MethodGenerator.new(@ie).parse
156
+ # @ie.goto(TEST_HOST + "/forms3.html")
157
+ # puts MethodGenerator.new(@ie).parse
158
+ # end