onlyoffice_webdriver_wrapper 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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