celerity 0.0.1 → 0.0.2

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 (93) hide show
  1. data/History.txt +10 -0
  2. data/README.txt +8 -11
  3. data/Rakefile +5 -3
  4. data/benchmark/bm_2000_spans.rb +48 -0
  5. data/benchmark/bm_digg.rb +26 -0
  6. data/benchmark/bm_google_images.rb +36 -0
  7. data/benchmark/bm_input_locator.rb +69 -0
  8. data/benchmark/loader.rb +9 -0
  9. data/lib/celerity.rb +3 -1
  10. data/lib/celerity/container.rb +23 -171
  11. data/lib/celerity/disabled_element.rb +1 -1
  12. data/lib/celerity/element.rb +78 -47
  13. data/lib/celerity/element_collections.rb +16 -32
  14. data/lib/celerity/element_locator.rb +135 -0
  15. data/lib/celerity/elements/button.rb +15 -0
  16. data/lib/celerity/elements/file_field.rb +1 -1
  17. data/lib/celerity/elements/form.rb +2 -1
  18. data/lib/celerity/elements/frame.rb +18 -21
  19. data/lib/celerity/elements/image.rb +2 -8
  20. data/lib/celerity/elements/label.rb +1 -3
  21. data/lib/celerity/elements/link.rb +1 -1
  22. data/lib/celerity/elements/option.rb +16 -0
  23. data/lib/celerity/elements/radio_check.rb +18 -7
  24. data/lib/celerity/elements/select_list.rb +1 -17
  25. data/lib/celerity/elements/table.rb +4 -4
  26. data/lib/celerity/elements/table_body.rb +6 -8
  27. data/lib/celerity/elements/table_cell.rb +3 -14
  28. data/lib/celerity/elements/table_row.rb +4 -10
  29. data/lib/celerity/elements/text_field.rb +16 -4
  30. data/lib/celerity/extra/method_generator.rb +144 -0
  31. data/lib/celerity/identifier.rb +10 -0
  32. data/lib/celerity/ie.rb +28 -13
  33. data/lib/celerity/input_element.rb +0 -4
  34. data/lib/celerity/non_control_elements.rb +12 -12
  35. data/lib/celerity/version.rb +1 -1
  36. data/spec/area_spec.rb +41 -41
  37. data/spec/areas_spec.rb +11 -11
  38. data/spec/button_spec.rb +73 -68
  39. data/spec/buttons_spec.rb +10 -10
  40. data/spec/checkbox_spec.rb +102 -96
  41. data/spec/checkboxes_spec.rb +10 -10
  42. data/spec/div_spec.rb +78 -73
  43. data/spec/divs_spec.rb +10 -10
  44. data/spec/element_spec.rb +20 -11
  45. data/spec/filefield_spec.rb +36 -41
  46. data/spec/filefields_spec.rb +10 -10
  47. data/spec/form_spec.rb +29 -29
  48. data/spec/forms_spec.rb +11 -11
  49. data/spec/frame_spec.rb +54 -49
  50. data/spec/hidden_spec.rb +43 -43
  51. data/spec/hiddens_spec.rb +10 -10
  52. data/spec/html/2000_spans.html +2009 -0
  53. data/spec/html/forms_with_input_elements.html +15 -9
  54. data/spec/html/non_control_elements.html +4 -2
  55. data/spec/ie_spec.rb +82 -48
  56. data/spec/image_spec.rb +83 -100
  57. data/spec/images_spec.rb +10 -10
  58. data/spec/label_spec.rb +29 -29
  59. data/spec/labels_spec.rb +10 -10
  60. data/spec/li_spec.rb +41 -41
  61. data/spec/link_spec.rb +65 -59
  62. data/spec/links_spec.rb +11 -11
  63. data/spec/lis_spec.rb +10 -10
  64. data/spec/map_spec.rb +30 -30
  65. data/spec/maps_spec.rb +10 -10
  66. data/spec/p_spec.rb +49 -49
  67. data/spec/pre_spec.rb +41 -41
  68. data/spec/pres_spec.rb +10 -10
  69. data/spec/ps_spec.rb +10 -10
  70. data/spec/radio_spec.rb +104 -97
  71. data/spec/radios_spec.rb +11 -11
  72. data/spec/select_list_spec.rb +118 -106
  73. data/spec/select_lists_spec.rb +15 -15
  74. data/spec/span_spec.rb +54 -54
  75. data/spec/spans_spec.rb +11 -11
  76. data/spec/spec.opts +1 -1
  77. data/spec/spec_helper.rb +23 -3
  78. data/spec/table_bodies.rb +8 -8
  79. data/spec/table_bodies_spec.rb +9 -9
  80. data/spec/table_body_spec.rb +28 -27
  81. data/spec/table_cell_spec.rb +25 -25
  82. data/spec/table_cells_spec.rb +16 -16
  83. data/spec/table_row_spec.rb +16 -16
  84. data/spec/table_rows_spec.rb +12 -12
  85. data/spec/table_spec.rb +36 -36
  86. data/spec/tables_spec.rb +12 -12
  87. data/spec/text_field_spec.rb +111 -92
  88. data/spec/text_fields_spec.rb +13 -13
  89. data/tasks/benchmark.rake +3 -0
  90. data/tasks/rspec.rake +2 -2
  91. data/tasks/testserver.rake +15 -0
  92. metadata +58 -46
  93. data/tasks/simple_ci.rake +0 -94
@@ -2,41 +2,38 @@ module Celerity
2
2
  class Frame < Element
3
3
  include Container
4
4
  attr_accessor :page
5
- TAGS = {'frame' => nil, 'iframe' => nil}
5
+
6
+ TAGS = [Identifier.new('frame'), Identifier.new('iframe')]
7
+
6
8
  ATTRIBUTES = BASE_ATTRIBUTES | [:longdesc, :name, :src, :frameborder, :marginwidth, :marginheight, :noresize, :scrolling]
7
9
  DEFAULT_HOW = :name
8
10
 
9
11
  def locate
10
- # Log.debug(@container.object.inspect)
11
- frame_elements = @container.object.getByXPath(".//iframe | .//frame").collect { |frame| frame.getEnclosedWindow.getFrameElement }
12
- unless frame_elements.empty?
13
- case @how
14
- when :id, :name, :src, :class
15
- matching_frame_elements = frame_elements.select { |frame_element| matches?(frame_element.getAttribute(@how.to_s), @what) }
16
- if @frame_element = matching_frame_elements.first
17
- @object = @frame_element.getEnclosedPage.getDocumentElement
18
- end
19
- when :index
20
- if @frame_element = frame_elements[@what-1]
21
- @object = @frame_element.getEnclosedPage.getDocumentElement
22
- end
23
- when :xpath
24
- raise NotImplementedError
25
- else
26
- raise MissingWayOfFindingObjectException
12
+ super
13
+ if @object
14
+ @inline_frame_object = @object.getEnclosedWindow.getFrameElement
15
+ if (frame = @object.getEnclosedPage.getDocumentElement)
16
+ @object = frame
17
+ else
18
+ @object = nil
27
19
  end
28
20
  end
29
- raise UnknownFrameException unless @object
21
+ end
22
+
23
+ def assert_exists
24
+ locate unless @object
25
+ unless @object
26
+ raise UnknownFrameException, "unable to locate frame, using #{identifier_string}"
27
+ end
30
28
  end
31
29
 
32
30
  def update_page(value)
33
- # Log.debug(value.asXml)
34
31
  @page_container.set_page(value.getEnclosingWindow.getTopWindow.getEnclosedPage)
35
32
  end
36
33
 
37
34
  def to_s
38
35
  assert_exists
39
- create_string(@frame_element)
36
+ create_string(@inline_frame_object)
40
37
  end
41
38
 
42
39
  end
@@ -9,7 +9,7 @@ module Celerity
9
9
  include ClickableElement
10
10
  include DisabledElement
11
11
 
12
- TAGS = ['img']
12
+ TAGS = [ Identifier.new('img') ]
13
13
  ATTRIBUTES = BASE_ATTRIBUTES | [:src, :alt, :longdesc, :name, :height, :width, :usemap, :ismap, :align, :border, :hspace, :vspace]
14
14
 
15
15
  # this method returns the file created date of the image
@@ -39,13 +39,7 @@ module Celerity
39
39
  assert_exists
40
40
  @object.getHeight
41
41
  end
42
-
43
- def disabled?
44
- assert_exists
45
- raise NotImplementedError
46
- end
47
- alias_method :disabled, :disabled?
48
-
42
+
49
43
  def loaded?
50
44
  assert_exists
51
45
  begin
@@ -1,10 +1,8 @@
1
1
  module Celerity
2
2
 
3
3
  class Label < Element
4
- TAGS = ['label']
4
+ TAGS = [ Identifier.new('label') ]
5
5
  ATTRIBUTES = BASE_ATTRIBUTES | [:for, :accesskey, :onfocus, :onblur]
6
-
7
-
8
6
  end
9
7
 
10
8
  end
@@ -1,6 +1,6 @@
1
1
  module Celerity
2
2
  class Link < Element
3
- TAGS = ['a']
3
+ TAGS = [ Identifier.new('a') ]
4
4
  ATTRIBUTES = BASE_ATTRIBUTES | [:charset, :type, :name, :href, :hreflang, :target, :rel, :rev, :accesskey, :shape, :coords, :tabindex, :onfocus, :onblur]
5
5
 
6
6
  def click
@@ -0,0 +1,16 @@
1
+ module Celerity
2
+ class Option < Element
3
+ include ClickableElement
4
+ include DisabledElement
5
+
6
+ TAGS = [ Identifier.new('option')]
7
+ ATTRIBUTES = BASE_ATTRIBUTES | [:selected, :disabled, :label, :value]
8
+
9
+ alias_method :select, :click
10
+
11
+ def selected?
12
+ assert_exists
13
+ @object.isSelected
14
+ end
15
+ end
16
+ end
@@ -6,14 +6,17 @@ module Celerity
6
6
  # most of the methods available to this element are inherited from the Element class
7
7
  #
8
8
  class RadioCheckCommon < InputElement
9
- def locate
10
- @object = @container.locate_input_element(self, @how, @what, @value)
11
- end
12
-
13
- def initialize(container, how, what, type, value = nil)
9
+ def initialize(container, type, *args)
14
10
  @type = type
15
- @value = value
16
- super(container, how, what)
11
+
12
+ case args.size
13
+ when 2
14
+ super(container, args[0] => args[1])
15
+ when 3
16
+ super(container, args[0] => args[1], :value => args[2])
17
+ else
18
+ super(container, *args)
19
+ end
17
20
  end
18
21
 
19
22
  def set?
@@ -35,6 +38,10 @@ module Celerity
35
38
  class Radio < RadioCheckCommon
36
39
  TAGS = [Identifier.new('input', :type => %w(radio))]
37
40
 
41
+ def initialize(container, *args)
42
+ super(container, ['radio'], *args)
43
+ end
44
+
38
45
  def set(value = true)
39
46
  assert_exists
40
47
  assert_enabled
@@ -47,6 +54,10 @@ module Celerity
47
54
  class CheckBox < RadioCheckCommon
48
55
  TAGS = [Identifier.new('input', :type => %w(checkbox))]
49
56
 
57
+ def initialize(container, *args)
58
+ super(container, ['checkbox'], *args)
59
+ end
60
+
50
61
  def set(value = true)
51
62
  assert_exists
52
63
  assert_enabled
@@ -43,7 +43,7 @@ module Celerity
43
43
 
44
44
  def selected?(value)
45
45
  assert_exists
46
- # This should probably raise NoValueFoundException as well?
46
+ # This should probably raise NoValueFoundException?
47
47
  raise UnknownObjectException, "unknown option with value #{value.inspect}" unless include?(value)
48
48
  !!@object.getOptions.find { |e| matches?(e.asText, value) && e.isSelected }
49
49
  end
@@ -65,20 +65,4 @@ module Celerity
65
65
  Option.new(self, attribute, value)
66
66
  end
67
67
  end
68
-
69
- class Option < Element
70
- TAGS = ['option']
71
- ATTRIBUTES = BASE_ATTRIBUTES | [:selected, :disabled, :label, :value]
72
-
73
- def select
74
- assert_exists
75
- # click?
76
- @object.setSelected(true)
77
- end
78
-
79
- def selected?
80
- assert_exists
81
- @object.isSelected
82
- end
83
- end
84
68
  end
@@ -2,13 +2,13 @@ module Celerity
2
2
 
3
3
  class Table < Element
4
4
  include Container
5
- TAGS = ['table']
5
+ TAGS = [ Identifier.new('table') ]
6
6
  ATTRIBUTES = BASE_ATTRIBUTES | [:summary, :width, :border, :frame, :rules, :cellspacing, :cellpadding, :align, :bgcolor]
7
7
  DEFAULT_HOW = :name
8
8
 
9
9
  def locate
10
- @object = @container.locate_tagged_element(self, @how, @what)
11
- if @object # cant call the assert_exists here, as an exists? method call will fail
10
+ super
11
+ if @object # cant call assert_exists here, as an exists? method call will fail
12
12
  @rows = @object.getRows
13
13
  @cells = []
14
14
  @rows.each do |row|
@@ -73,7 +73,7 @@ module Celerity
73
73
 
74
74
  def body(how, what)
75
75
  assert_exists
76
- return TableBody.new(@container, how, what, self)
76
+ return TableBody.new(@container, how, what)
77
77
  end
78
78
 
79
79
  def bodies
@@ -1,15 +1,12 @@
1
1
  module Celerity
2
2
 
3
3
  class TableBody < Element
4
- TAGS = ['tbody']
4
+ TAGS = [ Identifier.new('tbody') ]
5
5
 
6
6
  def locate
7
- if @how == :object
8
- @object = @what
9
- else
10
- @object = @container.locate_tagged_element(self, @how, @what)
11
- end
12
- if @object # cant call the assert_exists here, as an exists? method call will fail
7
+ super
8
+ # can't call the assert_exists here, as an exists? method call will fail
9
+ if @object
13
10
  @rows = @object.getRows
14
11
  @cells = []
15
12
  @rows.each do |row|
@@ -31,7 +28,8 @@ module Celerity
31
28
  end
32
29
 
33
30
  def each
34
- 0.upto(length-1) { |index| yield TableRow.new(self, :object, @rows[index]) }
31
+ assert_exists
32
+ @rows.each { |row| yield TableRow.new(self, :object, row) }
35
33
  end
36
34
 
37
35
  end
@@ -4,27 +4,16 @@ module Celerity
4
4
  include Celerity::Exception
5
5
  include Container
6
6
 
7
- TAGS = ['td']
7
+ TAGS = [ Identifier.new('td') ]
8
8
  ATTRIBUTES = BASE_ATTRIBUTES | [:abbr, :axis, :headers, :scope, :rowspan, :colspan] | CELLHALIGN_ATTRIBUTES | CELLVALIGN_ATTRIBUTES
9
9
 
10
- def locate
11
- if @how == :object
12
- @object = @what
13
- else
14
- @object = @container.locate_tagged_element(self, @how, @what)
15
- end
16
- end
10
+ alias_method :to_s, :text
17
11
 
18
12
  def colspan
19
13
  assert_exists
20
14
  attribute_value = @object.getAttributeValue('colspan').to_i
21
- if attribute_value > 0
22
- attribute_value
23
- else
24
- 1
25
- end
15
+ attribute_value > 0 ? attribute_value : 1
26
16
  end
27
17
 
28
- alias_method :to_s, :text
29
18
  end
30
19
  end
@@ -1,22 +1,16 @@
1
1
  module Celerity
2
2
 
3
3
  class TableRow < Element
4
- TAGS = ['tr']
4
+ TAGS = [ Identifier.new('tr') ]
5
5
 
6
6
  def locate
7
- if @how == :object
8
- @object = @what
9
- else
10
- @object = @container.locate_tagged_element(self, @how, @what)
11
- end
12
- if @object # cant call the assert_exists here, as an exists? method call will fail
13
- @cells = @object.getCells
14
- end
7
+ super
8
+ @cells = @object.getCells if @object
15
9
  end
16
10
 
17
11
  def each
18
12
  locate
19
- 0.upto(@cells.length-1) { |index| yield TableCell.new(self, :object, @cells[index]) }
13
+ @cells.each { |cell| yield TableCell.new(self, :object, cell) }
20
14
  end
21
15
 
22
16
  def [](index)
@@ -6,7 +6,7 @@ module Celerity
6
6
  # Normally a user would not need to create this object as it is returned by the Watir::Container#text_field method
7
7
  class TextField < InputElement
8
8
  TAGS = [ Identifier.new('textarea'),
9
- Identifier.new('input', :type => %w(text password)) ]
9
+ Identifier.new('input', :type => ["text", "password", /^(?!(file|radio|checkbox|submit|reset|image|button|hidden)$)/]) ]
10
10
 
11
11
  def clear
12
12
  assert_exists
@@ -22,11 +22,11 @@ module Celerity
22
22
  assert_enabled
23
23
  assert_not_readonly
24
24
  clear
25
- # not sure what else to do here
25
+ # workaround for bug in HtmlPasswordInput - should be fixed soon (Jari - 2008-05-14)
26
26
  if @object.class == com.gargoylesoftware.htmlunit.html.HtmlPasswordInput
27
27
  @object.setValueAttribute(value.to_s)
28
28
  else
29
- value.to_s.to_java_bytes.each do |char|
29
+ java.lang.String.new(value.to_s).toCharArray.each do |char|
30
30
  @container.update_page @object.type(char)
31
31
  end
32
32
  end
@@ -43,11 +43,23 @@ module Celerity
43
43
  @object.setValueAttribute(value.to_s)
44
44
  end
45
45
  end
46
+
47
+ def value
48
+ assert_exists
49
+ case @object.getTagName
50
+ when 'textarea'
51
+ @object.getText
52
+ when 'input'
53
+ @object.getValueAttribute
54
+ end
55
+ end
46
56
 
47
57
  def append(value)
48
58
  assert_enabled
49
59
  assert_not_readonly
50
- value.to_s.to_java_bytes.each { |char| @container.update_page @object.type(char) }
60
+ java.lang.String.new(value.to_s).toCharArray.each do |char|
61
+ @container.update_page @object.type(char)
62
+ end
51
63
  end
52
64
 
53
65
  # This bascially just moves the text to the other text field using TextField#append
@@ -0,0 +1,144 @@
1
+ require "rubygems"
2
+ require "uri"
3
+ require "active_support"
4
+
5
+ # http://api.rubyonrails.com/classes/Inflector.html#M001621
6
+ class String
7
+ def underscore
8
+ gsub(/::/, '/').
9
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
10
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
11
+ tr("-", "_").
12
+ downcase
13
+ end
14
+ end
15
+
16
+ module Celerity
17
+ class MethodGenerator
18
+
19
+ ELEMENTS = %w(text_field select_list radio checkbox button).map { |e| e.to_sym }
20
+ BUGGY_ELEMENTS = %w(radio checkbox).map { |e| e.to_sym }
21
+
22
+ def initialize(ie, opts = {})
23
+ @ie = ie
24
+ @opts = opts
25
+ @browser = @opts[:browser] || '@ie'
26
+
27
+ @docs = " # Fills in the page at #{@ie.url}\n #\n"
28
+ @docs << " # Parameters:\n #\n"
29
+ @doc_elements = []
30
+
31
+ @method = " def #{@opts[:method_name] || 'generated_method'}(opts = {})\n\n"
32
+ end
33
+
34
+ def parse
35
+ ELEMENTS.each do |elem|
36
+ @method << " # buggy!\n" if BUGGY_ELEMENTS.include?(elem)
37
+ add_elements(elem)
38
+ end
39
+ add_elements(:link) if @opts[:include_links]
40
+ @method << " end\n\n"
41
+
42
+ # fix docs
43
+ max = @doc_elements.map { |symbol, _| symbol.to_s.size }.max
44
+ @doc_elements.each do |sym, desc|
45
+ @docs << " # #{sym.to_s.ljust(max)} => #{desc}\n"
46
+ end
47
+ @docs << " #\n"*2
48
+ @docs + @method
49
+ end
50
+
51
+ private
52
+
53
+ def add_elements(symbol)
54
+ symbol = symbol.to_sym
55
+ symbol_pluralized = symbol.to_s.pluralize.to_sym
56
+ @ie.send(symbol_pluralized).each_with_index do |elem, idx|
57
+ self.send("add_#{symbol}".to_sym, elem, idx)
58
+ end
59
+ @method << "\n"
60
+ end
61
+
62
+ def add_text_field(elem, idx)
63
+ how, what = find_identifier(elem) || [:index, (idx + 1).to_s]
64
+ @method << " #{@browser}.text_field(#{how.inspect}, #{what.inspect}).value = "
65
+ symbol = (how == :index) ? ":text_field_#{what.underscore}" : ":#{what.underscore}"
66
+ @method << "opts[#{symbol}]\n"
67
+ @doc_elements << [symbol, "value for text field #{what.inspect}"]
68
+ end
69
+
70
+ def add_select_list(elem, idx)
71
+ how, what = find_identifier(elem) || [:index, (idx + 1).to_s]
72
+ @method << " #{@browser}.select_list(#{how.inspect}, #{what.inspect}).select("
73
+ symbol = (how == :index) ? ":select_list_#{what.underscore}" : ":#{what.underscore}"
74
+ @method << "opts[#{symbol}])\n"
75
+ @doc_elements << [symbol, "option to select for select list #{what.inspect}"]
76
+ end
77
+
78
+ def add_radio(elem, idx)
79
+ how, what = find_identifier(elem) || [:index, (idx + 1).to_s]
80
+ @method << " #{@browser}.radio(#{how.inspect}, #{what.inspect}, "
81
+ if (value = elem.value).empty?
82
+ symbol = (how == :index) ? ":radio_#{what.underscore}" : ":#{what.underscore}"
83
+ else
84
+ symbol = ":#{what.underscore}_#{value.underscore}"
85
+ @method << "#{value.inspect}).set if opts[#{symbol}]\n"
86
+ end
87
+ @doc_elements << [symbol, "set the radio with id/value #{what.inspect}"]
88
+ end
89
+
90
+ def add_checkbox(elem, idx)
91
+ how, what = find_identifier(elem) || [:index, (idx + 1).to_s]
92
+ @method << " #{@browser}.checkbox(#{how.inspect}, #{what.inspect}, "
93
+ symbol = (how == :index) ? ":checkbox_#{what.underscore}" : ":#{what.underscore}"
94
+ @method << "#{elem.value.inspect}).set if opts[#{symbol}]\n"
95
+ @doc_elements << [symbol, "set the checkbox with id/value #{what.inspect}"]
96
+ end
97
+
98
+ def add_button(elem, idx)
99
+ how, what = find_identifier(elem) || [:index, (idx + 1).to_s]
100
+ @method << " #{@browser}.button(#{how.inspect}, #{what.inspect}).click\n"
101
+ end
102
+
103
+ def add_link(elem, idx)
104
+ if (href = elem.href) =~ /javascript/
105
+ how, what = :index, (idx + 1).to_s
106
+ else
107
+ how = :url
108
+ uri = URI.parse(href)
109
+ what = Regexp.new(Regexp.escape(uri.to_s.sub(/.*#{uri.host}\//, '')))
110
+ end
111
+ @method << " #{@browser}.link(#{how.inspect}, #{what.inspect}).click\n"
112
+ end
113
+
114
+ def find_identifier(element)
115
+ # could use these if they were 'weighted' ?
116
+ attrs = element.class::ATTRIBUTES
117
+ [:id, :name].each do |attribute|
118
+ return [attribute, element.send(attribute)] if attrs.include?(attribute) && !element.send(attribute).empty?
119
+ end
120
+ nil
121
+ end
122
+
123
+ end # MethodGenerator
124
+
125
+ class IE
126
+ def generate_method
127
+ MethodGenerator.new(self).parse
128
+ end
129
+ end
130
+
131
+ end # Celerity
132
+
133
+
134
+
135
+ # if __FILE__ == $0
136
+ # require File.dirname(__FILE__) + "/../spec/spec_helper"
137
+ # $stdout.sync = true
138
+ # @ie = IE.new
139
+ # @ie.goto(TEST_HOST + "/forms_with_input_elements.html")
140
+ #
141
+ # puts MethodGenerator.new(@ie).parse
142
+ # @ie.goto(TEST_HOST + "/forms3.html")
143
+ # puts MethodGenerator.new(@ie).parse
144
+ # end