From bffdd0e6a4d8b8b22b853d58f2c787939b3eb23b Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Mon, 30 Mar 2026 08:08:56 +0300 Subject: [PATCH 01/16] Added the click_all_in_list method, old version revised, testing needed --- lib/core/device.rb | 82 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index ddc05549..03b301bf 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -468,10 +468,10 @@ def click(action) begin if (action.keys & ["OffsetX", "OffsetY", "OffsetFractionX", "OffsetFractionY"]).any? x_offset = y_offset = 0 - x_offset = el.size.width * action["OffsetFractionX"] if action.key?("OffsetFractionX") - y_offset = el.size.height * action["OffsetFractionY"] if action.key?("OffsetFractionY") - x_offset = action["OffsetX"] if action.key?("OffsetX") - y_offset = action["OffsetY"] if action.key?("OffsetY") + x_offset = el.size.width * convert_value(action["OffsetFractionX"]).to_f if action.key?("OffsetFractionX") + y_offset = el.size.height * convert_value(action["OffsetFractionY"]).to_f if action.key?("OffsetFractionY") + x_offset = convert_value(action["OffsetX"]).to_i if action.key?("OffsetX") + y_offset = convert_value(action["OffsetY"]).to_i if action.key?("OffsetY") @driver.action.move_to(el, x_offset, y_offset) .click .perform @@ -603,6 +603,66 @@ def click_and_hold(action) end end + # clicks on all provided elements with the same id. Multiple location strategies are + # accepted - css, xPath, id. + # Accepts: + # Strategy + # Id + # Condition + # CheckTime + # OffsetX + # OffsetY + # NoRaise + def click_all_in_list(action) + wait_time = (action["CheckTime"] ? action["CheckTime"] : @timeout) + loop do + before_find = Time.now + elements = wait_for_all(action) + if elements.empty? + log_info("Element array is empty. Array: #{elements}") + break + end + + after_find = Time.now + log_info("Time to find element: #{after_find - before_find}s") if action["CheckTime"] + error = nil + + el = elements.shift + + loop do + begin + @platform == "iOS" ? + @driver.action.move_to(el) : + @driver.action.move_to(el).perform + rescue => e + error = e + end + begin + if (action.keys & ["OffsetX", "OffsetY"]).any? + x_offset = y_offset = 0 + x_offset = convert_value(action["OffsetX"]).to_i if action.key?("OffsetX") + y_offset = convert_value(action["OffsetY"]).to_i if action.key?("OffsetY") + @driver.action.move_to(el, x_offset, y_offset) + .click + .perform + else + el.click + end + log_info("Time for click: #{Time.now - after_find}s") if action["CheckTime"] + return + rescue => e + error = e + end + break if (Time.now - before_find) >= wait_time + end + + if error && !action["NoRaise"] + path = take_error_screenshot() + raise "#{@role}: Element '#{action["Id"]}': #{error.message}\nError Screenshot: #{path}" + end + end + end + # sets the provided value for element. # Accepts: # Strategy @@ -938,7 +998,7 @@ def context(action) def get_attribute(action) el = wait_for(action) return unless el - + greps = action["Greps"] return if greps.nil? @@ -1549,7 +1609,7 @@ def state_checker(action) strategy, idlist, message, app = action["Strategy"], action["Id"], action["Message"], action["App"] default_wait_time = (action["Time"] ? action["Time"] : @timeout) $network_state = 0 - + filename = File.join(convert_value(action["Path"]), "network_states.csv") seen_list = [] file = File.open(filename, "w") @@ -1600,7 +1660,7 @@ def state_checker(action) rows_with_loading = csv.select {|row| row["Call state"] == '2'} last = rows_with_loading.last last_time = last["Time"] - + net_down = csv.find { |row| row["Network state"] == '1' } net_down = net_down["Time"] prew = nil @@ -1641,7 +1701,7 @@ def take_error_screenshot() folder = File.join(Dir.pwd, "Reports", "screenshots") end path = File.join(folder, "screenshot_#{@role}.png") - + begin FileUtils.mkdir_p(folder) unless Dir.exist? folder if @udid @@ -1723,7 +1783,7 @@ def assert(action) src_var = ENV[convert_value(assert["Var"])] cmp_var = assert["Value"].is_a?(Numeric) ? assert["Value"] : convert_value(assert["Value"]) op = assert["Type"].downcase - + # check for class mismatches if ["contain", "n_contain"].include?(op) raise "#{@role}: Value '#{cmp_var}' should be a String!" unless cmp_var.is_a?(String) @@ -1744,7 +1804,7 @@ def assert(action) else raise "#{@role}: Unknown assertion type '#{op}'!" end - + # do the actual operation on_fail_text = "" case op @@ -1765,7 +1825,7 @@ def assert(action) when "ge" on_fail_text = "be greater or equal to" unless src_var >= cmp_var end - + unless on_fail_text.empty? path = take_error_screenshot unless "command" == @application screenshot_error = (path ? "\nError Screenshot: #{path}" : "") From 6bdc53c1ec1ee71c96807f8f5489284a1d9f309b Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Mon, 30 Mar 2026 12:04:09 +0300 Subject: [PATCH 02/16] Added missing method wait_for_all --- lib/core/device.rb | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/lib/core/device.rb b/lib/core/device.rb index 03b301bf..95657084 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -1240,6 +1240,59 @@ def wait_for(action) end end + # waits for the provided elements to be present. + # Accepts: + # Strategy + # Id + # Index + # Time or CheckTime + # Condition + def wait_for_all(action) + locator_strategy, id = action["Strategy"], action["Id"] + if action["Condition"] + return unless check_condition(action) + end + + wait_time = (action["Time"] ? action["Time"] : @timeout) + wait_time = (action["CheckTime"] ? action["CheckTime"] : wait_time) + + elements = [] + exception = "" + start = Time.now + + if id.is_a?(String) + id = convert_value(id) + while (Time.now - start) < wait_time + begin + elements = @driver.find_elements(locator_strategy, id) || [] + return elements unless elements.empty? + rescue => e + exception = e + sleep(0.2) + end + end + else + while (Time.now - start) < wait_time + id.each_with_index do |locator, i| + locator = convert_value(locator) + begin + elements += @driver.find_elements(convert_value(locator_strategy[i]), locator) || [] + rescue => e + exception = e + sleep(0.1) + end + end + return elements unless elements.empty? + end + end + + if elements.empty? && !action["NoRaise"] + path = take_error_screenshot() + raise "\n#{@role}: Element '#{id}' is not visible after #{wait_time} " + + "seconds \nException: #{exception}\nError Screenshot: #{path}" + end + end + # sets provided network condition to driver. # Accepts: # Condition From b78f1db4ee4c6159eea01230e8d78cc7566df7cb Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Mon, 30 Mar 2026 12:25:47 +0300 Subject: [PATCH 03/16] Loop logic reworked for click_all_in_list --- lib/core/device.rb | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 95657084..24f54da2 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -615,13 +615,9 @@ def click_and_hold(action) # NoRaise def click_all_in_list(action) wait_time = (action["CheckTime"] ? action["CheckTime"] : @timeout) - loop do - before_find = Time.now - elements = wait_for_all(action) - if elements.empty? - log_info("Element array is empty. Array: #{elements}") - break - end + before_find = Time.now + elements = wait_for_all(action) + while elements.any? after_find = Time.now log_info("Time to find element: #{after_find - before_find}s") if action["CheckTime"] @@ -655,7 +651,8 @@ def click_all_in_list(action) end break if (Time.now - before_find) >= wait_time end - + before_find = Time.now + elements = wait_for_all(action) if error && !action["NoRaise"] path = take_error_screenshot() raise "#{@role}: Element '#{action["Id"]}': #{error.message}\nError Screenshot: #{path}" From d98866c68c3051746e28e665d82b460ac4f99a79 Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Mon, 30 Mar 2026 13:51:51 +0300 Subject: [PATCH 04/16] Added some debug lines and changed return to break in click_all_in_list --- lib/core/device.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 24f54da2..7a1d2bbe 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -617,6 +617,7 @@ def click_all_in_list(action) wait_time = (action["CheckTime"] ? action["CheckTime"] : @timeout) before_find = Time.now elements = wait_for_all(action) + log_info("Elements found: #{elements}") while elements.any? after_find = Time.now @@ -624,6 +625,7 @@ def click_all_in_list(action) error = nil el = elements.shift + log_info("Element to click: #{el}") loop do begin @@ -645,7 +647,7 @@ def click_all_in_list(action) el.click end log_info("Time for click: #{Time.now - after_find}s") if action["CheckTime"] - return + break rescue => e error = e end @@ -653,6 +655,7 @@ def click_all_in_list(action) end before_find = Time.now elements = wait_for_all(action) + log_info("Elements found: #{elements}") if error && !action["NoRaise"] path = take_error_screenshot() raise "#{@role}: Element '#{action["Id"]}': #{error.message}\nError Screenshot: #{path}" From bf67e1ffd221ee6ba0606325a605d363ab7e99b2 Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Mon, 30 Mar 2026 14:58:25 +0300 Subject: [PATCH 05/16] Removed debug lines, added error handling for element list in click_all_in_list --- lib/core/device.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 7a1d2bbe..8a9c1a02 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -617,7 +617,7 @@ def click_all_in_list(action) wait_time = (action["CheckTime"] ? action["CheckTime"] : @timeout) before_find = Time.now elements = wait_for_all(action) - log_info("Elements found: #{elements}") + while elements.any? after_find = Time.now @@ -625,7 +625,6 @@ def click_all_in_list(action) error = nil el = elements.shift - log_info("Element to click: #{el}") loop do begin @@ -653,9 +652,15 @@ def click_all_in_list(action) end break if (Time.now - before_find) >= wait_time end + before_find = Time.now - elements = wait_for_all(action) - log_info("Elements found: #{elements}") + + begin + elements = wait_for_all(action) + rescue => e + log_info("No more elements found.") + end + if error && !action["NoRaise"] path = take_error_screenshot() raise "#{@role}: Element '#{action["Id"]}': #{error.message}\nError Screenshot: #{path}" From 7cf1746c9f91620163f55876bc67c73daf87ee0e Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Tue, 31 Mar 2026 11:48:23 +0300 Subject: [PATCH 06/16] Added debug lines, added a scroll to element method --- lib/core/device.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 8a9c1a02..18d88917 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -617,7 +617,7 @@ def click_all_in_list(action) wait_time = (action["CheckTime"] ? action["CheckTime"] : @timeout) before_find = Time.now elements = wait_for_all(action) - + log_info("Initial elements found: #{elements}") if elements while elements.any? after_find = Time.now @@ -640,9 +640,10 @@ def click_all_in_list(action) x_offset = convert_value(action["OffsetX"]).to_i if action.key?("OffsetX") y_offset = convert_value(action["OffsetY"]).to_i if action.key?("OffsetY") @driver.action.move_to(el, x_offset, y_offset) - .click - .perform + .click + .perform else + scroll_until_element_visible(action) el.click end log_info("Time for click: #{Time.now - after_find}s") if action["CheckTime"] @@ -656,7 +657,8 @@ def click_all_in_list(action) before_find = Time.now begin - elements = wait_for_all(action) + elements = wait_for_all(action, checktime = 10) + log_info("Elements found: #{elements}") if elements rescue => e log_info("No more elements found.") end @@ -1252,7 +1254,7 @@ def wait_for(action) # Index # Time or CheckTime # Condition - def wait_for_all(action) + def wait_for_all(action, checktime = nil) locator_strategy, id = action["Strategy"], action["Id"] if action["Condition"] return unless check_condition(action) @@ -1260,6 +1262,7 @@ def wait_for_all(action) wait_time = (action["Time"] ? action["Time"] : @timeout) wait_time = (action["CheckTime"] ? action["CheckTime"] : wait_time) + wait_time = (checktime ? checktime : wait_time) elements = [] exception = "" From 9bd98483170cf3b0b53fae539ca4820e35b339f6 Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Tue, 31 Mar 2026 12:40:41 +0300 Subject: [PATCH 07/16] Scroll until visible changed, added sleeps --- lib/core/device.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 18d88917..8991f4ed 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -634,6 +634,8 @@ def click_all_in_list(action) rescue => e error = e end + scroll_until_element_visible(actions) + sleep(2) begin if (action.keys & ["OffsetX", "OffsetY"]).any? x_offset = y_offset = 0 @@ -643,9 +645,9 @@ def click_all_in_list(action) .click .perform else - scroll_until_element_visible(action) el.click end + log_info("Current element clicked: #{el.id}") log_info("Time for click: #{Time.now - after_find}s") if action["CheckTime"] break rescue => e @@ -657,6 +659,7 @@ def click_all_in_list(action) before_find = Time.now begin + sleep(2) elements = wait_for_all(action, checktime = 10) log_info("Elements found: #{elements}") if elements rescue => e From 9aa0f2858b27606110da0694e63e4857af84fea4 Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Tue, 31 Mar 2026 13:02:01 +0300 Subject: [PATCH 08/16] Scroll until visible typo fixed --- lib/core/device.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 8991f4ed..3b35f2e5 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -634,7 +634,7 @@ def click_all_in_list(action) rescue => e error = e end - scroll_until_element_visible(actions) + scroll_until_element_visible(action) sleep(2) begin if (action.keys & ["OffsetX", "OffsetY"]).any? From 47516655930ebea0d25a59f417bac64b9a542250 Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Wed, 1 Apr 2026 12:26:13 +0300 Subject: [PATCH 09/16] Disabling scrolling to check for errors --- lib/core/device.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 3b35f2e5..a4b4ada3 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -634,7 +634,7 @@ def click_all_in_list(action) rescue => e error = e end - scroll_until_element_visible(action) + # scroll_until_element_visible(action) sleep(2) begin if (action.keys & ["OffsetX", "OffsetY"]).any? From a535372077569560c594aa04b660769db0791622 Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Thu, 2 Apr 2026 10:49:47 +0300 Subject: [PATCH 10/16] Added scroll action for scroll until element visible method --- lib/core/device.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index a4b4ada3..a12c988b 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -614,6 +614,7 @@ def click_and_hold(action) # OffsetY # NoRaise def click_all_in_list(action) + log_info("Action: #{action}") wait_time = (action["CheckTime"] ? action["CheckTime"] : @timeout) before_find = Time.now elements = wait_for_all(action) @@ -634,7 +635,12 @@ def click_all_in_list(action) rescue => e error = e end - # scroll_until_element_visible(action) + scroll_action = { + "Strategy" => action["Strategy"], + "Id" => action["Id"], + "FullView" => true + } + scroll_until_element_visible(scroll_action) sleep(2) begin if (action.keys & ["OffsetX", "OffsetY"]).any? From df8d8d48c4f7849a8a29ead3a280532c6d28dc9d Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Thu, 2 Apr 2026 13:38:08 +0300 Subject: [PATCH 11/16] Added check after elements are finished on screen for elements off screen as well --- lib/core/device.rb | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index a12c988b..782e0b54 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -635,13 +635,7 @@ def click_all_in_list(action) rescue => e error = e end - scroll_action = { - "Strategy" => action["Strategy"], - "Id" => action["Id"], - "FullView" => true - } - scroll_until_element_visible(scroll_action) - sleep(2) + begin if (action.keys & ["OffsetX", "OffsetY"]).any? x_offset = y_offset = 0 @@ -667,9 +661,28 @@ def click_all_in_list(action) begin sleep(2) elements = wait_for_all(action, checktime = 10) - log_info("Elements found: #{elements}") if elements + log_info("Elements found: #{elements}") rescue => e log_info("No more elements found.") + # Check if there are anymore elements left off screen + begin + x_point = screen_size.width * 0.5 + y_start = screen_size.height * 0.5 + + @driver.action + .move_to_location(x_point, y_start) + .pointer_down(:left) + .move_to_location(x_point, y_start - 160, duration: 0.3) + .release + .perform + + sleep(2) + + elements = wait_for_all(action) + rescue => e + error = e + log_info("Error moving to element #{element.id}: #{e.message}") + end end if error && !action["NoRaise"] From 426f6df82a6dca77476cd1ea71550398530b1216 Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Thu, 2 Apr 2026 13:58:54 +0300 Subject: [PATCH 12/16] Removed missing variable --- lib/core/device.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 782e0b54..0661a666 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -681,7 +681,7 @@ def click_all_in_list(action) elements = wait_for_all(action) rescue => e error = e - log_info("Error moving to element #{element.id}: #{e.message}") + log_info("Error moving to element: #{e.message}") end end From 2c38e1c150fb298c409a5477a1111a9af5cf2546 Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Thu, 2 Apr 2026 14:10:30 +0300 Subject: [PATCH 13/16] Removed missing variable --- lib/core/device.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/core/device.rb b/lib/core/device.rb index 0661a666..5b3645b6 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -666,6 +666,7 @@ def click_all_in_list(action) log_info("No more elements found.") # Check if there are anymore elements left off screen begin + screen_size = @driver.window_size x_point = screen_size.width * 0.5 y_start = screen_size.height * 0.5 From 66ecb9fd12cfed0b63ad5b2325f03c1cef907a0d Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Tue, 7 Apr 2026 12:37:07 +0300 Subject: [PATCH 14/16] Changed variable naming --- lib/core/device.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 5b3645b6..5cc82c92 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -666,14 +666,14 @@ def click_all_in_list(action) log_info("No more elements found.") # Check if there are anymore elements left off screen begin - screen_size = @driver.window_size - x_point = screen_size.width * 0.5 - y_start = screen_size.height * 0.5 + window_size = @driver.window_size + x_middle = window_size.width * 0.5 + y_middle = window_size.height * 0.5 @driver.action - .move_to_location(x_point, y_start) + .move_to_location(x_middle, y_middle) .pointer_down(:left) - .move_to_location(x_point, y_start - 160, duration: 0.3) + .move_to_location(x_middle, y_middle - 160, duration: 0.3) .release .perform From 7e9ef55f8e8c713dbcf1a7555c83d153cdb9a38b Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Wed, 8 Apr 2026 06:30:43 +0300 Subject: [PATCH 15/16] Changed variable naming for swipe location --- lib/core/device.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 5cc82c92..5479f9b1 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -626,6 +626,8 @@ def click_all_in_list(action) error = nil el = elements.shift + el_location = el.location + el_size = el.size loop do begin @@ -666,9 +668,8 @@ def click_all_in_list(action) log_info("No more elements found.") # Check if there are anymore elements left off screen begin - window_size = @driver.window_size - x_middle = window_size.width * 0.5 - y_middle = window_size.height * 0.5 + x_middle = el_location.x + (el_size.width / 2) + y_middle = el_location.y + (el_size.height / 2) @driver.action .move_to_location(x_middle, y_middle) From aad182e6bc6dd8cb9ecbc76620103d7097392c70 Mon Sep 17 00:00:00 2001 From: "krisjanis.vilnis" Date: Wed, 8 Apr 2026 15:09:49 +0300 Subject: [PATCH 16/16] Redone some logic for scrolling to check if elements visible off screen --- lib/core/device.rb | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/core/device.rb b/lib/core/device.rb index 5479f9b1..c002c6cf 100644 --- a/lib/core/device.rb +++ b/lib/core/device.rb @@ -668,6 +668,7 @@ def click_all_in_list(action) log_info("No more elements found.") # Check if there are anymore elements left off screen begin + log_info("Checking if there are more elements off screen.") x_middle = el_location.x + (el_size.width / 2) y_middle = el_location.y + (el_size.height / 2) @@ -678,13 +679,22 @@ def click_all_in_list(action) .release .perform - sleep(2) - - elements = wait_for_all(action) rescue => e error = e log_info("Error moving to element: #{e.message}") end + sleep(2) + begin + search_action = { + "Strategy" => action["Strategy"], + "Id" => action["Id"], + "CheckTime" => 10 + } + elements = wait_for_all(search_action) + log_info("Elements found: #{elements}") + rescue => e + log_info("No more elements found after scroll.") + end end if error && !action["NoRaise"]