bugsnag-maze-runner 7.22.1
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 +74 -0
- data/bin/maze-runner +174 -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 +80 -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 +358 -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 +135 -0
- data/lib/features/steps/payload_steps.rb +257 -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 +186 -0
- data/lib/features/steps/runner_steps.rb +428 -0
- data/lib/features/steps/session_tracking_steps.rb +116 -0
- data/lib/features/steps/trace_steps.rb +206 -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 +207 -0
- data/lib/maze/api/appium/file_manager.rb +29 -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/aws_public_ip.rb +53 -0
- data/lib/maze/bugsnag_config.rb +42 -0
- data/lib/maze/checks/assert_check.rb +69 -0
- data/lib/maze/checks/noop_check.rb +34 -0
- data/lib/maze/client/appium/base_client.rb +131 -0
- data/lib/maze/client/appium/bb_client.rb +102 -0
- data/lib/maze/client/appium/bb_devices.rb +127 -0
- data/lib/maze/client/appium/bs_client.rb +91 -0
- data/lib/maze/client/appium/bs_devices.rb +141 -0
- data/lib/maze/client/appium/bs_legacy_client.rb +31 -0
- data/lib/maze/client/appium/local_client.rb +67 -0
- data/lib/maze/client/appium.rb +23 -0
- data/lib/maze/client/bb_api_client.rb +102 -0
- data/lib/maze/client/bb_client_utils.rb +181 -0
- data/lib/maze/client/bs_client_utils.rb +168 -0
- data/lib/maze/client/selenium/base_client.rb +15 -0
- data/lib/maze/client/selenium/bb_browsers.yml +188 -0
- data/lib/maze/client/selenium/bb_client.rb +38 -0
- data/lib/maze/client/selenium/bs_browsers.yml +257 -0
- data/lib/maze/client/selenium/bs_client.rb +89 -0
- data/lib/maze/client/selenium/local_client.rb +16 -0
- data/lib/maze/client/selenium.rb +16 -0
- data/lib/maze/compare.rb +161 -0
- data/lib/maze/configuration.rb +182 -0
- data/lib/maze/docker.rb +147 -0
- data/lib/maze/document_server.rb +46 -0
- data/lib/maze/driver/appium.rb +198 -0
- data/lib/maze/driver/browser.rb +124 -0
- data/lib/maze/errors.rb +52 -0
- data/lib/maze/generator.rb +55 -0
- data/lib/maze/helper.rb +122 -0
- data/lib/maze/hooks/appium_hooks.rb +55 -0
- data/lib/maze/hooks/browser_hooks.rb +15 -0
- data/lib/maze/hooks/command_hooks.rb +9 -0
- data/lib/maze/hooks/error_code_hook.rb +49 -0
- data/lib/maze/hooks/hooks.rb +61 -0
- data/lib/maze/http_request.rb +21 -0
- data/lib/maze/interactive_cli.rb +173 -0
- data/lib/maze/logger.rb +86 -0
- data/lib/maze/macos_utils.rb +14 -0
- data/lib/maze/maze_output.rb +88 -0
- data/lib/maze/network.rb +49 -0
- data/lib/maze/option/parser.rb +240 -0
- data/lib/maze/option/processor.rb +130 -0
- data/lib/maze/option/validator.rb +155 -0
- data/lib/maze/option.rb +62 -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/error_code_plugin.rb +21 -0
- data/lib/maze/plugins/global_retry_plugin.rb +38 -0
- data/lib/maze/proxy.rb +114 -0
- data/lib/maze/request_list.rb +87 -0
- data/lib/maze/request_repeater.rb +49 -0
- data/lib/maze/retry_handler.rb +67 -0
- data/lib/maze/runner.rb +149 -0
- data/lib/maze/schemas/OtelTraceSchema.json +390 -0
- data/lib/maze/schemas/trace_schema.rb +7 -0
- data/lib/maze/schemas/trace_validator.rb +98 -0
- data/lib/maze/server.rb +251 -0
- data/lib/maze/servlets/base_servlet.rb +27 -0
- data/lib/maze/servlets/command_servlet.rb +47 -0
- data/lib/maze/servlets/log_servlet.rb +64 -0
- data/lib/maze/servlets/reflective_servlet.rb +70 -0
- data/lib/maze/servlets/servlet.rb +199 -0
- data/lib/maze/servlets/temp.rb +0 -0
- data/lib/maze/servlets/trace_servlet.rb +13 -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
- data/lib/utils/deep_merge.rb +17 -0
- data/lib/utils/selenium_money_patch.rb +17 -0
- metadata +451 -0
@@ -0,0 +1,228 @@
|
|
1
|
+
# @!group App Automator steps
|
2
|
+
|
3
|
+
# Checks a UI element is present
|
4
|
+
# Requires a running Appium driver
|
5
|
+
#
|
6
|
+
# @step_input element_id [String] The locator id
|
7
|
+
Given('the element {string} is present') do |element_id|
|
8
|
+
present = Maze.driver.wait_for_element(element_id)
|
9
|
+
raise Maze::Error::AppiumElementNotFoundError.new("The element #{element_id} could not be found", element_id) unless present
|
10
|
+
end
|
11
|
+
|
12
|
+
# Checks a UI element is present within a specified number of seconds
|
13
|
+
# Requires a running Appium driver
|
14
|
+
#
|
15
|
+
# @step_input element_id [String] The locator id
|
16
|
+
# @step_input timeout [Int] The number of seconds to wait before timing out
|
17
|
+
Given('the element {string} is present within {int} seconds') do |element_id, timeout|
|
18
|
+
present = Maze.driver.wait_for_element(element_id, timeout)
|
19
|
+
raise Maze::Error::AppiumElementNotFoundError.new("The element #{element_id} could not be found", element_id) unless present
|
20
|
+
end
|
21
|
+
|
22
|
+
# Clicks a given element
|
23
|
+
# Requires a running Appium driver
|
24
|
+
#
|
25
|
+
# @step_input element_id [String] The locator id
|
26
|
+
When('I click the element {string}') do |element_id|
|
27
|
+
Maze.driver.click_element(element_id)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Sends the app to the background indefinitely
|
31
|
+
# Requires a running Appium driver
|
32
|
+
When('I send the app to the background') do
|
33
|
+
Maze.driver.background_app(-1)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Sends the app to the background for a number of seconds
|
37
|
+
# Requires a running Appium driver
|
38
|
+
#
|
39
|
+
# @step_input timeout [Integer] The amount of time the app is in the background in seconds
|
40
|
+
When('I send the app to the background for {int} second(s)') do |timeout|
|
41
|
+
Maze.driver.background_app(timeout)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Clears a given element
|
45
|
+
# Requires a running Appium driver
|
46
|
+
#
|
47
|
+
# @step_input element_id [String] The locator id
|
48
|
+
When('I clear the element {string}') do |element_id|
|
49
|
+
Maze.driver.clear_element(element_id)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Sends keys to a given element
|
53
|
+
# Requires a running Appium driver
|
54
|
+
#
|
55
|
+
# @step_input keys [String] The keys to send to the element
|
56
|
+
# @step_input element_id [String] The locator id
|
57
|
+
When('I send the keys {string} to the element {string}') do |keys, element_id|
|
58
|
+
Maze.driver.send_keys_to_element(element_id, keys)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Tests that the given payload value is correct for the target BrowserStack platform.
|
62
|
+
# This step will assume the expected and payload values are strings.
|
63
|
+
# If the step is invoked when a remote BrowserStack device is not in use this step will fail.
|
64
|
+
#
|
65
|
+
# The DataTable used for this step should have `ios` and `android` in the same row as their expected value:
|
66
|
+
# | android | Java.lang.RuntimeException |
|
67
|
+
# | ios | NSException |
|
68
|
+
#
|
69
|
+
# If the expected value is set to "@skip", the check should be skipped
|
70
|
+
# If the expected value is set to "@null", the check will be for null
|
71
|
+
# If the expected value is set to "@not_null", the check will be for a non-null value
|
72
|
+
#
|
73
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
74
|
+
# @step_input field_path [String] The field to test
|
75
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
76
|
+
Then('the {word} payload field {string} equals the platform-dependent string:') do |request_type, field_path, platform_values|
|
77
|
+
test_string_platform_values(request_type, field_path, platform_values)
|
78
|
+
end
|
79
|
+
|
80
|
+
# See `the error payload field {string} equals the platform-dependent string:`
|
81
|
+
#
|
82
|
+
# @step_input field_path [String] The field to test, prepended with "events.0"
|
83
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
84
|
+
Then('the event {string} equals the platform-dependent string:') do |field_path, platform_values|
|
85
|
+
test_string_platform_values('error', "events.0.#{field_path}", platform_values)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Tests that the given payload value is correct for the target BrowserStack platform.
|
89
|
+
# This step will assume the expected and payload values are numeric.
|
90
|
+
# If the step is invoked when a remote BrowserStack device is not in use this step will fail.
|
91
|
+
#
|
92
|
+
# The DataTable used for this step should have `ios` and `android` in the same row as their expected value:
|
93
|
+
# | android | 1 |
|
94
|
+
# | ios | 5.5 |
|
95
|
+
#
|
96
|
+
# If the expected value is set to "@skip", the check should be skipped
|
97
|
+
# If the expected value is set to "@null", the check will be for null
|
98
|
+
# If the expected value is set to "@not_null", the check will be for a non-null value
|
99
|
+
#
|
100
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
101
|
+
# @step_input field_path [String] The field to test
|
102
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
103
|
+
Then('the {word} payload field {string} equals the platform-dependent numeric:') do |request_type, field_path, platform_values|
|
104
|
+
test_numeric_platform_values(request_type, field_path, platform_values)
|
105
|
+
end
|
106
|
+
|
107
|
+
# See `the payload field {string} equals the platform-dependent numeric:`
|
108
|
+
#
|
109
|
+
# @step_input field_path [String] The field to test, prepended with "events.0"
|
110
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
111
|
+
Then('the event {string} equals the platform-dependent numeric:') do |field_path, platform_values|
|
112
|
+
test_numeric_platform_values('error', "events.0.#{field_path}", platform_values)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Tests that the given payload value is correct for the target BrowserStack platform.
|
116
|
+
# This step will assume the expected and payload values are booleans.
|
117
|
+
# If the step is invoked when a remote BrowserStack device is not in use this step will fail.
|
118
|
+
#
|
119
|
+
# The DataTable used for this step should have `ios` and `android` in the same row as their expected value:
|
120
|
+
# | android | 1 |
|
121
|
+
# | ios | 5 |
|
122
|
+
#
|
123
|
+
# If the expected value is set to "@skip", the check should be skipped
|
124
|
+
# If the expected value is set to "@null", the check will be for null
|
125
|
+
# If the expected value is set to "@not_null", the check will be for a non-null value
|
126
|
+
#
|
127
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
128
|
+
# @step_input field_path [String] The field to test
|
129
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
130
|
+
Then('the {word} payload field {string} equals the platform-dependent boolean:') do |request_type, field_path, platform_values|
|
131
|
+
test_boolean_platform_values(request_type, field_path, platform_values)
|
132
|
+
end
|
133
|
+
|
134
|
+
# See `the payload field {string} equals the platform-dependent boolean:`
|
135
|
+
#
|
136
|
+
# @step_input field_path [String] The field to test, prepended with "events.0"
|
137
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
138
|
+
Then('the event {string} equals the platform-dependent boolean:') do |field_path, platform_values|
|
139
|
+
test_boolean_platform_values('error', "events.0.#{field_path}", platform_values)
|
140
|
+
end
|
141
|
+
|
142
|
+
# See `the payload field {string} equals the platform-dependent string:`
|
143
|
+
#
|
144
|
+
# @step_input field_path [String] The field to test, prepended with "events.0.exceptions.0."
|
145
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
146
|
+
Then('the exception {string} equals the platform-dependent string:') do |field_path, platform_values|
|
147
|
+
test_string_platform_values('error', "events.0.exceptions.0.#{field_path}", platform_values)
|
148
|
+
end
|
149
|
+
|
150
|
+
# See `the payload field {string} equals the platform-dependent string:`
|
151
|
+
#
|
152
|
+
# @step_input field_path [String] The field to test, prepended with "events.0.exceptions.0.stacktrace.#!{num}"
|
153
|
+
# @step_input num [Integer] The index of the stack frame to test
|
154
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
155
|
+
Then('the {string} of stack frame {int} equals the platform-dependent string:') do |field_path, num, platform_values|
|
156
|
+
test_string_platform_values('error', "events.0.exceptions.0.stacktrace.#{num}.#{field_path}", platform_values)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Sends keys to a given element, clearing it first
|
160
|
+
# Requires a running Appium driver
|
161
|
+
#
|
162
|
+
# @step_input keys [String] The keys to send to the element
|
163
|
+
# @step_input element_id [String] The locator id
|
164
|
+
When('I clear and send the keys {string} to the element {string}') do |keys, element_id|
|
165
|
+
Maze.driver.clear_and_send_keys_to_element(element_id, keys)
|
166
|
+
end
|
167
|
+
|
168
|
+
def get_expected_platform_value(platform_values)
|
169
|
+
os = Maze::Helper.get_current_platform
|
170
|
+
expected_value = Hash[platform_values.raw][os.downcase]
|
171
|
+
raise("There is no expected value for the current platform \"#{os}\"") if expected_value.nil?
|
172
|
+
|
173
|
+
expected_value
|
174
|
+
end
|
175
|
+
|
176
|
+
def should_skip_platform_check(expected_value)
|
177
|
+
expected_value.eql?('@skip')
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_string_platform_values(request_type, field_path, platform_values)
|
181
|
+
expected_value = get_expected_platform_value(platform_values)
|
182
|
+
return if should_skip_platform_check(expected_value)
|
183
|
+
|
184
|
+
list = Maze::Server.list_for(request_type)
|
185
|
+
payload_value = Maze::Helper.read_key_path(list.current[:body], field_path)
|
186
|
+
assert_equal_with_nullability(expected_value, payload_value)
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_boolean_platform_values(request_type, field_path, platform_values)
|
190
|
+
expected_value = get_expected_platform_value(platform_values)
|
191
|
+
return if should_skip_platform_check(expected_value)
|
192
|
+
|
193
|
+
expected_bool = case expected_value.downcase
|
194
|
+
when 'true'
|
195
|
+
true
|
196
|
+
when 'false'
|
197
|
+
false
|
198
|
+
else
|
199
|
+
expected_value
|
200
|
+
end
|
201
|
+
list = Maze::Server.list_for(request_type)
|
202
|
+
payload_value = Maze::Helper.read_key_path(list.current[:body], field_path)
|
203
|
+
assert_equal_with_nullability(expected_bool, payload_value)
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_numeric_platform_values(request_type, field_path, platform_values)
|
207
|
+
expected_value = get_expected_platform_value(platform_values)
|
208
|
+
return if should_skip_platform_check(expected_value)
|
209
|
+
|
210
|
+
list = Maze::Server.list_for(request_type)
|
211
|
+
payload_value = Maze::Helper.read_key_path(list.current[:body], field_path)
|
212
|
+
|
213
|
+
# Need to do a little more processing here to allow floats
|
214
|
+
special_value = expected_value.eql?('@null') || expected_value.eql?('@not_null')
|
215
|
+
expectation = special_value ? expected_value : expected_value.to_f
|
216
|
+
assert_equal_with_nullability(expectation, payload_value)
|
217
|
+
end
|
218
|
+
|
219
|
+
def assert_equal_with_nullability(expected_value, payload_value)
|
220
|
+
case expected_value
|
221
|
+
when '@null'
|
222
|
+
Maze.check.nil(payload_value)
|
223
|
+
when '@not_null'
|
224
|
+
Maze.check.not_nil(payload_value)
|
225
|
+
else
|
226
|
+
Maze.check.equal(expected_value, payload_value)
|
227
|
+
end
|
228
|
+
end
|
@@ -0,0 +1,212 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../maze'
|
4
|
+
require_relative '../../maze/aws/sam'
|
5
|
+
|
6
|
+
# @!group AWS SAM steps
|
7
|
+
|
8
|
+
# Invoke a lambda directly with 'sam invoke'
|
9
|
+
#
|
10
|
+
# @step_input lambda_name [String] The name of the lambda to invoke
|
11
|
+
# @step_input directory [String] The directory to invoke the lambda in
|
12
|
+
Given('I invoke the {string} lambda in {string}') do |lambda_name, directory|
|
13
|
+
Maze::Aws::Sam.invoke(directory, lambda_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Invoke a lambda directly with 'sam invoke' and the given event
|
17
|
+
#
|
18
|
+
# @step_input lambda_name [String] The name of the lambda to invoke
|
19
|
+
# @step_input directory [String] The directory to invoke the lambda in
|
20
|
+
# @step_input event_file [String] The event file to call the lambda with
|
21
|
+
Given('I invoke the {string} lambda in {string} with the {string} event') do |lambda_name, directory, event_file|
|
22
|
+
Maze::Aws::Sam.invoke(directory, lambda_name, event_file)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Test the exit code of the SAM CLI process.
|
26
|
+
#
|
27
|
+
# @step_input expected [Integer] The expected exit code
|
28
|
+
Then('the SAM exit code equals {int}') do |expected|
|
29
|
+
Maze.check.equal(expected, Maze::Aws::Sam.last_exit_code)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Test the Lambda response is empty but not-null. This indicates the Lambda did
|
33
|
+
# not respond but did run successfully
|
34
|
+
Then('the lambda response is empty') do
|
35
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
36
|
+
|
37
|
+
Maze.check.equal({}, Maze::Aws::Sam.last_response)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Test a Lambda response field equals the given string.
|
41
|
+
#
|
42
|
+
# @step_input key_path [String] The response element to test
|
43
|
+
# @step_input expected [String] The string to test against
|
44
|
+
Then('the lambda response {string} equals {string}') do |key_path, expected|
|
45
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
46
|
+
|
47
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
48
|
+
|
49
|
+
Maze.check.equal(expected, actual)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Test a Lambda response field contains the given string.
|
53
|
+
#
|
54
|
+
# @step_input key_path [String] The response element to test
|
55
|
+
# @step_input expected [String] The string to test against
|
56
|
+
Then('the lambda response {string} contains {string}') do |key_path, expected|
|
57
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
58
|
+
|
59
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
60
|
+
|
61
|
+
Maze.check.include(actual, expected)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Test a Lambda response field equals the given integer.
|
65
|
+
#
|
66
|
+
# @step_input key_path [String] The response element to test
|
67
|
+
# @step_input expected [Integer] The integer to test against
|
68
|
+
Then('the lambda response {string} equals {int}') do |key_path, expected|
|
69
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
70
|
+
|
71
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
72
|
+
|
73
|
+
Maze.check.equal(expected, actual)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Test a Lambda response field is true.
|
77
|
+
#
|
78
|
+
# @step_input key_path [String] The response element to test
|
79
|
+
Then('the lambda response {string} is true') do |key_path|
|
80
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
81
|
+
|
82
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
83
|
+
|
84
|
+
Maze.check.true(actual)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Test a Lambda response field is false.
|
88
|
+
#
|
89
|
+
# @step_input key_path [String] The response element to test
|
90
|
+
Then('the lambda response {string} is false') do |key_path|
|
91
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
92
|
+
|
93
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
94
|
+
|
95
|
+
Maze.check.false(actual)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Test a Lambda response field is null.
|
99
|
+
#
|
100
|
+
# @step_input key_path [String] The response element to test
|
101
|
+
Then('the lambda response {string} is null') do |key_path|
|
102
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
103
|
+
|
104
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
105
|
+
|
106
|
+
Maze.check.nil(actual)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Test a Lambda response field is not null.
|
110
|
+
#
|
111
|
+
# @step_input key_path [String] The response element to test
|
112
|
+
Then('the lambda response {string} is not null') do |key_path|
|
113
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
114
|
+
|
115
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
116
|
+
|
117
|
+
Maze.check.not_nil(actual)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Test a Lambda response field is greater than the given integer.
|
121
|
+
#
|
122
|
+
# @step_input key_path [String] The response element to test
|
123
|
+
# @step_input expected [Integer] The integer to test against
|
124
|
+
Then('the lambda response {string} is greater than {int}') do |key_path, expected|
|
125
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
126
|
+
|
127
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
128
|
+
|
129
|
+
Maze.check.operator(actual, :>, expected)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Test a Lambda response field is less than the given integer.
|
133
|
+
#
|
134
|
+
# @step_input key_path [String] The response element to test
|
135
|
+
# @step_input expected [Integer] The integer to test against
|
136
|
+
Then('the lambda response {string} is less than {int}') do |key_path, expected|
|
137
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
138
|
+
|
139
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
140
|
+
|
141
|
+
Maze.check.operator(actual, :<, expected)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Test a Lambda response field starts with the given string.
|
145
|
+
#
|
146
|
+
# @step_input key_path [String] The response element to test
|
147
|
+
# @step_input expected [String] The string to test against
|
148
|
+
Then('the lambda response {string} starts with {string}') do |key_path, expected|
|
149
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
150
|
+
|
151
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
152
|
+
|
153
|
+
Maze.check.kind_of(String, actual)
|
154
|
+
Maze.check.true(
|
155
|
+
actual.start_with?(expected),
|
156
|
+
"Field '#{key_path}' value ('#{actual}') does not start with '#{expected}'"
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Test a Lambda response field ends with the given string.
|
161
|
+
#
|
162
|
+
# @step_input key_path [String] The response element to test
|
163
|
+
# @step_input expected [String] The string to test against
|
164
|
+
Then('the lambda response {string} ends with {string}') do |key_path, expected|
|
165
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
166
|
+
|
167
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
168
|
+
|
169
|
+
Maze.check.kind_of(String, actual)
|
170
|
+
Maze.check.true(
|
171
|
+
actual.end_with?(expected),
|
172
|
+
"Field '#{key_path}' value ('#{actual}') does not start with '#{expected}'"
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
# Test a Lambda response field is an array with a specific number of elements.
|
177
|
+
#
|
178
|
+
# @step_input key_path [String] The response element to test
|
179
|
+
# @step_input expected [Integer] The expected number of elements
|
180
|
+
Then('the lambda response {string} is an array with {int} element(s)') do |key_path, expected|
|
181
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
182
|
+
|
183
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
184
|
+
|
185
|
+
Maze.check.kind_of(Array, actual)
|
186
|
+
Maze.check.equal(expected, actual.length)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Test a Lambda response field is an array with at least 1 element.
|
190
|
+
#
|
191
|
+
# @step_input key_path [String] The response element to test
|
192
|
+
Then('the lambda response {string} is a non-empty array') do |key_path|
|
193
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
194
|
+
|
195
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
196
|
+
|
197
|
+
Maze.check.kind_of(Array, actual)
|
198
|
+
Maze.check.false(actual.empty?)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Test a Lambda response field matches the given regex.
|
202
|
+
#
|
203
|
+
# @step_input key_path [String] The response element to test
|
204
|
+
# @step_input expected [String] The regex to match against
|
205
|
+
Then('the lambda response {string} matches the regex {string}') do |key_path, regex|
|
206
|
+
expected = Regexp.new(regex)
|
207
|
+
Maze.check.not_nil(Maze::Aws::Sam.last_response, 'No lambda response!')
|
208
|
+
|
209
|
+
actual = Maze::Helper.read_key_path(Maze::Aws::Sam.last_response, key_path)
|
210
|
+
|
211
|
+
Maze.check.match(expected, actual)
|
212
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# @!group Breadcrumb steps
|
2
|
+
|
3
|
+
# Tests whether the first event entry contains the specified number of breadcrumbs.
|
4
|
+
#
|
5
|
+
# @step_input expected [Integer] The expected number of breadcrumbs
|
6
|
+
Then("the event has {int} breadcrumb(s)") do |expected|
|
7
|
+
breadcrumbs = Maze::Server.errors.current[:body]['events'].first['breadcrumbs']
|
8
|
+
|
9
|
+
Maze.check.equal(
|
10
|
+
expected,
|
11
|
+
breadcrumbs&.length || 0,
|
12
|
+
"Expected event to have '#{expected}' breadcrumbs, but got: #{breadcrumbs}"
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Tests whether the first event entry contains no breadcrumbs.
|
17
|
+
Then("the event has no breadcrumbs") do
|
18
|
+
breadcrumbs = Maze::Server.errors.current[:body]['events'].first['breadcrumbs']
|
19
|
+
|
20
|
+
Maze.check.true(
|
21
|
+
# some notifiers may omit breadcrumbs entirely when empty, otherwise it should
|
22
|
+
# be an empty array
|
23
|
+
breadcrumbs.nil? || breadcrumbs.empty?,
|
24
|
+
"Expected event not to have breadcrumbs, but got: #{breadcrumbs}"
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Tests whether the first event entry contains a specific breadcrumb with a type and name.
|
29
|
+
#
|
30
|
+
# @step_input type [String] The expected breadcrumb's type
|
31
|
+
# @step_input name [String] The expected breadcrumb's name
|
32
|
+
Then('the event has a {string} breadcrumb named {string}') do |type, name|
|
33
|
+
breadcrumbs = Maze::Server.errors.current[:body]['events'].first['breadcrumbs']
|
34
|
+
|
35
|
+
Maze.check.true(
|
36
|
+
breadcrumbs.any? { |crumb| crumb['type'] == type && crumb['name'] == name },
|
37
|
+
"Expected event to have a breadcrumb with type '#{type}' and name '#{name}', but got: #{breadcrumbs}"
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Tests whether the first event entry contains a specific breadcrumb with a type and message.
|
42
|
+
#
|
43
|
+
# @step_input type [String] The expected breadcrumb's type
|
44
|
+
# @step_input message [String] The expected breadcrumb's message
|
45
|
+
Then('the event has a {string} breadcrumb with message {string}') do |type, message|
|
46
|
+
value = Maze::Server.errors.current[:body]['events'].first['breadcrumbs']
|
47
|
+
found = value.any? { |crumb| crumb['type'] == type && crumb['metaData'] && crumb['metaData']['message'] == message }
|
48
|
+
raise("No breadcrumb matched: #{value}") unless found
|
49
|
+
end
|
50
|
+
|
51
|
+
# Tests whether the first event entry does not contain a breadcrumb with a specific type.
|
52
|
+
# Used for confirming filtering of breadcrumbs
|
53
|
+
#
|
54
|
+
# @step_input type [String] The type of breadcrumb expected to not be present
|
55
|
+
Then('the event does not have a {string} breadcrumb') do |type|
|
56
|
+
value = Maze::Server.errors.current[:body]['events'].first['breadcrumbs']
|
57
|
+
found = value.any? { |crumb| crumb['type'] == type }
|
58
|
+
raise("Breadcrumb with type: #{type} matched") if found
|
59
|
+
end
|
60
|
+
|
61
|
+
# Test whether the first event entry does not contain a breadcrumb with a specific type and message.
|
62
|
+
# Used for confirming filtering of breadcrumbs
|
63
|
+
#
|
64
|
+
# @step_input type [String] The type of the breadcrumb expected to be absent
|
65
|
+
# @step_input message [String] The message of the breadcrumb expected to be absent
|
66
|
+
Then('the event does not have a {string} breadcrumb with message {string}') do |type, message|
|
67
|
+
value = Maze::Server.errors.current[:body]['events'].first['breadcrumbs']
|
68
|
+
found = value.any? { |crumb| crumb['type'] == type && crumb['metaData'] && crumb['metaData']['message'] == message }
|
69
|
+
raise("Breadcrumb with type: #{type} and message: #{message} matched") if found
|
70
|
+
end
|
71
|
+
|
72
|
+
# Tests whether any breadcrumb matches a given JSON fixture. This follows all the usual rules for JSON fixture matching.
|
73
|
+
#
|
74
|
+
# @step_input json_fixture [String] A path to the JSON fixture to compare against
|
75
|
+
Then('the event contains a breadcrumb matching the JSON fixture in {string}') do |json_fixture|
|
76
|
+
breadcrumbs = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], 'events.0.breadcrumbs')
|
77
|
+
expected = JSON.parse(open(json_fixture, &:read))
|
78
|
+
match = breadcrumbs.any? { |breadcrumb| Maze::Compare.value(expected, breadcrumb).equal? }
|
79
|
+
Maze.check.true(match, 'No breadcrumbs in the event matched the given breadcrumb')
|
80
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# @!group Browser steps
|
2
|
+
|
3
|
+
When('I navigate to the URL {string}') do |path|
|
4
|
+
begin
|
5
|
+
$logger.debug "Navigating to: #{path}"
|
6
|
+
Maze.driver.navigate.to path
|
7
|
+
rescue => exception
|
8
|
+
$logger.error("#{exception.class} occurred during navigation attempt with message: #{exception.message}")
|
9
|
+
$logger.error("Restarting driver and retrying navigation to: #{path}")
|
10
|
+
Maze.driver.restart_driver
|
11
|
+
Maze.driver.navigate.to path
|
12
|
+
# If a further error occurs it will get thrown as normal
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Then(/^the error is a valid browser payload for the error reporting API$/) do
|
17
|
+
if !/^ie_(8|9|10)$/.match(Maze.config.browser)
|
18
|
+
steps %(
|
19
|
+
Then the error "Bugsnag-API-Key" header is not null
|
20
|
+
And the error "Content-Type" header equals one of:
|
21
|
+
| application/json |
|
22
|
+
| application/json; charset=UTF-8 |
|
23
|
+
And the error "Bugsnag-Payload-Version" header equals "4"
|
24
|
+
And the error "Bugsnag-Sent-At" header is a timestamp
|
25
|
+
)
|
26
|
+
else
|
27
|
+
steps %(
|
28
|
+
Then the error "apiKey" query parameter is not null
|
29
|
+
And the error "payloadVersion" query parameter equals "4"
|
30
|
+
And the error "sentAt" query parameter is a timestamp
|
31
|
+
)
|
32
|
+
end
|
33
|
+
steps %(
|
34
|
+
And the error payload field "notifier.name" is not null
|
35
|
+
And the error payload field "notifier.url" is not null
|
36
|
+
And the error payload field "notifier.version" is not null
|
37
|
+
And the error payload field "events" is a non-empty array
|
38
|
+
|
39
|
+
And each element in error payload field "events" has "severity"
|
40
|
+
And each element in error payload field "events" has "severityReason.type"
|
41
|
+
And each element in error payload field "events" has "unhandled"
|
42
|
+
And each element in error payload field "events" has "exceptions"
|
43
|
+
|
44
|
+
And the exception "type" equals "browserjs"
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
Then('the session is a valid browser payload for the session tracking API') do
|
49
|
+
if !/^ie_(8|9|10)$/.match(Maze.config.browser)
|
50
|
+
steps %(
|
51
|
+
Then the session "Bugsnag-API-Key" header is not null
|
52
|
+
And the session "Content-Type" header equals one of:
|
53
|
+
| application/json |
|
54
|
+
| application/json; charset=UTF-8 |
|
55
|
+
And the session "Bugsnag-Payload-Version" header equals "1"
|
56
|
+
And the session "Bugsnag-Sent-At" header is a timestamp
|
57
|
+
)
|
58
|
+
else
|
59
|
+
steps %(
|
60
|
+
Then the session "apiKey" query parameter is not null
|
61
|
+
And the session "payloadVersion" query parameter equals "1"
|
62
|
+
And the session "sentAt" query parameter is a timestamp
|
63
|
+
)
|
64
|
+
end
|
65
|
+
steps %(
|
66
|
+
And the session payload field "app" is not null
|
67
|
+
And the session payload field "device" is not null
|
68
|
+
And the session payload field "notifier.name" is not null
|
69
|
+
And the session payload field "notifier.url" is not null
|
70
|
+
And the session payload field "notifier.version" is not null
|
71
|
+
And the session payload has a valid sessions array
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
Then('the event device ID is valid') do
|
76
|
+
if Maze.driver.local_storage?
|
77
|
+
step('the event "device.id" matches "^c[a-z0-9]{20,32}$"')
|
78
|
+
else
|
79
|
+
$logger.info('Local storage is not supported in this browser, assuming device ID is null')
|
80
|
+
step('the event "device.id" is null')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
Then('the event device ID is {string}') do |expected_id|
|
85
|
+
if Maze.driver.local_storage?
|
86
|
+
step("the event \"device.id\" equals \"#{expected_id}\"")
|
87
|
+
else
|
88
|
+
$logger.info('Local storage is not supported in this browser, assuming device ID is null')
|
89
|
+
step('the event "device.id" is null')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# @!endgroup
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @!group Build API Steps
|
4
|
+
|
5
|
+
# Tests whether the top-most payload is valid for the Bugsnag build API
|
6
|
+
# APIKey fields and headers are tested against the '$api_key' global variable
|
7
|
+
Then('the build is valid for the Build API') do
|
8
|
+
steps %(
|
9
|
+
And the build payload field "apiKey" equals "#{$api_key}"
|
10
|
+
And the build payload field "appVersion" is not null
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Tests whether the top-most payload is valid for the Android mapping API
|
15
|
+
# APIKey fields and headers are tested against the '$api_key' global variable
|
16
|
+
Then('the build is valid for the Android Mapping API') do
|
17
|
+
steps %(
|
18
|
+
And the build payload field "apiKey" equals "#{$api_key}"
|
19
|
+
And the build payload field "proguard" is not null
|
20
|
+
And the build payload field "appId" is not null
|
21
|
+
And the build payload field "versionCode" is not null
|
22
|
+
And the build payload field "buildUUID" is not null
|
23
|
+
And the build payload field "versionName" is not null
|
24
|
+
)
|
25
|
+
end
|