onlyoffice_webdriver_wrapper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +7 -0
  2. data/lib/onlyoffice_webdriver_wrapper.rb +5 -0
  3. data/lib/onlyoffice_webdriver_wrapper/dimensions.rb +16 -0
  4. data/lib/onlyoffice_webdriver_wrapper/helpers/bin/chromedriver +0 -0
  5. data/lib/onlyoffice_webdriver_wrapper/helpers/bin/chromedriver_mac +0 -0
  6. data/lib/onlyoffice_webdriver_wrapper/helpers/bin/geckodriver +0 -0
  7. data/lib/onlyoffice_webdriver_wrapper/helpers/chrome_helper.rb +62 -0
  8. data/lib/onlyoffice_webdriver_wrapper/helpers/firefox_helper.rb +26 -0
  9. data/lib/onlyoffice_webdriver_wrapper/helpers/headless_helper.rb +65 -0
  10. data/lib/onlyoffice_webdriver_wrapper/helpers/headless_helper/real_display_tools.rb +22 -0
  11. data/lib/onlyoffice_webdriver_wrapper/helpers/headless_helper/ruby_helper.rb +14 -0
  12. data/lib/onlyoffice_webdriver_wrapper/helpers/os_helper.rb +9 -0
  13. data/lib/onlyoffice_webdriver_wrapper/version.rb +5 -0
  14. data/lib/onlyoffice_webdriver_wrapper/webdriver.rb +713 -0
  15. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_alert_helper.rb +25 -0
  16. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_attributes_helper.rb +53 -0
  17. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_browser_info_helper.rb +20 -0
  18. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_browser_log_helper.rb +9 -0
  19. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_exceptions.rb +3 -0
  20. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_extension.rb +2 -0
  21. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_helper.rb +22 -0
  22. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_js_methods.rb +56 -0
  23. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_screenshot_helper.rb +60 -0
  24. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_style_helper.rb +41 -0
  25. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_tab_helper.rb +74 -0
  26. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_type_helper.rb +104 -0
  27. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_user_agent_helper.rb +40 -0
  28. metadata +171 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f5c77f8a1e5352b76bd894aa9039fe4e3094ba5f9c66818e5ea5ba556fff4c8f
4
+ data.tar.gz: 935c4aaa607da023aa5cd59e5335c84d7cbc87becd1afc12252b1faecdd58e8b
5
+ SHA512:
6
+ metadata.gz: 2abcee5172ae2629bfea3610dc88d767db299a609d6de8c3c37ce05461ee78c10679f6af5be453799658ab2898999bdbe1845dc79a07e2607b7c7e845a582855
7
+ data.tar.gz: 4952374aa06647c64e94a7ade41e107f636cd40ab2144017118d44861bc7652b2af6ba392026fe591ddb9622d7da1bb47d1d2f889913cbf3d5aaa97e2d56ec0d
@@ -0,0 +1,5 @@
1
+ require 'onlyoffice_logger_helper'
2
+ require_relative 'onlyoffice_webdriver_wrapper/helpers/headless_helper'
3
+ require_relative 'onlyoffice_webdriver_wrapper/helpers/os_helper'
4
+ require_relative 'onlyoffice_webdriver_wrapper/dimensions'
5
+ require_relative 'onlyoffice_webdriver_wrapper/webdriver'
@@ -0,0 +1,16 @@
1
+ module OnlyofficeWebdriverWrapper
2
+ # Class for working with cursor coordinates
3
+ class Dimensions
4
+ attr_accessor :left, :top
5
+
6
+ def initialize(left, top)
7
+ @left = left
8
+ @top = top
9
+ end
10
+
11
+ alias width left
12
+ alias height top
13
+ alias x left
14
+ alias y top
15
+ end
16
+ end
@@ -0,0 +1,62 @@
1
+ module OnlyofficeWebdriverWrapper
2
+ # Class for working with Chrome
3
+ module ChromeHelper
4
+ DEFAULT_CHROME_SWITCHES = %w[--kiosk-printing
5
+ --start-maximized
6
+ --disable-popup-blocking
7
+ --disable-infobars
8
+ --no-sandbox
9
+ test-type].freeze
10
+
11
+ # @return [String] path to chromedriver
12
+ def chromedriver_path
13
+ driver_name = 'bin/chromedriver'
14
+ driver_name = 'bin/chromedriver_mac' if OSHelper.mac?
15
+ File.join(File.dirname(__FILE__), driver_name)
16
+ end
17
+
18
+ # @return [Webdriver::Chrome] Chrome webdriver
19
+ def start_chrome_driver
20
+ prefs = {
21
+ download: {
22
+ prompt_for_download: false,
23
+ default_directory: download_directory
24
+ },
25
+ profile: {
26
+ default_content_settings: {
27
+ 'multiple-automatic-downloads' => 1
28
+ }
29
+ },
30
+ credentials_enable_service: false
31
+ }
32
+ caps = Selenium::WebDriver::Remote::Capabilities.chrome
33
+ caps[:logging_prefs] = { browser: 'ALL' }
34
+ caps[:proxy] = Selenium::WebDriver::Proxy.new(ssl: "#{@proxy.proxy_address}:#{@proxy.proxy_port}") if @proxy
35
+ if ip_of_remote_server.nil?
36
+ switches = add_useragent_to_switches(DEFAULT_CHROME_SWITCHES)
37
+ options = Selenium::WebDriver::Chrome::Options.new(args: switches,
38
+ prefs: prefs)
39
+ webdriver_options = { options: options,
40
+ desired_capabilities: caps,
41
+ driver_path: chromedriver_path }
42
+ begin
43
+ driver = Selenium::WebDriver.for :chrome, webdriver_options
44
+ rescue Selenium::WebDriver::Error::WebDriverError,
45
+ Net::ReadTimeout,
46
+ Errno::ECONNREFUSED => e
47
+ OnlyofficeLoggerHelper.log("Starting chrome failed with error: #{e.backtrace}")
48
+ sleep 10
49
+ driver = Selenium::WebDriver.for :chrome, webdriver_options
50
+ end
51
+ driver.manage.window.size = Selenium::WebDriver::Dimension.new(headless.resolution_x, headless.resolution_y) if headless.running?
52
+ driver
53
+ else
54
+ caps['chromeOptions'] = {
55
+ profile: data['zip'],
56
+ extensions: data['extensions']
57
+ }
58
+ Selenium::WebDriver.for(:remote, url: 'http://' + remote_server + ':4444/wd/hub', desired_capabilities: caps)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,26 @@
1
+ module OnlyofficeWebdriverWrapper
2
+ # Module for working with firefox
3
+ module FirefoxHelper
4
+ # @return [Webdriver::Firefox] firefox webdriver
5
+ def start_firefox_driver
6
+ geckodriver = File.join(File.dirname(__FILE__), 'bin/geckodriver')
7
+ profile = Selenium::WebDriver::Firefox::Profile.new
8
+ profile['browser.download.folderList'] = 2
9
+ profile['browser.helperApps.neverAsk.saveToDisk'] = 'application/doct, application/mspowerpoint, application/msword, application/octet-stream, application/oleobject, application/pdf, application/powerpoint, application/pptt, application/rtf, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/vnd.oasis.opendocument.spreadsheet, application/vnd.oasis.opendocument.text, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/x-compressed, application/x-excel, application/xlst, application/x-msexcel, application/x-mspowerpoint, application/x-rtf, application/x-zip-compressed, application/zip, image/jpeg, image/pjpeg, image/pjpeg, image/x-jps, message/rfc822, multipart/x-zip, text/csv, text/html, text/html, text/plain, text/richtext'
10
+ profile['browser.download.dir'] = @download_directory
11
+ profile['browser.download.manager.showWhenStarting'] = false
12
+ profile['dom.disable_window_move_resize'] = false
13
+ options = Selenium::WebDriver::Firefox::Options.new(profile: profile)
14
+ caps = Selenium::WebDriver::Remote::Capabilities.firefox
15
+ caps[:proxy] = Selenium::WebDriver::Proxy.new(ssl: "#{@proxy.proxy_address}:#{@proxy.proxy_port}") if @proxy
16
+ if ip_of_remote_server.nil?
17
+ driver = Selenium::WebDriver.for :firefox, options: options, driver_path: geckodriver, desired_capabilities: caps
18
+ driver.manage.window.size = Selenium::WebDriver::Dimension.new(headless.resolution_x, headless.resolution_y) if headless.running?
19
+ driver
20
+ else
21
+ capabilities = Selenium::WebDriver::Remote::Capabilities.firefox(firefox_profile: profile, desired_capabilities: caps)
22
+ Selenium::WebDriver.for :remote, desired_capabilities: capabilities, url: 'http://' + ip_of_remote_server + ':4444/wd/hub'
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,65 @@
1
+ require_relative 'headless_helper/real_display_tools'
2
+ require_relative 'headless_helper/ruby_helper'
3
+ require 'headless'
4
+
5
+ module OnlyofficeWebdriverWrapper
6
+ # Class for using headless gem
7
+ class HeadlessHelper
8
+ include RealDisplayTools
9
+ include RubyHelper
10
+ attr_accessor :headless_instance
11
+ attr_accessor :resolution_x
12
+ attr_accessor :resolution_y
13
+
14
+ def initialize(resolution_x = 1680, resolution_y = 1050)
15
+ @resolution_x = resolution_x
16
+ @resolution_y = resolution_y
17
+ end
18
+
19
+ # Check if should start headless
20
+ # @return [True, False] result
21
+ def should_start?
22
+ return false if debug?
23
+ return false if OSHelper.mac?
24
+ true
25
+ end
26
+
27
+ def start
28
+ create_session = if real_display_connected?
29
+ should_start?
30
+ else
31
+ true
32
+ end
33
+ return unless create_session
34
+ OnlyofficeLoggerHelper.log('Starting Headless Session')
35
+ begin
36
+ @headless_instance = Headless.new(reuse: false,
37
+ destroy_at_exit: true,
38
+ dimensions: "#{@resolution_x + 1}x#{@resolution_y + 1}x24")
39
+ rescue Exception => e
40
+ OnlyofficeLoggerHelper.log("xvfb not started with problem #{e}")
41
+ RspecHelper.clean_up(true)
42
+ @headless_instance = Headless.new(reuse: false,
43
+ destroy_at_exit: true,
44
+ dimensions: "#{@resolution_x + 1}x#{@resolution_y + 1}x24")
45
+ end
46
+ headless_instance.start
47
+ end
48
+
49
+ def stop
50
+ return unless running?
51
+ OnlyofficeLoggerHelper.log('Stopping Headless Session')
52
+ headless_instance.destroy
53
+ end
54
+
55
+ def running?
56
+ !headless_instance.nil?
57
+ end
58
+
59
+ def take_screenshot(scr_path = '/tmp/screenshot.png')
60
+ return unless running?
61
+ headless_instance.take_screenshot(scr_path)
62
+ OnlyofficeLoggerHelper.log("Took Screenshot to file: #{scr_path}")
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,22 @@
1
+ module OnlyofficeWebdriverWrapper
2
+ # module for getting info about real display
3
+ module RealDisplayTools
4
+ def xrandr_result
5
+ begin
6
+ result = `xrandr 2>&1`
7
+ rescue Exception
8
+ result = 'xrandr throw an exception'
9
+ end
10
+ OnlyofficeLoggerHelper.log("xrandr answer: #{result}".delete("\n"))
11
+ result
12
+ end
13
+
14
+ def real_display_connected?
15
+ return true if OSHelper.mac?
16
+ result = xrandr_result
17
+ exists = result.include?(' connected') && !result.include?('Failed')
18
+ OnlyofficeLoggerHelper.log("Real Display Exists: #{exists}")
19
+ exists
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module OnlyofficeWebdriverWrapper
2
+ # Module for check ruby info
3
+ module RubyHelper
4
+ def debug?
5
+ ENV['RUBYLIB'].to_s.include?('ruby-debug')
6
+ end
7
+
8
+ # Check if current os is 64 bit
9
+ # @return [True, False] result of comparision
10
+ def os_64_bit?
11
+ RUBY_PLATFORM.include?('_64')
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ module OnlyofficeWebdriverWrapper
2
+ # Stuff for working with OS families
3
+ class OSHelper
4
+ # @return [True, False] Check if current platform is mac
5
+ def self.mac?
6
+ RUBY_PLATFORM.include?('darwin')
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module OnlyofficeWebdriverWrapper
2
+ module Version
3
+ STRING = '0.0.1'.freeze
4
+ end
5
+ end
@@ -0,0 +1,713 @@
1
+ require 'onlyoffice_file_helper'
2
+ require 'page-object'
3
+ require 'securerandom'
4
+ require 'selenium-webdriver'
5
+ require 'uri'
6
+ require_relative 'helpers/chrome_helper'
7
+ require_relative 'helpers/firefox_helper'
8
+ require_relative 'webdriver/webdriver_alert_helper'
9
+ require_relative 'webdriver/webdriver_attributes_helper'
10
+ require_relative 'webdriver/webdriver_browser_info_helper'
11
+ require_relative 'webdriver/webdriver_type_helper'
12
+ require_relative 'webdriver/webdriver_exceptions'
13
+ require_relative 'webdriver/webdriver_extension'
14
+ require_relative 'webdriver/webdriver_helper'
15
+ require_relative 'webdriver/webdriver_js_methods'
16
+ require_relative 'webdriver/webdriver_screenshot_helper'
17
+ require_relative 'webdriver/webdriver_style_helper'
18
+ require_relative 'webdriver/webdriver_tab_helper'
19
+ require_relative 'webdriver/webdriver_user_agent_helper'
20
+ require_relative 'webdriver/webdriver_browser_log_helper'
21
+
22
+ module OnlyofficeWebdriverWrapper
23
+ # noinspection RubyTooManyMethodsInspection, RubyInstanceMethodNamingConvention, RubyParameterNamingConvention
24
+ class WebDriver
25
+ include ChromeHelper
26
+ include FirefoxHelper
27
+ include RubyHelper
28
+ include WebdriverAlertHelper
29
+ include WebdriverAttributesHelper
30
+ include WebdriverBrowserInfo
31
+ include WebdriverTypeHelper
32
+ include WebdriverHelper
33
+ include WebdriverJsMethods
34
+ include WebdriverScreenshotHelper
35
+ include WebdriverStyleHelper
36
+ include WebdriverTabHelper
37
+ include WebdriverUserAgentHelper
38
+ include WebdriverBrowserLogHelper
39
+ TIMEOUT_WAIT_ELEMENT = 15
40
+ TIMEOUT_FILE_DOWNLOAD = 100
41
+ # @return [Array, String] default switches for chrome
42
+ attr_accessor :driver
43
+ attr_accessor :browser
44
+ # @return [Symbol] device of which we try to simulate, default - :desktop_linux
45
+ attr_accessor :device
46
+ attr_accessor :ip_of_remote_server
47
+ attr_accessor :download_directory
48
+ attr_accessor :server_address
49
+ attr_accessor :headless
50
+ # @return [Net::HTTP::Proxy] connection proxy
51
+ attr_accessor :proxy
52
+
53
+ singleton_class.class_eval { attr_accessor :web_console_error }
54
+
55
+ def initialize(browser = :firefox,
56
+ remote_server = nil,
57
+ device: :desktop_linux,
58
+ proxy: nil)
59
+ raise WebdriverSystemNotSupported, 'Your OS is not 64 bit. It is not supported' unless os_64_bit?
60
+ @device = device
61
+ @headless = HeadlessHelper.new
62
+ @headless.start
63
+
64
+ @download_directory = Dir.mktmpdir('webdriver-download')
65
+ @browser = browser
66
+ @ip_of_remote_server = remote_server
67
+ @proxy = proxy
68
+ case browser
69
+ when :firefox
70
+ @driver = start_firefox_driver
71
+ when :chrome
72
+ @driver = start_chrome_driver
73
+ else
74
+ raise 'Unknown Browser: ' + browser.to_s
75
+ end
76
+ end
77
+
78
+ def add_web_console_error(log)
79
+ WebDriver.web_console_error = log
80
+ end
81
+
82
+ def open(url)
83
+ url = 'http://' + url unless url.include?('http') || url.include?('file://')
84
+ loop do
85
+ begin
86
+ @driver.navigate.to url
87
+ break
88
+ rescue Timeout::Error
89
+ @driver.navigate.refresh
90
+ end
91
+ end
92
+ OnlyofficeLoggerHelper.log("Opened page: #{url}")
93
+ end
94
+
95
+ def quit
96
+ begin
97
+ @driver.execute_script('window.onbeforeunload = null') # off popup window
98
+ rescue StandardError
99
+ Exception
100
+ end
101
+ begin
102
+ @driver.quit
103
+ rescue Exception => e
104
+ OnlyofficeLoggerHelper.log("Some error happened on webdriver.quit #{e.backtrace}")
105
+ end
106
+ alert_confirm
107
+ @headless.stop
108
+ FileUtils.remove_dir(@download_directory) if Dir.exist?(@download_directory)
109
+ end
110
+
111
+ def get_element(object_identification)
112
+ return object_identification unless object_identification.is_a?(String)
113
+ @driver.find_element(:xpath, object_identification)
114
+ rescue StandardError
115
+ nil
116
+ end
117
+
118
+ def set_text_to_iframe(element, text)
119
+ element.click
120
+ @driver.action.send_keys(text).perform
121
+ end
122
+
123
+ def get_text_array(array_elements)
124
+ get_elements(array_elements).map { |current_element| get_text(current_element) }
125
+ end
126
+
127
+ def click(element)
128
+ element.click
129
+ end
130
+
131
+ def click_and_wait(element_to_click, element_to_wait)
132
+ element_to_click.click
133
+ count = 0
134
+ while !element_to_wait.visible? && count < 30
135
+ sleep 1
136
+ count += 1
137
+ end
138
+ webdriver_error("click_and_wait: Wait for element: #{element_to_click} for 30 seconds") if count == 30
139
+ end
140
+
141
+ def select_from_list(xpath_value, value)
142
+ @driver.find_element(:xpath, xpath_value).find_elements(tag_name: 'li').each do |element|
143
+ next unless element.text == value.to_s
144
+ element.click
145
+ return true
146
+ end
147
+
148
+ webdriver_error("select_from_list: Option #{value} in list #{xpath_value} not found")
149
+ end
150
+
151
+ def select_from_list_elements(value, elements_value)
152
+ index = get_element_index(value, elements_value)
153
+ elements_value[index].click
154
+ end
155
+
156
+ def get_element_index(title, list_elements)
157
+ list_elements.each_with_index do |current, i|
158
+ return i if get_text(current) == title
159
+ end
160
+ nil
161
+ end
162
+
163
+ def get_all_combo_box_values(xpath_name)
164
+ @driver.find_element(:xpath, xpath_name).find_elements(tag_name: 'option').map { |el| el.attribute('value') }
165
+ end
166
+
167
+ # @return [String] url of current frame, or browser url if
168
+ # it is a root frame
169
+ def get_url
170
+ execute_javascript('return window.location.href')
171
+ rescue Selenium::WebDriver::Error::NoSuchDriverError
172
+ raise 'Browser is crushed or hangup'
173
+ end
174
+
175
+ def refresh
176
+ @driver.navigate.refresh
177
+ OnlyofficeLoggerHelper.log('Refresh page')
178
+ end
179
+
180
+ def go_back
181
+ @driver.navigate.back
182
+ OnlyofficeLoggerHelper.log('Go back to previous page')
183
+ end
184
+
185
+ def self.host_name_by_full_url(full_url)
186
+ uri = URI(full_url)
187
+ uri.port == 80 || uri.port == 443 ? "#{uri.scheme}://#{uri.host}" : "#{uri.scheme}://#{uri.host}:#{uri.port}"
188
+ end
189
+
190
+ def get_host_name
191
+ WebDriver.host_name_by_full_url(get_url)
192
+ end
193
+
194
+ def remove_event(event_name)
195
+ execute_javascript("jQuery(document).unbind('#{event_name}');")
196
+ end
197
+
198
+ def remove_class_by_jquery(selector, class_name)
199
+ execute_javascript('cd(window.frames[0])')
200
+ execute_javascript("$('#{selector}').removeClass('#{class_name}');")
201
+ end
202
+
203
+ def add_class_by_jquery(selector, class_name)
204
+ execute_javascript("$('#{selector}').addClass('#{class_name}');")
205
+ end
206
+
207
+ # Perform drag'n'drop action in one element (for example on big canvas area)
208
+ # for drag'n'drop one whole element use 'drag_and_drop_by'
209
+ # ==== Attributes
210
+ #
211
+ # * +xpath+ - xpath of element on which drag and drop performed
212
+ # * +x1+ - x coordinate on element to start drag'n'drop
213
+ # * +y1+ - y coordinate on element to start drag'n'drop
214
+ # * +x2+ - shift vector x coordinate
215
+ # * +y2+ - shift vector y coordinate
216
+ # * +mouse_release+ - release mouse after move
217
+ def drag_and_drop(xpath, x1, y1, x2, y2, mouse_release: true)
218
+ canvas = get_element(xpath)
219
+ if mouse_release
220
+ @driver.action.move_to(canvas, x1.to_i, y1.to_i).click_and_hold.move_by(x2, y2).release.perform
221
+ else
222
+ @driver.action.move_to(canvas, x1.to_i, y1.to_i).click_and_hold.move_by(x2, y2).perform
223
+ end
224
+ rescue ArgumentError
225
+ raise "Replace 'click_and_hold(element)' to 'click_and_hold(element = nil)' in action_builder.rb"
226
+ rescue TypeError => e
227
+ webdriver_error("drag_and_drop(#{xpath}, #{x1}, #{y1}, #{x2}, #{y2}) TypeError: #{e.message}")
228
+ end
229
+
230
+ # Perform drag'n'drop one whole element
231
+ # for drag'n'drop inside one element (f.e. canvas) use drag_and_drop
232
+ # ==== Attributes
233
+ #
234
+ # * +source+ - xpath of element on which drag and drop performed
235
+ # * +right_by+ - shift vector x coordinate
236
+ # * +down_by+ - shift vector y coordinate
237
+ def drag_and_drop_by(source, right_by, down_by = 0)
238
+ @driver.action.drag_and_drop_by(get_element(source), right_by, down_by).perform
239
+ end
240
+
241
+ def scroll_list_to_element(list_xpath, element_xpath)
242
+ execute_javascript("$(document.evaluate(\"#{list_xpath}\", document, null, XPathResult.ANY_TYPE, null).
243
+ iterateNext()).jScrollPane().data('jsp').scrollToElement(document.evaluate(\"#{element_xpath}\",
244
+ document, null, XPathResult.ANY_TYPE, null).iterateNext());")
245
+ end
246
+
247
+ def scroll_list_by_pixels(list_xpath, pixels)
248
+ execute_javascript("$(document.evaluate(\"#{list_xpath.tr('"', "'")}\", document, null, XPathResult.ANY_TYPE, null).iterateNext()).scrollTop(#{pixels})")
249
+ end
250
+
251
+ # Open dropdown selector, like 'Color Selector', which has no element id
252
+ # @param [String] xpath_name name of dropdown list
253
+ def open_dropdown_selector(xpath_name, horizontal_shift = 30, vertical_shift = 0)
254
+ element = get_element(xpath_name)
255
+ if @browser == :firefox || @browser == :safari
256
+ set_style_attribute(xpath_name + '/button', 'display', 'none')
257
+ set_style_attribute(xpath_name, 'display', 'inline')
258
+ element.click
259
+ set_style_attribute(xpath_name + '/button', 'display', 'inline-block')
260
+ set_style_attribute(xpath_name, 'display', 'block')
261
+ else
262
+ @driver.action.move_to(element, horizontal_shift, vertical_shift).click.perform
263
+ end
264
+ end
265
+
266
+ # Click on locator
267
+ # @param count [Integer] count of clicks
268
+ def click_on_locator(xpath_name, by_javascript = false, count: 1)
269
+ element = get_element(xpath_name)
270
+ return webdriver_error("Element with xpath: #{xpath_name} not found") if element.nil?
271
+ if by_javascript
272
+ execute_javascript("document.evaluate(\"#{xpath_name}\", document, null, XPathResult.ANY_TYPE, null).iterateNext().click();")
273
+ else
274
+ begin
275
+ count.times { element.click }
276
+ rescue Selenium::WebDriver::Error::ElementNotVisibleError
277
+ webdriver_error("Selenium::WebDriver::Error::ElementNotVisibleError: element not visible for xpath: #{xpath_name}")
278
+ rescue Exception => e
279
+ webdriver_error(e.class, "UnknownError #{e.message} #{xpath_name}")
280
+ end
281
+ end
282
+ end
283
+
284
+ def left_mouse_click(xpath, x_coord, y_coord)
285
+ @driver.action.move_to(get_element(xpath), x_coord.to_i, y_coord.to_i).click.perform
286
+ end
287
+
288
+ # Context click on locator
289
+ # @param [String] xpath_name name of xpath to click
290
+ def context_click_on_locator(xpath_name)
291
+ wait_until_element_visible(xpath_name)
292
+
293
+ element = @driver.find_element(:xpath, xpath_name)
294
+ @driver.action.context_click(element).perform
295
+ end
296
+
297
+ def right_click(xpath_name)
298
+ @driver.action.context_click(@driver.find_element(:xpath, xpath_name)).perform
299
+ end
300
+
301
+ def context_click(xpath, x_coord, y_coord)
302
+ element = get_element(xpath)
303
+ if browser == :firefox
304
+ element.send_keys %i[shift f10]
305
+ else
306
+ @driver.action.move_to(element, x_coord.to_i, y_coord.to_i).context_click.perform
307
+ end
308
+ end
309
+
310
+ def click_on_displayed(xpath_name)
311
+ element = get_element_by_display(xpath_name)
312
+ begin
313
+ element.is_a?(Array) ? element.first.click : element.click
314
+ rescue Exception => e
315
+ webdriver_error("Exception #{e} in click_on_displayed(#{xpath_name})")
316
+ end
317
+ end
318
+
319
+ def click_on_locator_by_action(xpath)
320
+ @driver.action.move_to(get_element(xpath)).click.perform
321
+ end
322
+
323
+ def click_on_locator_coordinates(xpath_name, right_by, down_by)
324
+ wait_until_element_visible(xpath_name)
325
+ element = @driver.find_element(:xpath, xpath_name)
326
+ @driver.action.move_to(element, right_by.to_i, down_by.to_i).perform
327
+ @driver.action.move_to(element, right_by.to_i, down_by.to_i).click.perform
328
+ end
329
+
330
+ def right_click_on_locator_coordinates(xpath_name, right_by = nil, down_by = nil)
331
+ wait_until_element_visible(xpath_name)
332
+ element = @driver.find_element(:xpath, xpath_name)
333
+ @driver.action.move_to(element, right_by.to_i, down_by.to_i).perform
334
+ @driver.action.move_to(element, right_by.to_i, down_by.to_i).context_click.perform
335
+ end
336
+
337
+ def double_click(xpath_name)
338
+ wait_until_element_visible(xpath_name)
339
+ @driver.action.move_to(@driver.find_element(:xpath, xpath_name)).double_click.perform
340
+ end
341
+
342
+ def double_click_on_locator_coordinates(xpath_name, right_by, down_by)
343
+ wait_until_element_visible(xpath_name)
344
+ @driver.action.move_to(@driver.find_element(:xpath, xpath_name), right_by.to_i, down_by.to_i).double_click.perform
345
+ end
346
+
347
+ def action_on_locator_coordinates(xpath_name, right_by, down_by, action = :click, times = 1)
348
+ wait_until_element_visible(xpath_name)
349
+ element = @driver.find_element(:xpath, xpath_name)
350
+ (0...times).inject(@driver.action.move_to(element, right_by.to_i, down_by.to_i)) { |acc, _elem| acc.send(action) }.perform
351
+ end
352
+
353
+ def click_on_one_of_several_by_text(xpath_several_elements, text_to_click)
354
+ @driver.find_elements(:xpath, xpath_several_elements).each do |current_element|
355
+ next unless text_to_click.to_s == current_element.attribute('innerHTML')
356
+ begin
357
+ current_element.click
358
+ rescue Exception => e
359
+ webdriver_error("Error in click_on_one_of_several_by_text(#{xpath_several_elements}, #{text_to_click}): #{e.message}")
360
+ end
361
+ return true
362
+ end
363
+ false
364
+ end
365
+
366
+ def click_on_one_of_several_by_display(xpath_several_elements)
367
+ @driver.find_elements(:xpath, xpath_several_elements).each do |current_element|
368
+ if current_element.displayed?
369
+ current_element.click
370
+ return true
371
+ end
372
+ end
373
+ false
374
+ end
375
+
376
+ def click_on_one_of_several_with_display_by_text(xpath_several_elements, text_to_click)
377
+ @driver.find_elements(:xpath, xpath_several_elements).each do |current_element|
378
+ if current_element.displayed? && text_to_click == current_element.text
379
+ current_element.click
380
+ return true
381
+ end
382
+ end
383
+ false
384
+ end
385
+
386
+ def right_click_on_one_of_several_by_text(xpath_several_elements, text_to_click)
387
+ @driver.find_elements(:xpath, xpath_several_elements).each do |current_element|
388
+ if text_to_click == current_element.text
389
+ @driver.action.context_click(current_element).perform
390
+ return true
391
+ end
392
+ end
393
+ false
394
+ end
395
+
396
+ def click_on_one_of_several_with_display_by_number(xpath_several_elements, number)
397
+ @driver.find_elements(:xpath, "#{xpath_several_elements}[#{number}]").each do |current_element|
398
+ if current_element.displayed?
399
+ current_element.click
400
+ return true
401
+ end
402
+ end
403
+ false
404
+ end
405
+
406
+ def click_on_one_of_several_by_parameter(xpath_several_elements, parameter_name, parameter_value)
407
+ @driver.find_elements(:xpath, xpath_several_elements).each do |current_element|
408
+ if current_element.attribute(parameter_name).include? parameter_value
409
+ current_element.click
410
+ return true
411
+ end
412
+ end
413
+ false
414
+ end
415
+
416
+ def click_on_one_of_several_by_parameter_and_text(xpath_several_elements, parameter_name, parameter_value, text_to_click)
417
+ @driver.find_elements(:xpath, xpath_several_elements).each do |current_element|
418
+ if current_element.attribute(parameter_name).include?(parameter_value) && text_to_click == current_element.text
419
+ current_element.click
420
+ return true
421
+ end
422
+ end
423
+ false
424
+ end
425
+
426
+ def click_on_one_of_several_xpath_by_number(xpath, number_of_element)
427
+ click_on_locator("(#{xpath})[#{number_of_element}]")
428
+ end
429
+
430
+ def move_to_element(element)
431
+ element = get_element(element) if element.is_a?(String)
432
+ @driver.action.move_to(element).perform
433
+ end
434
+
435
+ def move_to_element_by_locator(xpath_name)
436
+ element = get_element(xpath_name)
437
+ @driver.action.move_to(element).perform
438
+ OnlyofficeLoggerHelper.log("Moved mouse to element: #{xpath_name}")
439
+ end
440
+
441
+ def move_to_one_of_several_displayed_element(xpath_several_elements)
442
+ get_elements(xpath_several_elements).each do |current_element|
443
+ if current_element.displayed?
444
+ move_to_element(current_element)
445
+ return true
446
+ end
447
+ end
448
+ false
449
+ end
450
+
451
+ def mouse_over(xpath_name, x_coordinate = 0, y_coordinate = 0)
452
+ wait_until_element_present(xpath_name)
453
+ @driver.action.move_to(@driver.find_element(:xpath, xpath_name), x_coordinate.to_i, y_coordinate.to_i).perform
454
+ end
455
+
456
+ def element_present?(xpath_name)
457
+ if xpath_name.is_a?(PageObject::Elements::Element)
458
+ xpath_name.visible?
459
+ elsif xpath_name.is_a?(Selenium::WebDriver::Element)
460
+ xpath_name.displayed?
461
+ else
462
+ @driver.find_element(:xpath, xpath_name)
463
+ true
464
+ end
465
+ rescue Exception
466
+ false
467
+ end
468
+
469
+ def wait_until_element_present(xpath_name)
470
+ wait = Selenium::WebDriver::Wait.new(timeout: TIMEOUT_WAIT_ELEMENT) # seconds
471
+ begin
472
+ wait.until { get_element(xpath_name) }
473
+ rescue Selenium::WebDriver::Error::TimeOutError
474
+ webdriver_error("wait_until_element_present(#{xpath_name}) Selenium::WebDriver::Error::TimeOutError: timed out after 15 seconds")
475
+ end
476
+ end
477
+
478
+ def wait_until_element_disappear(xpath_name)
479
+ wait = Selenium::WebDriver::Wait.new(timeout: TIMEOUT_WAIT_ELEMENT) # seconds
480
+ begin
481
+ wait.until { get_element(xpath_name) ? false : true }
482
+ rescue Selenium::WebDriver::Error::TimeOutError
483
+ webdriver_error("wait_until_element_present(#{xpath_name}) Selenium::WebDriver::Error::TimeOutError: timed out after 15 seconds")
484
+ end
485
+ end
486
+
487
+ def get_elements_from_array_before_some(xpath_several_elements, xpath_for_some)
488
+ elements = get_elements(xpath_several_elements)
489
+ result = []
490
+ some_element = get_element(xpath_for_some)
491
+ return result if some_element.nil?
492
+ elements.each do |current|
493
+ break if current == some_element
494
+ result << current
495
+ end
496
+ result
497
+ end
498
+
499
+ def get_elements_from_array_after_some(xpath_several_elements, xpath_for_some)
500
+ elements = get_elements(xpath_several_elements)
501
+ some_element = get_element(xpath_for_some)
502
+ return elements if some_element.nil?
503
+ elements.each do |current|
504
+ elements.delete(current)
505
+ break if current == some_element
506
+ end
507
+ elements
508
+ end
509
+
510
+ def get_element_by_display(xpath_name)
511
+ @driver.find_elements(:xpath, xpath_name).each do |element|
512
+ return element if element.displayed?
513
+ end
514
+ rescue Selenium::WebDriver::Error::InvalidSelectorError
515
+ webdriver_error("get_element_by_display(#{xpath_name}): invalid selector: Unable to locate an element with the xpath expression")
516
+ end
517
+
518
+ def get_element_count(xpath_name, only_visible = true)
519
+ if element_present?(xpath_name)
520
+ elements = @driver.find_elements(:xpath, xpath_name)
521
+ only_visible ? elements.delete_if { |element| @browser == :firefox && !element.displayed? }.length : elements.length
522
+ else
523
+ 0
524
+ end
525
+ end
526
+
527
+ def get_elements(objects_identification, only_visible = true)
528
+ return objects_identification if objects_identification.is_a?(Array)
529
+ elements = @driver.find_elements(:xpath, objects_identification)
530
+ if only_visible
531
+ elements.each do |current|
532
+ elements.delete(current) unless @browser == :firefox || current.displayed?
533
+ end
534
+ end
535
+ elements
536
+ end
537
+
538
+ def element_visible?(xpath_name)
539
+ if xpath_name.is_a?(PageObject::Elements::Element) # PageObject always visible
540
+ true
541
+ elsif element_present?(xpath_name)
542
+ element = get_element(xpath_name)
543
+ return false if element.nil?
544
+ begin
545
+ visible = element.displayed?
546
+ rescue Exception
547
+ visible = false
548
+ end
549
+ visible
550
+ else
551
+ false
552
+ end
553
+ end
554
+
555
+ def wait_until_element_visible(xpath_name, timeout = 15)
556
+ wait_until_element_present(xpath_name)
557
+ time = 0
558
+ while !element_visible?(xpath_name) && time < timeout
559
+ sleep(1)
560
+ time += 1
561
+ end
562
+ return unless time >= timeout
563
+ webdriver_error("Element #{xpath_name} not visible for #{timeout} seconds")
564
+ end
565
+
566
+ def one_of_several_elements_displayed?(xpath_several_elements)
567
+ @driver.find_elements(:xpath, xpath_several_elements).each do |current_element|
568
+ return true if current_element.displayed?
569
+ end
570
+ false
571
+ rescue Exception => e
572
+ webdriver_error("Raise unkwnown exception: #{e}")
573
+ end
574
+
575
+ def wait_element(xpath_name, period_of_wait = 1, critical_time = 3)
576
+ wait_until_element_present(xpath_name)
577
+ time = 0
578
+ until element_visible?(xpath_name)
579
+ sleep(period_of_wait)
580
+ time += 1
581
+ return if time == critical_time
582
+ end
583
+ end
584
+
585
+ def remove_element(xpath)
586
+ execute_javascript("element = document.evaluate(\"#{xpath}\", document, null, XPathResult.ANY_TYPE, null).iterateNext();if (element !== null) {element.parentNode.removeChild(element);};")
587
+ end
588
+
589
+ # Select frame as current
590
+ # @param [String] xpath_name name of current xpath
591
+ def select_frame(xpath_name = '//iframe', count_of_frames = 1)
592
+ (0...count_of_frames).each do
593
+ begin
594
+ frame = @driver.find_element(:xpath, xpath_name)
595
+ @driver.switch_to.frame frame
596
+ rescue Selenium::WebDriver::Error::NoSuchElementError
597
+ OnlyofficeLoggerHelper.log('Raise NoSuchElementError in the select_frame method')
598
+ rescue Exception => e
599
+ webdriver_error("Raise unkwnown exception: #{e}")
600
+ end
601
+ end
602
+ end
603
+
604
+ # Select top frame of browser (even if several subframes exists)
605
+ def select_top_frame
606
+ @driver.switch_to.default_content
607
+ rescue Timeout::Error
608
+ OnlyofficeLoggerHelper.log('Raise TimeoutError in the select_top_frame method')
609
+ rescue Exception => e
610
+ raise "Browser is crushed or hangup with error: #{e}"
611
+ end
612
+
613
+ # Get text of current element
614
+ # @param [String] xpath_name name of xpath
615
+ # @param [true, false] wait_until_visible wait until element visible [@default = true]
616
+ def get_text(xpath_name, wait_until_visible = true)
617
+ wait_until_element_visible(xpath_name) if wait_until_visible
618
+
619
+ element = get_element(xpath_name)
620
+ webdriver_error("get_text(#{xpath_name}, #{wait_until_visible}) not found element by xpath") if element.nil?
621
+ if element.tag_name == 'input' || element.tag_name == 'textarea'
622
+ element.attribute('value')
623
+ else
624
+ element.text
625
+ end
626
+ end
627
+
628
+ def get_text_of_several_elements(xpath_several_elements)
629
+ @driver.find_elements(:xpath, xpath_several_elements).map { |element| element.text unless element.text == '' }.compact
630
+ end
631
+
632
+ def set_parameter(xpath, attribute, attribute_value)
633
+ execute_javascript("document.evaluate(\"#{xpath.tr('"', "'")}\",document, null, XPathResult.ANY_TYPE, null ).iterateNext()." \
634
+ "#{attribute}=\"#{attribute_value}\";")
635
+ end
636
+
637
+ def remove_attribute(xpath, attribute)
638
+ execute_javascript("document.evaluate(\"#{xpath}\",document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)." \
639
+ "singleNodeValue.removeAttribute('#{attribute}');")
640
+ end
641
+
642
+ def select_text_from_page(xpath_name)
643
+ wait_until_element_visible(xpath_name)
644
+ elem = get_element xpath_name
645
+ @driver.action.key_down(:control).click(elem).send_keys('a').key_up(:control).perform
646
+ end
647
+
648
+ def select_combo_box(xpath_name, select_value, select_by = :value)
649
+ wait_until_element_visible(xpath_name)
650
+ option = Selenium::WebDriver::Support::Select.new(get_element(xpath_name))
651
+ begin
652
+ option.select_by(select_by, select_value)
653
+ rescue StandardError
654
+ option.select_by(:text, select_value)
655
+ end
656
+ end
657
+
658
+ def get_element_number_by_text(xpath_list, element_text)
659
+ @driver.find_elements(:xpath, xpath_list).each_with_index do |current_element, index|
660
+ return index if element_text == current_element.attribute('innerHTML')
661
+ end
662
+ nil
663
+ end
664
+
665
+ def get_page_source
666
+ @driver.execute_script('return document.documentElement.innerHTML;')
667
+ end
668
+
669
+ def webdriver_error(exception, error_message = nil)
670
+ if exception.is_a?(String) # If there is no error_message
671
+ error_message = exception
672
+ exception = RuntimeError
673
+ end
674
+ select_top_frame
675
+ current_url = get_url
676
+ raise exception, "#{error_message}\n\nPage address: #{current_url}\n\nError #{webdriver_screenshot}"
677
+ end
678
+
679
+ def wait_until(timeout = ::PageObject.default_page_wait, message = nil, wait_js: true, &block)
680
+ tries ||= 3
681
+ wait = Object::Selenium::WebDriver::Wait.new(timeout: timeout, message: message)
682
+ wait.until(&block)
683
+ if wait_js
684
+ wait.until { document_ready? }
685
+ wait.until { jquery_finished? }
686
+ end
687
+ rescue Selenium::WebDriver::Error::TimeOutError
688
+ webdriver_error("Wait until timeout: #{timeout} seconds in")
689
+ rescue Selenium::WebDriver::Error::StaleElementReferenceError
690
+ OnlyofficeLoggerHelper.log("Wait until: rescuing from Stale Element error, #{tries} attempts remaining")
691
+ retry unless (tries -= 1).zero?
692
+ webdriver_error('Wait until: rescuing from Stale Element error failed after 3 tries')
693
+ end
694
+
695
+ def wait_file_for_download(file_name, timeout = TIMEOUT_FILE_DOWNLOAD)
696
+ full_file_name = "#{@download_directory}/#{file_name}"
697
+ full_file_name = file_name if file_name[0] == '/'
698
+ counter = 0
699
+ while !File.exist?(full_file_name) && counter < timeout
700
+ OnlyofficeLoggerHelper.log("Waiting for download file #{full_file_name} for #{counter} of #{timeout}")
701
+ sleep 1
702
+ counter += 1
703
+ end
704
+ webdriver_error("File #{full_file_name} not download for #{timeout} seconds") if counter >= timeout
705
+ full_file_name
706
+ end
707
+
708
+ def service_unavailable?
709
+ source = get_page_source
710
+ source.include?('Error 503')
711
+ end
712
+ end
713
+ end