fastlane-plugin-saucectl 0.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6bdbb9912f67b89ebe6130337c9c0610909efcb95e21716f45fb1559268afb82
4
+ data.tar.gz: 747c9ce9d6cbf1cbceed7b9d4167a02d2174bd23ec29a8736b1730c4cdc1ae53
5
+ SHA512:
6
+ metadata.gz: 9a6ed65ee27a67ca9630e208e2c9f564daf7d9bb6fb81339eafbd0a20f24959cdc4693e8bd938c0241d5003ff612e03de4ec1aa109dc39b2ab17b45494ca6c67
7
+ data.tar.gz: 83cbd56a6e355ae11677d7b92e1bdc6ec37e17882a3ddb672ad98486e7ea53624ffceca8d86301e01009e200d9a46956f2ca2f36e3ca18f9fb4906fc2b875c5b
@@ -0,0 +1,96 @@
1
+ require 'fastlane/action'
2
+ require 'json'
3
+ require 'yaml'
4
+ require_relative '../helper/api'
5
+ require_relative '../helper/storage'
6
+
7
+ module Fastlane
8
+ module Actions
9
+ class DeleteFromStorageAction < Action
10
+ @messages = YAML.load_file("#{__dir__}/../strings/messages.yml")
11
+
12
+ def self.run(params)
13
+ if params[:group_id].nil?
14
+ Fastlane::Saucectl::Storage.new(params).delete_app_with_file_id
15
+ else
16
+ Fastlane::Saucectl::Storage.new(params).delete_all_apps_for_group_id
17
+ end
18
+ end
19
+
20
+ def self.description
21
+ "Delete test artifacts from sauce labs storage"
22
+ end
23
+
24
+ def self.details
25
+ "Delete test artifacts from sauce labs storage by storage id or group id"
26
+ end
27
+
28
+ def self.available_options
29
+ [
30
+ FastlaneCore::ConfigItem.new(key: :region,
31
+ description: "Data Center region (us or eu), set using: region: 'eu'",
32
+ optional: false,
33
+ is_string: true,
34
+ verify_block: proc do |value|
35
+ UI.user_error!(@messages['region_error'].gsub!('$region', value)) if value.empty? || !@messages['supported_regions'].include?(value)
36
+ end),
37
+ FastlaneCore::ConfigItem.new(key: :sauce_username,
38
+ env_name: "SAUCE_USERNAME",
39
+ description: "Your sauce labs username in order to authenticate delete file from app storage",
40
+ default_value: Actions.lane_context[SharedValues::SAUCE_USERNAME],
41
+ optional: false,
42
+ is_string: true,
43
+ verify_block: proc do |value|
44
+ UI.user_error!(@messages['sauce_username_error']) if value.empty?
45
+ end),
46
+ FastlaneCore::ConfigItem.new(key: :sauce_access_key,
47
+ env_name: "SAUCE_ACCESS_KEY",
48
+ description: "Your sauce labs access key in order to authenticate delete file from app storage",
49
+ default_value: Actions.lane_context[SharedValues::SAUCE_ACCESS_KEY],
50
+ optional: false,
51
+ is_string: true,
52
+ verify_block: proc do |value|
53
+ UI.user_error!(@messages['sauce_api_key_error']) if value.empty?
54
+ end),
55
+ FastlaneCore::ConfigItem.new(key: :app_id,
56
+ description: "The application id from sauce labs storage",
57
+ optional: true,
58
+ is_string: true),
59
+ FastlaneCore::ConfigItem.new(key: :group_id,
60
+ description: "The group id for sauce labs storage",
61
+ optional: true,
62
+ is_string: true)
63
+ ]
64
+ end
65
+
66
+ def self.authors
67
+ ["Ian Hamilton"]
68
+ end
69
+
70
+ def self.category
71
+ :testing
72
+ end
73
+
74
+ def self.is_supported?(platform)
75
+ [:ios, :android].include?(platform)
76
+ end
77
+
78
+ def self.example_code
79
+ [
80
+ "delete_from_storage(
81
+ region: 'eu',
82
+ sauce_username: 'sauce username',
83
+ sauce_access_key: 'sauce api name',
84
+ app_id: '1234-1234-1234-1234'
85
+ )",
86
+ "delete_from_storage(
87
+ region: 'eu',
88
+ sauce_username: 'sauce username',
89
+ sauce_access_key: 'sauce api name',
90
+ group_id: '123456789'
91
+ )"
92
+ ]
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,86 @@
1
+ require 'fastlane/action'
2
+ require 'json'
3
+ require 'yaml'
4
+ require_relative '../helper/espresso'
5
+ require_relative '../helper/xctest'
6
+
7
+ module Fastlane
8
+ module Actions
9
+ class DisabledTestsAction < Action
10
+ @messages = YAML.load_file("#{__dir__}/../strings/messages.yml")
11
+
12
+ def self.run(params)
13
+ verify_config(params)
14
+ if params[:platform].eql?('android')
15
+ params[:path_to_tests] ? params[:path_to_tests] : params[:path_to_tests] = "app/src/androidTest"
16
+ Fastlane::Saucectl::Espresso.new(params).fetch_disabled_tests(params[:path_to_tests])
17
+ else
18
+ Fastlane::Saucectl::XCTest.new(params).fetch_disabled_tests
19
+ end
20
+ end
21
+
22
+ def self.verify_config(params)
23
+ if params[:platform].eql?('ios') && params[:test_plan].nil?
24
+ UI.user_error!('Cannot get skipped tests for an ios project without a known test_plan')
25
+ end
26
+ if params[:platform].eql?('android') && !params[:test_plan].nil?
27
+ UI.user_error!('test_plan option is reserved for ios projects only')
28
+ end
29
+ end
30
+
31
+ def self.description
32
+ "Fetches any disabled ui test cases (for android searches for @Ignore tests, and for ios skipped tests within an xcode test plan). Will be used in future for generating pretty HTML reports"
33
+ end
34
+
35
+ def self.available_options
36
+ [
37
+ FastlaneCore::ConfigItem.new(key: :platform,
38
+ description: "application under test platform (ios or android)",
39
+ optional: false,
40
+ is_string: true,
41
+ verify_block: proc do |value|
42
+ UI.user_error!(@messages['platform_error']) if value.to_s.empty?
43
+ end),
44
+ FastlaneCore::ConfigItem.new(key: :path_to_tests,
45
+ description: "Android only, path to espresso tests. Default to app/src/androidTest",
46
+ optional: true,
47
+ is_string: true),
48
+ FastlaneCore::ConfigItem.new(key: :test_plan,
49
+ description: "Name of xcode test plan",
50
+ optional: true,
51
+ is_string: true),
52
+ FastlaneCore::ConfigItem.new(key: :test_target,
53
+ description: "Name of xcode test target",
54
+ optional: true,
55
+ is_string: true)
56
+ ]
57
+ end
58
+
59
+ def self.authors
60
+ ["Ian Hamilton"]
61
+ end
62
+
63
+ def self.category
64
+ :testing
65
+ end
66
+
67
+ def self.is_supported?(platform)
68
+ [:ios, :android].include?(platform)
69
+ end
70
+
71
+ def self.example_code
72
+ [
73
+ "disabled_tests({ platform: 'android',
74
+ path_to_tests: 'my-demo-app-android/app/src/androidTest'
75
+ })",
76
+ "disabled_tests({ platform: 'ios',
77
+ test_plan: 'UITests'
78
+ })",
79
+ "disabled_tests({ platform: 'ios',
80
+ test_plan: 'UITests'
81
+ })"
82
+ ]
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,30 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/installer'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class InstallToolkitAction < Action
7
+ def self.run(param = '')
8
+ UI.message("Installing saucectl 🤖 🚀")
9
+ installer = Saucectl::Installer.new
10
+ installer.install
11
+ end
12
+
13
+ def self.description
14
+ "Installs the Sauce Labs saucectl cli binary"
15
+ end
16
+
17
+ def self.authors
18
+ ["Ian Hamilton"]
19
+ end
20
+
21
+ def self.category
22
+ :testing
23
+ end
24
+
25
+ def self.is_supported?(platform)
26
+ [:ios, :android].include?(platform)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,96 @@
1
+ require 'fastlane/action'
2
+ require 'json'
3
+ require 'yaml'
4
+ require_relative '../helper/api'
5
+
6
+ module Fastlane
7
+ module Actions
8
+ class SauceAppsAction < Action
9
+ @messages = YAML.load_file("#{__dir__}/../strings/messages.yml")
10
+ def self.run(params)
11
+ Fastlane::Saucectl::Api.new(params).retrieve_all_apps
12
+ end
13
+
14
+ def self.description
15
+ "Returns the set of files by specific app id that have been uploaded to Sauce Storage by the requester"
16
+ end
17
+
18
+ def self.details
19
+ "Returns the set of files by specific app id that have been uploaded to Sauce Storage by the requester"
20
+ end
21
+
22
+ def self.available_options
23
+ [
24
+ FastlaneCore::ConfigItem.new(key: :platform,
25
+ description: "application under test platform (ios or android)",
26
+ optional: false,
27
+ type: String,
28
+ verify_block: proc do |value|
29
+ UI.user_error!(@messages['platform_error']) if value.to_s.empty?
30
+ end),
31
+ FastlaneCore::ConfigItem.new(key: :query,
32
+ description: "Any search term (such as build number or file name) by which you want to filter results",
33
+ optional: false,
34
+ type: String,
35
+ verify_block: proc do |value|
36
+ UI.user_error!(@messages['missing_file_name']) if value.to_s.empty?
37
+ end),
38
+ FastlaneCore::ConfigItem.new(key: :region,
39
+ description: "Data Center region (us or eu), set using: region: 'eu'",
40
+ optional: false,
41
+ type: String,
42
+ verify_block: proc do |value|
43
+ UI.user_error!(@messages['region_error'].gsub!('$region', value)) unless @messages['supported_regions'].include?(value)
44
+ end),
45
+ FastlaneCore::ConfigItem.new(key: :sauce_username,
46
+ env_name: "SAUCE_USERNAME",
47
+ description: "Your sauce labs username in order to authenticate upload requests",
48
+ default_value: Actions.lane_context[SharedValues::SAUCE_USERNAME],
49
+ optional: false,
50
+ type: String,
51
+ verify_block: proc do |value|
52
+ UI.user_error!(@messages['sauce_username_error']) unless value && !value.empty?
53
+ end),
54
+ FastlaneCore::ConfigItem.new(key: :sauce_access_key,
55
+ env_name: "SAUCE_ACCESS_KEY",
56
+ description: "Your sauce labs access key in order to authenticate upload requests",
57
+ default_value: Actions.lane_context[SharedValues::SAUCE_ACCESS_KEY],
58
+ optional: false,
59
+ type: String,
60
+ verify_block: proc do |value|
61
+ UI.user_error!(@messages['sauce_api_key_error']) unless value && !value.empty?
62
+ end)
63
+ ]
64
+ end
65
+
66
+ def self.authors
67
+ ["Ian Hamilton"]
68
+ end
69
+
70
+ def self.category
71
+ :testing
72
+ end
73
+
74
+ def self.is_supported?(platform)
75
+ [:ios, :android].include?(platform)
76
+ end
77
+
78
+ def self.example_code
79
+ [
80
+ "sauce_apps({platform: 'android',
81
+ query: 'test.apk',
82
+ region: 'eu',
83
+ sauce_username: 'foo',
84
+ sauce_access_key: 'bar123',
85
+ })",
86
+ "sauce_apps({platform: 'ios',
87
+ query: 'test.app',
88
+ region: 'eu',
89
+ sauce_username: 'foo',
90
+ sauce_access_key: 'bar123',
91
+ })"
92
+ ]
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,312 @@
1
+ require 'fastlane/action'
2
+ require 'json'
3
+ require 'yaml'
4
+ require_relative '../helper/config'
5
+ require_relative '../helper/runner'
6
+
7
+ module Fastlane
8
+ module Actions
9
+ class SauceConfigAction < Action
10
+ @messages = YAML.load_file("#{__dir__}/../strings/messages.yml")
11
+
12
+ def self.run(params)
13
+ if params[:platform].eql?('android')
14
+ UI.user_error!("❌ For android platform you must specify devices or emulators under test in order to execute tests") if params[:emulators].nil? && params[:devices].nil?
15
+ else
16
+ if params[:emulators]
17
+ UI.user_error!("❌ Sauce Labs platform does not currently support virtual device execution for ios apps")
18
+ end
19
+ UI.user_error!("❌ For ios platform you must specify devices under test in order to execute tests") if params[:devices].nil?
20
+ end
21
+
22
+ Fastlane::Saucectl::ConfigGenerator.new(params).create
23
+ end
24
+
25
+ def self.description
26
+ "Create SauceLabs configuration file for test execution based on given parameters"
27
+ end
28
+
29
+ def self.details
30
+ "Create SauceLabs configuration file for test execution based on given parameters"
31
+ end
32
+
33
+ def self.available_options
34
+ [
35
+ FastlaneCore::ConfigItem.new(key: :platform,
36
+ description: "application under test platform (ios or android)",
37
+ optional: false,
38
+ type: String,
39
+ verify_block: proc do |value|
40
+ UI.user_error!(@messages['platform_error']) if value.to_s.empty?
41
+ end),
42
+ FastlaneCore::ConfigItem.new(key: :kind,
43
+ description: "Specifies which framework is associated with the automation tests configured in this specification (xcuitest & espresso)",
44
+ optional: false,
45
+ type: String,
46
+ verify_block: proc do |value|
47
+ UI.user_error!(@messages['platform_error']) if value.to_s.empty?
48
+ end),
49
+ FastlaneCore::ConfigItem.new(key: :app,
50
+ description: "The path to the app",
51
+ optional: false,
52
+ type: String,
53
+ verify_block: proc do |value|
54
+ UI.user_error!(@messages['app_name_error']) unless value && !value.empty?
55
+ end),
56
+ FastlaneCore::ConfigItem.new(key: :test_app,
57
+ description: "The path to the testing app",
58
+ optional: false,
59
+ is_string: true,
60
+ verify_block: proc do |value|
61
+ UI.user_error!(@messages['test_runner_app_error']) unless value && !value.empty?
62
+ end),
63
+ FastlaneCore::ConfigItem.new(key: :region,
64
+ description: "Data Center region (us or eu), set using: region: 'eu'",
65
+ optional: false,
66
+ type: String,
67
+ verify_block: proc do |value|
68
+ UI.user_error!(@messages['region_error'].gsub!('$region', value)) unless @messages['supported_regions'].include?(value)
69
+ end),
70
+ FastlaneCore::ConfigItem.new(key: :retries,
71
+ description: "Sets the number of times to retry a failed suite",
72
+ optional: true,
73
+ type: Integer,
74
+ default_value: 0),
75
+ FastlaneCore::ConfigItem.new(key: :test_distribution,
76
+ description: "Test distribution method",
77
+ optional: true,
78
+ type: String,
79
+ default_value: 'class'),
80
+ FastlaneCore::ConfigItem.new(key: :test_class,
81
+ description: "Array of tests to execute",
82
+ optional: true,
83
+ type: Array),
84
+ FastlaneCore::ConfigItem.new(key: :emulators,
85
+ description: "The parent property that defines details for running this suite on virtual devices using an emulator",
86
+ optional: true,
87
+ type: Array,
88
+ verify_block: proc do |emulators|
89
+ emulators.each do |emulator|
90
+ if emulator.class != Hash
91
+ UI.user_error!("Each emulator must be represented by a Hash object, #{emulator.class} found")
92
+ end
93
+ verify_device_property(emulator, :name)
94
+ set_default_property(emulator, :orientation, 'portrait')
95
+ verify_device_property(emulator, :platform_versions)
96
+ end
97
+ end),
98
+ FastlaneCore::ConfigItem.new(key: :devices,
99
+ description: "The parent property that defines details for running this suite on real devices",
100
+ optional: true,
101
+ type: Array,
102
+ verify_block: proc do |devices|
103
+ devices.each do |device|
104
+ if device.class != Hash
105
+ UI.user_error!("Each device must be represented by a Hash object, #{device.class} found")
106
+ end
107
+ verify_optional_device_props(device)
108
+ set_default_property(device, :orientation, 'portrait')
109
+ set_default_property(device, :device_type, 'phone')
110
+ set_default_property(device, :private, true)
111
+ set_default_property(device, :carrier_connectivity, false)
112
+ end
113
+ end),
114
+ FastlaneCore::ConfigItem.new(key: :name,
115
+ description: "The name of the device or emulator",
116
+ optional: true,
117
+ type: String),
118
+ FastlaneCore::ConfigItem.new(key: :id,
119
+ description: "The id of the device",
120
+ optional: true,
121
+ type: String),
122
+ FastlaneCore::ConfigItem.new(key: :platform_versions,
123
+ description: "Platform versions of the virtual device you wish to test your application on: Virtual Device only",
124
+ optional: true,
125
+ type: Array),
126
+ FastlaneCore::ConfigItem.new(key: :platform_version,
127
+ description: "Platform version of the real device you wish to test your application on: Real device only",
128
+ optional: true,
129
+ type: String),
130
+ FastlaneCore::ConfigItem.new(key: :orientation,
131
+ description: "The orientation of the device. Default: portrait",
132
+ optional: true,
133
+ type: String,
134
+ default_value: 'portrait'),
135
+ FastlaneCore::ConfigItem.new(key: :device_type,
136
+ description: "Request that the matching device is a specific type of device. Valid values are: ANY TABLET PHONE any tablet phone",
137
+ optional: true,
138
+ type: String,
139
+ default_value: 'phone'),
140
+ FastlaneCore::ConfigItem.new(key: :private,
141
+ description: "Request that the matching device is from your organization's private pool",
142
+ optional: true,
143
+ is_string: false),
144
+ FastlaneCore::ConfigItem.new(key: :carrier_connectivity,
145
+ description: "Request that the matching device is also connected to a cellular network",
146
+ optional: true,
147
+ is_string: false),
148
+ FastlaneCore::ConfigItem.new(key: :test_target,
149
+ description: "Name of the Xcode test target name",
150
+ optional: true,
151
+ type: String),
152
+ FastlaneCore::ConfigItem.new(key: :test_plan,
153
+ description: "Name of the Xcode test plan",
154
+ optional: true,
155
+ type: String),
156
+ FastlaneCore::ConfigItem.new(key: :path_to_tests,
157
+ description: "Path to your espresso tests",
158
+ optional: true,
159
+ type: String,
160
+ default_value: "#{Dir.pwd}/app/src/androidTest"),
161
+ FastlaneCore::ConfigItem.new(key: :clear_data,
162
+ description: "Clear package data from device (android only)",
163
+ optional: true,
164
+ is_string: false,
165
+ default_value: true),
166
+ FastlaneCore::ConfigItem.new(key: :use_test_orchestrator,
167
+ description: "User Android test orchestrator (android only)",
168
+ optional: true,
169
+ is_string: false,
170
+ default_value: true),
171
+ FastlaneCore::ConfigItem.new(key: :max_concurrency_size,
172
+ description: "Sets the maximum number of suites to execute at the same time. If the test defines more suites than the max, excess suites are queued and run in order as each suite completes",
173
+ optional: true,
174
+ type: Integer,
175
+ default_value: 1)
176
+ ]
177
+ end
178
+
179
+ def self.verify_device_property(device, property)
180
+ UI.user_error!("Each device must have #{property} property") unless device.key?(property)
181
+ end
182
+
183
+ def self.verify_optional_device_props(device)
184
+ unless device.key?(:name) || device.key?(:id)
185
+ UI.user_error!("Real devices must have a device name or device id")
186
+ end
187
+ end
188
+
189
+ private_class_method :verify_device_property
190
+
191
+ def self.set_default_property(device, property, default)
192
+ unless device.key?(property)
193
+ device[property] = default
194
+ end
195
+ end
196
+
197
+ private_class_method :set_default_property
198
+
199
+ def self.authors
200
+ ["Ian Hamilton"]
201
+ end
202
+
203
+ def self.category
204
+ :testing
205
+ end
206
+
207
+ def self.is_supported?(platform)
208
+ [:ios, :android].include?(platform)
209
+ end
210
+
211
+ def self.example_code
212
+ [
213
+ "sauce_config({platform: 'android',
214
+ kind: 'espresso',
215
+ app: 'path/to/myTestApp.apk',
216
+ test_app: 'path/to/myTestRunner.apk',
217
+ path_to_tests: 'path/to/app/src/androidTest',
218
+ region: 'eu',
219
+ emulators: [ {name: 'Android GoogleApi Emulator', platform_versions: %w[10.0 11.0], orientation: 'portrait'}]
220
+ })",
221
+ "sauce_config({platform: 'android',
222
+ kind: 'espresso',
223
+ app: 'path/to/myTestApp.apk',
224
+ test_app: 'path/to/myTestRunner.apk',
225
+ path_to_tests: 'path/to/app/src/androidTest',
226
+ region: 'eu',
227
+ test_distribution: 'testCase',
228
+ devices: [ {name: 'RDC One', orientation: 'portrait', platform_version: '11.0'}]
229
+ })",
230
+ "sauce_config({platform: 'android',
231
+ kind: 'espresso',
232
+ app: 'path/to/myTestApp.apk',
233
+ test_app: 'path/to/myTestRunner.apk',
234
+ path_to_tests: 'path/to/app/src/androidTest',
235
+ region: 'eu',
236
+ test_distribution: 'shard',
237
+ devices: [ {name: 'RDC One', orientation: 'portrait', platform_version: '11.0'}]
238
+ })",
239
+ "sauce_config({platform: 'ios',
240
+ kind: 'xcuitest',
241
+ app: 'path/to/MyTestApp.ipa',
242
+ test_app: 'path/to/MyTestAppRunner.ipa',
243
+ region: 'eu',
244
+ devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
245
+ test_target: 'MyDemoAppUITests'
246
+ })",
247
+ "sauce_config({platform: 'ios',
248
+ kind: 'xcuitest',
249
+ app: 'path/to/MyTestApp.ipa',
250
+ test_app: 'path/to/MyTestAppRunner.ipa',
251
+ region: 'eu',
252
+ devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
253
+ test_target: 'MyDemoAppUITests',
254
+ test_distribution: 'shard',
255
+ })",
256
+ " sauce_config({platform: 'ios',
257
+ kind: 'xcuitest',
258
+ app: 'path/to/MyTestApp.ipa',
259
+ test_app: 'path/to/MyTestAppRunner.ipa',
260
+ region: 'eu',
261
+ devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
262
+ test_target: 'MyDemoAppUITests',
263
+ test_distribution: 'testCase'
264
+ })",
265
+ "sauce_config({platform: 'ios',
266
+ kind: 'xcuitest',
267
+ app: 'path/to/MyTestApp.ipa',
268
+ test_app: 'path/to/MyTestAppRunner.ipa',
269
+ region: 'eu',
270
+ devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
271
+ test_plan: 'EnabledUITests',
272
+ test_distribution: 'shard'
273
+ })",
274
+ "sauce_config({platform: 'ios',
275
+ kind: 'xcuitest',
276
+ app: 'path/to/MyTestApp.ipa',
277
+ test_app: 'path/to/MyTestAppRunner.ipa',
278
+ region: 'eu',
279
+ devices: [ {name: 'iPhone RDC One'}, {id: 'iphone_rdc_two'} ],
280
+ test_plan: 'UITests'
281
+ })",
282
+ "sauce_config({platform: 'android',
283
+ kind: 'espresso',
284
+ app: 'path/to/myTestApp.apk',
285
+ test_app: 'path/to/myTestRunner.apk',
286
+ path_to_tests: 'path/to/app/src/androidTest',
287
+ region: 'eu',
288
+ devices: [ {name: 'iPhone RDC One'}],
289
+ test_class: ['com.some.package.testing.SomeClassOne', 'com.some.package.testing.SomeClassTwo', 'com.some.package.testing.SomeClassThree', 'com.some.package.testing.SomeClassFour']
290
+ })",
291
+ "sauce_config({platform: 'android',
292
+ kind: 'espresso',
293
+ app: 'path/to/myTestApp.apk',
294
+ test_app: 'path/to/myTestRunner.apk',
295
+ path_to_tests: 'path/to/app/src/androidTest',
296
+ region: 'eu',
297
+ emulators: [ {name: 'iPhone RDC One', platform_versions: ['11.0']}, {name: 'iPhone RDC Two', platform_versions: ['11.0']}],
298
+ test_class: ['com.some.package.testing.SomeClassOne', 'com.some.package.testing.SomeClassTwo', 'com.some.package.testing.SomeClassThree', 'com.some.package.testing.SomeClassFour']
299
+ })",
300
+ "sauce_config({platform: 'ios',
301
+ kind: 'xcuitest',
302
+ app: 'path/to/myTestApp.app',
303
+ test_app: 'path/to/myTestRunner.app',
304
+ region: 'eu',
305
+ devices: [ {name: 'iPhone RDC One'}],
306
+ test_class: ['MyDemoAppUITests.SomeClassOne', 'MyDemoAppUITests.SomeClassTwo', 'MyDemoAppUITests.SomeClassThree', 'MyDemoAppUITests.SomeClassFour']
307
+ })"
308
+ ]
309
+ end
310
+ end
311
+ end
312
+ end