selwet 0.0.4 → 1.0.0
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/lib/selwet.rb +452 -896
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7579dfc91aa79cd2d24639fced1ca7aba474cd84
|
4
|
+
data.tar.gz: cd0889c3d291b4a51bcdfd0508d75cd4c6f28b2b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c74973d8e71021f9e088599eae6ae8ed487cc4a27c2e2ccb51b58b1c2f648677b357ff9d92b6a20d350ebfecb9ff2038e53d61319ea4e06860b564b7c86daeaf
|
7
|
+
data.tar.gz: d2805aecb6db3c397c3255580c4ee4bb653ec8677cbcc57f523a3afdf6091b1cc097281f3eb655bfaac844b0a17518038ae70f341a5721c124825fa1d6bffcc9
|
data/lib/selwet.rb
CHANGED
@@ -3,10 +3,9 @@
|
|
3
3
|
require 'selenium-webdriver'
|
4
4
|
require 'test-unit'
|
5
5
|
require 'shoulda-context'
|
6
|
-
|
6
|
+
#SelWeT (Selenium Web Test) - гем для веб тестирования.
|
7
7
|
module SelWeT
|
8
|
-
#Класс Unit содержит
|
9
|
-
#
|
8
|
+
#Класс Unit содержит необходимый набор методов для взаимодействия с браузером.
|
10
9
|
#Тесты пишутся с использованием shoulda-context.
|
11
10
|
#@example
|
12
11
|
# #!/usr/bin/env ruby
|
@@ -15,192 +14,80 @@ module SelWeT
|
|
15
14
|
#
|
16
15
|
# class SelWeT::Unit
|
17
16
|
#
|
18
|
-
#
|
17
|
+
# set_browser :firefox
|
19
18
|
# set_selenium_server_url 'http://127.0.0.1:4444/wd/hub'
|
20
19
|
#
|
21
20
|
# context "Example" do
|
22
|
-
#
|
21
|
+
#
|
22
|
+
# should "open page 'About Us'" do
|
23
23
|
# Unit.go_to "http://inventos.ru/"
|
24
24
|
# Unit.click '#menu-item-3795 a'
|
25
|
-
#
|
26
|
-
# assert_equal
|
25
|
+
# current_location = Unit.get_location
|
26
|
+
# assert_equal 'http://inventos.ru/about/#top', current_location, 'Invalid location!'
|
27
27
|
# end
|
28
|
+
#
|
28
29
|
# end
|
29
30
|
#
|
30
31
|
# end
|
31
|
-
class Unit < Test::Unit::TestCase
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
@@browsers = nil
|
37
|
-
@@opened_window = {}
|
38
|
-
@@win_num = 0
|
32
|
+
class Unit < Test::Unit::TestCase
|
33
|
+
|
34
|
+
include SelWeT
|
35
|
+
|
36
|
+
private
|
39
37
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@@
|
45
|
-
|
46
|
-
|
47
|
-
puts 'URL for selenium server not specified!'
|
48
|
-
exit 1
|
49
|
-
else
|
50
|
-
url = @@url_selenium
|
51
|
-
end
|
52
|
-
if @@browsers.nil?
|
53
|
-
puts 'Browsers not specified!'
|
54
|
-
exit 1
|
55
|
-
end
|
56
|
-
begin
|
57
|
-
@@browsers.each do |browser|
|
58
|
-
if [:firefox, :chrome, :ie, :safari].include? browser
|
59
|
-
@@driver[browser.to_s] = Selenium::WebDriver.for(:remote, :desired_capabilities => browser, :url => url)
|
60
|
-
@@driver[browser.to_s].manage.timeouts.implicit_wait = 15
|
61
|
-
@@driver[browser.to_s].manage.timeouts.script_timeout = 15
|
62
|
-
@@driver[browser.to_s].manage.timeouts.page_load = 15
|
63
|
-
@@driver[browser.to_s].manage.window.maximize
|
64
|
-
else
|
65
|
-
puts "Bad browser #{browser}"
|
66
|
-
end
|
67
|
-
end
|
68
|
-
rescue Exception => e
|
69
|
-
puts "ERROR: #{e.to_s}"
|
70
|
-
exit 1
|
71
|
-
end
|
72
|
-
if @@start_url
|
73
|
-
go_to @@start_url
|
74
|
-
end
|
75
|
-
end
|
76
|
-
#Закрывает все используемые браузеры после выполнения всех тестов.
|
77
|
-
#Выполняется автоматически.
|
78
|
-
def shutdown
|
79
|
-
@@driver.each do |name, driver|
|
80
|
-
begin
|
81
|
-
driver.close
|
82
|
-
driver.quit
|
83
|
-
rescue
|
84
|
-
puts 'Browser '+name+' not closed ...'
|
85
|
-
end
|
86
|
-
end
|
38
|
+
@@server_url = nil
|
39
|
+
@@timewait = 5
|
40
|
+
@@pageload_timewait = 5
|
41
|
+
@@browser = nil
|
42
|
+
@@handles = {}
|
43
|
+
|
44
|
+
class Error < RuntimeError
|
87
45
|
end
|
88
|
-
|
89
|
-
|
90
|
-
#@param url [String] URL запущенного Selenium Server
|
91
|
-
#@example
|
92
|
-
# class SelWeT::Unit
|
93
|
-
# set_browsers [:firefox, :chrome]
|
94
|
-
# set_selenium_server_url "http://localhost:4444/wd/hub"
|
95
|
-
# ...
|
96
|
-
def set_selenium_server_url url
|
97
|
-
@@url_selenium = url
|
98
|
-
end
|
99
|
-
#Устанавливает стартовую страницу при запуске браузеров. Использовать только перед блоками тестов.
|
100
|
-
#@param url [String] URL тестируемого сайта
|
101
|
-
#@example
|
102
|
-
# class SelWeT::Unit
|
103
|
-
# set_browsers [:firefox, :chrome]
|
104
|
-
# set_selenium_server_url "http://localhost:4444/wd/hub"
|
105
|
-
# open_link "http://inventos.ru/"
|
106
|
-
# ...
|
107
|
-
def open_link url
|
108
|
-
@@start_url = url
|
46
|
+
|
47
|
+
class ArgumentValueError < Error
|
109
48
|
end
|
110
|
-
|
111
|
-
|
112
|
-
#@example
|
113
|
-
# class SelWeT::Unit
|
114
|
-
# set_browsers [:firefox, :chrome]
|
115
|
-
# ...
|
116
|
-
def set_browsers params
|
117
|
-
@@browsers = params
|
49
|
+
|
50
|
+
class ElementIsMissingError < Error
|
118
51
|
end
|
119
|
-
|
120
|
-
|
52
|
+
|
53
|
+
class << self
|
54
|
+
#Кликает на кнопку 'Cancel' в окне алерта.
|
121
55
|
#@example
|
122
56
|
# class SelWeT::Unit
|
123
57
|
#
|
124
|
-
# set_browsers [:firefox, :chrome]
|
125
|
-
# set_selenium_server_url 'http://localhost:4444/wd/hub'
|
126
|
-
# @@somePage = 'http://inventos.ru/produkty/#top'
|
127
|
-
#
|
128
|
-
# context "Example" do
|
129
|
-
#
|
130
|
-
# setup do
|
131
|
-
# Unit.go_to @@somePage
|
132
|
-
# end
|
133
58
|
# ...
|
134
|
-
#@see refresh
|
135
|
-
def go_to url
|
136
|
-
threads = []
|
137
|
-
@@driver.each do |name, driver|
|
138
|
-
threads << Thread.new do
|
139
|
-
driver.navigate.to url
|
140
|
-
end
|
141
|
-
end
|
142
|
-
threads.each(&:join)
|
143
|
-
end
|
144
|
-
#Переключиться на iframe. Используется только в блоках should или setup. Для дальнейшего взаимодействия с основной страницей необходимо выполнить {to_page}.
|
145
|
-
#@param selector [String] css селектор на нужный iframe.
|
146
|
-
#@example
|
147
|
-
# class SelWeT::Unit
|
148
|
-
#
|
149
|
-
# ...
|
150
59
|
#
|
151
60
|
# context "Example" do
|
152
61
|
#
|
153
|
-
# should
|
154
|
-
#
|
62
|
+
# should "TODO something" do
|
63
|
+
# ...
|
64
|
+
# Unit.alert_cancel
|
155
65
|
# ...
|
156
|
-
#@see
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
unless status
|
161
|
-
return false, "to_frame: "+message
|
162
|
-
end
|
163
|
-
bad_values = []
|
164
|
-
tags.each do |name, tag|
|
165
|
-
if tag != 'iframe'
|
166
|
-
bad_values << name +" : "+tag
|
167
|
-
end
|
168
|
-
end
|
169
|
-
if bad_values.size != 0
|
170
|
-
return false, "to_frame: #{bad_values.join(", ")} - It is not 'iframe'! "
|
171
|
-
end
|
172
|
-
@@driver.each do |name, driver|
|
173
|
-
threads << Thread.new do
|
174
|
-
element = driver.find_element(:css => selector)
|
175
|
-
driver.action.move_to(element).perform
|
176
|
-
driver.switch_to.frame element
|
177
|
-
end
|
66
|
+
#@see click
|
67
|
+
#@see alert_ok
|
68
|
+
def alert_cancel
|
69
|
+
@@driver.switch_to.alert.dismiss
|
178
70
|
end
|
179
|
-
|
180
|
-
return true
|
181
|
-
end
|
182
|
-
#Очистить кэш браузера
|
71
|
+
#Кликает на кнопку 'Ok' в окне алерта.
|
183
72
|
#@example
|
184
73
|
# class SelWeT::Unit
|
185
74
|
#
|
186
|
-
#
|
75
|
+
# ...
|
187
76
|
#
|
188
77
|
# context "Example" do
|
189
78
|
#
|
190
|
-
# should
|
79
|
+
# should "TODO something" do
|
191
80
|
# ...
|
192
|
-
# Unit.
|
81
|
+
# Unit.alert_ok
|
193
82
|
# ...
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
driver.manage.delete_all_cookies
|
83
|
+
#@see click
|
84
|
+
#@see alert_cancel
|
85
|
+
def alert_ok
|
86
|
+
@@driver.switch_to.alert.accept
|
199
87
|
end
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
#Переключиться на основную страницу. Используется только в блоках should или setup.
|
88
|
+
#Возвращает состояние для radio и checkbox.
|
89
|
+
# @param selector [String] css селектор
|
90
|
+
# @return [FalseClass/TrueClass] checked ~ true, unchecked ~ false
|
204
91
|
#@example
|
205
92
|
# class SelWeT::Unit
|
206
93
|
#
|
@@ -208,832 +95,501 @@ class Unit < Test::Unit::TestCase
|
|
208
95
|
#
|
209
96
|
# context "Example" do
|
210
97
|
#
|
211
|
-
# should '
|
98
|
+
# should 'TODO something' do
|
99
|
+
# Unit.go_to 'http://some_page.com/
|
212
100
|
# ...
|
213
|
-
# Unit.
|
101
|
+
# status = Unit.checked?(#my_checkbox_id')
|
214
102
|
# ...
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
103
|
+
def checked? selector
|
104
|
+
raise(ArgumentValueError, "Invalid value of argument 'selector'") unless selector.class == String
|
105
|
+
if check_element(selector)
|
106
|
+
element = @@driver.find_element(:css => selector)
|
107
|
+
raise "Element #{selector} is not a checkbox/radio" unless ['radio', 'checkbox'].include?(element.tag_name)
|
108
|
+
raise "Element #{selector} not displayed" unless element.displayed?
|
109
|
+
return element.selected?.inspect
|
110
|
+
else
|
111
|
+
raise(ElementIsMissingError, "Element #{selector} is missing")
|
221
112
|
end
|
222
113
|
end
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
#
|
230
|
-
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
234
|
-
#
|
235
|
-
|
236
|
-
|
237
|
-
#
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
threads << Thread.new do
|
244
|
-
thread_status = true
|
245
|
-
begin
|
246
|
-
element = driver.find_element(:css => selector)
|
247
|
-
rescue Exception => e
|
248
|
-
errors << name+' : Bad selector : '+selector
|
249
|
-
thread_status = false
|
250
|
-
status = false
|
251
|
-
end
|
252
|
-
if thread_status
|
253
|
-
unless element.tag_name == 'select'
|
254
|
-
status = false
|
255
|
-
errors << "#{name} - set_select_items using only for select!"
|
256
|
-
else
|
257
|
-
option = Selenium::WebDriver::Support::Select.new(element)
|
258
|
-
if option.multiple?
|
259
|
-
option.deselect_all
|
260
|
-
if items
|
261
|
-
options = element.find_elements(:css => 'option')
|
262
|
-
options.each do |item|
|
263
|
-
if items.include? item.text
|
264
|
-
items.delete item.text
|
265
|
-
driver.action.key_down(:shift).click(item).key_up(:shift).perform
|
266
|
-
end
|
267
|
-
end
|
268
|
-
if items.size > 0
|
269
|
-
status = false
|
270
|
-
errors << "set_select_items: Some passed option values were not found (#{name}): "+items.join(' ')
|
271
|
-
end
|
272
|
-
end
|
273
|
-
else
|
274
|
-
if items
|
275
|
-
if items.size == 1
|
276
|
-
begin
|
277
|
-
option.select_by(:text, items[0])
|
278
|
-
rescue
|
279
|
-
status = false
|
280
|
-
errors << "set_select_items: Option '#{items}' does not exist!"
|
281
|
-
end
|
282
|
-
else
|
283
|
-
status = false
|
284
|
-
errors << "set_select_items: '#{selector}' is not multiple! You must pass a single value."
|
285
|
-
end
|
286
|
-
end
|
287
|
-
end
|
288
|
-
end
|
289
|
-
end
|
290
|
-
end
|
114
|
+
#Проверяет наличие элемента на странице. Если нужно получить количество элементов, то в качестве второго аргумента следует передать true.
|
115
|
+
#@param selector [String] css селектор элемент
|
116
|
+
#@param num [FalseClass/TrueClass]
|
117
|
+
#@return [FalseClass/TrueClass, Fixnum] первое значение - результат проверки наличия элемента, второе - число элементов (возвращается, если агрумент num имеет значение true)
|
118
|
+
#@example
|
119
|
+
# context "Example" do
|
120
|
+
#
|
121
|
+
# should "TODO something" do
|
122
|
+
# ...
|
123
|
+
# assert_equal true, Unit.check_element 'a.menu'
|
124
|
+
# end
|
125
|
+
# ...
|
126
|
+
def check_element selector, num = nil
|
127
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'selector'") unless selector.class == String
|
128
|
+
raise(ArgumentValueError, "Invalid value \"#{num}\" of argument 'num'") unless [FalseClass, TrueClass, NilClass].include?(num.class)
|
129
|
+
wait = Selenium::WebDriver::Wait.new(:timeout => @@timewait)
|
130
|
+
begin
|
131
|
+
wait.until { @@driver.find_element(:css => selector) }
|
132
|
+
rescue Selenium::WebDriver::Error::TimeOutError
|
133
|
+
return false
|
291
134
|
end
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
135
|
+
if num
|
136
|
+
return true, @@driver.find_elements(:css => selector).size
|
137
|
+
else
|
138
|
+
return true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
#Очистить кэш браузера
|
142
|
+
def clear_cache
|
143
|
+
@@driver.manage.delete_all_cookies
|
144
|
+
end
|
145
|
+
#Кликнуть на элемент.
|
146
|
+
#@param selector [String] css селектор элемента
|
299
147
|
#@example
|
300
|
-
#
|
301
|
-
#
|
302
|
-
# ...
|
303
|
-
#
|
304
|
-
# context "Example" do
|
148
|
+
# context "Example" do
|
305
149
|
#
|
306
|
-
#
|
307
|
-
# ...
|
308
|
-
# status, error = Unit.click 'input[type="submit"]'
|
150
|
+
# should "TODO something" do
|
309
151
|
# ...
|
152
|
+
# Unit.click 'input[type="submit"]'
|
153
|
+
# ...
|
310
154
|
#@see alert_ok
|
311
155
|
#@see alert_cancel
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
wait.until { driver.find_element(:css => selector).displayed? }
|
322
|
-
driver.action.move_to(element).perform
|
323
|
-
element.click
|
324
|
-
rescue Exception => e
|
325
|
-
status = false
|
326
|
-
end
|
327
|
-
end
|
156
|
+
def click selector, desc = nil
|
157
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'selector'") unless selector.class == String
|
158
|
+
raise(ArgumentValueError, "Invalid value \"#{desc}\" of argument 'desc'") unless [String, NilClass].include?(desc.class)
|
159
|
+
if check_element(selector)
|
160
|
+
element = @@driver.find_element(:css => selector)
|
161
|
+
raise "Element \"#{selector}\" is not displayed!" unless element.displayed?
|
162
|
+
element.click
|
163
|
+
else
|
164
|
+
raise(ElementIsMissingError, desc ? "Element #{desc} is missing" :"Element #{selector} is missing")
|
328
165
|
end
|
329
166
|
end
|
330
|
-
|
331
|
-
|
332
|
-
return [true, ""]
|
333
|
-
else
|
334
|
-
return [false, "click: Bad selector : #{selector}"]
|
335
|
-
end
|
336
|
-
end
|
337
|
-
#Кликает на кнопку 'Ok' в окне алерта. Используется только в блоках should или setup.
|
338
|
-
#@return [[Boolean,String]] Первый аргумент - статус выполнения, второй - текст сообщения об ошибке, если она возникнет
|
167
|
+
#Закрыть окно с номером num. Окна нумируются в порядке их открытия. Нумирация начинается с 0. Если необходимо закрыть текущее окно, то перед закрытием необходимо переключиться на другое окно. После закрытия окна происходить их переупорядочивание. Так, например, если было закрыто первое окно (num = 0), то второе окно станет первым (было num = 1, стало num = 0) и т.д.
|
168
|
+
#@param num [Fixnum] номер окна
|
339
169
|
#@example
|
340
|
-
#
|
341
|
-
#
|
342
|
-
#
|
343
|
-
#
|
344
|
-
#
|
345
|
-
|
346
|
-
|
347
|
-
#
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
170
|
+
# context "Example" do
|
171
|
+
#
|
172
|
+
# should 'TODO something' do
|
173
|
+
# Unit.close_window 2
|
174
|
+
# ...
|
175
|
+
#@see switch_to_window
|
176
|
+
def close_window num
|
177
|
+
raise ArgumentError.new("Invalid value \"#{num}\" of argument 'num'") unless num.class == Fixnum
|
178
|
+
update_window_handles
|
179
|
+
raise 'Invalid window number' unless @@handles.keys.include?(num.to_s)
|
180
|
+
current = @@handles.key(@@driver.window_handle)
|
181
|
+
raise 'Can not close active window' if num.to_s == current
|
182
|
+
@@driver.switch_to.window @@handles[num.to_s]
|
183
|
+
@@driver.close
|
184
|
+
@@handles.delete_if { |key, value| key == num.to_s }
|
185
|
+
@@driver.switch_to.window @@handles[current]
|
186
|
+
new_handles = {}
|
187
|
+
num = 0
|
188
|
+
@@handles.keys.sort.each do |key|
|
189
|
+
new_handles[num.to_s] = @@handles[key]
|
190
|
+
num += 1
|
191
|
+
end
|
192
|
+
@@handles = new_handles
|
193
|
+
end
|
194
|
+
#Проверяет, отображается ли элемент странице.
|
195
|
+
#@param selector [String] css селектор элемента
|
196
|
+
#@return [FalseClass/TrueClass]
|
197
|
+
#@example
|
198
|
+
# context "Example" do
|
199
|
+
#
|
200
|
+
# should "TODO something" do
|
201
|
+
# ...
|
202
|
+
# assert_equal true, Unit.displayed? '.menu'
|
203
|
+
# end
|
204
|
+
# ...
|
205
|
+
def displayed? selector
|
206
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'selector'") unless selector.class == String
|
207
|
+
if check_element(selector)
|
208
|
+
return @@driver.find_element(:css => selector).displayed?
|
209
|
+
else
|
210
|
+
raise(ElementIsMissingError, "Element #{selector} is missing")
|
364
211
|
end
|
365
212
|
end
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
#Кликает на кнопку 'Cancel' в окне алерта. Используется только в блоках should или setup.
|
370
|
-
#@return [[Boolean,String]] Первый аргумент - статус выполнения, второй - текст сообщения об ошибке, если она возникнет
|
213
|
+
#Заполнить поле или выбирает файл для загрузки.
|
214
|
+
# @param selector [String] css селектор
|
215
|
+
# @param value [String] значение, которое необходимо ввести
|
371
216
|
#@example
|
372
|
-
#
|
373
|
-
#
|
374
|
-
# set_browsers [:firefox, :chrome]
|
375
|
-
# set_selenium_server_url 'http://localhost:4444/wd/hub'
|
376
|
-
# @@somePage = 'http://inventos.ru/produkty/#top'
|
377
|
-
#
|
378
|
-
# context "Example" do
|
217
|
+
# context "Example" do
|
379
218
|
#
|
380
|
-
#
|
381
|
-
#
|
382
|
-
#
|
383
|
-
#
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
219
|
+
# should 'TODO something' do
|
220
|
+
# Unit.go_to @@somePage
|
221
|
+
# ...
|
222
|
+
# Unit.fill_in 'input#some_id', 'some text' #заполнить текстовое поле
|
223
|
+
# Unit.fill_in 'input#[type={"file"}]', '/path/to/file' #выбрать файл для загрузки
|
224
|
+
# ...
|
225
|
+
def fill_in selector, value
|
226
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'selector'") unless selector.class == String
|
227
|
+
raise(ArgumentValueError, "Invalid value \"#{value}\" of argument 'value'") unless value.class == String
|
228
|
+
if check_element(selector)
|
229
|
+
element = @@driver.find_element(:css => selector)
|
230
|
+
raise "Element \"#{selector}\" not displayed!" unless element.displayed?
|
392
231
|
begin
|
393
|
-
driver.
|
232
|
+
@@driver.action.move_to(element).perform
|
233
|
+
element.clear
|
394
234
|
rescue
|
395
|
-
|
235
|
+
#skip this
|
396
236
|
end
|
397
|
-
|
237
|
+
element.send_keys(value)
|
238
|
+
else
|
239
|
+
raise(ElementIsMissingError, "Element #{selector} is missing")
|
240
|
+
end
|
398
241
|
end
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
# @param selector [String] css селектор элемента.
|
404
|
-
# @param link [Boolean] параметр, позволяющий получить значение поля href. Работает только для ссылок.
|
405
|
-
#@return [[Boolean, String, Hash]]
|
406
|
-
#@example
|
407
|
-
# class SelWeT::Unit
|
408
|
-
#
|
409
|
-
# set_browsers [:firefox, :chrome]
|
410
|
-
# set_selenium_server_url 'http://localhost:4444/wd/hub'
|
411
|
-
# @@somePage = 'http://inventos.ru/produkty/#top'
|
412
|
-
#
|
413
|
-
# context "Example" do
|
242
|
+
#Навести курсор на элемент.
|
243
|
+
#@param selector [String] css селектор
|
244
|
+
# @example
|
245
|
+
# context "Example" do
|
414
246
|
#
|
415
|
-
#
|
416
|
-
#
|
417
|
-
#
|
418
|
-
#
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
@@driver.each do |name, driver|
|
425
|
-
threads << Thread.new do
|
426
|
-
begin
|
427
|
-
wait = Selenium::WebDriver::Wait.new(:timeout => 15)
|
428
|
-
wait.until { driver.find_element(:css => selector) }
|
429
|
-
elements = driver.find_elements(:css => selector)
|
430
|
-
rescue
|
431
|
-
Thread.current["issue"] = name
|
432
|
-
end
|
433
|
-
if elements.nil? or elements.size == 0
|
434
|
-
Thread.current["no_elems"] = name
|
435
|
-
else
|
436
|
-
elements.each do |element|
|
437
|
-
unless link
|
438
|
-
if element.attribute('type') == 'submit' or element.attribute('type') == 'button' or element.attribute('type') == 'reset'
|
439
|
-
data[name].nil? ? data[name] = [element.attribute('value')] : data[name] << element.attribute('value')
|
440
|
-
else
|
441
|
-
if element.tag_name == 'select'
|
442
|
-
opts = element.text.split("\n")
|
443
|
-
opts.each do |opt|
|
444
|
-
opt.strip!
|
445
|
-
end
|
446
|
-
opts.delete ''
|
447
|
-
data[name].nil? ? data[name] = [opts] : data[name] << opts
|
448
|
-
else
|
449
|
-
data[name].nil? ? data[name] = [element.text] : data[name] << element.text
|
450
|
-
end
|
451
|
-
end
|
452
|
-
else
|
453
|
-
data[name].nil? ? data[name] = [{"link"=>element.attribute('href'), "text"=>element.text}] : data[name] << {"link"=>element.attribute('href'), "text"=>element.text}
|
454
|
-
end
|
455
|
-
end
|
456
|
-
end
|
457
|
-
end
|
458
|
-
end
|
459
|
-
threads.each(&:join)
|
460
|
-
threads.each do |i|
|
461
|
-
unless i["issue"].nil?
|
462
|
-
result[1] = (result[1].empty? ? "Bad selector '#{selector}'! Browsers: "+i["issue"].to_s : result[1]+" "+i["issue"].to_s)
|
247
|
+
# should 'TODO somethin' do
|
248
|
+
# Unit.hover_over_element "div.menu"
|
249
|
+
# Unit.click "a.some_url"
|
250
|
+
# ...
|
251
|
+
def hover_over_element selector
|
252
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'selector'") unless selector.class == String
|
253
|
+
if check_element(selector)
|
254
|
+
element = @@driver.find_element(:css => selector)
|
255
|
+
@@driver.action.move_to(element).perform
|
463
256
|
else
|
464
|
-
|
465
|
-
result[1] = (result[1].empty? ? "Element '#{selector}' is missing. Browsers: "+i["no_elems"].to_s : result[1]+" "+i["no_elems"].to_s)
|
466
|
-
end
|
257
|
+
raise(ElementIsMissingError, "Element #{selector} is missing")
|
467
258
|
end
|
468
259
|
end
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
result[2] = data
|
474
|
-
return result
|
475
|
-
end
|
476
|
-
#Проверяет наличие элементов. Используется только в блоках should или setup. Возвращает первым аргументом статус выполнения операции (Boolean), вторым - сообщение об ошибке, если она возникнет (String), третьим - текст, содержащийся в элементах ([Hash, Hash, ...]). Хеши имеют ту же структуру, что и в {check_element}.
|
477
|
-
# @param selectors [Array] массив css селекторов элементов.
|
478
|
-
# @param link [Boolean] параметр, позволяющий получить значение поля href. Работает только для ссылок.
|
479
|
-
#@return [[Boolean, String, [Hash, Hash,...]]]
|
260
|
+
#Получить значение атрибута элемента.
|
261
|
+
#@param selector [String] css селектор элемента
|
262
|
+
#@param attr [String] атрибут
|
263
|
+
#@return [String] значение атрибута
|
480
264
|
#@example
|
481
|
-
#
|
482
|
-
#
|
483
|
-
# set_browsers [:firefox]
|
484
|
-
# set_selenium_server_url 'http://localhost:4444/wd/hub'
|
485
|
-
# @@somePage = 'http://inventos.ru/produkty/#top'
|
486
|
-
#
|
487
|
-
# context "Example" do
|
265
|
+
# context "Example" do
|
488
266
|
#
|
489
|
-
#
|
490
|
-
#
|
491
|
-
#
|
492
|
-
|
493
|
-
#
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
status, message, data = check_element(selector, link)
|
500
|
-
unless status
|
501
|
-
result[1] = (result[1].empty? ? message+"\n" : result[1]+message+"\n")
|
267
|
+
# should 'TODO somethin' do
|
268
|
+
# link = Unit.get_attr "a.class", 'href'
|
269
|
+
# ...
|
270
|
+
def get_attr selector, attr
|
271
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'selector'") unless selector.class == String
|
272
|
+
raise(ArgumentValueError, "Invalid value \"#{attr}\" of argument 'attr'") unless attr.class == String
|
273
|
+
if check_element(selector)
|
274
|
+
return @@driver.find_element(:css => selector).attribute(attr)
|
275
|
+
else
|
276
|
+
raise(ElementIsMissingError, "Element #{selector} is missing")
|
502
277
|
end
|
503
|
-
result[2] << data
|
504
278
|
end
|
505
|
-
|
506
|
-
|
507
|
-
end
|
508
|
-
return result
|
509
|
-
end
|
510
|
-
#Обновляет страницу. Используется только в блоках should или setup.
|
279
|
+
#Получить открытый URL текущего окна.
|
280
|
+
#@return [String] URL
|
511
281
|
#@example
|
512
|
-
#
|
513
|
-
#
|
514
|
-
# ...
|
515
|
-
# @@somePage = 'http://inventos.ru/produkty/#top'
|
516
|
-
#
|
517
|
-
# context "Example" do
|
282
|
+
# context "Example" do
|
518
283
|
#
|
519
|
-
#
|
520
|
-
#
|
521
|
-
#
|
522
|
-
|
523
|
-
|
524
|
-
threads = []
|
525
|
-
@@driver.each_value do |driver|
|
526
|
-
threads << Thread.new do
|
527
|
-
driver.navigate.refresh
|
528
|
-
end
|
529
|
-
end
|
530
|
-
threads.each(&:join)
|
531
|
-
end
|
532
|
-
#Возвращает тег по заданному селектору. Используется только в блоках should или setup.
|
533
|
-
# @param selector [String] css селектор
|
534
|
-
# @return [[Boolean, String, Hash]] первый аргумент - статус, второй - сообщение об ошибке, если она возникает, третий - хеш вида !{имя браузера => тег}.
|
535
|
-
# @example
|
536
|
-
# class SelWeT::Unit
|
537
|
-
#
|
538
|
-
# ...
|
539
|
-
#
|
540
|
-
# context "Example" do
|
541
|
-
#
|
542
|
-
# should 'TODO something' do
|
543
|
-
# Unit.go_to @@somePage
|
544
|
-
# ...
|
545
|
-
# status, message, tags = Unit.get_tag '#some_id'
|
546
|
-
# ...
|
547
|
-
def get_tag selector
|
548
|
-
threads = []
|
549
|
-
tags = {}
|
550
|
-
status, message = check_element selector
|
551
|
-
return [false, "get_tag: "+message] unless status
|
552
|
-
@@driver.each do |name, driver|
|
553
|
-
threads << Thread.new do
|
554
|
-
tags[name] = driver.find_element(:css => selector).tag_name
|
555
|
-
end
|
284
|
+
# should 'TODO somethin' do
|
285
|
+
# current_location = Unit.get_location
|
286
|
+
# ...
|
287
|
+
def get_location
|
288
|
+
@@driver.current_url
|
556
289
|
end
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
#Заполнить поле или выбирает файл для загрузки. Используется только в блоках should или setup.
|
561
|
-
# @param selector [String] css селектор
|
562
|
-
# @param value [String] значение, которое необходимо ввести.
|
563
|
-
# @param postfix [Boolean] используется, если в разных браузерах необходимо ввести разные значения. К value добавляется '_имя_браузера'.
|
564
|
-
# @return [[Boolean,String]] - первый аргумент - статус выполнения, второй - сообщение об ошибке, если она произойдёт.
|
290
|
+
#Получить тег элемента.
|
291
|
+
#@param selector [String] css селектор элемента
|
292
|
+
#@return [String] тег
|
565
293
|
#@example
|
566
|
-
#
|
567
|
-
#
|
568
|
-
# ...
|
569
|
-
#
|
570
|
-
# context "Example" do
|
294
|
+
# context "Example" do
|
571
295
|
#
|
572
|
-
#
|
573
|
-
#
|
574
|
-
#
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
result = [true, ""]
|
582
|
-
threads = []
|
583
|
-
status, message, data = check_element selector
|
584
|
-
unless status
|
585
|
-
return [false, message]
|
586
|
-
end
|
587
|
-
data.each_value do |i|
|
588
|
-
if i.size>1
|
589
|
-
return [false, "fill: Element with selector #{selector} not uniq!"]
|
590
|
-
end
|
591
|
-
end
|
592
|
-
@@driver.each do |name, driver|
|
593
|
-
threads << Thread.new do
|
594
|
-
element = driver.find_element(:css => selector)
|
595
|
-
driver.action.move_to(element).perform
|
596
|
-
begin
|
597
|
-
element.clear if element.attribute('type') != 'file'
|
598
|
-
rescue
|
599
|
-
#skip this
|
600
|
-
end
|
601
|
-
driver.find_element(:css => selector).send_keys((postfix.nil? ? value : value+"_"+name))
|
296
|
+
# should 'TODO somethin' do
|
297
|
+
# tag_name = Unit.get_tag '.element_class'
|
298
|
+
# ...
|
299
|
+
def get_tag selector
|
300
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'selector'") unless selector.class == String
|
301
|
+
if check_element(selector)
|
302
|
+
return @@driver.find_element(:css => selector).tag_name
|
303
|
+
else
|
304
|
+
raise(ElementIsMissingError, "Element #{selector} is missing")
|
602
305
|
end
|
603
306
|
end
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
# @param selector [String] css селектор
|
609
|
-
# @return [[Boolean,String/Hash] первый аргумент - статус выполнения, второй - хеш вида !{имя_браузера=>статус} (если radio или checkbox: 1. checked, то статус принимает значение true; 2. unchecked, то статус принимает значение false), или, если первый аргумент равен false - содержит текст ошибки.
|
307
|
+
#Получить текст, отображаемый на элементе или группе элементов.
|
308
|
+
#@param selector [String] css селектор элемента
|
309
|
+
#@param all [String] установить true, если необходимо получить текст для группы элементов
|
310
|
+
#@return [String/Array] текст, или массив строк, если all установлен как true
|
610
311
|
#@example
|
611
|
-
#
|
612
|
-
#
|
613
|
-
# ...
|
614
|
-
#
|
615
|
-
# context "Example" do
|
312
|
+
# context "Example" do
|
616
313
|
#
|
617
|
-
#
|
618
|
-
#
|
619
|
-
#
|
620
|
-
#
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
status = true
|
628
|
-
@@driver.each do |name, driver|
|
629
|
-
threads << Thread.new do
|
630
|
-
element = driver.find_element(:css => selector)
|
631
|
-
Thread.current['name'] = name
|
632
|
-
if element.attribute('type') == 'checkbox' or element.attribute('type') == 'radio'
|
633
|
-
Thread.current['status'] = driver.find_element(:css => selector).selected?.inspect
|
314
|
+
# should 'TODO somethin' do
|
315
|
+
# text = Unit.get_text 'div.element_class'
|
316
|
+
# text = Unit.get_text('div.other_class', true)
|
317
|
+
# ...
|
318
|
+
def get_text selector, all = nil
|
319
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'selector'") unless selector.class == String
|
320
|
+
raise(ArgumentValueError, "Invalid value \"#{all}\" of argument 'all'") unless [NilClass, FalseClass, TrueClass].include?(all.class)
|
321
|
+
if check_element(selector)
|
322
|
+
unless all
|
323
|
+
return @@driver.find_element(:css => selector).text
|
634
324
|
else
|
635
|
-
|
636
|
-
|
325
|
+
elems = @@driver.find_elements(:css => selector)
|
326
|
+
array = []
|
327
|
+
elems.each do |elem|
|
328
|
+
array.push elem.text
|
329
|
+
end
|
330
|
+
return array
|
637
331
|
end
|
332
|
+
else
|
333
|
+
raise(ElementIsMissingError, "Element #{selector} is missing")
|
638
334
|
end
|
639
335
|
end
|
640
|
-
|
641
|
-
|
642
|
-
threads.each do |i|
|
643
|
-
statuses[i['name']] = (i['status'] == "true" ? true : i['status'] == "false" ? false : i['status'])
|
644
|
-
end
|
645
|
-
return [status, statuses]
|
646
|
-
end
|
647
|
-
#Заполнить и отправить форму.
|
648
|
-
# @param selector [String] css селектор формы.
|
649
|
-
# @param fields [Hash] хеш. В качестве ключа передается css селектор элемента (String), в качестве значения: 1) для текстовых полей - строка со значением(String). Если в разных браузерах требуется ввести разные значения, то вначале строки необходимо поставить символ &. Тогда в поле запишется данная строка без символа &, но в конце будет добавлен постфикс "_имя браузера"; 2) для checkbox, radio и кнопок(не submit!) - значение :click; 3) для кнопки отправки формы - :submit. Если не будет указана кнопка для отправки формы, то форма всё равно будет отправлена; 4) для select - массив значений(String), которые необходимо выбрать; 5) для file - путь до файла.
|
650
|
-
# @return [[Boolean,String]] Первый аргумент - статус выполнения, второй - текст ошибки, если она возникнет.
|
336
|
+
#Переход по ссылке. При переходе функция дожидается полной загрузки страницы в пределах времени pageload_timeout.
|
337
|
+
#@param url [String] ссылка, по которой необходимо перейти.
|
651
338
|
#@example
|
652
|
-
#
|
653
|
-
#
|
654
|
-
# ...
|
655
|
-
#
|
656
|
-
# context "Example" do
|
339
|
+
# context "Example" do
|
657
340
|
#
|
658
|
-
#
|
659
|
-
#
|
341
|
+
# setup do
|
342
|
+
# Unit.go_to @@somePage
|
343
|
+
# end
|
660
344
|
# ...
|
661
|
-
#@see
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
return [false, message]
|
669
|
-
end
|
670
|
-
data.each do |key, value|
|
671
|
-
if value.size>1
|
672
|
-
return [false, "post_form: (#{key}) Found more than one form with selector '#{selector}'"]
|
673
|
-
end
|
674
|
-
end
|
675
|
-
check_elements = ''
|
676
|
-
fields.keys.each do |key|
|
677
|
-
status, message, data = check_element key
|
678
|
-
unless status
|
679
|
-
check_elements = (check_elements.empty? ? message+' : '+key+"\n" : check_elements+message+' : '+key+"\n")
|
680
|
-
end
|
681
|
-
data.each do |browser, value|
|
682
|
-
if value.size>1
|
683
|
-
check_elements = (check_elements.empty? ? "post_form:(#{browser}) Element of form not uniq : "+key+"\n" : check_elements+"post_form:(#{browser}) Element of form not uniq : "+key+"\n")
|
684
|
-
end
|
685
|
-
end
|
686
|
-
end
|
687
|
-
unless check_elements.empty?
|
688
|
-
return [false, check_elements]
|
689
|
-
end
|
690
|
-
submit_button = nil
|
691
|
-
bad_args = {}
|
692
|
-
fields.each do |key, value|
|
693
|
-
if value.class != String and value.class != Symbol
|
694
|
-
bad_args[key] = value
|
695
|
-
end
|
696
|
-
if value.class == Symbol
|
697
|
-
if value != :click and value != :submit
|
698
|
-
bad_args[key] = value
|
699
|
-
end
|
700
|
-
end
|
701
|
-
end
|
702
|
-
return [false, 'post_form: Bad args was passed: '+bad_args.to_s] unless bad_args.empty?
|
703
|
-
fields.each do |key, value|
|
704
|
-
if value == :click
|
705
|
-
click key
|
706
|
-
end
|
707
|
-
if value == :submit
|
708
|
-
submit_button = key
|
709
|
-
end
|
710
|
-
if value.class == Array
|
711
|
-
status, error = set_select_items(key, value)
|
712
|
-
return [false, error] unless status
|
713
|
-
end
|
714
|
-
end
|
715
|
-
fields.delete_if { |key,value| value == :click or value == :submit or value.class == Array }
|
716
|
-
threads = []
|
717
|
-
errors = nil
|
718
|
-
@@driver.each do |name, driver|
|
719
|
-
threads << Thread.new do
|
720
|
-
form = driver.find_element(:css => selector)
|
721
|
-
fields.each do |key, value|
|
722
|
-
tag = form.find_element(:css => key).tag_name
|
723
|
-
errors = true if tag == 'select'
|
724
|
-
begin
|
725
|
-
form.find_element(:css => key).clear
|
726
|
-
rescue
|
727
|
-
#skip this
|
728
|
-
end
|
729
|
-
if value[0] == '&'
|
730
|
-
send_value = value+'_'+name
|
731
|
-
send_value.slice! '&'
|
732
|
-
form.find_element(:css => key).send_keys(send_value)
|
733
|
-
else
|
734
|
-
form.find_element(:css => key).send_keys(value)
|
735
|
-
end
|
736
|
-
end
|
737
|
-
unless errors
|
738
|
-
form.submit unless submit_button
|
739
|
-
end
|
740
|
-
end
|
345
|
+
#@see refresh
|
346
|
+
|
347
|
+
def go_to url
|
348
|
+
raise(ArgumentValueError, "Invalid value of argument 'selector'") unless url.class == String
|
349
|
+
wait = Selenium::WebDriver::Wait.new
|
350
|
+
@@driver.navigate.to url
|
351
|
+
wait.until { @@driver.execute_script("return window.onload = function(){}; ") }
|
741
352
|
end
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
#
|
749
|
-
#
|
353
|
+
|
354
|
+
#Проверяет, открыто ли окно с номером num.
|
355
|
+
#@param num [Fixnum] номер окна
|
356
|
+
#@return [FalseClass/TrueClass]
|
357
|
+
#@example
|
358
|
+
# context "Example" do
|
359
|
+
#
|
360
|
+
# should 'TODO somethin' do
|
361
|
+
# ...
|
362
|
+
# assert_equal false, Unit.opened?(2), 'Window not closed!'
|
363
|
+
def opened? num
|
364
|
+
raise(ArgumentValueError, "Invalid value of argument 'num'") unless num.class == Fixnum
|
365
|
+
update_window_handles
|
366
|
+
return @@handles.keys.include?(num.to_s)
|
367
|
+
end
|
368
|
+
#Нажать клавишу на клавиатуре. Для клавиш, отличных от алфовитно-цифровых, в качестве параметра следует передавать значение типа Symbol, соответствующее необходимой клавише. Допустимые значения: :cancel,:help,:backspace,:tab,:clear,:return,:enter,:shift,:left_shift,:control,:left_control,
|
369
|
+
#:alt,:left_alt,:pause,:escape,:space,:page_up,:page_down,:end,:home,:left,:arrow_left,:up,:arrow_up,
|
370
|
+
#:right,:arrow_right,:down,:arrow_down,:insert,:delete,:semicolon,:equals,:numpad0,:numpad1,:numpad2,
|
371
|
+
#:numpad3,:numpad4,:numpad5,:numpad6,:numpad7,:numpad8,:numpad9,:multiply,:add,:separator,:subtract,
|
372
|
+
#:decimal,:divide,:f1,:f2,:f3,:f4,:f5,:f6,:f7,:f8,:f9,:f10,:f11,:f12,:meta,:command
|
373
|
+
#@param key [String/Symbol] клавиша
|
374
|
+
#@param state [Symbol] состояние. Допустимые значения: :down(нажать), :up(отпустить). Если параметр не будет указан, то будет сделано обычное нажатие.
|
375
|
+
def press_key key, state = nil
|
376
|
+
unless [
|
377
|
+
:null,:cancel,:help,:backspace,:tab,:clear,:return,:enter,:shift,:left_shift,:control,:left_control,
|
378
|
+
:alt,:left_alt,:pause,:escape,:space,:page_up,:page_down,:end,:home,:left,:arrow_left,:up,:arrow_up,
|
379
|
+
:right,:arrow_right,:down,:arrow_down,:insert,:delete,:semicolon,:equals,:numpad0,:numpad1,:numpad2,
|
380
|
+
:numpad3,:numpad4,:numpad5,:numpad6,:numpad7,:numpad8,:numpad9,:multiply,:add,:separator,:subtract,
|
381
|
+
:decimal,:divide,:f1,:f2,:f3,:f4,:f5,:f6,:f7,:f8,:f9,:f10,:f11,:f12,:meta,:command
|
382
|
+
].include? key
|
383
|
+
raise(ArgumentValueError, "Invalid value \"#{key}\" of argument 'key'") unless /^[A-Za-z0-9]$/ === key.to_s
|
384
|
+
end
|
385
|
+
raise(ArgumentValueError, "Invalid value \"#{state}\" of argument 'state'") unless [:up, :down, nil].include?(state)
|
386
|
+
case state
|
387
|
+
when :up
|
388
|
+
@@driver.action.key_up(key).perform
|
389
|
+
when :down
|
390
|
+
@@driver.action.key_down(key).perform
|
391
|
+
when nil
|
392
|
+
@@driver.action.send_keys(key).perform
|
393
|
+
end
|
394
|
+
end
|
395
|
+
#Обновить текущее окно
|
396
|
+
def refresh
|
397
|
+
@@driver.navigate.refresh
|
398
|
+
end
|
399
|
+
#Сделать скриншот. Файл будет сохранен в каталоге, из которого был произведен запуск теста с расширением .png.
|
400
|
+
#@param filename [String] имя файла
|
401
|
+
def screenshot filename
|
402
|
+
raise(ArgumentValueError, "Invalid value \"#{filename}\" of argument 'filename'") unless filename.class == String
|
403
|
+
@@driver.save_screenshot("./"+filename+".png")
|
404
|
+
end
|
405
|
+
#Устанавливает используемый для тестирования браузер. Необходимо использовать перед блоками тестов.
|
406
|
+
#@param browser [Symbol] браузер. Допустимые значения: :firefox, :chrome, :ie, :safari, :phantomjs.
|
750
407
|
#@example
|
751
408
|
# class SelWeT::Unit
|
752
|
-
#
|
753
|
-
#
|
754
|
-
|
755
|
-
#
|
756
|
-
|
409
|
+
# set_browser :firefox
|
410
|
+
# ...
|
411
|
+
def set_browser browser
|
412
|
+
raise(ArgumentValueError, "Invalid value \"#{browser}\" of argument 'browser'") unless [:firefox, :chrome, :ie, :safari, :phantomjs].include? browser
|
413
|
+
@@browser = browser
|
414
|
+
end
|
415
|
+
#Выбирает элементы в select по индексам. Нумирация начинается с 0. Если в multiple select необходимо выбрать несколько элементов, то нужно передать массив индексов.
|
416
|
+
#@param selector [String] css селектор
|
417
|
+
#@param items [Fixnum/Array] индекс или массив индексов элементов, которые необходимо выбрать
|
418
|
+
#@example
|
757
419
|
# context "Example" do
|
758
420
|
#
|
759
|
-
# should
|
760
|
-
# Unit.
|
761
|
-
#
|
762
|
-
#
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
421
|
+
# should "TODO something" do
|
422
|
+
# Unit.set_select_items 'select[name="some_name"]', 2
|
423
|
+
# Unit.set_select_items 'select[name="other_name"]', [1,3,6]
|
424
|
+
# ...
|
425
|
+
def set_select_items selector, items
|
426
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'selector'") unless selector.class == String
|
427
|
+
raise(ArgumentValueError, "Invalid value \"#{items}\" of argument 'items'") unless [Array, Fixnum].include?(items.class)
|
428
|
+
if check_element(selector)
|
429
|
+
select = Selenium::WebDriver::Support::Select.new(@@driver.find_element(:css => selector))
|
430
|
+
raise(ArgumentValueError, "Invalid value \"#{items}\" of argument 'items' for not multiple select") if items.class == Array and !select.multiple?
|
431
|
+
if select.multiple?
|
432
|
+
select.deselect_all
|
433
|
+
if items.class == Array
|
434
|
+
items.each do |item|
|
435
|
+
raise(ArgumentValueError, "Invalid value \"#{items}\" of argument 'items'") unless item.class == Fixnum
|
436
|
+
select.select_by(:index, item)
|
437
|
+
end
|
438
|
+
else
|
439
|
+
select.select_by(:index, items)
|
440
|
+
end
|
441
|
+
else
|
442
|
+
select.select_by(:index, items)
|
774
443
|
end
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
threads.each do |i|
|
779
|
-
unless i["value"].nil?
|
780
|
-
result[1] = (result[1].empty? ? "Wrong location '#{i['real']}': "+i["value"].to_s : result[1]+" "+i["value"].to_s)
|
781
|
-
end
|
782
|
-
end
|
783
|
-
unless result[1].empty?
|
784
|
-
result[0] = false
|
444
|
+
else
|
445
|
+
raise(ElementIsMissingError, "Element #{selector} is missing")
|
446
|
+
end
|
785
447
|
end
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
# @return [Hash] ключ - имя браузера, значение - URL.
|
448
|
+
#Устанавливает URL для Selenium Server или PhantomJS. Необходимо использовать перед блоками тестов.
|
449
|
+
#Если параметр не указан, то будет использован локальный браузер
|
450
|
+
#@param url [String] URL запущенного Selenium Server
|
790
451
|
#@example
|
791
452
|
# class SelWeT::Unit
|
792
|
-
#
|
793
|
-
#
|
794
|
-
#
|
795
|
-
|
796
|
-
#
|
797
|
-
|
798
|
-
#
|
799
|
-
# should 'Correct link' do
|
800
|
-
# Unit.go_to @@somePage
|
801
|
-
# ...
|
802
|
-
# location = Unit.get_location
|
803
|
-
# ...
|
804
|
-
#@see check_location
|
805
|
-
#@see go_to
|
806
|
-
def get_location
|
807
|
-
result = {}
|
808
|
-
threads = []
|
809
|
-
@@driver.each do |name, driver|
|
810
|
-
threads << Thread.new do
|
811
|
-
Thread.current["name"] = name
|
812
|
-
Thread.current["url"] = driver.current_url
|
813
|
-
end
|
814
|
-
end
|
815
|
-
threads.each(&:join)
|
816
|
-
threads.each do |i|
|
817
|
-
result[i['name']] = i['url']
|
453
|
+
# set_browser :firefox
|
454
|
+
# set_server_url "http://somewhere:4444/wd/hub"
|
455
|
+
# ...
|
456
|
+
def set_server_url url
|
457
|
+
raise(ArgumentValueError, "Invalid value \"#{url}\" of argument 'url'") unless url.class == String
|
458
|
+
@@server_url = url
|
818
459
|
end
|
819
|
-
|
820
|
-
|
821
|
-
#Сохраняет скриншот текущего состояния браузеров рядом со скриптом. Имя файла будет иметь следующий вид: browsername_filename.png
|
822
|
-
# @param filename [String] часть имени выходного файла.
|
460
|
+
#Устанавливает максимально допустимое время ожидания элемента (по умолчанию 5 секунд). Необходимо использовать перед блоками тестов.
|
461
|
+
#@param sec [Fixnum] время в секундах.
|
823
462
|
#@example
|
824
463
|
# class SelWeT::Unit
|
825
|
-
#
|
826
|
-
#
|
827
|
-
#
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
# should 'Make screenshot' do
|
833
|
-
# Unit.go_to @@somePage
|
834
|
-
# ...
|
835
|
-
# Unit.screenshot 'TestScreenshot'
|
836
|
-
# ...
|
837
|
-
def screenshot filename
|
838
|
-
threads = []
|
839
|
-
@@driver.each do |name, driver|
|
840
|
-
threads << Thread.new do
|
841
|
-
driver.save_screenshot("./"+name+"_"+filename+".png")
|
842
|
-
end
|
464
|
+
# set_browser :firefox
|
465
|
+
# set_timewait 15
|
466
|
+
# ...
|
467
|
+
#@see set_pageload_timewait
|
468
|
+
def set_timewait sec
|
469
|
+
raise(ArgumentValueError, "Invalid value \"#{sec}\" of argument 'sec'") unless sec.class == Fixnum
|
470
|
+
@@timewait = sec
|
843
471
|
end
|
844
|
-
|
845
|
-
|
846
|
-
#Открывает ссылку в новом окне и переключается на него.
|
847
|
-
#@param selector [String] css селектор ссылки.
|
848
|
-
# @return [[Boolean,String]] Первый аргумент - статус выполнения, второй - текст ошибки, если она возникнет.
|
472
|
+
#Устанавливает максимально допустимое время ожидания загрузки страницы(по умолчанию 5 секунд). Может отличаться от времени ожидания элементов. Необходимо использовать перед блоками тестов.
|
473
|
+
#@param sec [Fixnum] время в секундах.
|
849
474
|
#@example
|
850
475
|
# class SelWeT::Unit
|
851
|
-
#
|
852
|
-
#
|
853
|
-
#
|
854
|
-
#
|
855
|
-
|
856
|
-
|
857
|
-
#
|
858
|
-
|
859
|
-
# Unit.go_to @@somePage
|
860
|
-
# ...
|
861
|
-
# Unit.in_new_window 'a.someclass'
|
862
|
-
# ...
|
863
|
-
#@see switchToWindow
|
864
|
-
#@see close_window
|
865
|
-
def in_new_window selector
|
866
|
-
threads = []
|
867
|
-
not_opened = false
|
868
|
-
status, message = check_element selector
|
869
|
-
unless status
|
870
|
-
return [false, message]
|
476
|
+
# set_browser :firefox
|
477
|
+
# set_timewait 3
|
478
|
+
# set_pageload_timewait 15
|
479
|
+
# ...
|
480
|
+
#@see set_timewait
|
481
|
+
def set_pageload_timewait sec
|
482
|
+
raise(ArgumentValueError, "Invalid value \"#{sec}\" of argument 'sec'") unless sec.class == Fixnum
|
483
|
+
@@pageload_timewait = sec
|
871
484
|
end
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
driver.
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
485
|
+
|
486
|
+
#Закрывает браузер после выполнения всех тестов.
|
487
|
+
#Внутренний метод. Выполняется автоматически.
|
488
|
+
def shutdown
|
489
|
+
if @@driver
|
490
|
+
@@driver.close
|
491
|
+
@@driver.quit
|
492
|
+
end
|
493
|
+
end
|
494
|
+
#Запускает браузер перед выполнением тестов.
|
495
|
+
#Выполняется автоматически непосредственно перед запуском тестов.
|
496
|
+
def startup
|
497
|
+
@@driver = nil
|
498
|
+
url = nil
|
499
|
+
unless @@server_url
|
500
|
+
puts 'URL not specified! Local browser will be used.'
|
501
|
+
else
|
502
|
+
url = @@server_url
|
503
|
+
end
|
504
|
+
if @@browser.nil?
|
505
|
+
raise ArgumentError.new('Browser not specified!')
|
506
|
+
end
|
507
|
+
if url
|
508
|
+
if @@browser == :phantomjs
|
509
|
+
@@driver = Selenium::WebDriver.for(:remote, :url => url)
|
886
510
|
else
|
887
|
-
|
511
|
+
@@driver = Selenium::WebDriver.for(:remote, :desired_capabilities => @@browser, :url => url)
|
888
512
|
end
|
513
|
+
else
|
514
|
+
@@driver = Selenium::WebDriver.for @@browser
|
889
515
|
end
|
516
|
+
@@driver.manage.timeouts.implicit_wait = @@timewait
|
517
|
+
@@driver.manage.timeouts.script_timeout = @@timewait
|
518
|
+
@@driver.manage.timeouts.page_load = @@pageload_timewait
|
519
|
+
@@driver.manage.window.maximize
|
520
|
+
@@handles["0"] = @@driver.window_handle
|
890
521
|
end
|
891
|
-
threads.each(&:join)
|
892
|
-
return [false, "Window not opened!"] if not_opened
|
893
|
-
@@win_num += 1
|
894
|
-
return true
|
895
|
-
end
|
896
522
|
#Переключиться на другое окно. Окна нумируются в порядке их открытия. Нумирация начинается с 0.
|
897
523
|
#@param num [Integer] номер окна.
|
898
|
-
# @return [[Boolean,String]] Первый аргумент - статус выполнения, второй - текст ошибки, если она возникнет.
|
899
524
|
#@example
|
900
|
-
# class SelWeT::Unit
|
901
|
-
#
|
902
|
-
# set_browsers [:firefox, :chrome]
|
903
|
-
# set_selenium_server_url 'http://localhost:4444/wd/hub'
|
904
|
-
# @@somePage = 'http://www.example.com'
|
905
|
-
#
|
906
525
|
# context "Example" do
|
907
526
|
#
|
908
527
|
# should 'TODO something' do
|
909
|
-
# Unit.in_new_window 'a.someclass'
|
910
528
|
# ...
|
911
529
|
# Unit.switch_to_window 0
|
912
530
|
# Unit.close_window 1
|
913
531
|
# ...
|
914
|
-
#@see in_new_window
|
915
532
|
#@see close_window
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
status = false
|
925
|
-
end
|
926
|
-
end
|
927
|
-
end
|
928
|
-
threads.each(&:join)
|
929
|
-
return status, (status ? "" : "Invalid num: '#{num}'")
|
930
|
-
end
|
931
|
-
#Закрыть окно с номером num. Окна нумируются в порядке их открытия. Нумирация начинается с 0. Если необходимо закрыть текущее окно, то перед закрытием необходимо переключиться на другое окно.
|
932
|
-
#@param num [Integer] номер окна.
|
933
|
-
# @return [[Boolean,String]] Первый аргумент - статус выполнения, второй - текст ошибки, если она возникнет.
|
533
|
+
def switch_to_window num
|
534
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'num'") unless num.class == Fixnum
|
535
|
+
update_window_handles
|
536
|
+
raise "Invalid window number" unless @@handles.keys.include?(num.to_s)
|
537
|
+
@@driver.switch_to.window @@handles[num.to_s]
|
538
|
+
end
|
539
|
+
#Переключиться на iframe. Для дальнейшего взаимодействия с основной страницей необходимо выполнить {to_page}.
|
540
|
+
#@param selector [String] css селектор на iframe
|
934
541
|
#@example
|
935
|
-
#
|
936
|
-
#
|
937
|
-
# set_browsers [:firefox, :chrome]
|
938
|
-
# set_selenium_server_url 'http://localhost:4444/wd/hub'
|
939
|
-
# @@somePage = 'http://www.example.com'
|
940
|
-
#
|
542
|
+
# ...
|
941
543
|
# context "Example" do
|
942
544
|
#
|
943
|
-
# should '
|
944
|
-
# Unit.
|
945
|
-
#
|
946
|
-
#@see
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
driver.switch_to.window @@opened_window[name][num]
|
956
|
-
driver.close
|
957
|
-
@@opened_window[name].delete_if do |key, value|
|
958
|
-
key == num
|
959
|
-
end
|
960
|
-
driver.switch_to.window current
|
961
|
-
else
|
962
|
-
status = false
|
963
|
-
end
|
964
|
-
end
|
965
|
-
end
|
966
|
-
threads.each(&:join)
|
967
|
-
if status
|
968
|
-
return true
|
969
|
-
else
|
970
|
-
return [false, "You must switch to other window before closing this window"]
|
971
|
-
end
|
972
|
-
end
|
973
|
-
#Навести курсор на элемент.
|
974
|
-
#@param selector [String] css селектор элемента.
|
975
|
-
#@return [[Boolean,String]] Первый аргумент - статус выполнения, второй - текст ошибки, если она возникнет.
|
976
|
-
#@example
|
977
|
-
# class SelWeT::Unit
|
978
|
-
#
|
979
|
-
# set_browsers [:firefox, :chrome]
|
980
|
-
# set_selenium_server_url 'http://localhost:4444/wd/hub'
|
981
|
-
# @@somePage = 'http://www.example.com'
|
982
|
-
#
|
983
|
-
# context "Example" do
|
984
|
-
#
|
985
|
-
# should 'TODO somethin' do
|
986
|
-
# Unit.hover_over_element "div.menu"
|
987
|
-
# Unit.click "a.some_url"
|
988
|
-
# ...
|
989
|
-
def hover_over_element selector
|
990
|
-
status, message = check_element selector
|
991
|
-
unless status
|
992
|
-
return [false, message]
|
993
|
-
end
|
994
|
-
threads = []
|
995
|
-
@@driver.each do |name, driver|
|
996
|
-
threads << Thread.new do
|
997
|
-
element = driver.find_element(:css => selector)
|
998
|
-
driver.action.move_to(element).perform
|
545
|
+
# should 'show popup' do
|
546
|
+
# Unit.to_frame 'iframe#frame1'
|
547
|
+
# ...
|
548
|
+
#@see to_page
|
549
|
+
def to_frame selector
|
550
|
+
raise(ArgumentValueError, "Invalid value \"#{selector}\" of argument 'selector'") unless selector.class == String
|
551
|
+
if check_element(selector)
|
552
|
+
element = @@driver.find_element(:css => selector)
|
553
|
+
@@driver.action.move_to(element).perform
|
554
|
+
@@driver.switch_to.frame element
|
555
|
+
else
|
556
|
+
raise(ElementIsMissingError, "Element #{selector} is missing")
|
999
557
|
end
|
1000
558
|
end
|
1001
|
-
|
1002
|
-
return true
|
1003
|
-
end
|
1004
|
-
#Получить заголовок окна.
|
1005
|
-
#@return Hash ключ - имя браузера, аргумент - title.
|
559
|
+
#Переключиться на основную страницу.
|
1006
560
|
#@example
|
1007
|
-
#
|
1008
|
-
#
|
1009
|
-
# set_browsers [:firefox, :chrome]
|
1010
|
-
# set_selenium_server_url 'http://localhost:4444/wd/hub'
|
1011
|
-
# @@somePage = 'http://www.example.com'
|
1012
|
-
#
|
561
|
+
# ...
|
1013
562
|
# context "Example" do
|
1014
563
|
#
|
1015
|
-
# should '
|
564
|
+
# should 'Show popup' do
|
1016
565
|
# ...
|
1017
|
-
#
|
1018
|
-
#
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
566
|
+
# Unit.to_page
|
567
|
+
# ...
|
568
|
+
#@see to_frame
|
569
|
+
def to_page
|
570
|
+
@@driver.switch_to.default_content
|
571
|
+
end
|
572
|
+
#Обновить список handle. Внутренняя функция.
|
573
|
+
def update_window_handles
|
574
|
+
new_handles = @@driver.window_handles - @@handles.values
|
575
|
+
old_handles = @@handles.values - @@driver.window_handles
|
576
|
+
@@handles.delete_if{ |key, value| old_handles.include? value }
|
577
|
+
unless new_handles.empty?
|
578
|
+
num = @@handles.keys.max.to_i+1
|
579
|
+
new_handles.each do |handle|
|
580
|
+
@@handles[num.to_s] = handle
|
581
|
+
num += 1
|
582
|
+
end
|
1026
583
|
end
|
1027
584
|
end
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
585
|
+
#Получить залоговок текущего окна.
|
586
|
+
#@return [String] заголовок
|
587
|
+
def window_title
|
588
|
+
@@driver.title
|
1032
589
|
end
|
1033
|
-
|
590
|
+
|
1034
591
|
end
|
1035
|
-
|
592
|
+
|
1036
593
|
end
|
1037
|
-
|
594
|
+
|
1038
595
|
end
|
1039
|
-
end
|