onlyoffice_webdriver_wrapper 0.3.4

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 (32) hide show
  1. checksums.yaml +7 -0
  2. data/lib/onlyoffice_webdriver_wrapper.rb +7 -0
  3. data/lib/onlyoffice_webdriver_wrapper/dimensions.rb +22 -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 +67 -0
  8. data/lib/onlyoffice_webdriver_wrapper/helpers/firefox_helper.rb +37 -0
  9. data/lib/onlyoffice_webdriver_wrapper/helpers/firefox_helper/save_to_disk_files.list +35 -0
  10. data/lib/onlyoffice_webdriver_wrapper/helpers/headless_helper.rb +72 -0
  11. data/lib/onlyoffice_webdriver_wrapper/helpers/headless_helper/headless_screenshot_patch.rb +18 -0
  12. data/lib/onlyoffice_webdriver_wrapper/helpers/headless_helper/real_display_tools.rb +21 -0
  13. data/lib/onlyoffice_webdriver_wrapper/helpers/headless_helper/ruby_helper.rb +16 -0
  14. data/lib/onlyoffice_webdriver_wrapper/helpers/os_helper.rb +11 -0
  15. data/lib/onlyoffice_webdriver_wrapper/name.rb +7 -0
  16. data/lib/onlyoffice_webdriver_wrapper/version.rb +7 -0
  17. data/lib/onlyoffice_webdriver_wrapper/webdriver.rb +434 -0
  18. data/lib/onlyoffice_webdriver_wrapper/webdriver/click_methods.rb +125 -0
  19. data/lib/onlyoffice_webdriver_wrapper/webdriver/wait_until_methods.rb +71 -0
  20. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_alert_helper.rb +25 -0
  21. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_attributes_helper.rb +44 -0
  22. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_browser_info_helper.rb +22 -0
  23. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_browser_log_helper.rb +12 -0
  24. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_exceptions.rb +5 -0
  25. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_helper.rb +37 -0
  26. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_js_methods.rb +95 -0
  27. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_screenshot_helper.rb +68 -0
  28. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_style_helper.rb +35 -0
  29. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_tab_helper.rb +70 -0
  30. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_type_helper.rb +121 -0
  31. data/lib/onlyoffice_webdriver_wrapper/webdriver/webdriver_user_agent_helper.rb +51 -0
  32. metadata +193 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d0ca15252e6b9cabf55874698a42ba87bb66e2c320dd4e08b80504a4bd031254
4
+ data.tar.gz: fdc1eaf3a869680e756d4af74b05d3cc0ef603ef383509930f53e785b1f7b6aa
5
+ SHA512:
6
+ metadata.gz: de1324381dbd1a68e88679167a42d40252cb741ac5f6f881853d4bda7d98c61d6111f605f7ebb0b124b01ad3507a01697664f10ecf95bcbf4750e9584de66f43
7
+ data.tar.gz: c0141ead4b9c7ef3e6f71a4e2be8987973e4ae861806bfa074633068703bad0eec447d9833bbc6a7e8c33b45531d64bdb087df2c2a3016ac1cec327ea6be48e2
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onlyoffice_logger_helper'
4
+ require_relative 'onlyoffice_webdriver_wrapper/helpers/headless_helper'
5
+ require_relative 'onlyoffice_webdriver_wrapper/helpers/os_helper'
6
+ require_relative 'onlyoffice_webdriver_wrapper/dimensions'
7
+ require_relative 'onlyoffice_webdriver_wrapper/webdriver'
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlyofficeWebdriverWrapper
4
+ # Class for working with cursor coordinates
5
+ class Dimensions
6
+ attr_accessor :left, :top
7
+
8
+ def initialize(left, top)
9
+ @left = left
10
+ @top = top
11
+ end
12
+
13
+ alias width left
14
+ alias height top
15
+ alias x left
16
+ alias y top
17
+
18
+ def to_s
19
+ "Dimensions(left: #{@left}, top: #{@top})"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlyofficeWebdriverWrapper
4
+ # Class for working with Chrome
5
+ module ChromeHelper
6
+ DEFAULT_CHROME_SWITCHES = %w[--kiosk-printing
7
+ --disable-popup-blocking
8
+ --disable-infobars
9
+ --no-sandbox
10
+ test-type].freeze
11
+
12
+ # @return [String] path to chromedriver
13
+ def chromedriver_path
14
+ driver_name = 'bin/chromedriver'
15
+ driver_name = 'bin/chromedriver_mac' if OSHelper.mac?
16
+ File.join(File.dirname(__FILE__), driver_name)
17
+ end
18
+
19
+ def chrome_service
20
+ @chrome_service ||= Selenium::WebDriver::Chrome::Service.new(path: chromedriver_path)
21
+ end
22
+
23
+ # @return [Webdriver::Chrome] Chrome webdriver
24
+ def start_chrome_driver
25
+ prefs = {
26
+ download: {
27
+ 'prompt_for_download' => false,
28
+ 'default_directory' => download_directory
29
+ },
30
+ profile: {
31
+ 'default_content_setting_values' => {
32
+ 'automatic_downloads' => 1
33
+ }
34
+ },
35
+ credentials_enable_service: false
36
+ }
37
+ caps = Selenium::WebDriver::Remote::Capabilities.chrome
38
+ caps[:logging_prefs] = { browser: 'ALL' }
39
+ caps[:proxy] = Selenium::WebDriver::Proxy.new(ssl: "#{@proxy.proxy_address}:#{@proxy.proxy_port}") if @proxy
40
+ caps['chromeOptions'] = { w3c: false }
41
+ switches = add_useragent_to_switches(DEFAULT_CHROME_SWITCHES)
42
+ options = Selenium::WebDriver::Chrome::Options.new(args: switches,
43
+ prefs: prefs)
44
+ webdriver_options = { options: options,
45
+ desired_capabilities: caps,
46
+ service: chrome_service }
47
+ driver = Selenium::WebDriver.for :chrome, webdriver_options
48
+ maximize_chrome(driver)
49
+ driver
50
+ end
51
+
52
+ private
53
+
54
+ # Maximize chrome
55
+ # @param driver [Selenium::WebDriver] driver to use
56
+ # @return [Void]
57
+ def maximize_chrome(driver)
58
+ if headless.running?
59
+ # Cannot use `driver.manage.window.maximize` in xvfb session
60
+ # according to https://bugs.chromium.org/p/chromedriver/issues/detail?id=1901#c16
61
+ driver.manage.window.size = Selenium::WebDriver::Dimension.new(headless.resolution_x, headless.resolution_y)
62
+ else
63
+ driver.manage.window.maximize
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlyofficeWebdriverWrapper
4
+ # Module for working with firefox
5
+ module FirefoxHelper
6
+ def firefox_service
7
+ geckodriver = File.join(File.dirname(__FILE__), 'bin/geckodriver')
8
+ @firefox_service ||= Selenium::WebDriver::Firefox::Service.new(path: geckodriver)
9
+ end
10
+
11
+ # @return [Webdriver::Firefox] firefox webdriver
12
+ def start_firefox_driver
13
+ profile = Selenium::WebDriver::Firefox::Profile.new
14
+ profile['browser.download.folderList'] = 2
15
+ profile['browser.helperApps.neverAsk.saveToDisk'] = read_firefox_files_to_save
16
+ profile['browser.download.dir'] = @download_directory
17
+ profile['browser.download.manager.showWhenStarting'] = false
18
+ profile['dom.disable_window_move_resize'] = false
19
+ options = Selenium::WebDriver::Firefox::Options.new(profile: profile)
20
+ caps = Selenium::WebDriver::Remote::Capabilities.firefox
21
+ caps[:proxy] = Selenium::WebDriver::Proxy.new(ssl: "#{@proxy.proxy_address}:#{@proxy.proxy_port}") if @proxy
22
+ driver = Selenium::WebDriver.for :firefox, options: options, service: firefox_service, desired_capabilities: caps
23
+ driver.manage.window.size = Selenium::WebDriver::Dimension.new(headless.resolution_x, headless.resolution_y) if headless.running?
24
+ driver
25
+ end
26
+
27
+ private
28
+
29
+ # @return [Array<String>] list of formats to save
30
+ def read_firefox_files_to_save
31
+ path_to_file = "#{Dir.pwd}/lib/onlyoffice_webdriver_wrapper/"\
32
+ 'helpers/firefox_helper/save_to_disk_files.list'
33
+ OnlyofficeFileHelper::FileHelper.read_array_from_file(path_to_file)
34
+ .join(', ')
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,35 @@
1
+ application/doct
2
+ application/mspowerpoint
3
+ application/msword
4
+ application/octet-stream
5
+ application/oleobject
6
+ application/pdf
7
+ application/powerpoint
8
+ application/pptt
9
+ application/rtf
10
+ application/vnd.ms-excel
11
+ application/vnd.ms-powerpoint
12
+ application/vnd.oasis.opendocument.spreadsheet
13
+ application/vnd.oasis.opendocument.text
14
+ application/vnd.openxmlformats-officedocument.presentationml.presentation
15
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
16
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document
17
+ application/x-compressed
18
+ application/x-excel
19
+ application/xlst
20
+ application/x-msexcel
21
+ application/x-mspowerpoint
22
+ application/x-rtf
23
+ application/x-zip-compressed
24
+ application/zip
25
+ image/jpeg
26
+ image/pjpeg
27
+ image/pjpeg
28
+ image/x-jps
29
+ message/rfc822
30
+ multipart/x-zip
31
+ text/csv
32
+ text/html
33
+ text/html
34
+ text/plain
35
+ text/richtext
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'headless_helper/real_display_tools'
4
+ require_relative 'headless_helper/ruby_helper'
5
+ require 'headless'
6
+ require_relative 'headless_helper/headless_screenshot_patch'
7
+
8
+ module OnlyofficeWebdriverWrapper
9
+ # Class for using headless gem
10
+ class HeadlessHelper
11
+ include RealDisplayTools
12
+ include RubyHelper
13
+ attr_accessor :headless_instance
14
+ attr_accessor :resolution_x
15
+ attr_accessor :resolution_y
16
+
17
+ def initialize(resolution_x = 1680, resolution_y = 1050)
18
+ @resolution_x = resolution_x
19
+ @resolution_y = resolution_y
20
+ end
21
+
22
+ # Check if should start headless
23
+ # @return [True, False] result
24
+ def should_start?
25
+ return false if debug?
26
+ return false if OSHelper.mac?
27
+
28
+ true
29
+ end
30
+
31
+ def start
32
+ create_session = if real_display_connected?
33
+ should_start?
34
+ else
35
+ true
36
+ end
37
+ return unless create_session
38
+
39
+ OnlyofficeLoggerHelper.log('Starting Headless Session')
40
+ begin
41
+ @headless_instance = Headless.new(reuse: false,
42
+ destroy_at_exit: true,
43
+ dimensions: "#{@resolution_x + 1}x#{@resolution_y + 1}x24")
44
+ rescue Exception => e
45
+ OnlyofficeLoggerHelper.log("xvfb not started with problem #{e}")
46
+ WebDriver.clean_up(true)
47
+ @headless_instance = Headless.new(reuse: false,
48
+ destroy_at_exit: true,
49
+ dimensions: "#{@resolution_x + 1}x#{@resolution_y + 1}x24")
50
+ end
51
+ headless_instance.start
52
+ end
53
+
54
+ def stop
55
+ return unless running?
56
+
57
+ OnlyofficeLoggerHelper.log('Stopping Headless Session')
58
+ headless_instance.destroy
59
+ end
60
+
61
+ def running?
62
+ !headless_instance.nil?
63
+ end
64
+
65
+ def take_screenshot(scr_path = '/tmp/screenshot.png')
66
+ return unless running?
67
+
68
+ headless_instance.take_screenshot(scr_path)
69
+ OnlyofficeLoggerHelper.log("Took Screenshot to file: #{scr_path}")
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,18 @@
1
+ class Headless
2
+ def take_screenshot(file_path, options={})
3
+ using = options.fetch(:using, :imagemagick)
4
+ case using
5
+ when :imagemagick
6
+ CliUtil.ensure_application_exists!('import', "imagemagick is not found on your system. Please install it using sudo apt-get install imagemagick")
7
+ system "#{CliUtil.path_to('import')} -display :#{display} -window root #{file_path}"
8
+ when :xwd
9
+ CliUtil.ensure_application_exists!('xwd', "xwd is not found on your system. Please install it using sudo apt-get install X11-apps")
10
+ system "#{CliUtil.path_to('xwd')} -display localhost:#{display} -silent -root -out #{file_path}"
11
+ when :graphicsmagick, :gm
12
+ CliUtil.ensure_application_exists!('gm', "graphicsmagick is not found on your system. Please install it.")
13
+ system "#{CliUtil.path_to('gm')} import -display localhost:#{display} -window root #{file_path}"
14
+ else
15
+ raise Headless::Exception.new('Unknown :using option value')
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlyofficeWebdriverWrapper
4
+ # module for getting info about real display
5
+ module RealDisplayTools
6
+ def xrandr_result
7
+ result = `xrandr 2>&1`
8
+ OnlyofficeLoggerHelper.log("xrandr answer: #{result}".delete("\n"))
9
+ result
10
+ end
11
+
12
+ def real_display_connected?
13
+ return true if OSHelper.mac?
14
+
15
+ result = xrandr_result
16
+ exists = result.include?(' connected') && !result.include?('Failed')
17
+ OnlyofficeLoggerHelper.log("Real Display Exists: #{exists}")
18
+ exists
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlyofficeWebdriverWrapper
4
+ # Module for check ruby info
5
+ module RubyHelper
6
+ def debug?
7
+ ENV['RUBYLIB'].to_s.include?('ruby-debug')
8
+ end
9
+
10
+ # Check if current os is 64 bit
11
+ # @return [True, False] result of comparision
12
+ def os_64_bit?
13
+ RUBY_PLATFORM.include?('_64')
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlyofficeWebdriverWrapper
4
+ # Stuff for working with OS families
5
+ class OSHelper
6
+ # @return [True, False] Check if current platform is mac
7
+ def self.mac?
8
+ RUBY_PLATFORM.include?('darwin')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlyofficeWebdriverWrapper
4
+ module Name
5
+ STRING = 'onlyoffice_webdriver_wrapper'
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlyofficeWebdriverWrapper
4
+ module Version
5
+ STRING = '0.3.4'
6
+ end
7
+ end
@@ -0,0 +1,434 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onlyoffice_file_helper'
4
+ require 'page-object'
5
+ require 'securerandom'
6
+ require 'selenium-webdriver'
7
+ require 'uri'
8
+ require_relative 'helpers/chrome_helper'
9
+ require_relative 'helpers/firefox_helper'
10
+ require_relative 'webdriver/click_methods'
11
+ require_relative 'webdriver/wait_until_methods'
12
+ require_relative 'webdriver/webdriver_alert_helper'
13
+ require_relative 'webdriver/webdriver_attributes_helper'
14
+ require_relative 'webdriver/webdriver_browser_info_helper'
15
+ require_relative 'webdriver/webdriver_type_helper'
16
+ require_relative 'webdriver/webdriver_exceptions'
17
+ require_relative 'webdriver/webdriver_helper'
18
+ require_relative 'webdriver/webdriver_js_methods'
19
+ require_relative 'webdriver/webdriver_screenshot_helper'
20
+ require_relative 'webdriver/webdriver_style_helper'
21
+ require_relative 'webdriver/webdriver_tab_helper'
22
+ require_relative 'webdriver/webdriver_user_agent_helper'
23
+ require_relative 'webdriver/webdriver_browser_log_helper'
24
+
25
+ module OnlyofficeWebdriverWrapper
26
+ # noinspection RubyTooManyMethodsInspection, RubyInstanceMethodNamingConvention, RubyParameterNamingConvention
27
+ class WebDriver
28
+ include ChromeHelper
29
+ include ClickMethods
30
+ include FirefoxHelper
31
+ include RubyHelper
32
+ include WaitUntilMethods
33
+ include WebdriverAlertHelper
34
+ include WebdriverAttributesHelper
35
+ include WebdriverBrowserInfo
36
+ include WebdriverTypeHelper
37
+ include WebdriverHelper
38
+ include WebdriverJsMethods
39
+ include WebdriverScreenshotHelper
40
+ include WebdriverStyleHelper
41
+ include WebdriverTabHelper
42
+ include WebdriverUserAgentHelper
43
+ include WebdriverBrowserLogHelper
44
+ TIMEOUT_FILE_DOWNLOAD = 100
45
+ # @return [Array, String] default switches for chrome
46
+ attr_accessor :driver
47
+ attr_accessor :browser
48
+ # @return [True, False] is browser currently running
49
+ attr_reader :browser_running
50
+ # @return [Symbol] device of which we try to simulate, default - :desktop_linux
51
+ attr_accessor :device
52
+ attr_accessor :download_directory
53
+ attr_accessor :server_address
54
+ attr_accessor :headless
55
+ # @return [Net::HTTP::Proxy] connection proxy
56
+ attr_accessor :proxy
57
+
58
+ def initialize(browser = :firefox,
59
+ _remote_server = nil,
60
+ device: :desktop_linux,
61
+ proxy: nil)
62
+ raise WebdriverSystemNotSupported, 'Your OS is not 64 bit. It is not supported' unless os_64_bit?
63
+
64
+ @device = device
65
+ @headless = HeadlessHelper.new
66
+ @headless.start
67
+
68
+ @download_directory = Dir.mktmpdir('webdriver-download')
69
+ @browser = browser
70
+ @proxy = proxy
71
+ case browser
72
+ when :firefox
73
+ @driver = start_firefox_driver
74
+ when :chrome
75
+ @driver = start_chrome_driver
76
+ else
77
+ raise 'Unknown Browser: ' + browser.to_s
78
+ end
79
+ @browser_running = true
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
+ return unless browser_running
97
+
98
+ begin
99
+ @driver.execute_script('window.onbeforeunload = null') # off popup window
100
+ rescue StandardError
101
+ Exception
102
+ end
103
+ begin
104
+ @driver.quit
105
+ rescue Exception => e
106
+ OnlyofficeLoggerHelper.log("Some error happened on webdriver.quit #{e.backtrace}")
107
+ end
108
+ alert_confirm
109
+ @headless.stop
110
+ cleanup_download_folder
111
+ @browser_running = false
112
+ end
113
+
114
+ def get_element(object_identification)
115
+ return object_identification unless object_identification.is_a?(String)
116
+
117
+ @driver.find_element(:xpath, object_identification)
118
+ rescue StandardError
119
+ nil
120
+ end
121
+
122
+ # Get text from all elements with specified xpath
123
+ # @param array_elements [String] xpath of elements
124
+ # @return [Array<String>] values of elements
125
+ def get_text_array(array_elements)
126
+ get_elements(array_elements).map { |current_element| get_text(current_element) }
127
+ end
128
+
129
+ def select_from_list_elements(value, elements_value)
130
+ index = get_element_index(value, elements_value)
131
+ elements_value[index].click
132
+ end
133
+
134
+ def get_element_index(title, list_elements)
135
+ list_elements.each_with_index do |current, i|
136
+ return i if get_text(current) == title
137
+ end
138
+ nil
139
+ end
140
+
141
+ def get_all_combo_box_values(xpath_name)
142
+ @driver.find_element(:xpath, xpath_name).find_elements(tag_name: 'option').map { |el| el.attribute('value') }
143
+ end
144
+
145
+ # @return [String] url of current frame, or browser url if
146
+ # it is a root frame
147
+ def get_url
148
+ execute_javascript('return window.location.href')
149
+ rescue Selenium::WebDriver::Error::NoSuchDriverError
150
+ raise 'Browser is crushed or hangup'
151
+ end
152
+
153
+ def refresh
154
+ @driver.navigate.refresh
155
+ OnlyofficeLoggerHelper.log('Refresh page')
156
+ end
157
+
158
+ def go_back
159
+ @driver.navigate.back
160
+ OnlyofficeLoggerHelper.log('Go back to previous page')
161
+ end
162
+
163
+ # Perform drag'n'drop action in one element (for example on big canvas area)
164
+ # for drag'n'drop one whole element use 'drag_and_drop_by'
165
+ # ==== Attributes
166
+ #
167
+ # * +xpath+ - xpath of element on which drag and drop performed
168
+ # * +x1+ - x coordinate on element to start drag'n'drop
169
+ # * +y1+ - y coordinate on element to start drag'n'drop
170
+ # * +x2+ - shift vector x coordinate
171
+ # * +y2+ - shift vector y coordinate
172
+ # * +mouse_release+ - release mouse after move
173
+ def drag_and_drop(xpath, x1, y1, x2, y2, mouse_release: true)
174
+ canvas = get_element(xpath)
175
+
176
+ move_action = @driver.action
177
+ .move_to(canvas, x1.to_i, y1.to_i)
178
+ .click_and_hold
179
+ .move_by(x2, y2)
180
+ move_action = move_action.release if mouse_release
181
+
182
+ move_action.perform
183
+ end
184
+
185
+ # Perform drag'n'drop one whole element
186
+ # for drag'n'drop inside one element (f.e. canvas) use drag_and_drop
187
+ # ==== Attributes
188
+ #
189
+ # * +source+ - xpath of element on which drag and drop performed
190
+ # * +right_by+ - shift vector x coordinate
191
+ # * +down_by+ - shift vector y coordinate
192
+ def drag_and_drop_by(source, right_by, down_by = 0)
193
+ @driver.action.drag_and_drop_by(get_element(source), right_by, down_by).perform
194
+ end
195
+
196
+ def scroll_list_to_element(list_xpath, element_xpath)
197
+ execute_javascript("$(document.evaluate(\"#{list_xpath}\", document, null, XPathResult.ANY_TYPE, null).
198
+ iterateNext()).jScrollPane().data('jsp').scrollToElement(document.evaluate(\"#{element_xpath}\",
199
+ document, null, XPathResult.ANY_TYPE, null).iterateNext());")
200
+ end
201
+
202
+ def scroll_list_by_pixels(list_xpath, pixels)
203
+ execute_javascript("$(document.evaluate(\"#{list_xpath.tr('"', "'")}\", document, null, XPathResult.ANY_TYPE, null).iterateNext()).scrollTop(#{pixels})")
204
+ end
205
+
206
+ # Open dropdown selector, like 'Color Selector', which has no element id
207
+ # @param [String] xpath_name name of dropdown list
208
+ def open_dropdown_selector(xpath_name, horizontal_shift = 30, vertical_shift = 0)
209
+ element = get_element(xpath_name)
210
+ if @browser == :firefox || @browser == :safari
211
+ set_style_attribute(xpath_name + '/button', 'display', 'none')
212
+ set_style_attribute(xpath_name, 'display', 'inline')
213
+ element.click
214
+ set_style_attribute(xpath_name + '/button', 'display', 'inline-block')
215
+ set_style_attribute(xpath_name, 'display', 'block')
216
+ else
217
+ @driver.action.move_to(element, horizontal_shift, vertical_shift).click.perform
218
+ end
219
+ end
220
+
221
+ def action_on_locator_coordinates(xpath_name, right_by, down_by, action = :click, times = 1)
222
+ wait_until_element_visible(xpath_name)
223
+ element = @driver.find_element(:xpath, xpath_name)
224
+ (0...times).inject(@driver.action.move_to(element, right_by.to_i, down_by.to_i)) { |acc, _elem| acc.send(action) }.perform
225
+ end
226
+
227
+ def move_to_element(element)
228
+ element = get_element(element) if element.is_a?(String)
229
+ @driver.action.move_to(element).perform
230
+ end
231
+
232
+ def move_to_element_by_locator(xpath_name)
233
+ element = get_element(xpath_name)
234
+ @driver.action.move_to(element).perform
235
+ OnlyofficeLoggerHelper.log("Moved mouse to element: #{xpath_name}")
236
+ end
237
+
238
+ def mouse_over(xpath_name, x_coordinate = 0, y_coordinate = 0)
239
+ wait_until_element_present(xpath_name)
240
+ @driver.action.move_to(@driver.find_element(:xpath, xpath_name), x_coordinate.to_i, y_coordinate.to_i).perform
241
+ end
242
+
243
+ def element_present?(xpath_name)
244
+ if xpath_name.is_a?(PageObject::Elements::Element)
245
+ xpath_name.present?
246
+ elsif xpath_name.is_a?(Selenium::WebDriver::Element)
247
+ xpath_name.displayed?
248
+ else
249
+ @driver.find_element(:xpath, xpath_name)
250
+ true
251
+ end
252
+ rescue Exception
253
+ false
254
+ end
255
+
256
+ def get_element_by_display(xpath_name)
257
+ @driver.find_elements(:xpath, xpath_name).each do |element|
258
+ return element if element.displayed?
259
+ end
260
+ rescue Selenium::WebDriver::Error::InvalidSelectorError
261
+ webdriver_error("get_element_by_display(#{xpath_name}): invalid selector: Unable to locate an element with the xpath expression")
262
+ end
263
+
264
+ # Return count of elements (visible and not visible)
265
+ # @param xpath_name [String] xpath to find
266
+ # @param only_visible [True, False] count only visible elements?
267
+ # @return [Integer] element count
268
+ def get_element_count(xpath_name, only_visible = true)
269
+ if element_present?(xpath_name)
270
+ elements = @driver.find_elements(:xpath, xpath_name)
271
+ only_visible ? elements.delete_if { |element| !element.displayed? }.length : elements.length
272
+ else
273
+ 0
274
+ end
275
+ end
276
+
277
+ def get_elements(objects_identification, only_visible = true)
278
+ return objects_identification if objects_identification.is_a?(Array)
279
+
280
+ elements = @driver.find_elements(:xpath, objects_identification)
281
+ if only_visible
282
+ elements.each do |current|
283
+ elements.delete(current) unless @browser == :firefox || current.displayed?
284
+ end
285
+ end
286
+ elements
287
+ end
288
+
289
+ def element_visible?(xpath_name)
290
+ if xpath_name.is_a?(PageObject::Elements::Element) # PageObject always visible
291
+ true
292
+ elsif element_present?(xpath_name)
293
+ element = get_element(xpath_name)
294
+ return false if element.nil?
295
+
296
+ begin
297
+ visible = element.displayed?
298
+ rescue Exception
299
+ visible = false
300
+ end
301
+ visible
302
+ else
303
+ false
304
+ end
305
+ end
306
+
307
+ # Check if any element of xpath is displayed
308
+ # @param xpath_several_elements [String] xpath to check
309
+ # @return [True, False] result of visibility
310
+ def one_of_several_elements_displayed?(xpath_several_elements)
311
+ @driver.find_elements(:xpath, xpath_several_elements).each do |current_element|
312
+ return true if current_element.displayed?
313
+ end
314
+ false
315
+ rescue Exception => e
316
+ webdriver_error("Raise unkwnown exception: #{e}")
317
+ end
318
+
319
+ def wait_element(xpath_name, period_of_wait = 1, critical_time = 3)
320
+ wait_until_element_present(xpath_name)
321
+ time = 0
322
+ until element_visible?(xpath_name)
323
+ sleep(period_of_wait)
324
+ time += 1
325
+ return if time == critical_time
326
+ end
327
+ end
328
+
329
+ # Select frame as current
330
+ # @param [String] xpath_name name of current xpath
331
+ def select_frame(xpath_name = '//iframe', count_of_frames = 1)
332
+ (0...count_of_frames).each do
333
+ begin
334
+ frame = @driver.find_element(:xpath, xpath_name)
335
+ @driver.switch_to.frame frame
336
+ rescue Selenium::WebDriver::Error::NoSuchElementError
337
+ OnlyofficeLoggerHelper.log('Raise NoSuchElementError in the select_frame method')
338
+ rescue Exception => e
339
+ webdriver_error("Raise unkwnown exception: #{e}")
340
+ end
341
+ end
342
+ end
343
+
344
+ # Select top frame of browser (even if several subframes exists)
345
+ def select_top_frame
346
+ @driver.switch_to.default_content
347
+ rescue Timeout::Error
348
+ OnlyofficeLoggerHelper.log('Raise TimeoutError in the select_top_frame method')
349
+ rescue Exception => e
350
+ raise "Browser is crushed or hangup with error: #{e}"
351
+ end
352
+
353
+ # Get text of current element
354
+ # @param [String] xpath_name name of xpath
355
+ # @param [true, false] wait_until_visible wait until element visible [@default = true]
356
+ def get_text(xpath_name, wait_until_visible = true)
357
+ wait_until_element_visible(xpath_name) if wait_until_visible
358
+
359
+ element = get_element(xpath_name)
360
+ webdriver_error("get_text(#{xpath_name}, #{wait_until_visible}) not found element by xpath") if element.nil?
361
+ if element.tag_name == 'input' || element.tag_name == 'textarea'
362
+ element.attribute('value')
363
+ else
364
+ element.text
365
+ end
366
+ end
367
+
368
+ def get_text_of_several_elements(xpath_several_elements)
369
+ @driver.find_elements(:xpath, xpath_several_elements).map { |element| element.text unless element.text == '' }.compact
370
+ end
371
+
372
+ def set_parameter(xpath, attribute, attribute_value)
373
+ execute_javascript("document.evaluate(\"#{xpath.tr('"', "'")}\",document, null, XPathResult.ANY_TYPE, null ).iterateNext()." \
374
+ "#{attribute}=\"#{attribute_value}\";")
375
+ end
376
+
377
+ def remove_attribute(xpath, attribute)
378
+ execute_javascript("document.evaluate(\"#{xpath}\",document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)." \
379
+ "singleNodeValue.removeAttribute('#{attribute}');")
380
+ end
381
+
382
+ def select_combo_box(xpath_name, select_value, select_by = :value)
383
+ wait_until_element_visible(xpath_name)
384
+ option = Selenium::WebDriver::Support::Select.new(get_element(xpath_name))
385
+ begin
386
+ option.select_by(select_by, select_value)
387
+ rescue StandardError
388
+ option.select_by(:text, select_value)
389
+ end
390
+ end
391
+
392
+ # Get page source
393
+ # @return [String] all page source
394
+ def get_page_source
395
+ @driver.execute_script('return document.documentElement.innerHTML;')
396
+ end
397
+
398
+ def webdriver_error(exception, error_message = nil)
399
+ if exception.is_a?(String) # If there is no error_message
400
+ error_message = exception
401
+ exception = RuntimeError
402
+ end
403
+ select_top_frame
404
+ current_url = get_url
405
+ raise exception, "#{error_message}\n\nPage address: #{current_url}\n\nError #{webdriver_screenshot}"
406
+ end
407
+
408
+ def wait_file_for_download(file_name, timeout = TIMEOUT_FILE_DOWNLOAD)
409
+ full_file_name = "#{@download_directory}/#{file_name}"
410
+ full_file_name = file_name if file_name[0] == '/'
411
+ counter = 0
412
+ while !File.exist?(full_file_name) && counter < timeout
413
+ OnlyofficeLoggerHelper.log("Waiting for download file #{full_file_name} for #{counter} of #{timeout}")
414
+ sleep 1
415
+ counter += 1
416
+ end
417
+ webdriver_error("File #{full_file_name} not download for #{timeout} seconds") if counter >= timeout
418
+ full_file_name
419
+ end
420
+
421
+ # Perform cleanup if something went wrong during tests
422
+ # @param forced [True, False] should cleanup run in all cases
423
+ def self.clean_up(forced = false)
424
+ return unless OnlyofficeFileHelper::LinuxHelper.user_name.include?('nct-at') ||
425
+ OnlyofficeFileHelper::LinuxHelper.user_name.include?('ubuntu') ||
426
+ forced == true
427
+
428
+ OnlyofficeFileHelper::LinuxHelper.kill_all('chromedriver')
429
+ OnlyofficeFileHelper::LinuxHelper.kill_all('geckodriver')
430
+ OnlyofficeFileHelper::LinuxHelper.kill_all('Xvfb')
431
+ OnlyofficeFileHelper::LinuxHelper.kill_all_browsers
432
+ end
433
+ end
434
+ end