selenium-extjs 0.0.1

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.
@@ -0,0 +1,80 @@
1
+
2
+ = Selenium-extjs
3
+
4
+ Please, it's work in progress - wait for complete features or help us :)
5
+
6
+ More information about extjs and selenium tests:
7
+ * http://www.xeolabs.com/portal/articles/selenium-and-extjs
8
+ * http://stackoverflow.com/questions/107314/any-suggestions-for-testing-extjs-code-in-a-browser-preferably-with-selenium
9
+
10
+ == How it works?
11
+
12
+ It's used the 'get_eval' to get Ext's components information (like id) using the window.Ext object and common selenium methods (like: type, click_at) to change the application status.
13
+
14
+ ==Instalation
15
+
16
+ # TODO: deploy gem
17
+
18
+ * git clone git://github.com/cathoderay/selenium-extjs.git
19
+ * cd selenium-extjs
20
+ * rake package
21
+ * cd pkg
22
+ * gem install selenium-extjs-0.0.1.gem
23
+
24
+ ==Contributing
25
+
26
+ Send us a message!
27
+
28
+ ==Some Examples
29
+
30
+ Please, take a look at "/test" files.
31
+
32
+ ===Simple
33
+
34
+ @selenium = [..your selenium object..]
35
+
36
+ appfeedgrid = @selenium.find_ext(:xtype => "appfeedgrid")
37
+
38
+ button = @selenium.find_ext(:xtype => "button", :text => 'Open All', :xparent => appfeedgrid)
39
+
40
+ # click method wait for any request complete
41
+ button.click
42
+
43
+ === Working with Form
44
+
45
+ # search for form.
46
+ form = @selenium.find_ext(:xtype => "form", :title_has => 'Simple')
47
+
48
+ form.field[:email].value = "NotAEmail"
49
+
50
+ # convert to "isValid" and run at client.
51
+ assert_false form.field[:email].valid?
52
+
53
+ form.fields[:email].value = 'myemail@domain.br'
54
+
55
+ assert_true form.field[:email].valid?
56
+
57
+
58
+ === Working with Grid and Ajax Content.
59
+
60
+ # :wait blocks test, waiting for window
61
+ window = @selenium.find_ext(:xtype => 'window', :wait => true, :title => 'Store Load Callback')
62
+ # close the window
63
+ window.close
64
+
65
+ # search for editorgrid component.
66
+ editorgrid = @selenium.find(:xtype => "editorgrid")
67
+
68
+ # number of lines
69
+ print editorgrid.num_rows()
70
+
71
+ # set row 1 with data
72
+ editorgrid.edit_row(1, ["Jorge", "Shade", "10.10", "24/03/06", true]);
73
+
74
+ # get row (hash)
75
+ print editorgrid.get_row(3)
76
+
77
+ # clica at cell x,y
78
+ editorgrid.click_at_cell(2, 5)
79
+
80
+
@@ -0,0 +1,6 @@
1
+
2
+ module SeleniumExtJs
3
+ VERSION = "0.0.1"
4
+ end
5
+
6
+ require 'selenium-extjs/Ext'
@@ -0,0 +1,120 @@
1
+
2
+ require 'rubygems'
3
+ require 'selenium/client'
4
+ require 'selenium-extjs/Selenium'
5
+ require 'selenium-extjs/component/Component'
6
+ require 'selenium-extjs/component/Panel'
7
+ require 'selenium-extjs/component/Button'
8
+ require 'selenium-extjs/component/Field'
9
+ require 'selenium-extjs/component/Form'
10
+ require 'selenium-extjs/component/Grid'
11
+ require 'selenium-extjs/component/Window'
12
+ require 'selenium-extjs/component/Combo'
13
+ require 'selenium-extjs/component/FieldSet'
14
+
15
+
16
+ require 'json'
17
+
18
+
19
+ module Ext
20
+ def self.reg(xtype, cls)
21
+ Ext::ComponentMgr.register_type(xtype, cls)
22
+ end
23
+
24
+ def self.create(xtype, id, parent, selenium)
25
+ Ext::ComponentMgr.create(xtype, cls)
26
+ end
27
+
28
+ def self.condition_parent(cmp)
29
+ "(TODO)"
30
+ end
31
+
32
+ def self.condition_xtype(xtype)
33
+ "(el.getXType() == '#{xtype}')"
34
+ end
35
+
36
+ def self.condition_default(key, value)
37
+ key = key.to_s if key.is_a? Symbol
38
+ ret = "("
39
+ if key.end_with? '_has'
40
+ key = key.gsub(/_has$/, '')
41
+ ret += "(typeof el.initialConfig.#{key} == 'string' && el.initialConfig.#{key}.indexOf('#{value}') != -1)||"
42
+ end
43
+ ret += "(el.initialConfig.#{key} && el.initialConfig.#{key} == '#{value}')"
44
+ ret += ")"
45
+ ret
46
+ end
47
+
48
+ # build arguments list.
49
+ def self.arguments(args)
50
+ if args.is_a? Array
51
+ return args.to_json[1..-2] || ""
52
+ else
53
+ return args.to_json
54
+ end
55
+ end
56
+
57
+ def self.build_remote_call(id, method_name, arguments)
58
+ code = []
59
+ code << "(function(_) {"
60
+ code << " var r;"
61
+ code << " if (typeof _.#{method_name} == 'function') {"
62
+ code << " r = _.#{method_name}(#{arguments});"
63
+ code << " } else {"
64
+ code << " r = _.#{method_name};"
65
+ code << " }"
66
+ code << " if (typeof r.getId == 'function') {" # return hash map
67
+ code << " return 'JSON:' + window.Ext.util.JSON.encode({\"cmpid\":r.getId()});"
68
+ code << " } else {"
69
+ code << " return r;"
70
+ code << " }"
71
+ code << "})(window.Ext.getCmp('#{id}'));"
72
+ (code.collect {|t| t.strip }).join
73
+ end
74
+
75
+ # convert some ruby-style methods to ext-style
76
+ def self.extfy(method_name)
77
+ if method_name.end_with? '?'
78
+ method_name = "is_" + method_name
79
+ method_name.chop!
80
+ end
81
+ tokens = method_name.split("_")
82
+ tmp = tokens.shift
83
+ tokens.collect! {|t| t.capitalize }
84
+ tokens.unshift tmp
85
+ return tokens.join
86
+ end
87
+
88
+ class ComponentMgr
89
+ @@all = {}
90
+
91
+ def self.register_type(xtype, cls)
92
+ @@all[xtype] = cls
93
+ end
94
+
95
+ def self.registered?(xtype)
96
+ @@all.has_key? xtype
97
+ end
98
+
99
+ def self.create(xtype, id, parent, selenium)
100
+ @@all[xtype].new(id, parent, selenium)
101
+ end
102
+ end
103
+
104
+ {
105
+ :button => Button,
106
+ :component => Component,
107
+ :grid => Grid,
108
+ :editorgrid => EditorGrid,
109
+ :window => Window,
110
+ :form => Form,
111
+ :field => Field,
112
+ :panel => Panel,
113
+ :tabpanel => TabPanel,
114
+ :combo => Combo,
115
+ :fieldset => FieldSet
116
+ }.each do | xtype, cls |
117
+ Ext::reg(xtype, cls)
118
+ end
119
+
120
+ end
@@ -0,0 +1,71 @@
1
+ module Ext
2
+ class Selenium < Selenium::Client::Driver
3
+ def initialize(args)
4
+ super(args)
5
+ end
6
+
7
+ def find_ext(args)
8
+ if args.kind_of? Hash
9
+ exp = ""
10
+ parent = nil
11
+
12
+ xtype = nil
13
+ filters = []
14
+ args.each do |k,v|
15
+ filters << case k
16
+ # use para botões.
17
+ when :icon_cls
18
+ " (el.iconCls?(el.iconCls.indexOfind_extf('#{v}') != -1):false) "
19
+ when :title
20
+ " (el.title?(el.title == '#{v}'):false) "
21
+ when :title_has
22
+ " (el.title?(el.title.indexOf('#{v}') != -1):false) "
23
+ when :wait
24
+ nil
25
+ when :text
26
+ " (el.getText?(el.getText() == '#{v}'):false) "
27
+ when :xtype
28
+ xtype = v
29
+ Ext::condition_xtype(v)
30
+ when :xparent
31
+ if v.is_a? Ext::Component
32
+ parent = v
33
+ " el.findParentBy(function(o) { return o.getId() == '#{v.getId()}' }) "
34
+ else
35
+ " el.findParentBy(function(o) { return o.getXType() == '#{v}' }) "
36
+ end
37
+ else
38
+ Ext::condition_default(k, v)
39
+ end
40
+ end
41
+ exp = filters.compact().join(" && ")
42
+ p "window.Ext.ComponentMgr.all.find(function(el){ return #{exp} }).getId()"
43
+
44
+ # wait for element.
45
+ if args.has_key?(:wait) && args[:wait]
46
+ wait_for_condition("null != window.Ext.ComponentMgr.all.find(function(el){ return (#{exp}); })")
47
+ end
48
+
49
+ id = get_eval("window.Ext.ComponentMgr.all.find(function(el){ return (#{exp}); }).getId()")
50
+
51
+ return get_cmp(id, parent)
52
+ end
53
+ end
54
+
55
+ def wait_for_component_visible(id)
56
+ wait_for_condition("window.Ext.getCmp('#{id}').isVisible()")
57
+ end
58
+
59
+ def get_cmp(id, parent=nil)
60
+ xtypes = get_eval("window.Ext.getCmp('#{id}').getXTypes()")
61
+ selected_xtype = nil
62
+ for xtype in xtypes.split("/").reverse() do
63
+ if Ext::ComponentMgr::registered? xtype.to_sym
64
+ selected_xtype = xtype.to_sym
65
+ break
66
+ end
67
+ end
68
+ return Ext::ComponentMgr::create selected_xtype, id, parent, self
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,14 @@
1
+
2
+ module Ext
3
+ class Button < Component
4
+
5
+ def click
6
+ wait_for_ajax()
7
+ @selenium.click_at(selector(), "0,0")
8
+ end
9
+
10
+ def node
11
+ return "//table[@id='#{@id}']//button"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+
2
+ module Ext
3
+ class Combo < Field
4
+
5
+ def value= (v)
6
+ @selenium.type(@id, v)
7
+ blur
8
+ end
9
+
10
+ def blur
11
+ @selenium.fire_event(@id, "blur")
12
+ end
13
+
14
+ def value
15
+ # xpath or Ext?
16
+ # TODO: get more information from field (textarea or input[type=text])
17
+ @selenium.get_value(@id) #{}"//div[@id='#{@id}']//input")
18
+ # return @selenium.get_eval("window.Ext.getCmp('#{@id}').getValue()");
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,98 @@
1
+
2
+ require 'json'
3
+
4
+ module Ext
5
+ class Component
6
+ attr_accessor :parent
7
+
8
+
9
+ def initialize(id, parent = nil, selenium = nil)
10
+ @id = id
11
+ @parent = parent
12
+ @selenium = selenium
13
+ init_component()
14
+ end
15
+
16
+ def init_component()
17
+ end
18
+
19
+ # algumas ideias...
20
+ # obj.items_component_array -> serializar o retorno em uma lista
21
+ # tratar obj.store
22
+
23
+ def method_missing(method_name, *args, &block)
24
+
25
+ #
26
+ cmp = "window.Ext.getCmp('#{@id}')"
27
+
28
+ # TODO: unit for validate this :p
29
+ # registered?
30
+ # is_registered
31
+ # isRegistered()
32
+
33
+ if method_name.to_s.end_with? "="
34
+ return nil
35
+ end
36
+
37
+ # convert method name to ext model.
38
+ method_name = Ext::extfy(method_name.to_s)
39
+
40
+ # build js arguments list
41
+ arguments = Ext::arguments(args)
42
+
43
+ # move to selenium.
44
+ cmd = Ext::build_remote_call(@id, method_name, arguments)
45
+ p cmd
46
+
47
+ ret = @selenium.get_eval(cmd)
48
+ if ret.start_with? "JSON:"
49
+ ret = JSON ret.split(":", 2)[1]
50
+ end
51
+
52
+ if ret == "true" || ret == "false"
53
+ ret = (ret =="true")
54
+ end
55
+
56
+
57
+ if ret.is_a? Hash
58
+ if ret.has_key? "cmpid"
59
+ p "---->"
60
+ p ret
61
+ return @selenium.get_cmp(ret["cmpid"], nil)
62
+ else
63
+ return ret
64
+ end
65
+ else
66
+ return ret
67
+ end
68
+ end
69
+
70
+ def wait_for_ajax
71
+ @selenium.wait_for_condition("window.Ext.Ajax.isLoading() == false")
72
+ end
73
+
74
+ # common tag element for this element
75
+ def node
76
+ return "//div[@id='#{@id}']"
77
+ end
78
+
79
+ # xpath for this element.
80
+ def selector
81
+ p @parent
82
+ sel = ""
83
+ if @parent && @parent.getId()
84
+ sel += @parent.selector()
85
+ end
86
+ sel += node()
87
+ return sel
88
+ end
89
+
90
+ def getId()
91
+ return @id
92
+ end
93
+
94
+ def highlight
95
+ @selenium.highlight(selector())
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,32 @@
1
+
2
+ module Ext
3
+ class Field < Component
4
+
5
+ # attr_reader :name
6
+ # def init_component()
7
+ # @name = @selenium.get_eval("window.Ext.getCmp('#{@id}').getName()");
8
+ # end
9
+
10
+ def value= (v)
11
+ @selenium.type(@id, v)
12
+ blur
13
+ end
14
+
15
+ def blur
16
+ @selenium.fire_event(@id, "blur")
17
+ end
18
+
19
+ # user valid?
20
+ #def has_error?
21
+ # # using Ext.JS
22
+ # @selenium.get_eval("window.Ext.getCmp('#{@id}').isValid()") != "true"
23
+ #end
24
+
25
+ def value
26
+ # xpath or Ext?
27
+ # TODO: get more information from field (textarea or input[type=text])
28
+ @selenium.get_value(@id) #{}"//div[@id='#{@id}']//input")
29
+ # return @selenium.get_eval("window.Ext.getCmp('#{@id}').getValue()");
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+
2
+ module Ext
3
+ class FieldSet < Panel
4
+ def init_component()
5
+ super()
6
+ end
7
+
8
+ def collapsed=(flag)
9
+ if collapsed != flag
10
+ @selenium.click_at("//fieldset[@id='#{@id}']//*[contains(@class, 'x-tool-toggle') or @type='checkbox']", "0,0")
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+
2
+ module Ext
3
+ class Form < Ext::Panel
4
+
5
+ attr_reader :fields
6
+
7
+ def init_component()
8
+ super()
9
+
10
+ # # load all fields.
11
+ # fields = @selenium.get_eval("window.Ext.getCmp('#{@id}').findBy(function(el) { return el.getXTypes().indexOf('/field/') != -1 }).map(function(el) { return el.getId() })");
12
+ # @fields = {}
13
+ # fields.split(",").each do |field_id|
14
+ # field = @selenium.get_cmp(field_id, self);
15
+ # @fields[field.getName().to_sym] = field
16
+ # p field_id
17
+ # end
18
+ # # print @fields
19
+
20
+ end
21
+
22
+ # component/box/field/textfield
23
+ # window.Ext.ComponentMgr.all.find(function(el){ return el.getXType() == 'form' }).findBy(function(el) { console.debug(el.getXType()); })
24
+ end
25
+ end
@@ -0,0 +1,63 @@
1
+
2
+ module Ext
3
+ class Grid < Component
4
+ end
5
+
6
+ class EditorGrid < Grid
7
+
8
+
9
+ def click_at_cell(x,y)
10
+ @selenium.click_at(node() + "//div[contains(@class,'x-grid3-body')]//div[#{x}]//table//td[#{y}]", "0,0")
11
+ end
12
+
13
+ # number of lines of Grid (store!)
14
+ def num_rows()
15
+ @selenium.get_eval("window.Ext.getCmp('#{@id}').getStore().getCount()").to_i
16
+ end
17
+
18
+ def get_row(row)
19
+ len = @selenium.get_eval("window.Ext.getCmp('#{@id}').colModel.columns.length").to_i
20
+ ret = {}
21
+ len.times().each do |idx|
22
+ begin
23
+ data_index = @selenium.get_eval("window.Ext.getCmp('#{@id}').colModel.columns[#{idx}].dataIndex");
24
+ text = @selenium.get_text(node() + "//div[contains(@class,'x-grid3-body')]//div[#{row}]//table//td[#{idx+1}]")
25
+ ret[data_index.to_sym] = text
26
+ rescue Selenium::CommandError => ex
27
+ p ex
28
+ end
29
+ end
30
+ ret
31
+ end
32
+
33
+ def edit_row(row, data)
34
+ len = @selenium.get_eval("window.Ext.getCmp('#{@id}').colModel.columns.length").to_i
35
+ len.times().each do |idx|
36
+ print "window.Ext.getCmp('#{@id}').colModel.columns[#{idx}].getEditor().getId()"
37
+ begin
38
+ editable = @selenium.get_eval("window.Ext.getCmp('#{@id}').colModel.columns[#{idx}].getEditor().getId()");
39
+ click_at_cell(row, idx + 1)
40
+ # @selenium.highlight(node() + "//div[contains(@class,'x-grid3-body')]//div[#{row}]//table//td[#{idx+1}]")
41
+ @selenium.wait_for_component_visible(editable)
42
+ @selenium.type(node() + "//*[@id='#{editable}']", data[idx])
43
+ @selenium.fire_event(node() + "//*[@id='#{editable}']", "blur")
44
+ sleep 1
45
+ rescue RuntimeError => ex
46
+ p ex
47
+ end
48
+ end
49
+ end
50
+
51
+ # //div[contains(@class,"x-grid3-body")]//div[2]//table//td[3]
52
+ # // x-grid3-viewport
53
+ ## x-grid3-body
54
+ ## x-grid3-row x-grid3-row-first
55
+ ## //div[contains(@class,"x-grid3-body")]//div[2]
56
+ ## //div[contains(@class,"x-grid3-body")]//div[2]//table//td[2]
57
+
58
+ # Ext.getCmp("ext-comp-1005").store.getAt(2).data
59
+ # Ext.getCmp("ext-comp-1005").colModel.columns
60
+ # Ext.getCmp("ext-comp-1005").colModel.columns[0].getEditor().getXType()
61
+ # x-grid3-col
62
+ end
63
+ end
@@ -0,0 +1,53 @@
1
+
2
+ module Ext
3
+ class Panel < Component
4
+ attr_reader :items
5
+
6
+ def init_component()
7
+ @items = []
8
+ total = @selenium.get_eval("(window.Ext.getCmp('#{@id}').items)?(window.Ext.getCmp('#{@id}').items.length):0").to_i
9
+ total.times().each do |n|
10
+ cmp = get(n)
11
+ cmp.parent = self
12
+ @items << cmp
13
+ # p cmp
14
+ #Ext::build_cmp(@selenium.get_eval("window.Ext.getCmp('#{@id}').get(#{n}).getId()"), self)
15
+ end
16
+ end
17
+
18
+ def title
19
+ @selenium.get_eval("window.Ext.getCmp('#{@id}').title")
20
+ end
21
+ end
22
+
23
+ class TabPanel < Panel
24
+
25
+ =begin
26
+ def active_tab
27
+ tab = active_tab().getId()
28
+ # id = @selenium.get_eval("window.Ext.getCmp('#{@id}').getActiveTab().getId()")
29
+ p "--- active tab ---"
30
+ p id
31
+ p "?"
32
+ list = @items.select do |el|
33
+ p el.getId()
34
+ el.getId() == id
35
+ end
36
+ p list
37
+ return list.first()
38
+ end
39
+ =end
40
+
41
+ def active_tab=(param)
42
+ if param.is_a? String
43
+ if param =~ /^ext-/
44
+ # wait!
45
+ else
46
+ title = param
47
+ end
48
+ elsif param.is_a? Integer
49
+ @selenium.click_at( selector() + "//ul[contains(@class, 'x-tab-strip')]//li[#{param}]//span[contains(@class, 'x-tab-strip-text')]", "0,0")
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,8 @@
1
+
2
+ module Ext
3
+ class Window < Component
4
+ def close
5
+ @selenium.click_at( node() + "//div[contains(@class, 'x-tool-close')]", "0,0")
6
+ end
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: selenium-extjs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ronald Andreu Kaiser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-18 00:00:00 -02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: raios.catodicos@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ files:
25
+ - lib/selenium-extjs/component/Button.rb
26
+ - lib/selenium-extjs/component/Combo.rb
27
+ - lib/selenium-extjs/component/Component.rb
28
+ - lib/selenium-extjs/component/Field.rb
29
+ - lib/selenium-extjs/component/FieldSet.rb
30
+ - lib/selenium-extjs/component/Form.rb
31
+ - lib/selenium-extjs/component/Grid.rb
32
+ - lib/selenium-extjs/component/Panel.rb
33
+ - lib/selenium-extjs/component/Window.rb
34
+ - lib/selenium-extjs/Ext.rb
35
+ - lib/selenium-extjs/Selenium.rb
36
+ - lib/selenium-extjs.rb
37
+ - README.rdoc
38
+ has_rdoc: true
39
+ homepage: http://github.com/cathoderay/selenium-extjs
40
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.3.5
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: A framework in ruby to test your extjs applications with selenium
66
+ test_files: []
67
+