capybarista 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5d190cddc7761afa7b8b64d03980227c46051ddc
4
+ data.tar.gz: 58e660f9a37c9254f24dce17eb91aab10f0cd79e
5
+ SHA512:
6
+ metadata.gz: 21e7f7a7399b56dbef611917f9e7d0b16fc3d0df53cbf357ac166353c4cd157282bf8c5ee839efcfd7bdb4283b83be6c12fc637b8b90db1c6a82d120a57c3ae4
7
+ data.tar.gz: a50372ff46a47aeb66f3e73ddfe84e6c79b2e350429eec58baa0e94ace4320c2042a7af9ded6ac3d2960544b5d57cd13f9fe6d8b849fc4a02381308976cc9ee1
@@ -0,0 +1,111 @@
1
+
2
+ require 'capybarista/extensions'
3
+
4
+ module Capybarista
5
+
6
+ module Finders
7
+
8
+ def all(*args)
9
+ basis.all(*args).map{|f| Capybarista::Element.for(f) }
10
+ end
11
+
12
+ def find(*args)
13
+ Capybarista::Element.for basis.find(*args)
14
+ end
15
+
16
+ def find_button(*args)
17
+ Capybarista::Element.for basis.find_button(*args)
18
+ end
19
+
20
+ def find_by_id(*args)
21
+ Capybarista::Element.for basis.find_by_id(*args)
22
+ end
23
+
24
+ def find_field(*args)
25
+ Capybarista::Element.for basis.find_field(*args)
26
+ end
27
+
28
+ def find_link(*args)
29
+ Capybarista::Element.for basis.find_link(*args)
30
+ end
31
+
32
+ def first(*args)
33
+ Capybarista::Element.for basis.first(*args)
34
+ end
35
+
36
+ end
37
+
38
+
39
+
40
+ class Session
41
+ include Capybarista::Finders
42
+ include Capybarista::Extensions::Session
43
+
44
+ attr_reader :basis
45
+
46
+ def initialize(capybara_session)
47
+ @basis = capybara_session
48
+ end
49
+
50
+ def self.for(input)
51
+ if input.is_a? Capybarista::Session
52
+ return input
53
+ else
54
+ return Capybarista::Session.new input
55
+ end
56
+ end
57
+
58
+
59
+ def within(input, *args, &block)
60
+ input = Capybarista::Element.unwrap(input)
61
+ @basis.within(input, *args, &block)
62
+ end
63
+
64
+
65
+
66
+ def method_missing(name, *args, &block)
67
+ @basis.public_send(name, *args, &block)
68
+ end
69
+
70
+ end
71
+
72
+
73
+
74
+ class Element
75
+ include Capybarista::Finders
76
+ include Capybarista::Extensions::Element
77
+
78
+ attr_reader :basis, :session
79
+
80
+ def initialize(element, session)
81
+ @basis = element
82
+ @session = session
83
+ end
84
+
85
+ def self.for(input, session = nil)
86
+ if input.is_a? Capybarista::Element
87
+ return input
88
+ else
89
+ session ||= Capybarista::Session.new(input.session)
90
+ return Capybarista::Element.new input
91
+ end
92
+ end
93
+
94
+
95
+ def self.unwrap(input)
96
+ while input.is_a? Capybarista::Element
97
+ input = input.basis
98
+ end
99
+ input
100
+ end
101
+
102
+
103
+
104
+ def method_missing(name, *args, &block)
105
+ @basis.public_send(name, *args, &block)
106
+ end
107
+
108
+ end
109
+
110
+
111
+ end
@@ -0,0 +1,197 @@
1
+
2
+ require 'capybara'
3
+
4
+ require 'capybarista/queries'
5
+ require 'capybarista/unique_xpath'
6
+ require 'capybarista/javascript'
7
+
8
+ require 'logbert'
9
+
10
+ module Capybarista
11
+
12
+ module Extensions
13
+ LOG = Logbert[self]
14
+
15
+ J = Capybarista::Javascript
16
+
17
+ def self.applied?
18
+ @applied
19
+ end
20
+
21
+ def self.apply!
22
+
23
+ if applied?
24
+ LOG.debug "Capybarista extensions have already been applied"
25
+ else
26
+ Capybara::Session.class_eval do
27
+ include Capybarista::Extensions::Session
28
+ end
29
+
30
+ Capybara::Node::Element.class_eval do
31
+ include Capybarista::Extensions::Element
32
+ end
33
+
34
+ @applied = true
35
+ LOG.warning "Capybara::Session and Capybara::Node::Element have been monkey-patched w/ the Capybarista extensions"
36
+ end
37
+
38
+ end
39
+
40
+
41
+ module Base
42
+
43
+ # Returns the list of fields that require user input.
44
+ def all_fields(options = {})
45
+ all(:xpath, Capybarista::Queries::XPath.all_fields, options)
46
+ end
47
+
48
+ end
49
+
50
+
51
+ module Session
52
+ include Base
53
+
54
+ #this method returns a list of labels that are sorted from bottom up, right to left
55
+ def new_label_list
56
+ fields = all_fields(visible:true).map{|f| {f: f, pos: f.top_left} }
57
+ list_of_lists = fields.map{ |i| i[:pos] }
58
+ sorted_list = list_of_lists.sort {|item1, item2| item2[1]<=>item1[1]}
59
+ labels_list = Array.new
60
+ sorted_list.each do |item|
61
+ label = fields.find { |h| h[:pos] == item }[:f]
62
+ labels_list.push(label)
63
+ end
64
+ labels_list
65
+ end
66
+ end
67
+
68
+
69
+ module Element
70
+ include Base
71
+
72
+ # Syntactic sugar. Yum!
73
+ def scoped
74
+ s = session
75
+ s.within(self){ yield s }
76
+ end
77
+
78
+ # Returns a map containing only the specified attributes.
79
+ # If the element does not contain an attribute, then its
80
+ # key/value pairing will be omitted.
81
+ #
82
+ # FIXME: This methods filters attributes that are equal
83
+ # to the empty string :-(
84
+ def filtered_attributes(*keys)
85
+ retval = {}
86
+
87
+ keys.each do |k|
88
+ value = self[k]
89
+ if value and not value.empty?
90
+ retval[k] = value
91
+ end
92
+ end
93
+
94
+ return retval
95
+ end
96
+
97
+ # Returns 0 or more labels for the current element
98
+ def labels
99
+ ids = filtered_attributes(:id, :name).values
100
+
101
+ if ids.any?
102
+ query = Capybarista::Queries::XPath.labels_for(*ids)
103
+ return session.all(:xpath, query)
104
+ else
105
+ return []
106
+ end
107
+ end
108
+
109
+
110
+ # Attempts to find the label for the current element.
111
+ # If no label exists, then raise Capybara::ElementNotFound
112
+ def label!
113
+ ids = filtered_attributes(:id, :name).values
114
+
115
+ if ids.any?
116
+ query = Capybarista::Queries::XPath.labels_for(*ids)
117
+ return session.find(:xpath, query)
118
+ else
119
+ raise Capybara::ElementNotFound, "The element has no labels"
120
+ end
121
+ end
122
+
123
+
124
+ # Attempts to find the label for the current element.
125
+ # If no label exists, then return nil.
126
+ def label
127
+ ids = filtered_attributes(:id, :name).values
128
+ if ids.any?
129
+ query = Capybarista::Queries::XPath.labels_for(*ids)
130
+ return session.first(:xpath, query)
131
+ else
132
+ return nil
133
+ end
134
+ end
135
+
136
+ def top_left
137
+ long_function = %Q{
138
+ (
139
+ function(){
140
+ var obj = document.evaluate("#{unique_xpath}", document, null, XPathResult.ANY_TYPE, null ).iterateNext();
141
+ if(obj) {
142
+
143
+ var curleft = 0; var curtop = 0;
144
+ if (obj && obj.offsetParent) {
145
+ do {
146
+ curleft += obj.offsetLeft;
147
+ curtop += obj.offsetTop;
148
+ } while (obj = obj.offsetParent);
149
+ }
150
+ return [curleft,curtop];
151
+ };
152
+ }()
153
+ );
154
+ }
155
+ long_string = long_function.delete("\n")
156
+ session.evaluate_script(long_string)
157
+ end
158
+
159
+
160
+
161
+ def unique_xpath
162
+ Capybarista::UniqueXPath.for(self)
163
+ end
164
+
165
+ def inner_html
166
+ session.evaluate_script %Q{(function(){ var result = #{ J.find_xpath(unique_xpath) }; if(result) { return result.innerHTML; } }()); }
167
+ end
168
+
169
+
170
+ def outer_html
171
+ session.evaluate_script %Q{(function(){ var result = #{ J.find_xpath(unique_xpath) }; if(result) { return result.outerHTML; } }()); }
172
+ end
173
+
174
+
175
+ def highlight
176
+ session.execute_script %Q{(function(){ var result = #{ J.find_xpath(unique_xpath) }; if(result) { var old_color = result.style.backgroundColor; result.style.backgroundColor = "yellow"; setTimeout(function(){ result.style.backgroundColor = old_color; }, 1000); } }()); }
177
+ end
178
+
179
+
180
+ def blur
181
+ script = %Q{ (function() { var target = #{ J.find_xpath(unique_xpath) }; if(target) { var evt = document.createEvent("MouseEvents"); evt.initMouseEvent("blur", true, true,window, 1, 1, 1, 1, 1, false, false, false, false, 0, target); target.dispatchEvent(evt); } })(); }
182
+ session.execute_script(script)
183
+ end
184
+
185
+
186
+ def focus
187
+ script = %Q{ (function() { var target = #{ J.find_xpath(unique_xpath) }; if(target) { var evt = document.createEvent("MouseEvents"); evt.initMouseEvent("focus", true, true,window, 1, 1, 1, 1, 1, false, false, false, false, 0, target); target.dispatchEvent(evt); } })(); }
188
+ session.execute_script(script)
189
+ end
190
+
191
+
192
+ end
193
+
194
+
195
+ end
196
+
197
+ end
@@ -0,0 +1,19 @@
1
+
2
+
3
+ module Capybarista
4
+ module Javascript
5
+
6
+ # Generates a fragment of Javascript that will evaluate the
7
+ # specified XPath query.
8
+ def find_xpath(query)
9
+ %Q{document.evaluate("#{query}", document, null, XPathResult.ANY_TYPE, null ).iterateNext()}
10
+ end
11
+
12
+ module_function :find_xpath
13
+
14
+
15
+
16
+
17
+ end
18
+ end
19
+
@@ -0,0 +1,35 @@
1
+
2
+ require 'xpath'
3
+
4
+ module Capybarista
5
+
6
+ # This module contains a number of functions
7
+ # for generating XPath and CSS queries
8
+ module Queries
9
+
10
+ module XPath
11
+
12
+
13
+ def self.string(value)
14
+ # The underlying API changes betw/ versions
15
+ # 0.1.4 and 2.0.0 . So, let's wrap the method.
16
+ ::XPath::Expression::StringLiteral.new(value.to_s).to_xpath
17
+ end
18
+
19
+
20
+ # Queries returns all fields that accept user input
21
+ def self.all_fields
22
+ ".//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden' or ./@type='button')]"
23
+ end
24
+
25
+ def self.labels_for(*ids)
26
+ condition = ids.map{|id| "@for=#{string(id)}" }.join(" or ")
27
+ "//label[#{condition}]"
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
@@ -0,0 +1,46 @@
1
+
2
+ module Capybarista
3
+
4
+ module UniqueXPath
5
+
6
+ class UniquenessError < StandardError
7
+ end
8
+
9
+ def self.for(element)
10
+ session = element.session
11
+
12
+ fragments = []
13
+ loop do
14
+ fragments.unshift fragment(element)
15
+
16
+ query = "//" + fragments.join("/")
17
+
18
+ occurrences = session.all(:xpath, query).count
19
+ if occurrences == 1
20
+ return query
21
+ elsif occurrences == 0
22
+ raise UniquenessError, "Failed to produce a unique xpath for the element"
23
+ end
24
+
25
+ element = element.find(:xpath, "..")
26
+ end
27
+ end
28
+
29
+
30
+ def self.fragment(element)
31
+ tag = element.tag_name
32
+ id = element[:id]
33
+
34
+ if id.nil? or id.empty?
35
+ index = element.all(:xpath, "preceding-sibling::#{ tag }").count + 1
36
+ "#{tag}[#{index}]"
37
+ else
38
+ "#{tag}[@id='#{id}']"
39
+ end
40
+ end
41
+
42
+
43
+ end
44
+
45
+ end
46
+
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capybarista
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Brian Lauber
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capybara
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: xpath
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.4
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.1.4
41
+ - !ruby/object:Gem::Dependency
42
+ name: logbert
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.6.4
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.6.4
55
+ description: Useful extensions for Capybara
56
+ email: blauber@jibe.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - lib/capybarista/extensions.rb
62
+ - lib/capybarista/javascript.rb
63
+ - lib/capybarista/queries.rb
64
+ - lib/capybarista/unique_xpath.rb
65
+ - lib/capybarista.rb
66
+ homepage:
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 2.0.3
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: Useful extensions for Capybara
90
+ test_files: []