selenium-extjs 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+