insite 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.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: '094a111c4101a5cb18a2f76c6d46625ba32b255f'
|
4
|
+
data.tar.gz: c850f4e79fb102e8ab477d0de0821b6ed4deeb5e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 97aa7fa4c708b17b6b9bea7ea4408fa1aa566de7e2b4fa543329a06d55a9bde2ca0c9e73dc461ea2c3dd2c8305849b6b2774972f258a2f97e565104a8c955d41
|
7
|
+
data.tar.gz: a42caf8bf52e5f90a28e6f1909e1d14a6b5938fbe26fcaa427ba8112a3a9cecc6da47bdbe47c5ebd87864cd8632527e6b9935a6fcfed6433983802a9af3e5c49
|
data/lib/insite.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'watir'
|
2
|
+
require 'watir-scroll'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/core_ext'
|
5
|
+
require 'addressable/template'
|
6
|
+
require 'nokogiri'
|
7
|
+
|
8
|
+
require "insite/constants"
|
9
|
+
require "insite/insite"
|
10
|
+
require "insite/errors"
|
11
|
+
require "insite/version"
|
12
|
+
|
13
|
+
# Modules with method definitions used by UI metaclasses.
|
14
|
+
require "insite/methods/dom_methods"
|
15
|
+
require "insite/methods/common_methods"
|
16
|
+
|
17
|
+
# Files for Insite::Widget.
|
18
|
+
require "insite/widget/widget"
|
19
|
+
require "insite/widget/widget_methods"
|
20
|
+
|
21
|
+
# Files for Insite::Feature.
|
22
|
+
require "insite/feature/feature"
|
23
|
+
|
24
|
+
# Files for ElementContainer.
|
25
|
+
require "insite/element_container/element_container"
|
26
|
+
|
27
|
+
# Files for pages (defined/undefined.)
|
28
|
+
require "insite/page/defined_page"
|
29
|
+
require "insite/page/undefined_page"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# DOM_ELEMENTS
|
2
|
+
# DOM_COLLECTIONS
|
3
|
+
|
4
|
+
# Watir DOM methods. This data is used to create class-level element accessors
|
5
|
+
# for page objects.
|
6
|
+
DOM_METHODS = %i(
|
7
|
+
a br datalists elements forms hidden li meshpatches params rect source tbody tspan
|
8
|
+
abbr brs datas ellipse frame hiddens line meshrow path rects sources tbodys tspans
|
9
|
+
abbrs bs date_field ellipses frames hr linear_gradient meshrows paths rp span td u
|
10
|
+
address button date_fields em frameset hrs linear_gradients meta pattern rps spans tds ul
|
11
|
+
addresses buttons date_time_field embed framesets htmls lines metadata patterns rt ss template uls
|
12
|
+
area canvas date_time_fields embeds g i link metadatas picture rtc stop templates us
|
13
|
+
areas canvases dd ems gs iframe links metas pictures rtcs stops text_field use
|
14
|
+
article caption dds extract_selector h1 iframes lis meter polygon rts strong text_fields uses
|
15
|
+
articles captions defs field_set h1s image main meters polygons rubies strongs text_path var
|
16
|
+
as checkbox defss field_sets h2 images mains nav polyline ruby style text_paths vars
|
17
|
+
aside checkboxes del fieldset h2s img map navs polylines s styles textarea video
|
18
|
+
asides circle dels fieldsets h3 imgs maps noscript pre samp sub textareas videos
|
19
|
+
audio circles desc figcaption h3s input mark noscripts pres samps subs tfoot view
|
20
|
+
audios cite descs figcaptions h4 inputs marker object progress script summaries tfoots views
|
21
|
+
b cites details figure h4s ins markers objects progresses scripts summary th wbr
|
22
|
+
base code detailses figures h5 inses marks ol ps section sup thead wbrs
|
23
|
+
bases codes dfn file_field h5s is menu ols q sections sups theads
|
24
|
+
bdi col dfns file_fields h6 kbd menuitem optgroup qs select svg ths
|
25
|
+
bdis colgroup div font h6s kbds menuitems optgroups radial_gradient select_list svgs time
|
26
|
+
bdo colgroups divs fonts hatchpath keygen menus option radial_gradients select_lists switch times
|
27
|
+
bdos cols dl footer hatchpaths keygens mesh options radio selects switches titles
|
28
|
+
blockquote cursor dls footers head label meshes output radio_set small symbol tr
|
29
|
+
blockquotes cursors dt foreign_object header labels meshgradient outputs radios smalls symbols track
|
30
|
+
body data dts foreign_objects headers legend meshgradients p rb solidcolor table tracks
|
31
|
+
bodys datalist element form heads legends meshpatch param rbs solidcolors tables trs
|
32
|
+
).freeze
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class ElementContainer
|
2
|
+
attr_reader :target, :site
|
3
|
+
|
4
|
+
include Insite::CommonMethods
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
class << self
|
8
|
+
include Insite::DOMMethods
|
9
|
+
end # self
|
10
|
+
|
11
|
+
def initialize(site, element)
|
12
|
+
@site = site
|
13
|
+
@browser = @site.browser
|
14
|
+
@target = element
|
15
|
+
|
16
|
+
# Temporary replacement for custom wait_until.
|
17
|
+
# TODO: Continue looking at scolling solutions.
|
18
|
+
if @target.present?
|
19
|
+
@target.scroll.to
|
20
|
+
t = Time.now + 2
|
21
|
+
while Time.now <= t do
|
22
|
+
break if @target.present?
|
23
|
+
sleep 0.1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
@target
|
28
|
+
end
|
29
|
+
|
30
|
+
# For page widget code.
|
31
|
+
def method_missing(sym, *args, &block)
|
32
|
+
if @target.respond_to? sym
|
33
|
+
if @target.is_a? Watir::ElementCollection
|
34
|
+
@target.map { |x| self.class.new(x) }.send(sym, *args, &block)
|
35
|
+
else
|
36
|
+
@target.send(sym, *args, &block)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Insite
|
2
|
+
module Errors
|
3
|
+
class Insite::Errors::BrowserClosedError < StandardError; end
|
4
|
+
class Insite::Errors::BrowserLibraryNotSupportedError < StandardError; end
|
5
|
+
class Insite::Errors::BrowserNotAvailableError < StandardError; end
|
6
|
+
class Insite::Errors::BrowserNotOpenError < StandardError; end
|
7
|
+
class Insite::Errors::BrowserNotValidError < StandardError; end
|
8
|
+
class Insite::Errors::BrowserResponseError < StandardError; end
|
9
|
+
class Insite::Errors::PageConfigError < StandardError; end
|
10
|
+
class Insite::Errors::PageInitError < StandardError; end
|
11
|
+
class Insite::Errors::PageNavigationError < StandardError; end
|
12
|
+
class Insite::Errors::PageNavigationNotAllowedError < StandardError; end
|
13
|
+
class Insite::Errors::SiteInitError < StandardError; end
|
14
|
+
class Insite::Errors::WrongPageError < StandardError; end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Insite
|
2
|
+
class Feature
|
3
|
+
attr_reader :args, :page, :page_elements, :browser
|
4
|
+
|
5
|
+
include Insite::CommonMethods
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :alias, :page_elements
|
9
|
+
|
10
|
+
include Insite::DOMMethods
|
11
|
+
include Insite::WidgetMethods
|
12
|
+
end # Self.
|
13
|
+
|
14
|
+
def initialize(site, **args)
|
15
|
+
if self.class.ancestors.include?(Insite::DefinedPage)
|
16
|
+
# if site.is_a? Insite:DefinedPage # TODO: Bandaid.
|
17
|
+
@site = site.site
|
18
|
+
@page = site
|
19
|
+
elsif site.class.ancestors.include?(Insite)
|
20
|
+
@site = site
|
21
|
+
@page = site.page
|
22
|
+
end
|
23
|
+
|
24
|
+
@args = args
|
25
|
+
@page = page
|
26
|
+
@browser = @site.browser
|
27
|
+
@page_elements = @site.page_elements
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,294 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
3
|
+
# Usage:
|
4
|
+
# require 'insite'
|
5
|
+
#
|
6
|
+
# class MySite
|
7
|
+
# include Insite
|
8
|
+
# end
|
9
|
+
module Insite
|
10
|
+
attr_reader :base_url, :unique_methods, :browser_type
|
11
|
+
attr_accessor :pages, :browser, :arguments, :most_recent_page
|
12
|
+
|
13
|
+
# Automatically sets up a Page class when Insite is included. Probably overkill
|
14
|
+
# but it protects against the case where two different sites are used at the
|
15
|
+
# same time: Each site will use its own page objects only.
|
16
|
+
def self.included(base)
|
17
|
+
mod = Module.new
|
18
|
+
base.const_set('WidgetMethods', mod)
|
19
|
+
|
20
|
+
klass = Class.new(DefinedPage)
|
21
|
+
base.const_set('Page', klass)
|
22
|
+
base::send(:extend, WidgetMethods)
|
23
|
+
|
24
|
+
klass = Class.new(UndefinedPage)
|
25
|
+
base.const_set('UndefinedPage', klass)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns true if there's an open browser (that's also responding.) False if not.
|
29
|
+
def browser?
|
30
|
+
begin
|
31
|
+
@browser.exists?
|
32
|
+
rescue => e
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Closes the site object's browser/driver.
|
38
|
+
def close
|
39
|
+
@browser.close
|
40
|
+
end
|
41
|
+
|
42
|
+
def describe
|
43
|
+
puts <<-EOF
|
44
|
+
Wrapper class for all pages defined for the site.
|
45
|
+
Site:\t#{self.class} (#{__FILE__})
|
46
|
+
Base URL:\t#{@base_url}
|
47
|
+
Browser:\t#{@browser}
|
48
|
+
Current Page:\t#{page.class}
|
49
|
+
|
50
|
+
Page Accessor Methods (Use '?' with name to check for presence.)
|
51
|
+
-----------------------------------------------------------------
|
52
|
+
#{
|
53
|
+
tmp = []
|
54
|
+
max = pages.map(&:to_s).max { |x| x.length }
|
55
|
+
if max.length > 40
|
56
|
+
pages.map(&:to_s).sort.map(&:underscore).join("\n")
|
57
|
+
else
|
58
|
+
pages.map(&:to_s).sort.map(&:underscore).each_slice(2) do |arr|
|
59
|
+
tmp << arr[0].to_s.ljust(40) + arr[1].to_s.ljust(40)
|
60
|
+
end
|
61
|
+
tmp.join("\n")
|
62
|
+
end
|
63
|
+
}
|
64
|
+
EOF
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns a Selenium driver object.
|
68
|
+
def driver
|
69
|
+
@browser.driver
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns true if there's an open driver (that's also responding.) False if not.
|
73
|
+
def driver?
|
74
|
+
browser?
|
75
|
+
end
|
76
|
+
|
77
|
+
# Creates a site object, which will have accessor methods for all pages that
|
78
|
+
# you have defined for the site. This object takes a hash argument. There is
|
79
|
+
# only one required value (the base_url for the site.) Example:
|
80
|
+
#
|
81
|
+
# class MySite
|
82
|
+
# include Insite
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# # Note: This base URL can be overridden when defining a page.
|
86
|
+
# site = MySite.new("https://foo.com")
|
87
|
+
#
|
88
|
+
# You can also specify any other arguments that you want for later use:
|
89
|
+
#
|
90
|
+
# site = MySite.new("http://foo.com", arg1, arg2, key1: val1, key2: val2)
|
91
|
+
#
|
92
|
+
# site.foo
|
93
|
+
# => true
|
94
|
+
# site.bar
|
95
|
+
# => 1
|
96
|
+
# TODO: Sort args.
|
97
|
+
def initialize(base_url, **hsh)
|
98
|
+
@arguments = hsh.with_indifferent_access
|
99
|
+
@base_url = base_url
|
100
|
+
@browser_type = (@arguments[:browser] ? @arguments[:browser].to_sym : nil)
|
101
|
+
@pages = self.class::DefinedPage.descendants.reject { |p| p.page_template? }
|
102
|
+
|
103
|
+
# Set up accessor methods for each page and page checking methods..
|
104
|
+
@pages.each do |current_page|
|
105
|
+
unless current_page.page_template?
|
106
|
+
current_page.set_url_template(@base_url)
|
107
|
+
|
108
|
+
if current_page.url_matcher
|
109
|
+
unless current_page.url_matcher.is_a? Regexp
|
110
|
+
raise Insite::Errors::PageConfigError,
|
111
|
+
"A url_matcher was defined for the #{current_page} page but it was not a " \
|
112
|
+
"regular expression. Check the value provided to the set_url_matcher method " \
|
113
|
+
"in the class definition for this page. Object provided was a " \
|
114
|
+
"#{current_page.url_matcher.class.name}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
self.class.class_eval do
|
119
|
+
define_method(current_page.to_s.underscore) do |args = nil, block = nil|
|
120
|
+
current_page.new(self, args)
|
121
|
+
end
|
122
|
+
|
123
|
+
define_method("#{current_page.to_s.underscore}?") do
|
124
|
+
on_page? current_page
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
visited = Set.new
|
131
|
+
tmp = @pages.map {|p| p.instance_methods }.flatten
|
132
|
+
tmp.each do |element|
|
133
|
+
if visited.include?(element)
|
134
|
+
else
|
135
|
+
visited << element
|
136
|
+
end
|
137
|
+
end
|
138
|
+
@unique_methods = visited
|
139
|
+
end
|
140
|
+
|
141
|
+
# Custom inspect method so that console output doesn't get in the way when debugging.
|
142
|
+
def inspect
|
143
|
+
"#<#{self.class.name}:0x#{object_id}\n @base_url=\"#{@base_url}\" " \
|
144
|
+
"@most_recent_page=#{@most_recent_page}>"
|
145
|
+
end
|
146
|
+
|
147
|
+
# In cases where Insite doesn't recognize a method call it will try to do the following:
|
148
|
+
# - Delegate the method call to the most recently accessed page, which is stored in
|
149
|
+
# Insite#most_recent_page.
|
150
|
+
#
|
151
|
+
# - If the cached page doesn't respond to the method, Insite will update the cache and
|
152
|
+
# then try to delegate the method again.
|
153
|
+
#
|
154
|
+
# If delegation doesn't work then a NoMethodError will be raised with some details about
|
155
|
+
# what was attempted.
|
156
|
+
def method_missing(sym, *args, &block)
|
157
|
+
original_page = @most_recent_page
|
158
|
+
if original_page.respond_to?(sym)
|
159
|
+
original_page.public_send(sym, *args, &block)
|
160
|
+
else
|
161
|
+
new_page = page
|
162
|
+
if new_page.respond_to?(sym)
|
163
|
+
page.public_send(sym, *args, &block)
|
164
|
+
else
|
165
|
+
raise(
|
166
|
+
NoMethodError,
|
167
|
+
"Unable to apply #{sym}. The site object doesn't support it and the" \
|
168
|
+
"currently displayed page doesn't support it either.\n" \
|
169
|
+
"Page:\t\t#{new_page.class}\n" \
|
170
|
+
"Current URL:\t#{@browser.url}\n\n",
|
171
|
+
caller
|
172
|
+
)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns true or false depending on whether the specified page is displayed. You can use a page
|
178
|
+
# object or a PageObject class name to identify the page you are looking for. Examples:
|
179
|
+
#
|
180
|
+
# page = site.account_summary_page
|
181
|
+
# =>#<AccountSummaryPage:70341126478080 ...>
|
182
|
+
# site.on_page? page
|
183
|
+
# =>true
|
184
|
+
#
|
185
|
+
# site.on_page? AccountSummaryPage
|
186
|
+
# =>true
|
187
|
+
#
|
188
|
+
# If no arguments are provided, the currently displayed page will be checked. If a
|
189
|
+
# matching page object can be found then true will be returned. if there's no matching
|
190
|
+
# page object, false will be returned.
|
191
|
+
#
|
192
|
+
# Insite caches the most recently accessed page. This method updates that cached value,
|
193
|
+
# which can be accessed by calling Insite#most_recent_page.
|
194
|
+
def on_page?(page_arg = nil)
|
195
|
+
if page_arg
|
196
|
+
if pages.include?(page_arg) # See if the currently displayed page has the same class.
|
197
|
+
if @most_recent_page == page_arg && @most_recent_page.on_page?
|
198
|
+
true
|
199
|
+
else
|
200
|
+
@most_recent_page = page
|
201
|
+
@most_recent_page.class == page_arg
|
202
|
+
end
|
203
|
+
else # See if the currently displayed page is the same type of object.
|
204
|
+
if @most_recent_page == page_arg
|
205
|
+
@most_recent_page.on_page?
|
206
|
+
else
|
207
|
+
@most_recent_page = page
|
208
|
+
@most_recent_page == page_arg
|
209
|
+
end
|
210
|
+
end
|
211
|
+
else # Just see if the currently displayed page has been defined.
|
212
|
+
if @most_recent_page.defined? && @most_recent_page.on_page?
|
213
|
+
true
|
214
|
+
else
|
215
|
+
@most_recent_page = page
|
216
|
+
@most_recent_page.on_page?
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Opens a browser. The arguments used here get passed down to the browser
|
222
|
+
# constructor. Example:
|
223
|
+
# s = SomeSite.new("http://foo.com")
|
224
|
+
# s.open :firefox
|
225
|
+
def open(btype = nil, *args)
|
226
|
+
browser_platform = btype ||= @browser_type
|
227
|
+
|
228
|
+
if browser_platform
|
229
|
+
self.instance_variable_set(
|
230
|
+
:@browser,
|
231
|
+
Watir::Browser.new(browser_platform, *args)
|
232
|
+
)
|
233
|
+
else
|
234
|
+
self.instance_variable_set(
|
235
|
+
:@browser,
|
236
|
+
Watir::Browser.new(*args)
|
237
|
+
)
|
238
|
+
end
|
239
|
+
|
240
|
+
Watir.logger.level = :error
|
241
|
+
self
|
242
|
+
end
|
243
|
+
|
244
|
+
# Looks at the page currently being displayed in the browser and tries to
|
245
|
+
# return a page object for it. Does this by looking at the currently displayed
|
246
|
+
# URL in the browser.
|
247
|
+
#
|
248
|
+
# If a matching page can't be found then Insite will return an "undefined page"
|
249
|
+
# object. See the Un class for more details.
|
250
|
+
def page
|
251
|
+
return @most_recent_page if @most_recent_page && @most_recent_page.on_page?
|
252
|
+
url = @browser.url
|
253
|
+
found_page = nil
|
254
|
+
@pages.each do |pg|
|
255
|
+
if pg.url_matcher && pg.url_matcher =~ url
|
256
|
+
found_page = pg
|
257
|
+
elsif !pg.url_matcher && pg.url_template.match(url)
|
258
|
+
found_page = pg
|
259
|
+
else
|
260
|
+
next
|
261
|
+
end
|
262
|
+
|
263
|
+
break if found_page
|
264
|
+
end
|
265
|
+
|
266
|
+
if found_page && found_page.required_arguments.present?
|
267
|
+
if hsh = found_page.url_template.extract(url)
|
268
|
+
return found_page.new(self, found_page.url_template.extract(url))
|
269
|
+
else
|
270
|
+
return found_page.new(self, found_page.url_template.extract(url.split(/(\?|#)/)[0]))
|
271
|
+
end
|
272
|
+
elsif found_page
|
273
|
+
return found_page.new(self)
|
274
|
+
else
|
275
|
+
return UndefinedPage.new(self)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def text
|
280
|
+
@browser.text
|
281
|
+
end
|
282
|
+
|
283
|
+
# Returns an Addressable::URI object for the current browser URL.
|
284
|
+
def uri
|
285
|
+
Addressable::URI.parse(@browser.url)
|
286
|
+
end
|
287
|
+
|
288
|
+
# Returns the current browser URL.
|
289
|
+
def url
|
290
|
+
@browser.url
|
291
|
+
end
|
292
|
+
|
293
|
+
at_exit { @browser.close if @browser }
|
294
|
+
end
|