bugsnag-maze-runner 6.27.0
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 +7 -0
- data/bin/bugsnag-print-load-paths +6 -0
- data/bin/download-logs +76 -0
- data/bin/maze-runner +136 -0
- data/bin/upload-app +56 -0
- data/lib/features/scripts/await-android-emulator.sh +11 -0
- data/lib/features/scripts/clear-android-app-data.sh +8 -0
- data/lib/features/scripts/force-stop-android-app.sh +8 -0
- data/lib/features/scripts/install-android-app.sh +15 -0
- data/lib/features/scripts/launch-android-app.sh +38 -0
- data/lib/features/scripts/launch-android-emulator.sh +15 -0
- data/lib/features/steps/android_steps.rb +51 -0
- data/lib/features/steps/app_automator_steps.rb +228 -0
- data/lib/features/steps/aws_sam_steps.rb +212 -0
- data/lib/features/steps/breadcrumb_steps.rb +50 -0
- data/lib/features/steps/browser_steps.rb +93 -0
- data/lib/features/steps/build_api_steps.rb +25 -0
- data/lib/features/steps/document_server_steps.rb +7 -0
- data/lib/features/steps/error_reporting_steps.rb +342 -0
- data/lib/features/steps/feature_flag_steps.rb +190 -0
- data/lib/features/steps/header_steps.rb +72 -0
- data/lib/features/steps/log_steps.rb +29 -0
- data/lib/features/steps/multipart_request_steps.rb +142 -0
- data/lib/features/steps/network_steps.rb +75 -0
- data/lib/features/steps/payload_steps.rb +234 -0
- data/lib/features/steps/proxy_steps.rb +34 -0
- data/lib/features/steps/query_parameter_steps.rb +31 -0
- data/lib/features/steps/request_assertion_steps.rb +107 -0
- data/lib/features/steps/runner_steps.rb +406 -0
- data/lib/features/steps/session_tracking_steps.rb +116 -0
- data/lib/features/steps/value_steps.rb +119 -0
- data/lib/features/support/env.rb +7 -0
- data/lib/features/support/internal_hooks.rb +260 -0
- data/lib/maze/appium_server.rb +112 -0
- data/lib/maze/assertions/request_set_assertions.rb +97 -0
- data/lib/maze/aws/sam.rb +112 -0
- data/lib/maze/bitbar_devices.rb +84 -0
- data/lib/maze/bitbar_utils.rb +112 -0
- data/lib/maze/browser_stack_devices.rb +160 -0
- data/lib/maze/browser_stack_utils.rb +164 -0
- data/lib/maze/browsers_bs.yml +220 -0
- data/lib/maze/browsers_cbt.yml +100 -0
- data/lib/maze/bugsnag_config.rb +42 -0
- data/lib/maze/capabilities.rb +126 -0
- data/lib/maze/checks/assert_check.rb +91 -0
- data/lib/maze/checks/noop_check.rb +34 -0
- data/lib/maze/compare.rb +161 -0
- data/lib/maze/configuration.rb +174 -0
- data/lib/maze/docker.rb +108 -0
- data/lib/maze/document_server.rb +46 -0
- data/lib/maze/driver/appium.rb +217 -0
- data/lib/maze/driver/browser.rb +138 -0
- data/lib/maze/driver/resilient_appium.rb +51 -0
- data/lib/maze/errors.rb +20 -0
- data/lib/maze/helper.rb +118 -0
- data/lib/maze/hooks/appium_hooks.rb +216 -0
- data/lib/maze/hooks/browser_hooks.rb +68 -0
- data/lib/maze/hooks/command_hooks.rb +9 -0
- data/lib/maze/hooks/hooks.rb +61 -0
- data/lib/maze/interactive_cli.rb +173 -0
- data/lib/maze/logger.rb +73 -0
- data/lib/maze/macos_utils.rb +14 -0
- data/lib/maze/network.rb +49 -0
- data/lib/maze/option/parser.rb +245 -0
- data/lib/maze/option/processor.rb +143 -0
- data/lib/maze/option/validator.rb +184 -0
- data/lib/maze/option.rb +64 -0
- data/lib/maze/plugins/bugsnag_reporting_plugin.rb +49 -0
- data/lib/maze/plugins/cucumber_report_plugin.rb +101 -0
- data/lib/maze/plugins/global_retry_plugin.rb +38 -0
- data/lib/maze/proxy.rb +114 -0
- data/lib/maze/request_list.rb +82 -0
- data/lib/maze/retry_handler.rb +76 -0
- data/lib/maze/runner.rb +149 -0
- data/lib/maze/sauce_labs_utils.rb +96 -0
- data/lib/maze/server.rb +207 -0
- data/lib/maze/servlets/base_servlet.rb +22 -0
- data/lib/maze/servlets/command_servlet.rb +44 -0
- data/lib/maze/servlets/log_servlet.rb +64 -0
- data/lib/maze/servlets/reflective_servlet.rb +69 -0
- data/lib/maze/servlets/servlet.rb +160 -0
- data/lib/maze/smart_bear_utils.rb +71 -0
- data/lib/maze/store.rb +15 -0
- data/lib/maze/terminating_server.rb +129 -0
- data/lib/maze/timers.rb +51 -0
- data/lib/maze/wait.rb +35 -0
- data/lib/maze.rb +27 -0
- metadata +371 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'appium_lib'
|
2
|
+
require_relative '../logger'
|
3
|
+
|
4
|
+
module Maze
|
5
|
+
module Driver
|
6
|
+
# Handles Appium driver restarts and retries in the case of failure. BrowserStack's iOS 10 and 11 iOS devices in
|
7
|
+
# particular seemed prone to the underlying Appium connection failing.
|
8
|
+
#
|
9
|
+
# For methods available on this class, @see AppAutomateDriver.
|
10
|
+
class ResilientAppium
|
11
|
+
# Creates the Appium Driver
|
12
|
+
#
|
13
|
+
# @param server_url [String] URL of the Appium server
|
14
|
+
# @param capabilities [Hash] a hash of capabilities to be used in this test run
|
15
|
+
# @param locator [Symbol] the primary locator strategy Appium should use to find elements
|
16
|
+
def initialize(server_url, capabilities, locator = :id)
|
17
|
+
@driver = Appium.new server_url,
|
18
|
+
capabilities,
|
19
|
+
locator
|
20
|
+
end
|
21
|
+
|
22
|
+
def respond_to_missing?(method_name, include_private = false)
|
23
|
+
@driver.respond_to_missing? method_name, include_private
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(method, *args, &block)
|
27
|
+
return super unless @driver.respond_to?(method)
|
28
|
+
|
29
|
+
retries = 0
|
30
|
+
until retries >= 5
|
31
|
+
begin
|
32
|
+
return @driver.send(method, *args, &block)
|
33
|
+
rescue Selenium::WebDriver::Error::UnknownError, Selenium::WebDriver::Error::WebDriverError => error
|
34
|
+
retries += 1
|
35
|
+
$logger.warn 'Appium Error occurred - restarting driver:'
|
36
|
+
$logger.warn error
|
37
|
+
sleep 3
|
38
|
+
restart
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Re-raise the last error, although it might be better to re-raise the
|
43
|
+
# first error instead. Review based on whether we ever hit this.
|
44
|
+
return if error.nil?
|
45
|
+
|
46
|
+
$logger.error 'Maximum retries exceeded - raising the last error'
|
47
|
+
raise error
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/maze/errors.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Maze
|
2
|
+
module Error
|
3
|
+
# An error raised when an appium element cannot be found
|
4
|
+
class AppiumElementNotFoundError < StandardError
|
5
|
+
|
6
|
+
# @# @!attribute [r] element
|
7
|
+
# @return [String] The named element that could not be found
|
8
|
+
attr_reader :element
|
9
|
+
|
10
|
+
# Creates the error
|
11
|
+
#
|
12
|
+
# @param message [String] The error to display
|
13
|
+
# @param element [String] The name of the element that could not be located
|
14
|
+
def initialize(message='Element not found', element='No element specified')
|
15
|
+
@element = element
|
16
|
+
super(message)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/maze/helper.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'digest/sha1'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
# A collection of helper routines
|
7
|
+
module Maze
|
8
|
+
# Miscellaneous helper functions.
|
9
|
+
module Helper
|
10
|
+
class << self
|
11
|
+
# Parses a request's query string, because WEBrick doesn't in POST requests
|
12
|
+
#
|
13
|
+
# @param request [Hash] The received request
|
14
|
+
#
|
15
|
+
# @return [Hash] The parsed query string.
|
16
|
+
def parse_querystring(request)
|
17
|
+
CGI.parse(request[:request].query_string)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Enables traversal of a hash using Mongo-style dot notation.
|
21
|
+
#
|
22
|
+
# @example hash["array"][0]["item"] becomes "hash.array.0.item"
|
23
|
+
#
|
24
|
+
# @param hash [Hash] The hash to traverse
|
25
|
+
# @param key_path [String] The dot notation path within the hash
|
26
|
+
#
|
27
|
+
# @return [Any] The value found by the key path
|
28
|
+
def read_key_path(hash, key_path)
|
29
|
+
value = hash
|
30
|
+
key_path.split('.').each do |key|
|
31
|
+
if key =~ /^(\d+)$/
|
32
|
+
key = key.to_i
|
33
|
+
if value.length > key
|
34
|
+
value = value[key]
|
35
|
+
else
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
else
|
39
|
+
if value.key? key
|
40
|
+
value = value[key]
|
41
|
+
else
|
42
|
+
return nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
value
|
47
|
+
end
|
48
|
+
|
49
|
+
# Determines if the Bugsnag-Integrity header is valid.
|
50
|
+
# Whether a missing header is deemed valid depends on @see Maze.config.enforce_bugsnag_integrity.
|
51
|
+
#
|
52
|
+
# @return [Boolean] True if the header is present and valid, or not present and not enforced. False otherwise.
|
53
|
+
def valid_bugsnag_integrity_header(request)
|
54
|
+
header = request[:request]['Bugsnag-Integrity']
|
55
|
+
return !Maze.config.enforce_bugsnag_integrity if header.nil?
|
56
|
+
|
57
|
+
digests = request[:digests]
|
58
|
+
if header.start_with?('sha1')
|
59
|
+
computed_digest = "sha1 #{digests[:sha1]}"
|
60
|
+
elsif header.start_with?('simple')
|
61
|
+
computed_digest = "simple #{digests[:simple]}"
|
62
|
+
else
|
63
|
+
return false
|
64
|
+
end
|
65
|
+
header == computed_digest
|
66
|
+
end
|
67
|
+
|
68
|
+
# Nil-safe version of File.expand_path
|
69
|
+
#
|
70
|
+
# @param path [String] Path to expand
|
71
|
+
#
|
72
|
+
# @return [String] Expanded path, or nil if path is nil.
|
73
|
+
def expand_path(path)
|
74
|
+
return nil unless path
|
75
|
+
|
76
|
+
File.expand_path path
|
77
|
+
end
|
78
|
+
|
79
|
+
# Helps interpret "@file" arguments. I.e. if the argument starts with an "@",
|
80
|
+
# read the contents of the filename given.
|
81
|
+
def read_at_arg_file(argument)
|
82
|
+
return nil if argument.nil?
|
83
|
+
return argument unless argument.start_with? '@'
|
84
|
+
|
85
|
+
file = argument[1..argument.size]
|
86
|
+
File.read file
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns the current platform all lower-case.
|
90
|
+
# @return Typically 'ios', 'android', 'mac' or 'browser'
|
91
|
+
def get_current_platform
|
92
|
+
if Maze.mode == :browser
|
93
|
+
os = 'browser'
|
94
|
+
else
|
95
|
+
os = case Maze.config.farm
|
96
|
+
when :bs
|
97
|
+
Maze.config.capabilities['os']
|
98
|
+
when :sl
|
99
|
+
Maze.driver.capabilities['platformName']
|
100
|
+
else
|
101
|
+
Maze.config.os
|
102
|
+
end
|
103
|
+
os = os&.downcase
|
104
|
+
end
|
105
|
+
|
106
|
+
raise('Unable to determine the current platform') if os.nil?
|
107
|
+
|
108
|
+
os
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns the name of the scenario to
|
112
|
+
# @param string [String] a string to convert to a file name
|
113
|
+
def to_friendly_filename(string)
|
114
|
+
string.gsub(/[:"& ]/, "_").gsub(/_+/, "_")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
# Contains logic for the Cucumber hooks when in Appium mode
|
2
|
+
module Maze
|
3
|
+
module Hooks
|
4
|
+
# Hooks for Appium mode use
|
5
|
+
class AppiumHooks < InternalHooks
|
6
|
+
def before_all
|
7
|
+
# Setup Appium capabilities. Note that the 'app' capability is
|
8
|
+
# set in a hook as it will change if uploaded to BrowserStack.
|
9
|
+
|
10
|
+
config = Maze.config
|
11
|
+
case config.farm
|
12
|
+
when :bs
|
13
|
+
tunnel_id = SecureRandom.uuid
|
14
|
+
config.app = Maze::BrowserStackUtils.upload_app config.username,
|
15
|
+
config.access_key,
|
16
|
+
config.app
|
17
|
+
Maze::BrowserStackUtils.start_local_tunnel config.bs_local,
|
18
|
+
tunnel_id,
|
19
|
+
config.access_key
|
20
|
+
when :sl
|
21
|
+
config.app = Maze::SauceLabsUtils.upload_app config.username,
|
22
|
+
config.access_key,
|
23
|
+
config.app
|
24
|
+
tunnel_id = SecureRandom.uuid
|
25
|
+
Maze::SauceLabsUtils.start_sauce_connect config.sl_local,
|
26
|
+
tunnel_id,
|
27
|
+
config.username,
|
28
|
+
config.access_key
|
29
|
+
when :bb
|
30
|
+
if ENV['BUILDKITE']
|
31
|
+
credentials = Maze::BitBarUtils.account_credentials config.tms_uri
|
32
|
+
config.username = credentials[:username]
|
33
|
+
config.access_key = credentials[:access_key]
|
34
|
+
end
|
35
|
+
config.app = Maze::BitBarUtils.upload_app config.access_key,
|
36
|
+
config.app
|
37
|
+
Maze::SmartBearUtils.start_local_tunnel config.sb_local,
|
38
|
+
config.username,
|
39
|
+
config.access_key
|
40
|
+
when :local
|
41
|
+
# Attempt to start the local appium server
|
42
|
+
appium_uri = URI(config.appium_server_url)
|
43
|
+
Maze::AppiumServer.start(address: appium_uri.host, port: appium_uri.port) if config.start_appium
|
44
|
+
end
|
45
|
+
|
46
|
+
start_driver(config, tunnel_id)
|
47
|
+
|
48
|
+
# Ensure the device is unlocked
|
49
|
+
Maze.driver.unlock
|
50
|
+
|
51
|
+
# Write links to device farm sessions, where applicable
|
52
|
+
write_session_link
|
53
|
+
end
|
54
|
+
|
55
|
+
def before
|
56
|
+
Maze.driver.start_driver if Maze.config.farm != :none && Maze.config.appium_session_isolation
|
57
|
+
|
58
|
+
# Launch the app on macOS, if Appium is being used
|
59
|
+
Maze.driver.get(Maze.config.app) if Maze.driver && Maze.config.os == 'macos'
|
60
|
+
end
|
61
|
+
|
62
|
+
def after
|
63
|
+
if Maze.config.appium_session_isolation
|
64
|
+
Maze.driver.driver_quit
|
65
|
+
elsif Maze.config.os == 'macos'
|
66
|
+
# Close the app - without the sleep, launching the app for the next scenario intermittently fails
|
67
|
+
system("killall -KILL #{Maze.config.app} && sleep 1")
|
68
|
+
elsif [:bb].include? Maze.config.farm
|
69
|
+
Maze.driver.launch_app
|
70
|
+
else
|
71
|
+
Maze.driver.reset
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def at_exit
|
76
|
+
# Stop the Appium session and server
|
77
|
+
Maze.driver.driver_quit unless Maze.config.appium_session_isolation
|
78
|
+
Maze::AppiumServer.stop if Maze::AppiumServer.running
|
79
|
+
|
80
|
+
if Maze.config.farm == :local && Maze.config.os == 'macos'
|
81
|
+
# Acquire and output the logs for the current session
|
82
|
+
Maze::Runner.run_command("log show --predicate '(process == \"#{Maze.config.app}\")' --style syslog --start '#{Maze.start_time}' > #{Maze.config.app}.log")
|
83
|
+
elsif Maze.config.farm == :bs
|
84
|
+
Maze::BrowserStackUtils.stop_local_tunnel
|
85
|
+
elsif Maze.config.farm == :sl
|
86
|
+
$logger.info 'Stopping Sauce Connect'
|
87
|
+
Maze::SauceLabsUtils.stop_sauce_connect
|
88
|
+
elsif Maze.config.farm == :bb
|
89
|
+
Maze::SmartBearUtils.stop_local_tunnel
|
90
|
+
Maze::BitBarUtils.release_account(Maze.config.tms_uri) if ENV['BUILDKITE']
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def write_session_link
|
95
|
+
config = Maze.config
|
96
|
+
if config.farm == :bs && (config.device || config.browser)
|
97
|
+
# Log a link to the BrowserStack session search dashboard
|
98
|
+
build = Maze.driver.capabilities[:build]
|
99
|
+
url = "https://app-automate.browserstack.com/dashboard/v2/search?query=#{build}&type=builds"
|
100
|
+
if ENV['BUILDKITE']
|
101
|
+
$logger.info Maze::LogUtil.linkify url, 'BrowserStack session(s)'
|
102
|
+
else
|
103
|
+
$logger.info "BrowserStack session(s): #{url}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def device_capabilities(config, tunnel_id = nil)
|
109
|
+
case config.farm
|
110
|
+
when :bs
|
111
|
+
capabilities = Maze::Capabilities.for_browser_stack_device config.device,
|
112
|
+
tunnel_id,
|
113
|
+
config.appium_version,
|
114
|
+
config.capabilities_option
|
115
|
+
capabilities['app'] = config.app
|
116
|
+
when :sl
|
117
|
+
capabilities = Maze::Capabilities.for_sauce_labs_device config.device,
|
118
|
+
config.os,
|
119
|
+
config.os_version,
|
120
|
+
tunnel_id,
|
121
|
+
config.appium_version,
|
122
|
+
config.capabilities_option
|
123
|
+
capabilities['app'] = "storage:#{config.app}"
|
124
|
+
when :local
|
125
|
+
capabilities = Maze::Capabilities.for_local config.os,
|
126
|
+
config.capabilities_option,
|
127
|
+
config.apple_team_id,
|
128
|
+
config.device_id
|
129
|
+
capabilities['app'] = config.app
|
130
|
+
when :bb
|
131
|
+
capabilities = Maze::Capabilities.for_bitbar_device config.access_key,
|
132
|
+
config.device,
|
133
|
+
config.os,
|
134
|
+
config.os_version,
|
135
|
+
config.capabilities_option
|
136
|
+
capabilities['bitbar_app'] = config.app
|
137
|
+
capabilities['bundleId'] = config.app_bundle_id
|
138
|
+
end
|
139
|
+
capabilities
|
140
|
+
end
|
141
|
+
|
142
|
+
def create_driver(config)
|
143
|
+
if Maze.config.resilient
|
144
|
+
$logger.info 'Creating ResilientAppium driver instance'
|
145
|
+
Maze::Driver::ResilientAppium.new config.appium_server_url,
|
146
|
+
config.capabilities,
|
147
|
+
config.locator
|
148
|
+
else
|
149
|
+
$logger.info 'Creating Appium driver instance'
|
150
|
+
Maze::Driver::Appium.new config.appium_server_url,
|
151
|
+
config.capabilities,
|
152
|
+
config.locator
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def start_driver(config, tunnel_id = nil)
|
157
|
+
retry_failure = config.device_list.nil? || config.device_list.empty?
|
158
|
+
until Maze.driver
|
159
|
+
begin
|
160
|
+
config.capabilities = device_capabilities(config, tunnel_id)
|
161
|
+
driver = create_driver(config)
|
162
|
+
|
163
|
+
start_driver_closure = Proc.new do
|
164
|
+
begin
|
165
|
+
driver.start_driver
|
166
|
+
true
|
167
|
+
rescue => start_error
|
168
|
+
raise start_error unless retry_failure
|
169
|
+
false
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
unless config.appium_session_isolation
|
174
|
+
if retry_failure
|
175
|
+
wait = Maze::Wait.new(interval: 10, timeout: 60)
|
176
|
+
success = wait.until(&start_driver_closure)
|
177
|
+
|
178
|
+
unless success
|
179
|
+
$logger.error 'Appium driver failed to start after 6 attempts in 60 seconds'
|
180
|
+
raise RuntimeError.new('Appium driver failed to start in 60 seconds')
|
181
|
+
end
|
182
|
+
else
|
183
|
+
start_driver_closure.call
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Infer OS version if necessary when running locally
|
188
|
+
if Maze.config.farm == :local && Maze.config.os_version.nil?
|
189
|
+
version = case Maze.config.os
|
190
|
+
when 'android'
|
191
|
+
driver.session_capabilities['platformVersion'].to_f
|
192
|
+
when 'ios'
|
193
|
+
driver.session_capabilities['sdkVersion'].to_f
|
194
|
+
end
|
195
|
+
$logger.info "Inferred OS version to be #{version}"
|
196
|
+
Maze.config.os_version = version
|
197
|
+
end
|
198
|
+
|
199
|
+
Maze.driver = driver
|
200
|
+
rescue Selenium::WebDriver::Error::UnknownError => original_exception
|
201
|
+
$logger.warn "Attempt to acquire #{config.device} device from farm #{config.farm} failed"
|
202
|
+
$logger.warn "Exception: #{original_exception.message}"
|
203
|
+
if config.device_list.empty?
|
204
|
+
$logger.error 'No further devices to try - raising original exception'
|
205
|
+
raise original_exception
|
206
|
+
else
|
207
|
+
config.device = config.device_list.first
|
208
|
+
config.device_list = config.device_list.drop(1)
|
209
|
+
$logger.warn "Retrying driver initialisation using next device: #{config.device}"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Contains logic for the Cucumber hooks when in Browser mode
|
2
|
+
module Maze
|
3
|
+
module Hooks
|
4
|
+
# Hooks for Browser mode use
|
5
|
+
class BrowserHooks < InternalHooks
|
6
|
+
def before_all
|
7
|
+
config = Maze.config
|
8
|
+
case config.farm
|
9
|
+
when :bs
|
10
|
+
# BrowserStack browser
|
11
|
+
tunnel_id = SecureRandom.uuid
|
12
|
+
config.capabilities = Maze::Capabilities.for_browser_stack_browser config.browser,
|
13
|
+
tunnel_id,
|
14
|
+
config.capabilities_option
|
15
|
+
Maze::BrowserStackUtils.start_local_tunnel config.bs_local,
|
16
|
+
tunnel_id,
|
17
|
+
config.access_key
|
18
|
+
when :cbt
|
19
|
+
# CrossBrowserTesting browser
|
20
|
+
tunnel_id = SecureRandom.uuid
|
21
|
+
config.capabilities = Maze::Capabilities.for_cbt_browser config.browser,
|
22
|
+
tunnel_id,
|
23
|
+
config.capabilities_option
|
24
|
+
Maze::SmartBearUtils.start_local_tunnel config.sb_local,
|
25
|
+
config.username,
|
26
|
+
config.access_key,
|
27
|
+
tunnel_id
|
28
|
+
end
|
29
|
+
|
30
|
+
# Create and start the relevant driver
|
31
|
+
case config.farm
|
32
|
+
when :cbt
|
33
|
+
selenium_url = "http://#{config.username}:#{config.access_key}@hub.crossbrowsertesting.com:80/wd/hub"
|
34
|
+
Maze.driver = Maze::Driver::Browser.new :remote, selenium_url, config.capabilities
|
35
|
+
when :bs
|
36
|
+
selenium_url = "http://#{config.username}:#{config.access_key}@hub.browserstack.com/wd/hub"
|
37
|
+
Maze.driver = Maze::Driver::Browser.new :remote, selenium_url, config.capabilities
|
38
|
+
when :local
|
39
|
+
Maze.driver = Maze::Driver::Browser.new Maze.config.browser.to_sym
|
40
|
+
end
|
41
|
+
|
42
|
+
# Write links to device farm sessions, where applicable
|
43
|
+
write_session_link
|
44
|
+
end
|
45
|
+
|
46
|
+
def at_exit
|
47
|
+
if Maze.config.farm == :bs
|
48
|
+
Maze::BrowserStackUtils.stop_local_tunnel
|
49
|
+
Maze.driver.driver_quit
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def write_session_link
|
54
|
+
config = Maze.config
|
55
|
+
if config.farm == :bs
|
56
|
+
# Log a link to the BrowserStack session search dashboard
|
57
|
+
build = Maze.driver.capabilities[:build]
|
58
|
+
url = "https://automate.browserstack.com/dashboard/v2/search?query=#{build}&type=builds"
|
59
|
+
if ENV['BUILDKITE']
|
60
|
+
$logger.info Maze::LogUtil.linkify url, 'BrowserStack session(s)'
|
61
|
+
else
|
62
|
+
$logger.info "BrowserStack session(s): #{url}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Maze
|
4
|
+
module Hooks
|
5
|
+
# Provides the ability for callbacks to be provided as part of running Cucumber.
|
6
|
+
# These are akin to Cucumber's BeforeAll, Before, After and AfterAll hooks, but are invoked in such a way that
|
7
|
+
# Maze Runner's hooks do not interfere with callbacks registered by clients.
|
8
|
+
class Hooks
|
9
|
+
def initialize
|
10
|
+
@before_all = []
|
11
|
+
@before = []
|
12
|
+
@after = []
|
13
|
+
end
|
14
|
+
|
15
|
+
# Register blocks to be called from a Cucumber BeforeAll hook (after MazeRunner does everything it needs to)
|
16
|
+
def before_all(&block)
|
17
|
+
@before_all << block
|
18
|
+
end
|
19
|
+
|
20
|
+
# Register blocks to be called from a Cucumber Before hook (after MazeRunner does everything it needs to)
|
21
|
+
def before(&block)
|
22
|
+
@before << block
|
23
|
+
end
|
24
|
+
|
25
|
+
# Register blocks to be called from a Cucumber After hook (before MazeRunner does everything it needs to)
|
26
|
+
def after(&block)
|
27
|
+
@after << block
|
28
|
+
end
|
29
|
+
|
30
|
+
# For MazeRunner use only, call the registered BeforeAll blocks
|
31
|
+
def call_before_all
|
32
|
+
@before_all.each(&:call)
|
33
|
+
end
|
34
|
+
|
35
|
+
# For MazeRunner use only, call the registered Before blocks
|
36
|
+
# @param scenario The current Cucumber scenario
|
37
|
+
def call_before(scenario)
|
38
|
+
@before.each { |block| block.call(scenario) }
|
39
|
+
end
|
40
|
+
|
41
|
+
# For MazeRunner use only, call the registered After blocks
|
42
|
+
# @param scenario The current Cucumber scenario
|
43
|
+
def call_after(scenario)
|
44
|
+
@after.each { |block| block.call(scenario) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Base class for hooks internal to Maze Runner
|
49
|
+
class InternalHooks
|
50
|
+
def before_all; end
|
51
|
+
|
52
|
+
def before; end
|
53
|
+
|
54
|
+
def after; end
|
55
|
+
|
56
|
+
def after_all; end
|
57
|
+
|
58
|
+
def at_exit; end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|