bugsnag-maze-runner 9.22.0 → 9.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/maze-runner +3 -0
- data/lib/features/support/internal_hooks.rb +8 -1
- data/lib/maze/api/appium/app_manager.rb +91 -0
- data/lib/maze/api/appium/device_manager.rb +61 -0
- data/lib/maze/api/appium/file_manager.rb +37 -8
- data/lib/maze/api/appium/manager.rb +20 -0
- data/lib/maze/aws/sam.rb +5 -4
- data/lib/maze/client/appium/base_client.rb +13 -0
- data/lib/maze/client/selenium/base_client.rb +56 -0
- data/lib/maze/client/selenium/bb_client.rb +14 -13
- data/lib/maze/client/selenium/bs_client.rb +37 -29
- data/lib/maze/configuration.rb +3 -0
- data/lib/maze/option/parser.rb +3 -2
- data/lib/maze/option/processor.rb +23 -24
- data/lib/maze/option/validator.rb +20 -15
- data/lib/maze.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8884abca15e25562492a3411949b061374130f0975c39da3635939c31ab94ccb
|
4
|
+
data.tar.gz: fe80b49925c6579219f0e8a307d31be1915e6cfacabe30293d3c24898e663a29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 748f7b6a945799d375b4b7d18d3183b3627f696fa229c0572e21ba5074b8d23f4c7833605b470deaaf3ef00acef2b6f54f48a3d3a4eb8f105f62de592903a20e
|
7
|
+
data.tar.gz: a06ea26f1055c4837fe9ccf22703bdcad6bab92dc58caa2c04edfa5aaefec0950c82bc39805dc5dd47fb7a8ce754dc6a6888cda11ff04f9ff9c428ec354a94a3
|
data/bin/maze-runner
CHANGED
@@ -11,6 +11,9 @@ require_relative '../lib/utils/deep_merge'
|
|
11
11
|
require_relative '../lib/maze'
|
12
12
|
|
13
13
|
require_relative '../lib/maze/appium_server'
|
14
|
+
require_relative '../lib/maze/api/appium/manager'
|
15
|
+
require_relative '../lib/maze/api/appium/app_manager'
|
16
|
+
require_relative '../lib/maze/api/appium/device_manager'
|
14
17
|
require_relative '../lib/maze/api/appium/file_manager'
|
15
18
|
require_relative '../lib/maze/api/cucumber/scenario'
|
16
19
|
require_relative '../lib/maze/api/exit_code'
|
@@ -8,7 +8,6 @@ require 'selenium-webdriver'
|
|
8
8
|
require 'uri'
|
9
9
|
|
10
10
|
BeforeAll do
|
11
|
-
|
12
11
|
Maze.check = Maze::Checks::AssertCheck.new
|
13
12
|
|
14
13
|
# Infer mode of operation from config, one of:
|
@@ -101,6 +100,8 @@ end
|
|
101
100
|
|
102
101
|
# Before each scenario
|
103
102
|
Before do |scenario|
|
103
|
+
next if scenario.status == :skipped
|
104
|
+
|
104
105
|
Maze.scenario = Maze::Api::Cucumber::Scenario.new(scenario)
|
105
106
|
|
106
107
|
# Skip scenario if the driver it needs has failed
|
@@ -133,6 +134,8 @@ end
|
|
133
134
|
|
134
135
|
# General processing to be run after each scenario
|
135
136
|
After do |scenario|
|
137
|
+
next if scenario.status == :skipped
|
138
|
+
|
136
139
|
# If we're running on macos, take a screenshot if the scenario fails
|
137
140
|
if Maze.config.os == "macos" && scenario.status == :failed
|
138
141
|
Maze::MacosUtils.capture_screen(scenario)
|
@@ -225,6 +228,8 @@ end
|
|
225
228
|
#
|
226
229
|
# Furthermore, this hook should appear after the general hook as they are executed in reverse order by Cucumber.
|
227
230
|
After do |scenario|
|
231
|
+
next if scenario.status == :skipped
|
232
|
+
|
228
233
|
# Call any pre_complete hooks registered by the client
|
229
234
|
Maze.hooks.call_pre_complete scenario
|
230
235
|
|
@@ -239,6 +244,8 @@ end
|
|
239
244
|
# Test all requests against schemas or extra validation rules. These will only run if the schema/validation is
|
240
245
|
# specified for the specific endpoint
|
241
246
|
After do |scenario|
|
247
|
+
next if scenario.status == :skipped
|
248
|
+
|
242
249
|
['error', 'session', 'build', 'trace'].each do |endpoint|
|
243
250
|
Maze::Schemas::Validator.validate_payload_elements(Maze::Server.list_for(endpoint), endpoint)
|
244
251
|
end
|
@@ -0,0 +1,91 @@
|
|
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 AppManager < Maze::Api::Appium::Manager
|
9
|
+
|
10
|
+
# Activates the app
|
11
|
+
# @returns [Boolean] Whether the app was successfully launched
|
12
|
+
def activate
|
13
|
+
if failed_driver?
|
14
|
+
$logger.error 'Cannot activate the app - Appium driver failed.'
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
|
18
|
+
@driver.activate_app(@driver.app_id)
|
19
|
+
true
|
20
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
21
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
22
|
+
fail_driver
|
23
|
+
raise e
|
24
|
+
end
|
25
|
+
|
26
|
+
# Terminates the app
|
27
|
+
# @returns [Boolean] Whether the app was successfully closed
|
28
|
+
def terminate
|
29
|
+
if failed_driver?
|
30
|
+
$logger.error 'Cannot terminate the app - Appium driver failed.'
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
|
34
|
+
@driver.terminate_app(@driver.app_id)
|
35
|
+
true
|
36
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
37
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
38
|
+
fail_driver
|
39
|
+
raise e
|
40
|
+
end
|
41
|
+
|
42
|
+
# Launches the app (legacy method).
|
43
|
+
# @returns [Boolean] Whether the app was successfully launched
|
44
|
+
def launch
|
45
|
+
if failed_driver?
|
46
|
+
$logger.error 'Cannot launch the app - Appium driver failed.'
|
47
|
+
return false
|
48
|
+
end
|
49
|
+
|
50
|
+
@driver.launch_app
|
51
|
+
true
|
52
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
53
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
54
|
+
fail_driver
|
55
|
+
raise e
|
56
|
+
end
|
57
|
+
|
58
|
+
# Closes the app (legacy method).
|
59
|
+
# @returns [Boolean] Whether the app was successfully closed
|
60
|
+
def close
|
61
|
+
if failed_driver?
|
62
|
+
$logger.error 'Cannot close the app - Appium driver failed.'
|
63
|
+
return false
|
64
|
+
end
|
65
|
+
|
66
|
+
@driver.close_app
|
67
|
+
true
|
68
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
69
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
70
|
+
fail_driver
|
71
|
+
raise e
|
72
|
+
end
|
73
|
+
|
74
|
+
# Gets the app state.
|
75
|
+
# @returns [Symbol, nil] The app state, such as :not_running, :running_in_foreground, :running_in_background - of nil if the driver has failed.
|
76
|
+
def state
|
77
|
+
if failed_driver?
|
78
|
+
$logger.error('Cannot get the app state - Appium driver failed.')
|
79
|
+
return nil
|
80
|
+
end
|
81
|
+
|
82
|
+
@driver.app_state(@driver.app_id)
|
83
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
84
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
85
|
+
fail_driver
|
86
|
+
raise e
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'json'
|
2
|
+
require_relative '../../helper'
|
3
|
+
require_relative './manager'
|
4
|
+
|
5
|
+
module Maze
|
6
|
+
module Api
|
7
|
+
module Appium
|
8
|
+
# Provides operations for working with the app.
|
9
|
+
class DeviceManager < Maze::Api::Appium::Manager
|
10
|
+
|
11
|
+
# Unlocks the device.
|
12
|
+
# @returns [Boolean] Success status
|
13
|
+
def unlock
|
14
|
+
if failed_driver?
|
15
|
+
$logger.error 'Cannot unlock the device - Appium driver failed.'
|
16
|
+
return false
|
17
|
+
end
|
18
|
+
|
19
|
+
@driver.unlock
|
20
|
+
true
|
21
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
22
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
23
|
+
fail_driver
|
24
|
+
raise e
|
25
|
+
end
|
26
|
+
|
27
|
+
# Sets the rotation of the device.
|
28
|
+
# @param orientation [Symbol] The orientation to set the device to, :portrait or :landscape
|
29
|
+
# @returns [Boolean] Success status
|
30
|
+
def set_rotation(orientation)
|
31
|
+
if failed_driver?
|
32
|
+
$logger.error 'Cannot set the device rotation - Appium driver failed.'
|
33
|
+
return false
|
34
|
+
end
|
35
|
+
|
36
|
+
@driver.set_rotation(orientation)
|
37
|
+
true
|
38
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
39
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
40
|
+
fail_driver
|
41
|
+
raise e
|
42
|
+
end
|
43
|
+
|
44
|
+
# Gets the device info, in JSON format
|
45
|
+
# @returns [String, nil] Device info or nil
|
46
|
+
def info
|
47
|
+
if failed_driver?
|
48
|
+
$logger.error 'Cannot get the device info - Appium driver failed.'
|
49
|
+
return nil
|
50
|
+
end
|
51
|
+
|
52
|
+
JSON.generate(@driver.device_info)
|
53
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
54
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
55
|
+
fail_driver
|
56
|
+
raise e
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,29 +1,43 @@
|
|
1
|
+
require_relative '../../helper'
|
2
|
+
require_relative './manager'
|
3
|
+
|
1
4
|
module Maze
|
2
5
|
module Api
|
3
6
|
module Appium
|
4
7
|
# Provides operations for working with files during Appium runs.
|
5
|
-
class FileManager
|
6
|
-
# param driver
|
7
|
-
def initialize
|
8
|
-
@driver = Maze.driver
|
9
|
-
end
|
10
|
-
|
8
|
+
class FileManager < Maze::Api::Appium::Manager
|
11
9
|
# Creates a file with the given contents on the device (using Appium). The file will be located in the app's
|
12
10
|
# documents directory for iOS. On Android, it will be /sdcard/Android/data/<app-id>/files unless
|
13
11
|
# Maze.config.android_app_files_directory has been set.
|
14
12
|
# @param contents [String] Content of the file to be written
|
15
13
|
# @param filename [String] Name (with no path) of the file to be written on the device
|
14
|
+
# @return [Boolean] Whether the file was successfully written to the device
|
16
15
|
def write_app_file(contents, filename)
|
16
|
+
if failed_driver?
|
17
|
+
$logger.error 'Cannot write file to device - Appium driver failed.'
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
17
21
|
path = case Maze::Helper.get_current_platform
|
18
22
|
when 'ios'
|
19
23
|
"@#{@driver.app_id}/Documents/#{filename}"
|
20
24
|
when 'android'
|
21
25
|
directory = Maze.config.android_app_files_directory || "/sdcard/Android/data/#{@driver.app_id}/files"
|
22
26
|
"#{directory}/#{filename}"
|
27
|
+
else
|
28
|
+
raise 'write_app_file is not supported on this platform'
|
23
29
|
end
|
24
30
|
|
25
31
|
$logger.trace "Pushing file to '#{path}' with contents: #{contents}"
|
26
32
|
@driver.push_file(path, contents)
|
33
|
+
true
|
34
|
+
rescue Selenium::WebDriver::Error::UnknownError => e
|
35
|
+
$logger.error "Error writing file to device: #{e.message}"
|
36
|
+
false
|
37
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
38
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
39
|
+
fail_driver
|
40
|
+
raise e
|
27
41
|
end
|
28
42
|
|
29
43
|
# Attempts to retrieve a given file from the device (using Appium). The default location for the file will be
|
@@ -31,9 +45,15 @@ module Maze
|
|
31
45
|
# Maze.config.android_app_files_directory has been set.
|
32
46
|
# @param filename [String] Name (with no path) of the file to be retrieved from the device
|
33
47
|
# @param directory [String] Directory on the device where the file is located (optional)
|
48
|
+
# @return [String, nil] The content of the file read, or nil
|
34
49
|
def read_app_file(filename, directory = nil)
|
50
|
+
if failed_driver?
|
51
|
+
$logger.error 'Cannot read file from device - Appium driver failed.'
|
52
|
+
return nil
|
53
|
+
end
|
54
|
+
|
35
55
|
if directory
|
36
|
-
path = directory
|
56
|
+
path = "#{directory}/#{filename}"
|
37
57
|
else
|
38
58
|
path = case Maze::Helper.get_current_platform
|
39
59
|
when 'ios'
|
@@ -41,11 +61,20 @@ module Maze
|
|
41
61
|
when 'android'
|
42
62
|
dir = Maze.config.android_app_files_directory || "/sdcard/Android/data/#{@driver.app_id}/files"
|
43
63
|
"#{dir}/#{filename}"
|
64
|
+
else
|
65
|
+
raise 'read_app_file is not supported on this platform'
|
44
66
|
end
|
45
67
|
end
|
46
68
|
|
47
69
|
$logger.trace "Attempting to read file from '#{path}'"
|
48
|
-
|
70
|
+
@driver.pull_file(path)
|
71
|
+
rescue Selenium::WebDriver::Error::UnknownError => e
|
72
|
+
$logger.error "Error reading file from device: #{e.message}"
|
73
|
+
nil
|
74
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
75
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
76
|
+
fail_driver
|
77
|
+
raise e
|
49
78
|
end
|
50
79
|
end
|
51
80
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Maze
|
2
|
+
module Api
|
3
|
+
module Appium
|
4
|
+
# Base class for all Appium managers.
|
5
|
+
class Manager
|
6
|
+
def initialize
|
7
|
+
@driver = Maze.driver
|
8
|
+
end
|
9
|
+
|
10
|
+
def failed_driver?
|
11
|
+
@driver.failed?
|
12
|
+
end
|
13
|
+
|
14
|
+
def fail_driver
|
15
|
+
@driver.fail_driver
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/maze/aws/sam.rb
CHANGED
@@ -65,7 +65,7 @@ module Maze
|
|
65
65
|
unless valid?(output)
|
66
66
|
message = <<-WARNING
|
67
67
|
The lambda function did not successfully complete.
|
68
|
-
This may be expected and a normal result of the
|
68
|
+
This may be expected and a normal result of the test execution.
|
69
69
|
The listed cause is:
|
70
70
|
> #{output.last.chomp}
|
71
71
|
|
@@ -75,11 +75,12 @@ module Maze
|
|
75
75
|
$logger.warn message
|
76
76
|
end
|
77
77
|
|
78
|
-
# Attempt to parse
|
79
|
-
#
|
78
|
+
# Attempt to parse response line of the output.
|
79
|
+
# It's possible for a Lambda to output nothing,
|
80
80
|
# e.g. if it forcefully exited, so we allow JSON parse failures here
|
81
81
|
begin
|
82
|
-
|
82
|
+
response_line = output.find { |line| /{.*}/.match(line.strip) }
|
83
|
+
parsed_output = JSON.parse(response_line)
|
83
84
|
rescue JSON::ParserError
|
84
85
|
return {}
|
85
86
|
end
|
@@ -33,6 +33,9 @@ module Maze
|
|
33
33
|
$logger.debug "session_capabilities: #{Maze.driver.session_capabilities.inspect}"
|
34
34
|
end
|
35
35
|
|
36
|
+
# Log the device information after it's started
|
37
|
+
write_device_info
|
38
|
+
|
36
39
|
# Ensure the device is unlocked
|
37
40
|
begin
|
38
41
|
Maze.driver.unlock
|
@@ -56,6 +59,16 @@ module Maze
|
|
56
59
|
raise 'Method not implemented by this class'
|
57
60
|
end
|
58
61
|
|
62
|
+
def write_device_info
|
63
|
+
info = Maze.driver.device_info
|
64
|
+
filepath = File.join(Dir.pwd, 'maze_output', 'device_info.json')
|
65
|
+
File.open(filepath, 'w+') do |file|
|
66
|
+
file.puts(JSON.pretty_generate(info))
|
67
|
+
end
|
68
|
+
rescue => error
|
69
|
+
$logger.warn "Could not write device information file, #{error.message}"
|
70
|
+
end
|
71
|
+
|
59
72
|
def attempt_start_driver(config)
|
60
73
|
config.capabilities = device_capabilities
|
61
74
|
driver = Maze::Driver::Appium.new config.appium_server_url,
|
@@ -6,6 +6,62 @@ module Maze
|
|
6
6
|
raise 'Method not implemented by this class'
|
7
7
|
end
|
8
8
|
|
9
|
+
def start_driver(config, selenium_url, max_attempts = 5)
|
10
|
+
attempts = 0
|
11
|
+
|
12
|
+
while attempts < max_attempts && Maze.driver.nil?
|
13
|
+
attempts += 1
|
14
|
+
start_error = nil
|
15
|
+
|
16
|
+
$logger.trace "Attempting to start Selenium driver with capabilities: #{config.capabilities.to_json}"
|
17
|
+
$logger.trace "Attempt #{attempts}"
|
18
|
+
begin
|
19
|
+
Maze.driver = Maze::Driver::Browser.new(:remote, selenium_url, config.capabilities)
|
20
|
+
Maze.driver.start_driver
|
21
|
+
rescue => error
|
22
|
+
Maze.driver = nil
|
23
|
+
$logger.error "Session creation failed: #{error}"
|
24
|
+
start_error = error
|
25
|
+
end
|
26
|
+
|
27
|
+
unless Maze.driver
|
28
|
+
interval = handle_start_error(config, start_error)
|
29
|
+
if interval.nil? || attempts >= max_attempts
|
30
|
+
$logger.error 'Failed to create Selenium driver, exiting'
|
31
|
+
Kernel.exit(::Maze::Api::ExitCode::SESSION_CREATION_FAILURE)
|
32
|
+
else
|
33
|
+
$logger.warn "Failed to create Selenium driver, retrying in #{interval} seconds"
|
34
|
+
$logger.info "Error: #{start_error.message}" if start_error
|
35
|
+
Kernel.sleep(interval)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_start_error(config, error)
|
42
|
+
notify = true
|
43
|
+
interval = nil
|
44
|
+
|
45
|
+
# Used if we have a want to determine fatal errors later
|
46
|
+
case error.class.to_s
|
47
|
+
when 'Selenium::WebDriver::Error::WebDriverError'
|
48
|
+
interval = 5
|
49
|
+
notify = false
|
50
|
+
else
|
51
|
+
interval = 10
|
52
|
+
end
|
53
|
+
|
54
|
+
Bugsnag.notify error if notify
|
55
|
+
|
56
|
+
unless config.browser_list.empty?
|
57
|
+
# If the list is empty we have only one browser to continue with
|
58
|
+
config.browser = config.browser_list.shift
|
59
|
+
config.capabilities = create_capabilities(config)
|
60
|
+
end
|
61
|
+
|
62
|
+
interval
|
63
|
+
end
|
64
|
+
|
9
65
|
def log_run_outro
|
10
66
|
raise 'Method not implemented by this class'
|
11
67
|
end
|
@@ -4,6 +4,19 @@ module Maze
|
|
4
4
|
class BitBarClient < BaseClient
|
5
5
|
def start_session
|
6
6
|
config = Maze.config
|
7
|
+
if Maze::Client::BitBarClientUtils.use_local_tunnel?
|
8
|
+
Maze::Client::BitBarClientUtils.start_local_tunnel config.sb_local,
|
9
|
+
config.username,
|
10
|
+
config.access_key
|
11
|
+
end
|
12
|
+
|
13
|
+
create_capabilities(config)
|
14
|
+
|
15
|
+
selenium_url = Maze.config.selenium_server_url
|
16
|
+
start_driver(config, selenium_url)
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_capabilities(config)
|
7
20
|
capabilities = ::Selenium::WebDriver::Remote::Capabilities.new
|
8
21
|
capabilities['bitbar_apiKey'] = config.access_key
|
9
22
|
browsers = YAML.safe_load(File.read("#{__dir__}/bb_browsers.yml"))
|
@@ -13,20 +26,8 @@ module Maze
|
|
13
26
|
capabilities.merge! JSON.parse(config.capabilities_option)
|
14
27
|
capabilities['bitbar:options']['testTimeout'] = 900
|
15
28
|
capabilities['acceptInsecureCerts'] = true unless Maze.config.browser.include? 'ie_'
|
29
|
+
capabilities['bitbar_apiKey'] = config.access_key if Maze::Client::BitBarClientUtils.use_local_tunnel?
|
16
30
|
config.capabilities = capabilities
|
17
|
-
|
18
|
-
if Maze::Client::BitBarClientUtils.use_local_tunnel?
|
19
|
-
capabilities['bitbar_apiKey'] = config.access_key
|
20
|
-
Maze::Client::BitBarClientUtils.start_local_tunnel config.sb_local,
|
21
|
-
config.username,
|
22
|
-
config.access_key
|
23
|
-
end
|
24
|
-
|
25
|
-
selenium_url = Maze.config.selenium_server_url
|
26
|
-
|
27
|
-
$logger.trace "Starting Selenium driver with capabilities: #{config.capabilities.to_json}"
|
28
|
-
Maze.driver = Maze::Driver::Browser.new :remote, selenium_url, config.capabilities
|
29
|
-
Maze.driver.start_driver
|
30
31
|
end
|
31
32
|
|
32
33
|
def log_run_outro
|
@@ -5,55 +5,63 @@ module Maze
|
|
5
5
|
module Selenium
|
6
6
|
class BrowserStackClient < BaseClient
|
7
7
|
def start_session
|
8
|
-
# Set up the capabilities
|
9
|
-
browsers = YAML.safe_load(File.read("#{__dir__}/bs_browsers.yml"))
|
10
|
-
|
11
8
|
config = Maze.config
|
12
|
-
browser = browsers[config.browser]
|
13
9
|
|
10
|
+
# Start the tunnel
|
11
|
+
Maze::Client::BrowserStackClientUtils.start_local_tunnel config.bs_local,
|
12
|
+
Maze.run_uuid,
|
13
|
+
config.access_key
|
14
|
+
|
15
|
+
create_capabilities(config)
|
16
|
+
|
17
|
+
# Start the driver
|
18
|
+
selenium_url = "https://#{config.username}:#{config.access_key}@hub.browserstack.com/wd/hub"
|
19
|
+
start_driver(config, selenium_url)
|
20
|
+
|
21
|
+
# Log details for the session
|
22
|
+
log_session_info
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_capabilities(config)
|
14
26
|
if config.legacy_driver?
|
15
27
|
capabilities = ::Selenium::WebDriver::Remote::Capabilities.new
|
16
28
|
capabilities['browserstack.local'] = 'true'
|
17
29
|
capabilities['browserstack.localIdentifier'] = Maze.run_uuid
|
18
30
|
capabilities['browserstack.console'] = 'errors'
|
19
31
|
capabilities['acceptInsecureCerts'] = 'true'
|
20
|
-
|
21
|
-
# Convert W3S capabilities to JSON-WP
|
22
|
-
capabilities['browser'] = browser['browserName']
|
23
|
-
capabilities['browser_version'] = browser['browserVersion']
|
24
|
-
capabilities['device'] = browser['device']
|
25
|
-
capabilities['os'] = browser['os']
|
26
|
-
capabilities['os_version'] = browser['osVersion']
|
27
|
-
|
28
32
|
capabilities.merge! JSON.parse(config.capabilities_option)
|
29
33
|
capabilities.merge! project_name_capabilities
|
30
|
-
config
|
34
|
+
add_browser_capabilities(config, capabilities)
|
31
35
|
else
|
32
|
-
|
36
|
+
raw_capabilities = {
|
33
37
|
'acceptInsecureCerts' => true,
|
34
38
|
'bstack:options' => {
|
35
39
|
'local' => 'true',
|
36
40
|
'localIdentifier' => Maze.run_uuid
|
37
41
|
}
|
38
42
|
}
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
raw_capabilities.deep_merge! JSON.parse(config.capabilities_option)
|
44
|
+
raw_capabilities.merge! project_name_capabilities
|
45
|
+
add_browser_capabilities(config, raw_capabilities)
|
46
|
+
capabilities = ::Selenium::WebDriver::Remote::Capabilities.new raw_capabilities
|
43
47
|
end
|
48
|
+
config.capabilities = capabilities
|
49
|
+
end
|
44
50
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
config.access_key
|
49
|
-
|
50
|
-
# Start the driver
|
51
|
-
selenium_url = "https://#{config.username}:#{config.access_key}@hub.browserstack.com/wd/hub"
|
52
|
-
Maze.driver = Maze::Driver::Browser.new :remote, selenium_url, config.capabilities
|
53
|
-
Maze.driver.start_driver
|
51
|
+
def add_browser_capabilities(config, capabilities)
|
52
|
+
browsers = YAML.safe_load(File.read("#{__dir__}/bs_browsers.yml"))
|
53
|
+
browser = browsers[config.browser]
|
54
54
|
|
55
|
-
|
56
|
-
|
55
|
+
if config.legacy_driver?
|
56
|
+
# Convert W3S capabilities to JSON-WP
|
57
|
+
capabilities['browser'] = browser['browserName']
|
58
|
+
capabilities['browser_version'] = browser['browserVersion']
|
59
|
+
capabilities['device'] = browser['device']
|
60
|
+
capabilities['os'] = browser['os']
|
61
|
+
capabilities['os_version'] = browser['osVersion']
|
62
|
+
else
|
63
|
+
capabilities.deep_merge! browser
|
64
|
+
end
|
57
65
|
end
|
58
66
|
|
59
67
|
def stop_session
|
data/lib/maze/configuration.rb
CHANGED
data/lib/maze/option/parser.rb
CHANGED
@@ -124,9 +124,10 @@ module Maze
|
|
124
124
|
type: :string,
|
125
125
|
multi: true
|
126
126
|
opt Option::BROWSER,
|
127
|
-
'Browser to use (an entry in <farm>_browsers.yml)',
|
127
|
+
'Browser to use (an entry in <farm>_browsers.yml). Can be listed multiple times to have a prioritised list of browsers',
|
128
128
|
short: :none,
|
129
|
-
type: :string
|
129
|
+
type: :string,
|
130
|
+
multi: true
|
130
131
|
opt Option::BROWSER_VERSION,
|
131
132
|
'Browser version to use (applies to entries in <farm>_browsers.yml that do not include a version)',
|
132
133
|
short: :none,
|
@@ -57,21 +57,18 @@ module Maze
|
|
57
57
|
case config.farm
|
58
58
|
when :bs
|
59
59
|
device_option = options[Maze::Option::DEVICE]
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
config.device = device_option.first
|
65
|
-
config.device_list = device_option.drop(1)
|
66
|
-
else
|
67
|
-
config.device = device_option
|
68
|
-
config.device_list = []
|
69
|
-
end
|
60
|
+
browser_option = options[Maze::Option::BROWSER]
|
61
|
+
if !device_option.empty?
|
62
|
+
config.device = device_option.first
|
63
|
+
config.device_list = device_option.drop(1)
|
70
64
|
if config.legacy_driver?
|
71
65
|
config.os_version = Maze::Client::Appium::BrowserStackDevices::DEVICE_HASH[config.device]['os_version'].to_f
|
72
66
|
else
|
73
67
|
config.os_version = Maze::Client::Appium::BrowserStackDevices::DEVICE_HASH[config.device]['platformVersion'].to_f
|
74
68
|
end
|
69
|
+
elsif !browser_option.empty?
|
70
|
+
config.browser = browser_option.first
|
71
|
+
config.browser_list = browser_option.drop(1)
|
75
72
|
end
|
76
73
|
config.bs_local = Maze::Helper.expand_path(options[Maze::Option::BS_LOCAL])
|
77
74
|
config.appium_version = options[Maze::Option::APPIUM_VERSION]
|
@@ -83,18 +80,20 @@ module Maze
|
|
83
80
|
config.access_key = options[Maze::Option::ACCESS_KEY]
|
84
81
|
config.appium_version = options[Maze::Option::APPIUM_VERSION]
|
85
82
|
device_option = options[Maze::Option::DEVICE]
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
config.
|
90
|
-
|
91
|
-
|
92
|
-
if
|
93
|
-
config.
|
94
|
-
config.
|
83
|
+
browser_option = options[Maze::Option::BROWSER]
|
84
|
+
browser_version = options[Maze::Option::BROWSER_VERSION]
|
85
|
+
if !device_option.empty?
|
86
|
+
config.device = device_option.first
|
87
|
+
config.device_list = device_option.drop(1)
|
88
|
+
elsif !browser_option.empty?
|
89
|
+
if browser_version.nil?
|
90
|
+
config.browser = browser_option.first
|
91
|
+
config.browser_list = browser_option.drop(1)
|
95
92
|
else
|
96
|
-
|
97
|
-
config.
|
93
|
+
# Dropping all but the first browser as the version is specified
|
94
|
+
config.browser = browser_option.first
|
95
|
+
config.browser_list = []
|
96
|
+
config.browser_version = browser_version
|
98
97
|
end
|
99
98
|
end
|
100
99
|
config.os = options[Maze::Option::OS]
|
@@ -104,9 +103,7 @@ module Maze
|
|
104
103
|
config.selenium_server_url = options[Maze::Option::SELENIUM_SERVER]
|
105
104
|
config.app_bundle_id = options[Maze::Option::APP_BUNDLE_ID]
|
106
105
|
when :local then
|
107
|
-
if options[Maze::Option::BROWSER]
|
108
|
-
config.browser = options[Maze::Option::BROWSER]
|
109
|
-
else
|
106
|
+
if options[Maze::Option::BROWSER].empty?
|
110
107
|
os = config.os = options[Maze::Option::OS].downcase
|
111
108
|
config.os_version = options[Maze::Option::OS_VERSION].to_f unless options[Maze::Option::OS_VERSION].nil?
|
112
109
|
config.appium_server_url = options[Maze::Option::APPIUM_SERVER]
|
@@ -116,6 +113,8 @@ module Maze
|
|
116
113
|
config.apple_team_id = options[Maze::Option::APPLE_TEAM_ID]
|
117
114
|
config.device_id = options[Maze::Option::UDID]
|
118
115
|
end
|
116
|
+
else
|
117
|
+
config.browser = options[Maze::Option::BROWSER].first
|
119
118
|
end
|
120
119
|
when :none
|
121
120
|
if options[Maze::Option::OS]
|
@@ -53,17 +53,17 @@ module Maze
|
|
53
53
|
# Device
|
54
54
|
browser = options[Option::BROWSER]
|
55
55
|
device = options[Option::DEVICE]
|
56
|
-
if browser.
|
56
|
+
if browser.empty? && device.empty?
|
57
57
|
errors << "Either --#{Option::BROWSER} or --#{Option::DEVICE} must be specified"
|
58
|
-
elsif browser
|
59
|
-
|
58
|
+
elsif !browser.empty?
|
60
59
|
browsers = YAML.safe_load(File.read("#{__dir__}/../client/selenium/bs_browsers.yml"))
|
61
60
|
|
62
|
-
|
61
|
+
rejected_browsers = browser.reject { |br| browsers.include? br }
|
62
|
+
unless rejected_browsers.empty?
|
63
63
|
browser_list = browsers.keys.join ', '
|
64
|
-
errors << "Browser
|
64
|
+
errors << "Browser types '#{rejected_browsers.join(', ')}' unknown on BrowserStack. Must be one of: #{browser_list}."
|
65
65
|
end
|
66
|
-
elsif device
|
66
|
+
elsif !device.empty?
|
67
67
|
device.each do |device_key|
|
68
68
|
next if Maze::Client::Appium::BrowserStackDevices::DEVICE_HASH.key? device_key
|
69
69
|
errors << "Device type '#{device_key}' unknown on BrowserStack. Must be one of #{Maze::Client::Appium::BrowserStackDevices::DEVICE_HASH.keys}"
|
@@ -89,25 +89,30 @@ module Maze
|
|
89
89
|
def validate_bitbar(options, errors)
|
90
90
|
browser = options[Option::BROWSER]
|
91
91
|
device = options[Option::DEVICE]
|
92
|
-
|
92
|
+
|
93
93
|
errors << "--#{Option::USERNAME} must be specified" if options[Option::USERNAME].nil?
|
94
94
|
errors << "--#{Option::ACCESS_KEY} must be specified" if options[Option::ACCESS_KEY].nil?
|
95
95
|
|
96
96
|
# Device
|
97
|
-
if browser.
|
97
|
+
if browser.empty? && device.empty?
|
98
98
|
errors << "Either --#{Option::BROWSER} or --#{Option::DEVICE} must be specified"
|
99
|
-
elsif browser
|
99
|
+
elsif !browser.empty?
|
100
100
|
browsers = YAML.safe_load(File.read("#{__dir__}/../client/selenium/bb_browsers.yml"))
|
101
101
|
|
102
|
-
|
103
|
-
|
104
|
-
|
102
|
+
rejected_browsers = browser.reject { |br| browsers.include? br }
|
103
|
+
if rejected_browsers.empty?
|
104
|
+
if options[Option::BROWSER_VERSION].nil?
|
105
|
+
browser.each do |br|
|
106
|
+
next if browsers[br].include?('version')
|
107
|
+
errors << "--#{Option::BROWSER_VERSION} must be specified for browser '#{br}'"
|
108
|
+
end
|
105
109
|
end
|
106
110
|
else
|
107
111
|
browser_list = browsers.keys.join ', '
|
108
|
-
errors << "Browser
|
112
|
+
errors << "Browser types '#{rejected_browsers.join(', ')}' unknown on BitBar. Must be one of: #{browser_list}."
|
109
113
|
end
|
110
|
-
|
114
|
+
|
115
|
+
elsif !device.empty?
|
111
116
|
app = Maze::Helper.read_at_arg_file options[Option::APP]
|
112
117
|
if app.nil?
|
113
118
|
errors << "--#{Option::APP} must be provided when running on a device"
|
@@ -123,7 +128,7 @@ module Maze
|
|
123
128
|
|
124
129
|
# Validates Local device options
|
125
130
|
def validate_local(options, errors)
|
126
|
-
if options[Option::BROWSER].
|
131
|
+
if options[Option::BROWSER].empty?
|
127
132
|
errors << "--#{Option::APP} must be specified" if options[Option::APP].nil?
|
128
133
|
|
129
134
|
# OS
|
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.
|
11
|
+
VERSION = '9.23.0'
|
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.
|
4
|
+
version: 9.23.0
|
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-
|
11
|
+
date: 2025-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cucumber
|
@@ -440,7 +440,10 @@ files:
|
|
440
440
|
- lib/features/support/env.rb
|
441
441
|
- lib/features/support/internal_hooks.rb
|
442
442
|
- lib/maze.rb
|
443
|
+
- lib/maze/api/appium/app_manager.rb
|
444
|
+
- lib/maze/api/appium/device_manager.rb
|
443
445
|
- lib/maze/api/appium/file_manager.rb
|
446
|
+
- lib/maze/api/appium/manager.rb
|
444
447
|
- lib/maze/api/cucumber/scenario.rb
|
445
448
|
- lib/maze/api/exit_code.rb
|
446
449
|
- lib/maze/appium_server.rb
|