insite 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/insite.rb +29 -0
- data/lib/insite/constants.rb +32 -0
- data/lib/insite/element_container/element_container.rb +42 -0
- data/lib/insite/errors.rb +16 -0
- data/lib/insite/feature/feature.rb +30 -0
- data/lib/insite/insite.rb +294 -0
- data/lib/insite/methods/common_methods.rb +216 -0
- data/lib/insite/methods/dom_methods.rb +60 -0
- data/lib/insite/page/defined_page.rb +518 -0
- data/lib/insite/page/undefined_page.rb +74 -0
- data/lib/insite/version.rb +3 -0
- data/lib/insite/widget/widget.rb +342 -0
- data/lib/insite/widget/widget_methods.rb +4 -0
- metadata +198 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
module Insite
|
2
|
+
class UndefinedPage
|
3
|
+
attr_reader :arguments, :browser, :has_fragment, :page_attributes, :page_elements, :page_features, :page_url, :query_arguments, :required_arguments, :site, :url_template, :url_matcher
|
4
|
+
|
5
|
+
include Insite::CommonMethods
|
6
|
+
|
7
|
+
# Always returns false.
|
8
|
+
def defined?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def describe
|
13
|
+
puts <<-EOF
|
14
|
+
Page Class:\t#{name} (#{__FILE__})
|
15
|
+
URL Template:\tNA
|
16
|
+
URL Matcher:\tNA
|
17
|
+
|
18
|
+
Page class for any page that hasn't been defined (or that Insite doesn't recognize.)
|
19
|
+
|
20
|
+
Note: If there is a page class that is defined for this page that isn't getting
|
21
|
+
loaded, try the following:
|
22
|
+
- Review the pages URL template for problems. A URL template is *not* an interpolated
|
23
|
+
string -- it just looks like one. See the documentation for more details.
|
24
|
+
- If the URL template seems to be designed correctly for loading the page, but the
|
25
|
+
page's URL changes after the load, you will need to look at adding a URL matcher,
|
26
|
+
which overrides the URL template for purposes of checking whether the page object
|
27
|
+
is matching the currently displayed page after it has been loaded.
|
28
|
+
|
29
|
+
Page Elements:\tNA
|
30
|
+
EOF
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(site)
|
34
|
+
@site = site
|
35
|
+
@browser = process_browser
|
36
|
+
@url = @site.browser.url
|
37
|
+
end
|
38
|
+
|
39
|
+
# TODO: Do the same cache check that's done for a defined page and reapply the
|
40
|
+
# method if the cache is updated and the new page DOES respond to the method.
|
41
|
+
def method_missing(mth, *args, &block)
|
42
|
+
raise NoMethodError, "Could not apply #{mth}. The current page could not be " \
|
43
|
+
"recognized. Current URL #{@browser.url}"
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns a Nokogiri object for the page HTML.
|
47
|
+
def nokogiri
|
48
|
+
@site.nokogiri
|
49
|
+
end
|
50
|
+
|
51
|
+
# Similar to the method that you can call on a page object you've defined (but always
|
52
|
+
# returns false since the Undefined page class is only returned when the current page
|
53
|
+
# doesn't match up to any page that you've actually defined.
|
54
|
+
def on_page?
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns an empty Array (since the page hasn't been defined.)
|
59
|
+
def page_elements
|
60
|
+
[]
|
61
|
+
end
|
62
|
+
alias_method :widget_elements, :page_elements
|
63
|
+
|
64
|
+
# Returns the current URL.
|
65
|
+
def url
|
66
|
+
@browser.url
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the page title displayed by the browser.
|
70
|
+
def title
|
71
|
+
@browser.title
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,342 @@
|
|
1
|
+
require_relative 'widget_methods'
|
2
|
+
require_relative '../methods/common_methods'
|
3
|
+
|
4
|
+
# Allows the page object developer to encapsulate common web application features
|
5
|
+
# into a "widget" that can be reused across multiple pages. Let's say that a
|
6
|
+
# web application has a search widget that is used in 11 of the application's pages.
|
7
|
+
# With a modern web app all of those search widgets will likely be implemented
|
8
|
+
# in a common way, with a similar or identical structure in the HTML. The widget
|
9
|
+
# would look something like this:
|
10
|
+
#
|
11
|
+
# class SearchWidget < Widget
|
12
|
+
# text_field :query, id: 'q'
|
13
|
+
# button :search_button, name: 'Search'
|
14
|
+
#
|
15
|
+
# def search(search_query)
|
16
|
+
# query.set search_query
|
17
|
+
# search_button.click
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def clear
|
21
|
+
# query.set ''
|
22
|
+
# search_button.click
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# Once the widget has been defined, it can be included in a page object definition
|
27
|
+
# like this:
|
28
|
+
#
|
29
|
+
# class SomePage < SomeSite::Page
|
30
|
+
# set_url 'some_page'
|
31
|
+
# search_widget :search_for_foo, :div, class: 'search-div'
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# The search widget can then be accessed like this when working with the site:
|
35
|
+
# site.some_page.search_for_foo 'some search term'
|
36
|
+
# site.search_for_foo.clear
|
37
|
+
#
|
38
|
+
# Widgets can be embedded in other widgets, but in that case, the arguments for
|
39
|
+
# accessing the child widget need to be RELATIVE to the parent widget. For example:
|
40
|
+
#
|
41
|
+
# # Generic link menu, you hover over it and one or more links are displayed.
|
42
|
+
# class LinkMenu < Widget
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # Card widget that uses the link_menu widget. In this case, link_menu widget
|
46
|
+
# # arguments will be used to find a div a div with class == 'card-action-links'
|
47
|
+
# # WITHIN the card itself. This ensures that, if there are multiple cards
|
48
|
+
# # on the page that have link_menus, the CORRECT link_menu will be accessed
|
49
|
+
# # rather than one for some other card widget.
|
50
|
+
# class Card < Widget
|
51
|
+
# link_menu :card_menu, :div, class: 'card-action-links'
|
52
|
+
# end
|
53
|
+
module Insite
|
54
|
+
class Widget
|
55
|
+
attr_reader :site, :browser, :type, :args, :target
|
56
|
+
|
57
|
+
include CommonMethods
|
58
|
+
alias_method :update_widget, :update_object
|
59
|
+
|
60
|
+
class << self
|
61
|
+
attr_reader :widget_elements
|
62
|
+
|
63
|
+
include DOMMethods
|
64
|
+
include WidgetMethods
|
65
|
+
|
66
|
+
# - Don't allow the user to create a widget with a name that matches a DOM
|
67
|
+
# element.
|
68
|
+
#
|
69
|
+
# - Don't allow the user to create a widget method that references a
|
70
|
+
# collection (because this will be done automatically.)
|
71
|
+
tmp = name.to_s.underscore.to_sym
|
72
|
+
if DOM_METHODS.include?(name.to_s.underscore.to_sym)
|
73
|
+
raise "#{name} cannot be used as a widget name, as the methodized version of the class name (#{name.to_s.underscore} conflicts with a Watir DOM method.)"
|
74
|
+
elsif Watir::Browser.methods.include?(name.to_s.underscore.to_sym)
|
75
|
+
raise "#{name} cannot be used as a widget name, as the methodized version of the class name (#{name.to_s.underscore} conflicts with a Watir::Browser method.)"
|
76
|
+
end
|
77
|
+
|
78
|
+
if tmp =~ /.*s+/
|
79
|
+
raise "Invalid widget type :#{tmp}. You can create a widget for the DOM object but it must be for :#{tmp.singularize} (:#{tmp} will be created automatically.)"
|
80
|
+
end
|
81
|
+
end # Self.
|
82
|
+
|
83
|
+
extend Forwardable
|
84
|
+
|
85
|
+
def self.inherited(subclass)
|
86
|
+
name_string = subclass.name.demodulize.underscore
|
87
|
+
pluralized_name_string = name_string.pluralize
|
88
|
+
|
89
|
+
if name_string == pluralized_name_string
|
90
|
+
raise ArgumentError, "When defining a new widget, define the singular version only (Plural case will be handled automatically.)"
|
91
|
+
end
|
92
|
+
|
93
|
+
# Creates an accessor method for a new widget when one gets defined via inheritance.
|
94
|
+
# In this case the method is for a single instance of the widget. The top-level block
|
95
|
+
# defines the widget accessor in the Insite::Widget module. The methods in that module
|
96
|
+
# automatically get included in page classes and are used to define widget accessors.
|
97
|
+
#
|
98
|
+
# In this case an accessor for an individual widget is being defined.
|
99
|
+
WidgetMethods.send(:define_method, name_string) do |method_name, dom_type, *args, &block|
|
100
|
+
unless name_string == 'Widget'
|
101
|
+
@widget_elements ||= []
|
102
|
+
@widget_elements << method_name.to_sym unless @widget_elements.include?(method_name.to_sym)
|
103
|
+
|
104
|
+
define_method(method_name) do
|
105
|
+
if is_a? Widget
|
106
|
+
elem = send(dom_type, *args, &block)
|
107
|
+
else
|
108
|
+
elem = @browser.send(dom_type, *args, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
# TODO: Bandaid.
|
112
|
+
if dom_type.to_s == dom_type.to_s.pluralize
|
113
|
+
raise ArgumentError, "Individual widget method :#{method_name} cannot initialize a widget using an element collection (#{elem.class}.) Use :#{method_name.pluralize} rather than :#{method_name} if you want to define a widget collection."
|
114
|
+
else
|
115
|
+
subclass.new(self, dom_type, *args, &block)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Creates an accessor method for a new widget when one gets defined via inheritance.
|
122
|
+
# In this case the method is for a single instance of the widget. The top-level block
|
123
|
+
# defines the widget accessor in the Insite::Widget module. The methods in that module
|
124
|
+
# automatically get included in page classes and are used to define widget accessors.
|
125
|
+
#
|
126
|
+
# In this case an accessor is being defined for a widget collection.
|
127
|
+
#
|
128
|
+
# TODO: The current implementation for widget collections isn't ideal and should be
|
129
|
+
# replaced at some point. It'd be much better to use a (lazy) custom collection for this.
|
130
|
+
WidgetMethods.send(:define_method, pluralized_name_string) do |method_name, dom_type, *args, &block|
|
131
|
+
unless name_string == 'Widget'
|
132
|
+
@widget_elements ||= []
|
133
|
+
@widget_elements << method_name.to_sym unless @widget_elements.include?(method_name.to_sym)
|
134
|
+
|
135
|
+
define_method(method_name) do
|
136
|
+
if is_a?(Widget) && present?
|
137
|
+
elem = send(dom_type, *args, &block)
|
138
|
+
elsif is_a?(Widget) && !present?
|
139
|
+
return []
|
140
|
+
else
|
141
|
+
elem = @browser.send(dom_type, *args, &block)
|
142
|
+
end
|
143
|
+
|
144
|
+
# TODO: Bandaid.
|
145
|
+
if dom_type.to_s == dom_type.to_s.singularize
|
146
|
+
raise ArgumentError, "Widget collection method :#{method_name} cannot initialize a widget collection using an individual element (#{elem.class}.) Use :#{method_name.to_s.singularize} rather than :#{method_name} if you want to define a widget for an individual element."
|
147
|
+
else
|
148
|
+
# TODO: Revisit the whole .to_a thing, need a custom collection or
|
149
|
+
# somesuch (don't bypass watir wait logic.)
|
150
|
+
t = Time.now
|
151
|
+
loop do
|
152
|
+
elem = @browser.send(dom_type, *args, &block)
|
153
|
+
break if elem.present? && elem.length > 0
|
154
|
+
break if Time.now > t + 4
|
155
|
+
end
|
156
|
+
|
157
|
+
if elem.present?
|
158
|
+
elem.to_a.map! { |x| subclass.new(self, x, [], &block) }
|
159
|
+
else
|
160
|
+
[]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end # self.
|
167
|
+
|
168
|
+
# This method gets used 2 different ways. Most of the time, dom_type and args
|
169
|
+
# will be a symbol and a set of hash arguments that will be used to locate an
|
170
|
+
# element.
|
171
|
+
#
|
172
|
+
# In some cases, dom_type can be a Watir DOM object, and in this case, the
|
173
|
+
# args are ignored and the widget is initialized using the Watir object.
|
174
|
+
#
|
175
|
+
# TODO: Needs a rewrite, lines between individual and collection are blurred
|
176
|
+
# here and that makes the code more confusing. And there should be a proper
|
177
|
+
# collection class for element collections, with possibly some AR-like accessors.
|
178
|
+
def initialize(parent, dom_type, *args)
|
179
|
+
@parent = parent
|
180
|
+
@site = parent.class.ancestors.include?(Insite) ? parent : parent.site
|
181
|
+
@browser = @site.browser
|
182
|
+
@widget_elements = self.class.widget_elements
|
183
|
+
|
184
|
+
if dom_type.is_a?(Watir::HTMLElement) || dom_type.is_a?(Watir::Element)
|
185
|
+
@dom_type = nil
|
186
|
+
@args = nil
|
187
|
+
@target = dom_type
|
188
|
+
elsif [String, Symbol].include? dom_type.class
|
189
|
+
@dom_type = dom_type
|
190
|
+
@args = args
|
191
|
+
|
192
|
+
if @parent.is_a? Widget
|
193
|
+
@target = @parent.send(dom_type, *args)
|
194
|
+
else
|
195
|
+
@target = @browser.send(dom_type, *args)
|
196
|
+
end
|
197
|
+
|
198
|
+
# New webdriver approach.
|
199
|
+
begin
|
200
|
+
@target.scroll.to
|
201
|
+
sleep 0.1
|
202
|
+
rescue => e
|
203
|
+
t = Time.now + 2
|
204
|
+
while Time.now <= t do
|
205
|
+
break if @target.present?
|
206
|
+
sleep 0.1
|
207
|
+
end
|
208
|
+
end
|
209
|
+
elsif dom_type.is_a? Watir::ElementCollection
|
210
|
+
@dom_type = nil
|
211
|
+
@args = nil
|
212
|
+
if @parent.is_a? Widget
|
213
|
+
@target = dom_type.map { |x| self.class.new(@parent, x.to_subtype) }
|
214
|
+
else
|
215
|
+
@target = dom_type.map { |x| self.class.new(@site, x.to_subtype) }
|
216
|
+
end
|
217
|
+
else
|
218
|
+
raise "Unhandled exception."
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Delegates method calls down to the widget's wrapped element if the element supports the method.
|
223
|
+
#
|
224
|
+
# Supports dynamic link methods. Examples:
|
225
|
+
# s.accounts_page account
|
226
|
+
#
|
227
|
+
# # Nav to linked page only.
|
228
|
+
# s.account_actions.edit_account_info
|
229
|
+
#
|
230
|
+
# # Update linked page after nav:
|
231
|
+
# s.account_actions.edit_account_info username: 'foo'
|
232
|
+
#
|
233
|
+
# # Link with modal (if the modal requires args they should be passed as hash keys):
|
234
|
+
# # s.hosted_pages.refresh_urls
|
235
|
+
def method_missing(mth, *args, &block)
|
236
|
+
if @target.respond_to? mth
|
237
|
+
@target.send(mth, *args, &block)
|
238
|
+
else
|
239
|
+
if args[0].is_a? Hash
|
240
|
+
page_arguments = args[0]#.with_indifferent_access
|
241
|
+
elsif args.empty?
|
242
|
+
# Do nothing.
|
243
|
+
elsif args[0].nil?
|
244
|
+
raise ArgumentError, "Optional argument for :#{mth} must be a hash. Got NilClass."
|
245
|
+
else
|
246
|
+
raise ArgumentError, "Optional argument must be a hash (got #{args[0].class}.)"
|
247
|
+
end
|
248
|
+
|
249
|
+
if present?
|
250
|
+
# If it's a widget we want to hover over it to ensure links are visible
|
251
|
+
# before trying to find them.
|
252
|
+
if self.is_a?(Widget)
|
253
|
+
t = Time.now
|
254
|
+
loop do
|
255
|
+
begin
|
256
|
+
scroll.to
|
257
|
+
hover
|
258
|
+
sleep 0.2
|
259
|
+
break
|
260
|
+
rescue => e
|
261
|
+
break if Time.now > t + 10
|
262
|
+
sleep 0.2
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
# Dynamic helper method, returns DOM object for link (no validation).
|
268
|
+
if mth.to_s =~ /_link$/
|
269
|
+
return a(text: /^#{mth.to_s.sub(/_link$/, '').gsub('_', '.*')}/i)
|
270
|
+
# Dynamic helper method, returns DOM object for button (no validation).
|
271
|
+
elsif mth.to_s =~ /_button$/
|
272
|
+
return button(value: /^#{mth.to_s.sub(/_button$/, '').gsub('_', '.*')}/i)
|
273
|
+
# Dynamic helper method for links. If a match is found, clicks on the link and performs follow up actions.
|
274
|
+
elsif elem = as.find { |x| x.text =~ /^#{mth.to_s.gsub('_', '.*')}/i } # See if there's a matching button and treat it as a method call if so.
|
275
|
+
elem.click
|
276
|
+
sleep 1
|
277
|
+
|
278
|
+
current_page = @site.page
|
279
|
+
|
280
|
+
if page_arguments.present?
|
281
|
+
|
282
|
+
if current_page.respond_to?(:submit)
|
283
|
+
current_page.submit page_arguments
|
284
|
+
elsif @browser.input(xpath: "//div[starts-with(@class,'Row') and last()]//input[@type='submit' and last()]").present?
|
285
|
+
current_page.update_page page_arguments
|
286
|
+
@browser.input(xpath: "//div[starts-with(@class,'Row') and last()]//input[@type='submit' and last()]").click
|
287
|
+
end
|
288
|
+
current_page = @site.page
|
289
|
+
end
|
290
|
+
# Dynamic helper method for buttons. If a match is found, clicks on the link and performs follow up actions.
|
291
|
+
elsif elem = buttons.find { |x| x.text =~ /^#{mth.to_s.gsub('_', '.*')}/i } # See if there's a matching button and treat it as a method call if so.
|
292
|
+
elem.click
|
293
|
+
sleep 1
|
294
|
+
|
295
|
+
if @site.modal.present?
|
296
|
+
@site.modal.continue(page_arguments)
|
297
|
+
else
|
298
|
+
current_page = @site.page
|
299
|
+
|
300
|
+
if page_arguments.present?
|
301
|
+
if current_page.respond_to?(:submit)
|
302
|
+
current_page.submit page_arguments
|
303
|
+
elsif @browser.input(xpath: "//div[starts-with(@class,'Row') and last()]//input[@type='submit' and last()]").present?
|
304
|
+
current_page.update_page page_arguments
|
305
|
+
@browser.input(xpath: "//div[starts-with(@class,'Row') and last()]//input[@type='submit' and last()]").click
|
306
|
+
end
|
307
|
+
current_page = @site.page
|
308
|
+
end
|
309
|
+
end
|
310
|
+
else
|
311
|
+
raise NoMethodError, "undefined method `#{mth}' for #{self.class}."
|
312
|
+
end
|
313
|
+
else
|
314
|
+
raise NoMethodError, "Unhandled method call `#{mth}' for #{self.class} (The widget was not present in the DOM at the point that the method was called.)"
|
315
|
+
end
|
316
|
+
|
317
|
+
page_arguments.present? ? page_arguments : current_page
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def present?
|
322
|
+
sleep 0.1
|
323
|
+
begin
|
324
|
+
if @parent
|
325
|
+
if @parent.present? && @target.present?
|
326
|
+
true
|
327
|
+
else
|
328
|
+
false
|
329
|
+
end
|
330
|
+
else
|
331
|
+
if @target.present?
|
332
|
+
true
|
333
|
+
else
|
334
|
+
false
|
335
|
+
end
|
336
|
+
end
|
337
|
+
rescue => e
|
338
|
+
false
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
metadata
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: insite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Fitisoff
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-04-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: addressable
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: watir
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 6.0.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 6.0.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: watir-scroll
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.2.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.2.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: coveralls
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rake
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rspec
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description: Page object library.
|
154
|
+
email: jfitisoff@yahoo.com
|
155
|
+
executables: []
|
156
|
+
extensions: []
|
157
|
+
extra_rdoc_files: []
|
158
|
+
files:
|
159
|
+
- lib/insite.rb
|
160
|
+
- lib/insite/constants.rb
|
161
|
+
- lib/insite/element_container/element_container.rb
|
162
|
+
- lib/insite/errors.rb
|
163
|
+
- lib/insite/feature/feature.rb
|
164
|
+
- lib/insite/insite.rb
|
165
|
+
- lib/insite/methods/common_methods.rb
|
166
|
+
- lib/insite/methods/dom_methods.rb
|
167
|
+
- lib/insite/page/defined_page.rb
|
168
|
+
- lib/insite/page/undefined_page.rb
|
169
|
+
- lib/insite/version.rb
|
170
|
+
- lib/insite/widget/widget.rb
|
171
|
+
- lib/insite/widget/widget_methods.rb
|
172
|
+
homepage: http://rubygems.org/gems/insite
|
173
|
+
licenses:
|
174
|
+
- MIT
|
175
|
+
metadata: {}
|
176
|
+
post_install_message:
|
177
|
+
rdoc_options: []
|
178
|
+
require_paths:
|
179
|
+
- lib
|
180
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
181
|
+
requirements:
|
182
|
+
- - ">="
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '0'
|
185
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
requirements: []
|
191
|
+
rubyforge_project:
|
192
|
+
rubygems_version: 2.5.2.1
|
193
|
+
signing_key:
|
194
|
+
specification_version: 4
|
195
|
+
summary: Wraps page objects up into a site object, which provides some introspection
|
196
|
+
and navigation capabilities that page objects don't provide. Works with Watir and
|
197
|
+
Selenium.
|
198
|
+
test_files: []
|