shiken 0.0.8 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/shiken +44 -0
- data/spec/google/spec_helper.rb +23 -0
- data/spec/google/test01_simple_spec.rb +11 -0
- metadata +7 -17
- data/lib/browser.rb +0 -266
- data/lib/button.rb +0 -7
- data/lib/clickable.rb +0 -22
- data/lib/downloads.rb +0 -80
- data/lib/dropdown.rb +0 -30
- data/lib/element.rb +0 -109
- data/lib/field.rb +0 -16
- data/lib/kendo.rb +0 -138
- data/lib/link.rb +0 -7
- data/lib/page.rb +0 -62
- data/lib/radio_set.rb +0 -20
- data/lib/shiken.rb +0 -83
- data/lib/table.rb +0 -56
- data/lib/trace.rb +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ced3037fa94afc954c1451d7232a39cbc40646b816dec0b0a677bbddd19f393
|
4
|
+
data.tar.gz: f5ffe32be611987465d5b999812deaff2c7db4b24903965b6a4972f1fb6a106a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cfd4db0f9c2709bb7d4fe4adc4d74a38c5c49328113d268e1c9486f169a82b648d3e794ec9f777f5121de903cecb3946044294dad72d921d7d1743cf8a4b7955
|
7
|
+
data.tar.gz: 55b4efe0c2714699e1f32d1e83620799e516730e84f1076858a331ea18b04f8f87e96b9852b2c48f6115db712beadf24441fa610cdb34d505ea03ddf6326c9dd
|
data/bin/shiken
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
class ShikenCLI < Thor
|
6
|
+
|
7
|
+
desc "hello NAME [FROM]", "say hello to NAME"
|
8
|
+
long_desc <<-LONGDESC
|
9
|
+
`shiken hello` will print out a message to a person of
|
10
|
+
your choosing.\n
|
11
|
+
You can optionally specify a second parameter, which will
|
12
|
+
print out a from message as well.\n
|
13
|
+
: $ shiken hello mike "Pat Conley"
|
14
|
+
\x5: from: Pat Conley
|
15
|
+
\x5: Hello mike!\n
|
16
|
+
LONGDESC
|
17
|
+
|
18
|
+
def hello(name, from=nil)
|
19
|
+
puts "from: #{from}" if from
|
20
|
+
puts "Hello #{name}!"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "install DIRECTORY", "create the directory with shiken helpers"
|
24
|
+
long_desc <<-LONGDESC
|
25
|
+
`shiken install` will create a subdirectory and populate it with
|
26
|
+
the shiken helper files.\n
|
27
|
+
The default directory is called webtests but the first parameter
|
28
|
+
is the name of the directory you prefer.\n
|
29
|
+
: $ shiken install my_tests
|
30
|
+
LONGDESC
|
31
|
+
|
32
|
+
def install(dir='webtests')
|
33
|
+
source = File.join(__dir__,"..","spec")
|
34
|
+
target = File.join(Dir.pwd, dir)
|
35
|
+
# puts "source = #{source}"
|
36
|
+
puts "creating and populating #{target}"
|
37
|
+
# puts "create complete [#{target}]"
|
38
|
+
FileUtils.copy_entry source, target
|
39
|
+
puts "copy complete"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
ShikenCLI.start(ARGV)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'shiken'
|
2
|
+
|
3
|
+
RSpec.configure do |config|
|
4
|
+
|
5
|
+
config.before :suite do |x|
|
6
|
+
# puts "*** before suite"
|
7
|
+
SK::init()
|
8
|
+
end
|
9
|
+
|
10
|
+
config.after :suite do |x|
|
11
|
+
# puts "*** after suite"
|
12
|
+
SK::quit()
|
13
|
+
end
|
14
|
+
|
15
|
+
config.expect_with :rspec do |expectations|
|
16
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
17
|
+
end
|
18
|
+
|
19
|
+
config.mock_with :rspec do |mocks|
|
20
|
+
mocks.verify_partial_doubles = true
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shiken
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pat Conley
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -40,24 +40,14 @@ dependencies:
|
|
40
40
|
version: '3.8'
|
41
41
|
description: A layer to simplify ruby use of selenium
|
42
42
|
email: pconley312@gmail.com
|
43
|
-
executables:
|
43
|
+
executables:
|
44
|
+
- shiken
|
44
45
|
extensions: []
|
45
46
|
extra_rdoc_files: []
|
46
47
|
files:
|
47
|
-
-
|
48
|
-
-
|
49
|
-
-
|
50
|
-
- lib/downloads.rb
|
51
|
-
- lib/dropdown.rb
|
52
|
-
- lib/element.rb
|
53
|
-
- lib/field.rb
|
54
|
-
- lib/kendo.rb
|
55
|
-
- lib/link.rb
|
56
|
-
- lib/page.rb
|
57
|
-
- lib/radio_set.rb
|
58
|
-
- lib/shiken.rb
|
59
|
-
- lib/table.rb
|
60
|
-
- lib/trace.rb
|
48
|
+
- bin/shiken
|
49
|
+
- spec/google/spec_helper.rb
|
50
|
+
- spec/google/test01_simple_spec.rb
|
61
51
|
homepage: https://github.com/pconley/Shiken.git
|
62
52
|
licenses:
|
63
53
|
- MIT
|
data/lib/browser.rb
DELETED
@@ -1,266 +0,0 @@
|
|
1
|
-
require 'selenium-webdriver'
|
2
|
-
require 'trace'
|
3
|
-
require 'uri'
|
4
|
-
|
5
|
-
module SK::Browser
|
6
|
-
|
7
|
-
extend self
|
8
|
-
|
9
|
-
### local utilities
|
10
|
-
|
11
|
-
def pause(secs,text="")
|
12
|
-
trace("pause #{secs} seconds #{text}")
|
13
|
-
sleep secs
|
14
|
-
end
|
15
|
-
def trace(s)
|
16
|
-
SK::Trace.trace(s)
|
17
|
-
end
|
18
|
-
def error(s)
|
19
|
-
SK::Trace.error(s)
|
20
|
-
end
|
21
|
-
def warn(s)
|
22
|
-
SK::Trace.notice(s)
|
23
|
-
end
|
24
|
-
|
25
|
-
###### main stuff #########
|
26
|
-
|
27
|
-
def goto(site,page='')
|
28
|
-
gotourl("https://#{site}/#{page}")
|
29
|
-
end
|
30
|
-
def gotox(site,page='')
|
31
|
-
gotourl("http://#{site}/#{page}")
|
32
|
-
end
|
33
|
-
def gotourl(url,seconds=1)
|
34
|
-
uri = URI.escape(url)
|
35
|
-
trace("go to #{uri}")
|
36
|
-
rescue_exceptions { SK::driver.get uri }
|
37
|
-
sleep seconds
|
38
|
-
end
|
39
|
-
|
40
|
-
def option(dd)
|
41
|
-
warn "browser.option is depricated. use SK::Dropdown instead"
|
42
|
-
Selenium::WebDriver::Support::Select.new(dd)
|
43
|
-
end
|
44
|
-
|
45
|
-
def select(locator,value)
|
46
|
-
dropdown(locator,"option",value)
|
47
|
-
end
|
48
|
-
|
49
|
-
def dropdown(locator,tagname,list_option)
|
50
|
-
warn "browser.dropdown is depricated. use SK::Dropdown instead. locator=#{locator}"
|
51
|
-
# actually returns the option object for the dropdown
|
52
|
-
# so the calling code can chain a select by method
|
53
|
-
# option(find({name: name}))
|
54
|
-
select_box = find(locator)
|
55
|
-
# select_box = $driver.find_element(locator)
|
56
|
-
_dropdown_el(select_box,tagname,list_option)
|
57
|
-
end
|
58
|
-
def _dropdown_el(select_box,tagname,list_option)
|
59
|
-
# trace "dropdown el... select_box=#{select_box}"
|
60
|
-
# trace "dropdown el... tagname=#{tagname} option=#{list_option}"
|
61
|
-
|
62
|
-
# actually returns the option object for the dropdown
|
63
|
-
# so the calling code can chain a select by method
|
64
|
-
# option(find({name: name}))
|
65
|
-
options = select_box.find_elements(:tag_name => "#{tagname}")
|
66
|
-
|
67
|
-
options.each do |option_field|
|
68
|
-
# trace "looking at #{option_field.text}"
|
69
|
-
if option_field.text == "#{list_option}"
|
70
|
-
option_field.click
|
71
|
-
break
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def search(base_locator,target_locator,value,attr='text')
|
77
|
-
# search within the locator element for all matching tags (by name)
|
78
|
-
# return that element that has the attribute of text that matches
|
79
|
-
# the text_value passed
|
80
|
-
element = find(base_locator)
|
81
|
-
unless element # was found
|
82
|
-
error "wt search: element not found. locator = #{base_locator}"
|
83
|
-
return false
|
84
|
-
end
|
85
|
-
elements = element.find_elements(target_locator)
|
86
|
-
elements.each do |el|
|
87
|
-
el_attr = _get_attribute(el,attr)
|
88
|
-
# trace "wt search at #{el_attr} for #{value}"
|
89
|
-
return el if el_attr == "#{value}"
|
90
|
-
end
|
91
|
-
return false
|
92
|
-
end
|
93
|
-
|
94
|
-
def _get_attribute(el,attr)
|
95
|
-
attr == 'text' ? el.text : el.attribute(attr)
|
96
|
-
end
|
97
|
-
|
98
|
-
def radio(locator)
|
99
|
-
warn "browser.radio is depricated. use SK::RadioSet instead. locator=#{locator}"
|
100
|
-
self.click(locator,0)
|
101
|
-
end
|
102
|
-
|
103
|
-
def set(locator,value)
|
104
|
-
# set now accepts a single or an
|
105
|
-
# array of locators, by using newfind
|
106
|
-
el = find(locator)
|
107
|
-
error "cannot set #{locator}" unless el
|
108
|
-
_set_el(el,value) if el
|
109
|
-
end
|
110
|
-
def _set_el(el,value)
|
111
|
-
el.clear
|
112
|
-
el.send_keys(value)
|
113
|
-
end
|
114
|
-
|
115
|
-
def submit(name,secs=1)
|
116
|
-
click(name: name)
|
117
|
-
sleep secs
|
118
|
-
end
|
119
|
-
|
120
|
-
def find(param)
|
121
|
-
# find accepts a single value or array
|
122
|
-
# of locators to find an element. the array
|
123
|
-
# is meant to be a this under this structure
|
124
|
-
if param.kind_of?(Array)
|
125
|
-
base = driver
|
126
|
-
param.reverse.each do |loc|
|
127
|
-
base = _find_inside(loc,base)
|
128
|
-
end
|
129
|
-
return base
|
130
|
-
else
|
131
|
-
# not an array, a single
|
132
|
-
_find_inside(param,driver)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def _find_inside(locator, base)
|
137
|
-
# trace "find inside. locator=#{locator} base=#{base}"
|
138
|
-
# find an element by locator inside another element (base)
|
139
|
-
case
|
140
|
-
when locator.has_key?(:value)
|
141
|
-
# trace "... locate by value: #{locator[:value]}}"
|
142
|
-
find_input(:value,locator[:value])
|
143
|
-
when locator.has_key?(:type)
|
144
|
-
# trace "... locate by type: #{locator[:type]}"
|
145
|
-
find_input(:type,locator[:type])
|
146
|
-
else
|
147
|
-
# a standard selenium locator so just use it
|
148
|
-
rescue_exceptions { base.find_element(locator) }
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def find_input(key,type)
|
153
|
-
# selenium does not support a locator search by type
|
154
|
-
# so we need a specialized function to find the element
|
155
|
-
elements = all({tag_name: 'input'})
|
156
|
-
elements.find do |e|
|
157
|
-
# trace "> #{e.attribute(key)} :: #{type}"
|
158
|
-
e.attribute(key) == type
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
def all(locator)
|
163
|
-
rescue_exceptions { driver.find_elements(locator) }
|
164
|
-
end
|
165
|
-
|
166
|
-
def match(text,locator)
|
167
|
-
elements = all(locator)
|
168
|
-
# trace("searching #{elements.length} links...")
|
169
|
-
elements.find{ |e| e.text.include? text }
|
170
|
-
end
|
171
|
-
|
172
|
-
def count_refs(ref, locator)
|
173
|
-
elements = all(locator)
|
174
|
-
# trace("count from #{elements.length} links...")
|
175
|
-
elements.count{ |e| e.attribute('href').include? ref }
|
176
|
-
end
|
177
|
-
|
178
|
-
def has_content?(content)
|
179
|
-
# puts trace("has content? #{content}")
|
180
|
-
return self.source.include? content
|
181
|
-
end
|
182
|
-
|
183
|
-
def has_el?(locator)
|
184
|
-
find(locator)
|
185
|
-
# rescue_exceptions { driver.find_element(locator) }
|
186
|
-
end
|
187
|
-
|
188
|
-
def has_text?(locator,text)
|
189
|
-
find(locator).text == text
|
190
|
-
end
|
191
|
-
|
192
|
-
def get_rows(locator,less_row)
|
193
|
-
rest = less_row.to_i
|
194
|
-
#table = rescue_exceptions { driver.find_elements(table_count) }
|
195
|
-
table = all(locator)
|
196
|
-
return table.count-rest
|
197
|
-
end
|
198
|
-
|
199
|
-
def get_text(locator)
|
200
|
-
find(locator).text
|
201
|
-
# return rescue_exceptions { driver.find_element(locator).text }
|
202
|
-
end
|
203
|
-
|
204
|
-
def get_value(locator)
|
205
|
-
find(locator).attribute('value')
|
206
|
-
end
|
207
|
-
|
208
|
-
### Actions ####
|
209
|
-
|
210
|
-
def click(locator,pause=0)
|
211
|
-
SK::Trace.trace("*** click is depricated")
|
212
|
-
el = find(locator)
|
213
|
-
_click_el(el,pause) if el
|
214
|
-
end
|
215
|
-
|
216
|
-
def _click_el(el,extra)
|
217
|
-
SK::Trace.trace("*** click_el")
|
218
|
-
rescue_exceptions { el.click }
|
219
|
-
sleep 1+extra
|
220
|
-
self
|
221
|
-
end
|
222
|
-
|
223
|
-
### Key Core Operations ###
|
224
|
-
|
225
|
-
def rescue_exceptions
|
226
|
-
# we do not want our tests to fail because selenium throws an error
|
227
|
-
# instead we want to explicitly test using "expects" in the cases
|
228
|
-
begin
|
229
|
-
yield
|
230
|
-
rescue Selenium::WebDriver::Error::NoSuchElementError
|
231
|
-
warn "Element does not exist."
|
232
|
-
false
|
233
|
-
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
234
|
-
warn "Element is stale."
|
235
|
-
false
|
236
|
-
rescue Selenium::WebDriver::Error::ElementNotVisibleError
|
237
|
-
warn "Element is not visible."
|
238
|
-
false
|
239
|
-
rescue Selenium::WebDriver::Error::WebDriverError => e
|
240
|
-
error "Webdriver Error. #{e}"
|
241
|
-
false
|
242
|
-
rescue Net::ReadTimeout
|
243
|
-
error "Network Timeout - no response."
|
244
|
-
false
|
245
|
-
rescue IOError
|
246
|
-
error "IOError"
|
247
|
-
false
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
### Simple Accessors ####
|
252
|
-
|
253
|
-
def driver
|
254
|
-
SK::driver
|
255
|
-
end
|
256
|
-
def source
|
257
|
-
driver.page_source
|
258
|
-
end
|
259
|
-
def url
|
260
|
-
driver.current_url
|
261
|
-
end
|
262
|
-
def title
|
263
|
-
driver.title
|
264
|
-
end
|
265
|
-
|
266
|
-
end
|
data/lib/button.rb
DELETED
data/lib/clickable.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
class SK::Clickable < SK::Element
|
2
|
-
|
3
|
-
# a clickable element can be created with a custom delay
|
4
|
-
# so that the tester does not have to set the delay at
|
5
|
-
# every calling point... just once at the creation oint
|
6
|
-
|
7
|
-
def initialize(locator,delay: 0)
|
8
|
-
super(locator) # creates the el and locator
|
9
|
-
@delay = delay
|
10
|
-
end
|
11
|
-
|
12
|
-
def click(delay = @delay)
|
13
|
-
if self.el
|
14
|
-
# SK::Trace.trace "SK::Clickable.click #{self.locator} #{self.el}"
|
15
|
-
self.el.click
|
16
|
-
sleep delay
|
17
|
-
else
|
18
|
-
SK::Trace.error "SK::Clickable.click: element not initialized for #{locator}"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
data/lib/downloads.rb
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
module SK::Downloads
|
2
|
-
|
3
|
-
@path = nil
|
4
|
-
|
5
|
-
extend self
|
6
|
-
|
7
|
-
def path=(p)
|
8
|
-
@path = p
|
9
|
-
end
|
10
|
-
|
11
|
-
def path
|
12
|
-
@path = @path || determine_mac_path
|
13
|
-
end
|
14
|
-
|
15
|
-
def determine_mac_path
|
16
|
-
parts = File.dirname(__FILE__).split("/")
|
17
|
-
# will work for AR and PC on a Mac (for now)
|
18
|
-
"/#{parts[1]}/#{parts[2]}/downloads"
|
19
|
-
end
|
20
|
-
|
21
|
-
def files
|
22
|
-
# NOTE: every time this is called it goes out to the OS for
|
23
|
-
# a fresh list of the files... we may want to change to a
|
24
|
-
# "refresh" or "readfiles" model for performance
|
25
|
-
Dir["#{self.path}/*"]
|
26
|
-
end
|
27
|
-
|
28
|
-
def names
|
29
|
-
files.collect {|f| File.basename(f) }
|
30
|
-
end
|
31
|
-
|
32
|
-
def include?(filename)
|
33
|
-
filepath = "#{path}/#{filename}"
|
34
|
-
files.include? filepath
|
35
|
-
end
|
36
|
-
|
37
|
-
def last
|
38
|
-
files.max_by {|f| File.mtime(f)}
|
39
|
-
end
|
40
|
-
|
41
|
-
def last_name
|
42
|
-
File.basename last # just the file name
|
43
|
-
end
|
44
|
-
|
45
|
-
def count
|
46
|
-
files.length
|
47
|
-
end
|
48
|
-
|
49
|
-
# def first
|
50
|
-
# files.first
|
51
|
-
# end
|
52
|
-
|
53
|
-
# def first_content
|
54
|
-
# wait_for_download
|
55
|
-
# File.read(first)
|
56
|
-
# end
|
57
|
-
|
58
|
-
def wait_for_download
|
59
|
-
Timeout.timeout(1) do
|
60
|
-
sleep 0.1 until downloaded?
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def downloaded?
|
65
|
-
!downloading? && files.any?
|
66
|
-
end
|
67
|
-
|
68
|
-
def downloading?
|
69
|
-
files.grep(/\.part$/).any?
|
70
|
-
end
|
71
|
-
|
72
|
-
def delete_any(name)
|
73
|
-
list = files.select { |f| File.basename(f).include?(name) }
|
74
|
-
FileUtils.rm_f(list)
|
75
|
-
end
|
76
|
-
|
77
|
-
def delete_all
|
78
|
-
FileUtils.rm_f(files)
|
79
|
-
end
|
80
|
-
end
|
data/lib/dropdown.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
class SK::Dropdown < SK::Element
|
2
|
-
|
3
|
-
def initialize(locator)
|
4
|
-
super(locator) # creates the el and locator via
|
5
|
-
SK::Trace.warn "Dropdown failed to initialize. locator = #{locator}" unless el
|
6
|
-
@options = el.find_elements(tag_name: "option")
|
7
|
-
end
|
8
|
-
|
9
|
-
def select(value)
|
10
|
-
select_by('text',value)
|
11
|
-
end
|
12
|
-
|
13
|
-
def select_by(attr,value)
|
14
|
-
@options.each do |option|
|
15
|
-
optval = option.attribute(attr)
|
16
|
-
# trace "looking at #{optval}"
|
17
|
-
if optval == value
|
18
|
-
option.click
|
19
|
-
break
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def select_index(index)
|
25
|
-
n = [@options.length-1,index].min
|
26
|
-
@options[n].click
|
27
|
-
return @options[n].attribute('text')
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
data/lib/element.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
class SK::Element
|
2
|
-
|
3
|
-
def initialize(arg,src="xxx")
|
4
|
-
# puts "element init arg=#{arg} src=#{src}"
|
5
|
-
if !arg
|
6
|
-
# sometimes we want to create an element from
|
7
|
-
# a find that fails... so create a dummy element
|
8
|
-
@locator = { src: src }
|
9
|
-
@el = false
|
10
|
-
elsif arg.instance_of?(Selenium::WebDriver::Element)
|
11
|
-
@locator = { src: src }
|
12
|
-
@el = arg
|
13
|
-
else # it is a locator
|
14
|
-
@locator = arg # remember
|
15
|
-
@el = SK::Browser.find(arg)
|
16
|
-
SK::Trace.debug "element locator=#{arg} el=#{@el}"
|
17
|
-
SK::Trace.warn "element failed to initialize with locator = #{arg}" unless @el
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
attr_reader :el
|
22
|
-
attr_reader :locator
|
23
|
-
|
24
|
-
def to_s
|
25
|
-
"<SK::Element #{locator}>"
|
26
|
-
end
|
27
|
-
|
28
|
-
def exists?
|
29
|
-
!!el
|
30
|
-
end
|
31
|
-
alias :exist? :exists?
|
32
|
-
|
33
|
-
def displayed?
|
34
|
-
puts "+++ element displayed?"
|
35
|
-
SK::Browser.rescue_exceptions { self.el.displayed? }
|
36
|
-
end
|
37
|
-
|
38
|
-
def html
|
39
|
-
# useful to see for debugging
|
40
|
-
self.el.attribute('innerHTML')
|
41
|
-
end
|
42
|
-
|
43
|
-
def enabled?
|
44
|
-
puts "enabled? 1:#{exists?}"
|
45
|
-
false unless exists?
|
46
|
-
puts "enabled? 2:#{el.enabled?}"
|
47
|
-
el.enabled?
|
48
|
-
end
|
49
|
-
|
50
|
-
def text
|
51
|
-
# useful to see contents for debugging
|
52
|
-
str1 = self.el ? self.el.text : ''
|
53
|
-
# str2 = str1.gsub(/\n\s+/, " ") # shrink white space
|
54
|
-
str1.gsub(/\n+/, " ").strip # remove new lines
|
55
|
-
end
|
56
|
-
|
57
|
-
def empty?
|
58
|
-
# make the rspec read... expect(field).to be_empty
|
59
|
-
self.text == ''
|
60
|
-
end
|
61
|
-
|
62
|
-
def find(locator,klass=SK::Element)
|
63
|
-
# trace "find #{locator} in #{self.locator}"
|
64
|
-
child_el = find_child_el(locator)
|
65
|
-
# trace "child el = #{child_el}"
|
66
|
-
klass.new(child_el,"#{locator}")
|
67
|
-
end
|
68
|
-
alias :child :find
|
69
|
-
|
70
|
-
def find_child_el(locator)
|
71
|
-
# trace "find child of #{self.locator}. locator=#{locator}"
|
72
|
-
# find an element by locator inside another element (base)
|
73
|
-
case
|
74
|
-
when locator.has_key?(:value)
|
75
|
-
# trace "... locate by value: #{locator[:value]}}"
|
76
|
-
search(:value,locator[:value])
|
77
|
-
when locator.has_key?(:type)
|
78
|
-
# trace "... locate by type: #{locator[:type]}"
|
79
|
-
search(:type,locator[:type])
|
80
|
-
else
|
81
|
-
# a standard selenium locator so just use selenium
|
82
|
-
SK::Browser.rescue_exceptions { self.el.find_element(locator) }
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def children(locator,klass=SK::Element)
|
87
|
-
# get the matching children elements
|
88
|
-
els = SK::Browser.rescue_exceptions { self.el.find_elements(locator) }
|
89
|
-
# but return as one of our class types
|
90
|
-
els.map { |el| klass.new(el) }
|
91
|
-
end
|
92
|
-
|
93
|
-
def search(key,val)
|
94
|
-
trace "element#search key=#{key} val=#{val}"
|
95
|
-
# selenium does not support a locator search by type
|
96
|
-
# so we need a specialized function to find the element
|
97
|
-
elements = self.el.find_elements({})
|
98
|
-
#elements = all({tag_name: 'input'})
|
99
|
-
elements.find do |e|
|
100
|
-
# trace "> #{e.attribute(key)} :: #{val}"
|
101
|
-
e.attribute(key) == val
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def parent_el
|
106
|
-
self.el.find_element({xpath: ".."})
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
data/lib/field.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
class SK::Field < SK::Element
|
2
|
-
|
3
|
-
def initialize(locator)
|
4
|
-
super(locator) # creates the el and locator
|
5
|
-
end
|
6
|
-
|
7
|
-
def set(value)
|
8
|
-
if self.el
|
9
|
-
self.el.clear
|
10
|
-
self.el.send_keys(value)
|
11
|
-
else
|
12
|
-
SK::Trace.error "SK::Field.set: element not initialized for #{locator}"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
data/lib/kendo.rb
DELETED
@@ -1,138 +0,0 @@
|
|
1
|
-
class SK::KElement
|
2
|
-
|
3
|
-
def initialize(el)
|
4
|
-
@element = el
|
5
|
-
end
|
6
|
-
|
7
|
-
def el
|
8
|
-
@element
|
9
|
-
end
|
10
|
-
|
11
|
-
def exists?
|
12
|
-
!!el
|
13
|
-
end
|
14
|
-
|
15
|
-
def text
|
16
|
-
# useful to see for debugging
|
17
|
-
self.el.text
|
18
|
-
end
|
19
|
-
|
20
|
-
def html
|
21
|
-
# useful to see for debugging
|
22
|
-
self.el.attribute('innerHTML')
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
class SK::KCell < SK::KElement
|
28
|
-
def as_num
|
29
|
-
# trace "cell = #{cell.text}"
|
30
|
-
sign = self.text.include?('(') ? -1 : 1
|
31
|
-
sign * self.text.gsub(/[$,()]/, '').to_f
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class SK::KRow < SK::KElement
|
36
|
-
def cells()
|
37
|
-
self.el.find_elements({tag_name: 'td'}).collect{ |e| SK::KCell.new(e) }
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class SK::KGrid < SK::KElement
|
42
|
-
def initialize(locator={id: 'grid'})
|
43
|
-
super(SK::Browser.find(locator))
|
44
|
-
end
|
45
|
-
def grid
|
46
|
-
el
|
47
|
-
end
|
48
|
-
def items_label()
|
49
|
-
return nil unless grid
|
50
|
-
self.grid.find_element({class: 'k-pager-info'})
|
51
|
-
end
|
52
|
-
def items_count()
|
53
|
-
return 0 unless self.grid
|
54
|
-
return 0 unless self.items_label
|
55
|
-
# trace "*** items label = #{self.items_label.text}"
|
56
|
-
count = /(\d*) items/.match(self.items_label.text)[1].to_i
|
57
|
-
return count
|
58
|
-
end
|
59
|
-
def pages_count
|
60
|
-
last_page_button.attribute('data-page').to_i
|
61
|
-
end
|
62
|
-
def last_page_button
|
63
|
-
self.grid.find_element({class: 'k-pager-last'})
|
64
|
-
end
|
65
|
-
def first_page_button
|
66
|
-
self.grid.find_element({class: 'k-pager-first'})
|
67
|
-
end
|
68
|
-
def prev_page_button
|
69
|
-
# there is an easily identifiable span inside the button
|
70
|
-
span = self.grid.find_element({class: 'k-i-arrow-w'})
|
71
|
-
span.find_element({xpath: '..'})
|
72
|
-
end
|
73
|
-
def next_page_button
|
74
|
-
# there is an easily identifiable span inside the button
|
75
|
-
span = self.grid.find_element({class: 'k-i-arrow-e'})
|
76
|
-
span.find_element({xpath: '..'})
|
77
|
-
end
|
78
|
-
def rows
|
79
|
-
set = self.grid.find_elements({tag_name: 'tr'})
|
80
|
-
# trace "wt grid rows length = #{set.length}"
|
81
|
-
set
|
82
|
-
end
|
83
|
-
def row(n)
|
84
|
-
SK::KRow.new(self.rows[n])
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
class SK::KFilter
|
90
|
-
def initialize(n)
|
91
|
-
@filter = nil # in case of error
|
92
|
-
# first check that the current page has a kendo grid
|
93
|
-
grid = SK::KGrid.new()
|
94
|
-
return if ! grid
|
95
|
-
# then work our way throught the page/grid...
|
96
|
-
# list of all the column headers; this is a little
|
97
|
-
# fragile if the page has other tables before the grid
|
98
|
-
th_list = SK::Browser.all({tag_name: 'th'})
|
99
|
-
return if !th_list
|
100
|
-
return if th_list.length < n
|
101
|
-
header = th_list[n] # the nth header for the column
|
102
|
-
# puts "attribute = #{header.attribute('data-field')}"
|
103
|
-
@filter = header.find_element({class: 'k-grid-filter'})
|
104
|
-
# puts "find filter = #{@filter}"
|
105
|
-
end
|
106
|
-
def click
|
107
|
-
# puts "click filter = #{@filter}"
|
108
|
-
@filter.click() # makes AC it visible
|
109
|
-
# pause 1
|
110
|
-
end
|
111
|
-
def clear
|
112
|
-
buttons = SK::Browser.all({tag_name: 'button'})
|
113
|
-
button = buttons.find { |el| el.text == 'Clear' }
|
114
|
-
button.click if button
|
115
|
-
sleep 1
|
116
|
-
end
|
117
|
-
def select(value)
|
118
|
-
containers = SK::Browser.all({class: 'k-animation-container'})
|
119
|
-
container = containers.find { |c| c.displayed? }
|
120
|
-
sleep 1 # to find the textbox???
|
121
|
-
textbox = container.find_element({class: 'k-textbox'})
|
122
|
-
trace "filter's textbox is not visisble" unless textbox.displayed?
|
123
|
-
textbox.send_keys(value)
|
124
|
-
button = container.find_element({class: 'k-primary'})
|
125
|
-
button.click()
|
126
|
-
sleep 1
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
module SK::Kendo
|
131
|
-
class << self
|
132
|
-
|
133
|
-
def grid()
|
134
|
-
return SK::KGrid.new()
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
end
|
data/lib/link.rb
DELETED
data/lib/page.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
# TODO: move some of the browser methods to page
|
2
|
-
|
3
|
-
class SK::Page
|
4
|
-
|
5
|
-
def initialize(base,page)
|
6
|
-
@url = "#{base}/#{page}"
|
7
|
-
end
|
8
|
-
|
9
|
-
def url
|
10
|
-
@url
|
11
|
-
end
|
12
|
-
|
13
|
-
# def goto
|
14
|
-
# SK::Browser.gotox(url)
|
15
|
-
# end
|
16
|
-
|
17
|
-
def goto(opts={})
|
18
|
-
query = opts.map { |k,v| k.to_s+"="+v.to_s }.join("&")
|
19
|
-
url = @url
|
20
|
-
url += "?" + query unless query == ""
|
21
|
-
SK::Trace.trace("goto: url=#{url}")
|
22
|
-
SK::Browser.gotox(url)
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
def present?
|
27
|
-
urls_match?
|
28
|
-
end
|
29
|
-
|
30
|
-
def urls_match?
|
31
|
-
# change to the looser include instead of equal
|
32
|
-
return true if SK::Browser.url.include? self.url
|
33
|
-
|
34
|
-
# return true if SK::Browser.url == self.url # old code
|
35
|
-
|
36
|
-
# because we almost always need to see some clues when the expected page is
|
37
|
-
# not present we trace some outpout the the tester
|
38
|
-
SK::Trace.trace "SK::Page url_match? expected: #{url} did not match current: #{SK::Browser.url}"
|
39
|
-
false # returned
|
40
|
-
end
|
41
|
-
|
42
|
-
def has_content?(content)
|
43
|
-
result = SK::Browser.source.include? content
|
44
|
-
# SK::Trace.trace "missing content = #{content}" unless result
|
45
|
-
return result
|
46
|
-
end
|
47
|
-
|
48
|
-
def here?(text)
|
49
|
-
return false unless urls_match?
|
50
|
-
# urls do match, but also require that
|
51
|
-
has_content? text
|
52
|
-
end
|
53
|
-
|
54
|
-
def source
|
55
|
-
SK::Browser.source
|
56
|
-
end
|
57
|
-
|
58
|
-
def title
|
59
|
-
SK::Browser.title
|
60
|
-
end
|
61
|
-
|
62
|
-
end
|
data/lib/radio_set.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
class SK::RadioSet
|
2
|
-
|
3
|
-
def initialize(locator)
|
4
|
-
# get all the elements for the radio
|
5
|
-
@els = SK::Browser.all(locator)
|
6
|
-
# trace("radio els = #{@els}")
|
7
|
-
end
|
8
|
-
|
9
|
-
def select(value)
|
10
|
-
# trace("radio els = #{@els}")
|
11
|
-
@els.each do |el|
|
12
|
-
#trace "radio looking at #{el.text}: #{value}"
|
13
|
-
if el.attribute('value') == value
|
14
|
-
el.click
|
15
|
-
break
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
data/lib/shiken.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'selenium-webdriver'
|
2
|
-
|
3
|
-
# NOTE: the requires are at bottom
|
4
|
-
|
5
|
-
module SK
|
6
|
-
|
7
|
-
@driver = nil
|
8
|
-
|
9
|
-
extend self
|
10
|
-
|
11
|
-
def version
|
12
|
-
v = "0.0.8"
|
13
|
-
# Trace.trace "version: #{v}"
|
14
|
-
return v
|
15
|
-
end
|
16
|
-
|
17
|
-
def init(seconds=2, browser=:safari)
|
18
|
-
|
19
|
-
# browser_stack_url = "http://patconley2:LBqJyYGj5TsyNBWe2Bjy@hub.browserstack.com/wd/hub"
|
20
|
-
# $driver = Selenium::WebDriver.for(:remote, :url => browser_stack_url)
|
21
|
-
|
22
|
-
# Trace.trace "SK::init"
|
23
|
-
# seconds = max time to wait for the element to appear
|
24
|
-
wait = Selenium::WebDriver::Wait.new(:timeout => seconds)
|
25
|
-
|
26
|
-
profile = Selenium::WebDriver::Firefox::Profile.new
|
27
|
-
profile["javascript.enabled"] = false # NOT SURE WHY????
|
28
|
-
# trace "wt init download path = #{SK::Downloads.path}"
|
29
|
-
profile['browser.download.dir'] = SK::Downloads.path
|
30
|
-
#
|
31
|
-
# # The value of browser.download.folderList can be set to either 0, 1, or 2.
|
32
|
-
# # When set to 0, Firefox will save all files downloaded via the browser on the
|
33
|
-
# # user's desktop. When set to 1, these downloads are stored in the Downloads folder.
|
34
|
-
# # When set to 2, the location specified for the most recent download is utilized again
|
35
|
-
profile['browser.download.folderList'] = 2 # use the specified directory
|
36
|
-
|
37
|
-
# Suppress "open with" dialog for a file types
|
38
|
-
profile['browser.helperApps.neverAsk.saveToDisk'] = "text/csv,application/pdf,application/xls,image/tiff"
|
39
|
-
profile['browser.helperApps.alwaysAsk.force'] = false
|
40
|
-
# disable Firefox's built-in PDF viewer
|
41
|
-
profile["pdfjs.disabled"] = true
|
42
|
-
# disable Adobe Acrobat PDF preview plugin
|
43
|
-
profile["plugin.scan.plid.all"] = false
|
44
|
-
profile["plugin.scan.Acrobat"] = "99.0"
|
45
|
-
|
46
|
-
@driver = Selenium::WebDriver.for(browser)
|
47
|
-
|
48
|
-
# NOTE 3/4/17 the profile code failed for safari... see use of FIREFOX in creating profile!!
|
49
|
-
|
50
|
-
# @driver = Selenium::WebDriver.for(browser, :profile => profile)
|
51
|
-
# $driver = Selenium::WebDriver.for :firefox # :safari :chrome
|
52
|
-
|
53
|
-
# TODO: what does this do... overried the above???
|
54
|
-
# @driver.manage.timeouts.implicit_wait = 5
|
55
|
-
|
56
|
-
@driver # returned ????
|
57
|
-
end
|
58
|
-
|
59
|
-
def quit
|
60
|
-
# Trace.trace "SK::quit"
|
61
|
-
driver.quit if driver
|
62
|
-
@driver = nil
|
63
|
-
end
|
64
|
-
|
65
|
-
def driver
|
66
|
-
@driver
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
require 'trace'
|
72
|
-
require 'browser'
|
73
|
-
require 'page'
|
74
|
-
require 'element'
|
75
|
-
require 'field'
|
76
|
-
require 'clickable'
|
77
|
-
require 'button'
|
78
|
-
require 'link'
|
79
|
-
require 'dropdown'
|
80
|
-
require 'radio_set'
|
81
|
-
require 'kendo'
|
82
|
-
require 'table'
|
83
|
-
require 'downloads'
|
data/lib/table.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
class SK::Cell < SK::Element
|
2
|
-
|
3
|
-
# row is an element that "remembers" it's index in the row
|
4
|
-
|
5
|
-
attr_reader :index
|
6
|
-
|
7
|
-
def initialize(locator,index)
|
8
|
-
super(locator) # creates the el and locator
|
9
|
-
@index = index # remember your position
|
10
|
-
end
|
11
|
-
|
12
|
-
def as_num
|
13
|
-
# trace "cell = #{cell.text}"
|
14
|
-
sign = self.text.include?('(') ? -1 : 1
|
15
|
-
sign * self.text.gsub(/[$,()]/, '').to_f
|
16
|
-
end
|
17
|
-
|
18
|
-
def to_s
|
19
|
-
"<SK::Cell #{@index} [#{self.text}]>"
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
class SK::Row < SK::Element
|
25
|
-
|
26
|
-
# row is an element that "remembers" it's index in the table
|
27
|
-
|
28
|
-
attr_reader :index
|
29
|
-
|
30
|
-
def initialize(locator,index)
|
31
|
-
super(locator) # creates the el and locator
|
32
|
-
@index = index # remember your position
|
33
|
-
end
|
34
|
-
|
35
|
-
def cells()
|
36
|
-
ds = self.el.find_elements({tag_name: 'td'})
|
37
|
-
ds.map.with_index { |e,i| SK::Cell.new(e,i) }
|
38
|
-
end
|
39
|
-
|
40
|
-
def to_s
|
41
|
-
text = cells.map { |cell| cell.text }.join("][")
|
42
|
-
"<SK::Row #{@index} [#{text}] >"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class SK::Table < SK::Element
|
47
|
-
|
48
|
-
def rows
|
49
|
-
rs = self.el.find_elements({tag_name: 'tr'})
|
50
|
-
SK::Trace.debug "SK::Table el rows length = #{rs.length}"
|
51
|
-
ws = rs.map.with_index { |r,i| SK::Row.new(r,i) }
|
52
|
-
SK::Trace.debug "SK::Table wt rows length = #{ws.length}"
|
53
|
-
ws # returned
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
data/lib/trace.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'colorize'
|
2
|
-
|
3
|
-
module SK::Trace
|
4
|
-
|
5
|
-
DEBUG = 3
|
6
|
-
WARN = 2
|
7
|
-
ERROR = 1
|
8
|
-
QUIET = 0
|
9
|
-
|
10
|
-
extend self
|
11
|
-
|
12
|
-
@level = WARN # default
|
13
|
-
|
14
|
-
def level=(value)
|
15
|
-
case value
|
16
|
-
when :debug
|
17
|
-
n = DEBUG
|
18
|
-
when :warn
|
19
|
-
n = WARN
|
20
|
-
when :error
|
21
|
-
n = ERROR
|
22
|
-
when :quiet
|
23
|
-
n = QUIET
|
24
|
-
else
|
25
|
-
n = value.to_i
|
26
|
-
end
|
27
|
-
@level = n
|
28
|
-
end
|
29
|
-
|
30
|
-
def level
|
31
|
-
@level
|
32
|
-
end
|
33
|
-
|
34
|
-
def trace(s)
|
35
|
-
write "SK::Trace : #{s}".cyan, DEBUG
|
36
|
-
end
|
37
|
-
def debug(s)
|
38
|
-
write "SK::Debug : #{s}".cyan, DEBUG
|
39
|
-
end
|
40
|
-
def error(s)
|
41
|
-
write "SK::Error: #{s}".red, ERROR
|
42
|
-
end
|
43
|
-
def notice(s)
|
44
|
-
write "SK::Notice: #{s}".yellow, WARN
|
45
|
-
end
|
46
|
-
def warn(s)
|
47
|
-
write "SK::Warn : #{s}".yellow, WARN
|
48
|
-
end
|
49
|
-
|
50
|
-
def write(text,lev)
|
51
|
-
puts text if level >= lev
|
52
|
-
end
|
53
|
-
|
54
|
-
# def xfail(num,s)
|
55
|
-
# error num, s
|
56
|
-
# fail
|
57
|
-
# end
|
58
|
-
|
59
|
-
end
|