shiken 0.0.8 → 0.1.5
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 +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
|