bugsnag-maze-runner 9.26.0 → 9.27.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: abe6839c118433a185e262346bb616d17f0b2b90072eeb5962b25bf25c9a5f22
4
- data.tar.gz: bc1741d029fba29158f2508ce191735c983ee216a2c6aa9beced5c2c7b908062
3
+ metadata.gz: 9bd02873165d9c325474a4b82e5f9852fedec9a0bbb9c8b44cfcfb380d8100d9
4
+ data.tar.gz: 0cb7d33cca48f70ae817bd458c22e86667ca71deecb31ec2e7961b7e6fbfa0a0
5
5
  SHA512:
6
- metadata.gz: 74da6521237c5610846964b81407ab8316d1eebac30a7347cfd598e29508731e3ed0549679c8d08ccde20f2c08ae135c29224009ecfb45f8678237e044b6bd88
7
- data.tar.gz: 3c852d53478a052d0950d9c35174c0ada1d223d2f7208fa98024547d6bc51e6d5bd4596d83afb332b8a85f505067c6e94e6cebfeaed623350a9cd3135a86d99e
6
+ metadata.gz: fad90d03b281add0d5d2ebbd47927564addaf90ef732898feb7d92c6194ef2fbd491c556c18e298aedb20520db22a71755b37cc2cbbc7c9bcd5fb2ed6ab97b43
7
+ data.tar.gz: c58286e20b34451e0e50411d44b3105ff675ff5ed650709321b49da29f5c2e11e9dd7d5ab7a7aa459215315c55e90fc2998af27d62b16cf852e8aaa441b57ff7
data/bin/maze-runner CHANGED
@@ -15,6 +15,7 @@ require_relative '../lib/maze/api/appium/manager'
15
15
  require_relative '../lib/maze/api/appium/app_manager'
16
16
  require_relative '../lib/maze/api/appium/device_manager'
17
17
  require_relative '../lib/maze/api/appium/file_manager'
18
+ require_relative '../lib/maze/api/appium/ui_manager'
18
19
  require_relative '../lib/maze/api/cucumber/scenario'
19
20
  require_relative '../lib/maze/api/exit_code'
20
21
  require_relative '../lib/maze/bugsnag_config'
@@ -40,7 +41,6 @@ require_relative '../lib/maze/aws_public_ip'
40
41
  require_relative '../lib/maze/compare'
41
42
  require_relative '../lib/maze/docker'
42
43
  require_relative '../lib/maze/document_server'
43
- require_relative '../lib/maze/error_captor'
44
44
  require_relative '../lib/maze/errors'
45
45
  require_relative '../lib/maze/generator'
46
46
  require_relative '../lib/maze/helper'
@@ -5,7 +5,7 @@
5
5
  #
6
6
  # @step_input element_id [String] The locator id
7
7
  Given('the element {string} is present') do |element_id|
8
- present = Maze.driver.wait_for_element(element_id)
8
+ present = Maze::Api::Appium::UiManager.new.wait_for_element(element_id)
9
9
  raise Maze::Error::AppiumElementNotFoundError.new("The element #{element_id} could not be found", element_id) unless present
10
10
  end
11
11
 
@@ -15,7 +15,7 @@ end
15
15
  # @step_input element_id [String] The locator id
16
16
  # @step_input timeout [Int] The number of seconds to wait before timing out
17
17
  Given('the element {string} is present within {int} seconds') do |element_id, timeout|
18
- present = Maze.driver.wait_for_element(element_id, timeout)
18
+ present = Maze::Api::Appium::UiManager.new.wait_for_element(element_id, timeout)
19
19
  raise Maze::Error::AppiumElementNotFoundError.new("The element #{element_id} could not be found", element_id) unless present
20
20
  end
21
21
 
@@ -24,7 +24,15 @@ end
24
24
  #
25
25
  # @step_input element_id [String] The locator id
26
26
  When('I click the element {string}') do |element_id|
27
- Maze.driver.click_element(element_id)
27
+ Maze::Api::Appium::UiManager.new.click_element(element_id)
28
+ end
29
+
30
+ # Clicks a given element if present
31
+ # Requires a running Appium driver
32
+ #
33
+ # @step_input element_id [String] The locator id
34
+ When('I click the element {string} if present') do |element_id|
35
+ Maze::Api::Appium::UiManager.new.click_element_if_present(element_id)
28
36
  end
29
37
 
30
38
  # Sends the app to the background indefinitely
@@ -45,6 +53,7 @@ end
45
53
  # Requires a running Appium driver
46
54
  #
47
55
  # @step_input element_id [String] The locator id
56
+ # @deprecated To be removed in the next major version
48
57
  When('I clear the element {string}') do |element_id|
49
58
  Maze.driver.clear_element(element_id)
50
59
  end
@@ -54,6 +63,7 @@ end
54
63
  #
55
64
  # @step_input keys [String] The keys to send to the element
56
65
  # @step_input element_id [String] The locator id
66
+ # @deprecated To be removed in the next major version
57
67
  When('I send the keys {string} to the element {string}') do |keys, element_id|
58
68
  Maze.driver.send_keys_to_element(element_id, keys)
59
69
  end
@@ -61,7 +71,7 @@ end
61
71
  # Set the device orientation to either portrait or landscape
62
72
  # Requires a running Appium driver
63
73
  When('I set the device orientation to {orientation}') do |orientation|
64
- Maze.driver.set_rotation orientation
74
+ Maze::Api::Appium::DeviceManager.new.set_rotation orientation
65
75
  end
66
76
 
67
77
  # Sends keys to a given element, clearing it first
@@ -69,6 +79,7 @@ end
69
79
  #
70
80
  # @step_input keys [String] The keys to send to the element
71
81
  # @step_input element_id [String] The locator id
82
+ # @deprecated To be removed in the next major version
72
83
  When('I clear and send the keys {string} to the element {string}') do |keys, element_id|
73
84
  Maze.driver.clear_and_send_keys_to_element(element_id, keys)
74
85
  end
@@ -194,7 +194,6 @@ ensure
194
194
  Maze::Runner.environment.clear
195
195
  Maze::Store.values.clear
196
196
  Maze::Aws::Sam.reset!
197
- Maze::ErrorCaptor.reset
198
197
  end
199
198
 
200
199
  def output_received_requests(request_type)
@@ -40,6 +40,23 @@ module Maze
40
40
  raise e
41
41
  end
42
42
 
43
+ # Gets logs from the device.
44
+ # @param log_type [String] The type pf log to get as recognised by Appium, such as 'syslog'
45
+ #
46
+ # @returns [Array, nil] Array of Selenium::WebDriver::LogEntry, or nil if the driver has failed
47
+ def get_log(log_type)
48
+ if failed_driver?
49
+ $logger.error 'Cannot get logs - Appium driver failed.'
50
+ return nil
51
+ end
52
+
53
+ @driver.get_log(log_type)
54
+ rescue Selenium::WebDriver::Error::ServerError => e
55
+ # Assume the remote appium session has stopped, so crash out of the session
56
+ fail_driver(e.message)
57
+ raise e
58
+ end
59
+
43
60
  # Sets the rotation of the device.
44
61
  # @param orientation [Symbol] The orientation to set the device to, :portrait or :landscape
45
62
  # @returns [Boolean] Success status
@@ -0,0 +1,69 @@
1
+ require_relative '../../helper'
2
+ require_relative './manager'
3
+
4
+ module Maze
5
+ module Api
6
+ module Appium
7
+ # Provides operations for working with the app.
8
+ class UiManager < Maze::Api::Appium::Manager
9
+
10
+ # Checks for an element, waiting until it is present or the method times out
11
+ #
12
+ # @param element_id [String] the element to search for
13
+ # @param timeout [Integer] the maximum time to wait for an element to be present in seconds
14
+ # @param retry_if_stale [Boolean] enables the method to retry acquiring the element if a StaleObjectException occurs
15
+ #
16
+ # @returns [Boolean] Whether the operation was successfully performed
17
+ def wait_for_element(element_id, timeout = 15, retry_if_stale = true)
18
+ if failed_driver?
19
+ $logger.error 'Cannot wait for element - Appium driver failed.'
20
+ return false
21
+ end
22
+
23
+ @driver.wait_for_element(element_id, timeout, retry_if_stale)
24
+ rescue Selenium::WebDriver::Error::ServerError => e
25
+ # Assume the remote appium session has stopped, so crash out of the session
26
+ fail_driver(e.message)
27
+ raise e
28
+ end
29
+
30
+ # Clicks a given element.
31
+ #
32
+ # @param element_id [String] the element to click
33
+ #
34
+ # @returns [Boolean] Whether the operation was successfully performed
35
+ def click_element(element_id)
36
+ if failed_driver?
37
+ $logger.error 'Cannot click element - Appium driver failed.'
38
+ return false
39
+ end
40
+
41
+ @driver.click_element(element_id)
42
+ true
43
+ rescue Selenium::WebDriver::Error::ServerError => e
44
+ # Assume the remote appium session has stopped, so crash out of the session
45
+ fail_driver(e.message)
46
+ raise e
47
+ end
48
+
49
+ # Clicks a given element if present.
50
+ #
51
+ # @param element_id [String] the element to click
52
+ #
53
+ # @returns [Boolean] Whether the element was clicked
54
+ def click_element_if_present(element_id)
55
+ if failed_driver?
56
+ $logger.error 'Cannot click element - Appium driver failed.'
57
+ return false
58
+ end
59
+
60
+ @driver.click_element_if_present(element_id)
61
+ rescue Selenium::WebDriver::Error::ServerError => e
62
+ # Assume the remote appium session has stopped, so crash out of the session
63
+ fail_driver(e.message)
64
+ raise e
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -33,7 +33,6 @@ module Maze
33
33
  end
34
34
  config.middleware.use(AssertErrorMiddleware)
35
35
  config.middleware.use(AmbiguousErrorMiddleware)
36
- config.middleware.use(ErrorCaptureMiddleware)
37
36
  config.add_metadata(:'buildkite', metadata)
38
37
  config.project_root = Dir.pwd
39
38
  end
@@ -71,10 +70,7 @@ module Maze
71
70
  end
72
71
 
73
72
  class AmbiguousErrorMiddleware
74
- AMBIGUOUS_ERROR_CLASSES = [
75
- 'Selenium::WebDriver::Error::ServerError',
76
- 'Selenium::WebDriver::Error::UnknownError'
77
- ]
73
+ AMBIGUOUS_ERROR_CLASSES = %w[Selenium::WebDriver::Error::ServerError Selenium::WebDriver::Error::UnknownError]
78
74
 
79
75
  def initialize(middleware)
80
76
  @middleware = middleware
@@ -89,18 +85,5 @@ module Maze
89
85
  @middleware.call(report)
90
86
  end
91
87
  end
92
-
93
- class ErrorCaptureMiddleware
94
-
95
- def initialize(middleware)
96
- @middleware = middleware
97
- end
98
-
99
- def call(report)
100
- Maze::ErrorCaptor.add(report.dup)
101
-
102
- @middleware.call(report)
103
- end
104
- end
105
88
  end
106
89
  end
@@ -37,7 +37,7 @@ module Maze
37
37
 
38
38
  # Ensure the device is unlocked
39
39
  begin
40
- Maze.driver.unlock
40
+ Maze::Api::Appium::DeviceManager.new.unlock
41
41
  rescue => error
42
42
  Bugsnag.notify error
43
43
  $logger.warn "Failed to unlock device: #{error}"
@@ -59,7 +59,7 @@ module Maze
59
59
  end
60
60
 
61
61
  def write_device_info
62
- info = Maze.driver.device_info
62
+ info = Maze::Api::Appium::DeviceManager.new.info
63
63
  filepath = File.join(Dir.pwd, 'maze_output', 'device_info.json')
64
64
  File.open(filepath, 'w+') do |file|
65
65
  file.puts(JSON.pretty_generate(info))
@@ -4,12 +4,6 @@ module Maze
4
4
  # Hooks for Appium mode use
5
5
  class AppiumHooks < InternalHooks
6
6
 
7
- APPIUM_DRIVER_FAILED_ERRORS = [
8
- Selenium::WebDriver::Error::UnknownError,
9
- Selenium::WebDriver::Error::ServerError,
10
- Selenium::WebDriver::Error::WebDriverError
11
- ]
12
-
13
7
  @client
14
8
 
15
9
  def before_all
@@ -30,11 +24,7 @@ module Maze
30
24
  end
31
25
 
32
26
  def after(scenario)
33
- if scenario.failed?
34
- Maze.driver = nil if driver_has_failed?
35
- $logger.warn('The appium driver has failed, removing it to prevent future errors')
36
- end
37
-
27
+ manager = Maze::Api::Appium::AppManager.new
38
28
  if Maze.config.os == 'macos'
39
29
  # Close the app - without the sleep, launching the app for the next scenario intermittently fails
40
30
  system("killall -KILL #{Maze.config.app} && sleep 1")
@@ -42,17 +32,17 @@ module Maze
42
32
  # Reset the server to ensure that test fixtures cannot fetch
43
33
  # commands from the previous scenario (in idempotent mode).
44
34
  begin
45
- Maze.driver.terminate_app Maze.driver.app_id
35
+ manager.terminate
46
36
  rescue Selenium::WebDriver::Error::UnknownError, Selenium::WebDriver::Error::InvalidSessionIdError
47
37
  if Maze.config.appium_version && Maze.config.appium_version.to_f < 2.0
48
38
  $logger.warn 'terminate_app failed, using the slower but more forceful close_app instead'
49
- Maze.driver.close_app
39
+ manager.close
50
40
  else
51
41
  $logger.warn 'terminate_app failed, future errors may occur if the application did not close remotely'
52
42
  end
53
43
  end
54
44
  Maze::Server.reset!
55
- Maze.driver.activate_app Maze.driver.app_id
45
+ manager.activate
56
46
  end
57
47
  rescue => error
58
48
  # Notify and re-raise for Cucumber to handle
@@ -79,30 +69,6 @@ module Maze
79
69
  @client.stop_session
80
70
  end
81
71
  end
82
-
83
- private
84
-
85
- def driver_has_failed?
86
- return false if Maze::ErrorCaptor.empty?
87
-
88
- Maze::ErrorCaptor.classes.any? do |error_class|
89
- APPIUM_DRIVER_FAILED_ERRORS.include?(error_class)
90
- end
91
- end
92
-
93
- # Pulls the device logs using Appium and writes them to file in the maze_output folder
94
- def write_device_logs(scenario)
95
- log_name = case Maze::Helper.get_current_platform
96
- when 'android'
97
- 'logcat'
98
- when 'ios'
99
- 'syslog'
100
- end
101
- unless Maze.driver.nil?
102
- logs = Maze.driver.get_log(log_name)
103
- Maze::MazeOutput.new(scenario).write_device_logs(logs)
104
- end
105
- end
106
72
  end
107
73
  end
108
74
  end
@@ -90,19 +90,6 @@ module Maze
90
90
  end
91
91
  end
92
92
 
93
- # Writes a set of logs to a device logs file
94
- # @param logs [Array<String>] The lines of log to be written
95
- def write_device_logs(logs)
96
-
97
- dir = output_folder
98
- FileUtils.makedirs(dir)
99
- filepath = File.join(dir, 'device.log')
100
-
101
- File.open(filepath, 'w+') do |file|
102
- logs.each { |line| file.puts line }
103
- end
104
- end
105
-
106
93
  # Determines the output folder for the scenario
107
94
  def output_folder
108
95
  folder1 = File.join(Dir.pwd, 'maze_output')
@@ -20,7 +20,7 @@ module Maze
20
20
  return false if !Maze.config.enable_retries || retried_previously?(test_case)
21
21
 
22
22
  if retry_on_driver_error?(event)
23
- if Maze.driver.is_a?(Maze::Driver::Appium)
23
+ if Maze.mode == :appium
24
24
  if Maze.config.farm.eql?(:bb)
25
25
  Maze::Hooks::ErrorCodeHook.exit_code = Maze::Api::ExitCode::APPIUM_SESSION_FAILURE
26
26
  return false
@@ -28,7 +28,7 @@ module Maze
28
28
  $logger.warn "Retrying #{test_case.name} due to appium driver error: #{event.result.exception}"
29
29
  Maze.driver.restart
30
30
  end
31
- elsif Maze.driver.is_a?(Maze::Driver::Browser)
31
+ elsif Maze.mode == :browser
32
32
  $logger.warn "Retrying #{test_case.name} due to selenium driver error: #{event.result.exception}"
33
33
  Maze.driver.refresh
34
34
  end
data/lib/maze.rb CHANGED
@@ -8,7 +8,7 @@ require_relative 'maze/timers'
8
8
  # providing an alternative to the proliferation of global variables or singletons.
9
9
  module Maze
10
10
 
11
- VERSION = '9.26.0'
11
+ VERSION = '9.27.1'
12
12
 
13
13
  class << self
14
14
  attr_accessor :check, :driver, :internal_hooks, :mode, :start_time, :dynamic_retry, :public_address,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bugsnag-maze-runner
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.26.0
4
+ version: 9.27.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Kirkland
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-18 00:00:00.000000000 Z
11
+ date: 2025-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cucumber
@@ -444,6 +444,7 @@ files:
444
444
  - lib/maze/api/appium/device_manager.rb
445
445
  - lib/maze/api/appium/file_manager.rb
446
446
  - lib/maze/api/appium/manager.rb
447
+ - lib/maze/api/appium/ui_manager.rb
447
448
  - lib/maze/api/cucumber/scenario.rb
448
449
  - lib/maze/api/exit_code.rb
449
450
  - lib/maze/appium_server.rb
@@ -478,7 +479,6 @@ files:
478
479
  - lib/maze/document_server.rb
479
480
  - lib/maze/driver/appium.rb
480
481
  - lib/maze/driver/browser.rb
481
- - lib/maze/error_captor.rb
482
482
  - lib/maze/errors.rb
483
483
  - lib/maze/generator.rb
484
484
  - lib/maze/helper.rb
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Maze
4
- class ErrorCaptor
5
- attr_reader :captured_errors
6
-
7
- class << self
8
-
9
- # Sets the last error report that BugSnag has captured
10
- #
11
- # @param report [Bugsnag::Report] The report to set
12
- def add(report)
13
- captured_errors << report
14
- end
15
-
16
- # Returns an array of the primary error classes of captured error reports
17
- #
18
- # @return [Array<String>] The error classes
19
- def classes
20
- captured_errors.map { |report| report.summary[:error_class] }
21
- end
22
-
23
- # Returns the primary error messages of the captured error reports
24
- #
25
- # @return [Array<String>] The error messages
26
- def messages
27
- captured_errors.map { |report| report.summary[:message] }
28
- end
29
-
30
- # Resets the captured errors array
31
- def reset
32
- @captured_errors = []
33
- end
34
-
35
- # Whether any error reports exist in the current context
36
- #
37
- # @return [Boolean] Whether a report exists
38
- def empty?
39
- captured_errors.empty?
40
- end
41
-
42
- def captured_errors
43
- @captured_errors ||= []
44
- end
45
- end
46
- end
47
- end