bugsnag-maze-runner 6.27.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|