xcmonkey 0.3.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/issue_template/bug_report.md +26 -0
- data/.github/issue_template/feature_request.md +26 -0
- data/.github/pull_request_template.md +5 -0
- data/.gitignore +3 -0
- data/README.md +28 -1
- data/bin/xcmonkey +21 -4
- data/lib/xcmonkey/describer.rb +1 -2
- data/lib/xcmonkey/driver.rb +55 -4
- data/lib/xcmonkey/repeater.rb +39 -0
- data/lib/xcmonkey/version.rb +1 -1
- data/lib/xcmonkey.rb +6 -9
- data/spec/driver_spec.rb +41 -4
- data/spec/repeater_spec.rb +52 -0
- data/spec/xcmonkey_spec.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be5b38b4ec7977038ba4f739a4516a376bc79652447a0cc52c10465ea85657d2
|
4
|
+
data.tar.gz: 97d3eefd65f8a438bfb2ed2919bdaa6bf42e0324235d10a7f7df5b0ede316d88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94b8daa5da4df0d18b1644bf9d110978c070ba032e661d4bf1079f7fad90a2ed6df553bc8685a7267d7f819159ac615474c88c4ebdd6e00627b74339cc2f9e0e
|
7
|
+
data.tar.gz: 66fe245043c8f4887a3849c7e60bc6b8ee81cecfb56781f409e09a6651511d009acd2a2284e3534d67ef59abffb5432b3d85ff9495a951a4fc26dbd44bff38fb
|
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Create a report to help us improve
|
4
|
+
title: ''
|
5
|
+
labels: ''
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
## What did you do?
|
11
|
+
|
12
|
+
|
13
|
+
## What did you expect to happen?
|
14
|
+
|
15
|
+
|
16
|
+
## What happened instead?
|
17
|
+
|
18
|
+
|
19
|
+
## Environment
|
20
|
+
|
21
|
+
- `xcmonkey` version:
|
22
|
+
- `idb` version:
|
23
|
+
- `xcode` version:
|
24
|
+
- `macOS` version:
|
25
|
+
|
26
|
+
## Additional context
|
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
name: Feature Request
|
3
|
+
about: Got any ideas about new features? Let us know!
|
4
|
+
title: ''
|
5
|
+
labels: ''
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
## What are you trying to achieve?
|
11
|
+
|
12
|
+
|
13
|
+
## If possible, how can you achieve this currently?
|
14
|
+
|
15
|
+
|
16
|
+
## What would be the better way?
|
17
|
+
|
18
|
+
|
19
|
+
## Environment
|
20
|
+
|
21
|
+
- `xcmonkey` version:
|
22
|
+
- `idb` version:
|
23
|
+
- `xcode` version:
|
24
|
+
- `macOS` version:
|
25
|
+
|
26
|
+
## Additional context
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
|
12
12
|
## Description
|
13
13
|
|
14
|
-
*xcmonkey* is a tool for doing
|
14
|
+
*xcmonkey* is a tool for doing stress testing of iOS apps. It's inspired by and has similar goals to [*monkey*](https://developer.android.com/studio/test/monkey) on Android.
|
15
15
|
|
16
16
|
Under the hood, *xcmonkey* uses [iOS Development Bridge](https://fbidb.io/) as a driver, that's why it's pretty smart and can do a lot of things, such as taps, swipes and presses. All that comes «pseudo-random» because it has access to the screen hierarchy, and so can either do actions blindly (like tapping on random points) or precisely (like tapping on the existing elements).
|
17
17
|
|
@@ -63,6 +63,33 @@ $ xcmonkey test --udid "413EA256-CFFB-4312-94A6-12592BEE4CBA" --bundle-id "com.a
|
|
63
63
|
}
|
64
64
|
```
|
65
65
|
|
66
|
+
### To repeat the stress test from generated session
|
67
|
+
|
68
|
+
```bash
|
69
|
+
$ xcmonkey repeat --session-path "./xcmonkey-session.json"
|
70
|
+
12:48:13.333: Device info: iPhone 14 Pro | 413EA256-CFFB-4312-94A6-12592BEE4CBA | Booted | simulator | iOS 16.2 | x86_64 | /tmp/idb/413EA256-CFFB-4312-94A6-12592BEE4CBA_companion.sock
|
71
|
+
|
72
|
+
12:48:16.542: App info: com.apple.Maps | Maps | system | arm64, x86_64 | Running | Not Debuggable | pid=73416
|
73
|
+
|
74
|
+
12:48:20.195: Tap: {
|
75
|
+
"x": 53,
|
76
|
+
"y": 749
|
77
|
+
}
|
78
|
+
|
79
|
+
12:48:20.404: Swipe (0.5s): {
|
80
|
+
"x": 196,
|
81
|
+
"y": 426
|
82
|
+
} => {
|
83
|
+
"x": 143,
|
84
|
+
"y": 447
|
85
|
+
}
|
86
|
+
|
87
|
+
12:48:21.155: Press (1.2s): {
|
88
|
+
"x": 143,
|
89
|
+
"y": 323
|
90
|
+
}
|
91
|
+
```
|
92
|
+
|
66
93
|
### To describe the required point
|
67
94
|
|
68
95
|
```bash
|
data/bin/xcmonkey
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'commander/import'
|
4
4
|
require_relative '../lib/xcmonkey'
|
5
5
|
require_relative '../lib/xcmonkey/describer'
|
6
|
+
require_relative '../lib/xcmonkey/repeater'
|
6
7
|
require_relative '../lib/xcmonkey/logger'
|
7
8
|
require_relative '../lib/xcmonkey/driver'
|
8
9
|
require_relative '../lib/xcmonkey/version'
|
@@ -18,25 +19,41 @@ module Xcmonkey
|
|
18
19
|
c.option('-b', '--bundle-id STRING', String, 'Set target bundle identifier')
|
19
20
|
c.option('-d', '--duration SECONDS', Integer, 'Test duration in seconds. Defaults to `60`')
|
20
21
|
c.option('-k', '--enable-simulator-keyboard', 'Should simulator keyboard be enabled? Defaults to `true`')
|
21
|
-
c.
|
22
|
-
|
22
|
+
c.option('-s', '--session-path STRING', String, 'Path where monkey testing session should be saved. Defaults to current directory')
|
23
|
+
c.action do |_, options|
|
24
|
+
options.default(
|
25
|
+
duration: 60,
|
26
|
+
session_path: Dir.pwd,
|
27
|
+
enable_simulator_keyboard: true
|
28
|
+
)
|
23
29
|
params = {
|
24
30
|
udid: options.udid,
|
25
31
|
bundle_id: options.bundle_id,
|
26
32
|
duration: options.duration,
|
27
|
-
|
33
|
+
session_path: options.session_path,
|
34
|
+
enable_simulator_keyboard: options.enable_simulator_keyboard
|
28
35
|
}
|
29
36
|
Xcmonkey.new(params).run
|
30
37
|
end
|
31
38
|
end
|
32
39
|
|
40
|
+
command :repeat do |c|
|
41
|
+
c.syntax = 'xcmonkey repeat [options]'
|
42
|
+
c.description = 'Repeats given session'
|
43
|
+
c.option('-s', '--session-path STRING', String, 'Path to monkey testing session')
|
44
|
+
c.action do |_, options|
|
45
|
+
params = { session_path: options.session_path }
|
46
|
+
Repeater.new(params).run
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
33
50
|
command :describe do |c|
|
34
51
|
c.syntax = 'xcmonkey describe [options]'
|
35
52
|
c.description = 'Describes given point'
|
36
53
|
c.option('-u', '--udid STRING', String, 'Set device UDID')
|
37
54
|
c.option('-x', '--x STRING', 'Point `x` coordinate')
|
38
55
|
c.option('-y', '--y STRING', 'Point `y` coordinate')
|
39
|
-
c.action do |
|
56
|
+
c.action do |_, options|
|
40
57
|
params = {
|
41
58
|
udid: options.udid,
|
42
59
|
x: options.x,
|
data/lib/xcmonkey/describer.rb
CHANGED
data/lib/xcmonkey/driver.rb
CHANGED
@@ -1,18 +1,30 @@
|
|
1
1
|
class Driver
|
2
|
-
attr_accessor :udid, :bundle_id, :
|
2
|
+
attr_accessor :udid, :bundle_id, :enable_simulator_keyboard, :session_duration, :session_path, :session_actions
|
3
3
|
|
4
4
|
def initialize(params)
|
5
5
|
self.udid = params[:udid]
|
6
6
|
self.bundle_id = params[:bundle_id]
|
7
|
-
self.
|
7
|
+
self.session_duration = params[:duration]
|
8
|
+
self.session_path = params[:session_path]
|
8
9
|
self.enable_simulator_keyboard = params[:enable_simulator_keyboard]
|
10
|
+
self.session_actions = params[:session_actions]
|
11
|
+
@session = { params: params, actions: [] }
|
9
12
|
ensure_driver_installed
|
10
13
|
end
|
11
14
|
|
15
|
+
def monkey_test_precondition
|
16
|
+
ensure_device_exists
|
17
|
+
ensure_app_installed
|
18
|
+
terminate_app
|
19
|
+
open_home_screen(with_tracker: true)
|
20
|
+
launch_app
|
21
|
+
end
|
22
|
+
|
12
23
|
def monkey_test(gestures)
|
24
|
+
monkey_test_precondition
|
13
25
|
app_elements = describe_ui.shuffle
|
14
26
|
current_time = Time.now
|
15
|
-
while Time.now < current_time +
|
27
|
+
while Time.now < current_time + session_duration
|
16
28
|
el1_coordinates = central_coordinates(app_elements.first)
|
17
29
|
el2_coordinates = central_coordinates(app_elements.last)
|
18
30
|
case gestures.sample
|
@@ -40,7 +52,30 @@ class Driver
|
|
40
52
|
next
|
41
53
|
end
|
42
54
|
app_elements = describe_ui.shuffle
|
43
|
-
|
55
|
+
next unless app_elements.include?(@home_tracker)
|
56
|
+
|
57
|
+
save_session
|
58
|
+
Logger.error('App lost')
|
59
|
+
end
|
60
|
+
save_session
|
61
|
+
end
|
62
|
+
|
63
|
+
def repeat_monkey_test
|
64
|
+
monkey_test_precondition
|
65
|
+
session_actions.each do |action|
|
66
|
+
case action['type']
|
67
|
+
when 'tap'
|
68
|
+
tap(coordinates: { x: action['x'], y: action['y'] })
|
69
|
+
when 'press'
|
70
|
+
press(coordinates: { x: action['x'], y: action['y'] }, duration: action['duration'])
|
71
|
+
when 'swipe'
|
72
|
+
swipe(
|
73
|
+
start_coordinates: { x: action['x'], y: action['y'] },
|
74
|
+
end_coordinates: { x: action['endX'], y: action['endY'] },
|
75
|
+
duration: action['duration']
|
76
|
+
)
|
77
|
+
end
|
78
|
+
Logger.error('App lost') if describe_ui.shuffle.include?(@home_tracker)
|
44
79
|
end
|
45
80
|
end
|
46
81
|
|
@@ -113,11 +148,13 @@ class Driver
|
|
113
148
|
|
114
149
|
def tap(coordinates:)
|
115
150
|
Logger.info('Tap:', payload: JSON.pretty_generate(coordinates))
|
151
|
+
@session[:actions] << { type: :tap, x: coordinates[:x], y: coordinates[:y] } unless session_actions
|
116
152
|
`idb ui tap --udid #{udid} #{coordinates[:x]} #{coordinates[:y]}`
|
117
153
|
end
|
118
154
|
|
119
155
|
def press(coordinates:, duration:)
|
120
156
|
Logger.info("Press (#{duration}s):", payload: JSON.pretty_generate(coordinates))
|
157
|
+
@session[:actions] << { type: :press, x: coordinates[:x], y: coordinates[:y], duration: duration } unless session_actions
|
121
158
|
`idb ui tap --udid #{udid} --duration #{duration} #{coordinates[:x]} #{coordinates[:y]}`
|
122
159
|
end
|
123
160
|
|
@@ -126,6 +163,16 @@ class Driver
|
|
126
163
|
"Swipe (#{duration}s):",
|
127
164
|
payload: "#{JSON.pretty_generate(start_coordinates)} => #{JSON.pretty_generate(end_coordinates)}"
|
128
165
|
)
|
166
|
+
unless session_actions
|
167
|
+
@session[:actions] << {
|
168
|
+
type: :swipe,
|
169
|
+
x: start_coordinates[:x],
|
170
|
+
y: start_coordinates[:y],
|
171
|
+
endX: end_coordinates[:x],
|
172
|
+
endY: end_coordinates[:y],
|
173
|
+
duration: duration
|
174
|
+
}
|
175
|
+
end
|
129
176
|
coordinates = "#{start_coordinates[:x]} #{start_coordinates[:y]} #{end_coordinates[:x]} #{end_coordinates[:y]}"
|
130
177
|
`idb ui swipe --udid #{udid} --duration #{duration} #{coordinates}`
|
131
178
|
end
|
@@ -168,6 +215,10 @@ class Driver
|
|
168
215
|
rand(0.5..1.5).ceil(1)
|
169
216
|
end
|
170
217
|
|
218
|
+
def save_session
|
219
|
+
File.write("#{session_path}/xcmonkey-session.json", JSON.pretty_generate(@session))
|
220
|
+
end
|
221
|
+
|
171
222
|
private
|
172
223
|
|
173
224
|
def ensure_driver_installed
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Repeater
|
2
|
+
attr_accessor :udid, :bundle_id, :enable_simulator_keyboard, :actions
|
3
|
+
|
4
|
+
def initialize(params)
|
5
|
+
validate_session(params[:session_path])
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
params = {
|
10
|
+
udid: udid,
|
11
|
+
bundle_id: bundle_id,
|
12
|
+
enable_simulator_keyboard: enable_simulator_keyboard,
|
13
|
+
session_actions: actions
|
14
|
+
}
|
15
|
+
Driver.new(params).repeat_monkey_test
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate_session(session_path)
|
19
|
+
Logger.error("Provided session can't be found: #{session_path}") unless File.exist?(session_path)
|
20
|
+
|
21
|
+
session = JSON.parse(File.read(session_path))
|
22
|
+
|
23
|
+
if session['params'].nil?
|
24
|
+
Logger.error('Provided session is not valid: `params` should not be `nil`')
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
self.actions = session['actions']
|
29
|
+
Logger.error('Provided session is not valid: `actions` should not be `nil` or `empty`') if actions.nil? || actions.empty?
|
30
|
+
|
31
|
+
self.udid = session['params']['udid']
|
32
|
+
Logger.error('Provided session is not valid: `udid` should not be `nil`') if udid.nil?
|
33
|
+
|
34
|
+
self.bundle_id = session['params']['bundle_id']
|
35
|
+
Logger.error('Provided session is not valid: `bundle_id` should not be `nil`') if bundle_id.nil?
|
36
|
+
|
37
|
+
self.enable_simulator_keyboard = session['params']['enable_simulator_keyboard']
|
38
|
+
end
|
39
|
+
end
|
data/lib/xcmonkey/version.rb
CHANGED
data/lib/xcmonkey.rb
CHANGED
@@ -1,28 +1,21 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'colorize'
|
3
3
|
require_relative 'xcmonkey/describer'
|
4
|
+
require_relative 'xcmonkey/repeater'
|
4
5
|
require_relative 'xcmonkey/version'
|
5
6
|
require_relative 'xcmonkey/logger'
|
6
7
|
require_relative 'xcmonkey/driver'
|
7
8
|
|
8
9
|
module Xcmonkey
|
9
10
|
class Xcmonkey
|
10
|
-
attr_accessor :
|
11
|
+
attr_accessor :driver
|
11
12
|
|
12
13
|
def initialize(params)
|
13
14
|
ensure_required_params(params)
|
14
|
-
self.udid = params[:udid]
|
15
|
-
self.bundle_id = params[:bundle_id]
|
16
|
-
self.duration = params[:duration]
|
17
15
|
self.driver = Driver.new(params)
|
18
16
|
end
|
19
17
|
|
20
18
|
def run
|
21
|
-
driver.ensure_device_exists
|
22
|
-
driver.ensure_app_installed
|
23
|
-
driver.terminate_app
|
24
|
-
driver.open_home_screen(with_tracker: true)
|
25
|
-
driver.launch_app
|
26
19
|
driver.monkey_test(gestures)
|
27
20
|
end
|
28
21
|
|
@@ -35,7 +28,11 @@ module Xcmonkey
|
|
35
28
|
|
36
29
|
def ensure_required_params(params)
|
37
30
|
Logger.error('UDID should be provided') if params[:udid].nil?
|
31
|
+
|
38
32
|
Logger.error('Bundle identifier should be provided') if params[:bundle_id].nil?
|
33
|
+
|
34
|
+
Logger.error('Session path should be a directory') if params[:session_path].nil? || !File.directory?(params[:session_path])
|
35
|
+
|
39
36
|
if params[:duration].nil? || !params[:duration].kind_of?(Integer) || !params[:duration].positive?
|
40
37
|
Logger.error('Duration must be Integer and not less than 1 second')
|
41
38
|
end
|
data/spec/driver_spec.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
describe Driver do
|
2
2
|
let(:udid) { `xcrun simctl list | grep " iPhone 14 Pro Max"`.split("\n")[0].split('(')[1].split(')')[0] }
|
3
3
|
let(:bundle_id) { 'com.apple.Maps' }
|
4
|
-
let(:driver) { described_class.new(udid: udid, bundle_id: bundle_id) }
|
4
|
+
let(:driver) { described_class.new(udid: udid, bundle_id: bundle_id, session_path: Dir.pwd) }
|
5
|
+
let(:driver_with_session) { described_class.new(udid: udid, bundle_id: bundle_id, session_actions: [{ type: 'tap', x: 0, y: 0 }]) }
|
5
6
|
|
6
7
|
it 'verifies that sumulator was booted' do
|
7
8
|
error_message = "Failed to boot #{udid}"
|
@@ -150,28 +151,64 @@ describe Driver do
|
|
150
151
|
expect { driver.launch_app }.not_to raise_error
|
151
152
|
end
|
152
153
|
|
153
|
-
it 'verifies tap' do
|
154
|
+
it 'verifies tap in new session' do
|
154
155
|
driver.boot_simulator
|
155
156
|
coordinates = { x: 1, y: 1 }
|
156
157
|
expect(Logger).to receive(:info).with('Tap:', payload: JSON.pretty_generate(coordinates))
|
157
158
|
driver.tap(coordinates: coordinates)
|
159
|
+
expect(driver.instance_variable_get(:@session)[:actions]).not_to be_empty
|
158
160
|
end
|
159
161
|
|
160
|
-
it 'verifies
|
162
|
+
it 'verifies tap in old session' do
|
163
|
+
driver_with_session.boot_simulator
|
164
|
+
coordinates = { x: 1, y: 1 }
|
165
|
+
expect(Logger).to receive(:info).with('Tap:', payload: JSON.pretty_generate(coordinates))
|
166
|
+
driver_with_session.tap(coordinates: coordinates)
|
167
|
+
expect(driver_with_session.instance_variable_get(:@session)[:actions]).to be_empty
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'verifies press in new session' do
|
161
171
|
driver.boot_simulator
|
162
172
|
duration = 0.5
|
163
173
|
coordinates = { x: 1, y: 1 }
|
164
174
|
expect(Logger).to receive(:info).with("Press (#{duration}s):", payload: JSON.pretty_generate(coordinates))
|
165
175
|
driver.press(coordinates: coordinates, duration: duration)
|
176
|
+
expect(driver.instance_variable_get(:@session)[:actions]).not_to be_empty
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'verifies press in old session' do
|
180
|
+
driver_with_session.boot_simulator
|
181
|
+
duration = 0.5
|
182
|
+
coordinates = { x: 1, y: 1 }
|
183
|
+
expect(Logger).to receive(:info).with("Press (#{duration}s):", payload: JSON.pretty_generate(coordinates))
|
184
|
+
driver_with_session.press(coordinates: coordinates, duration: duration)
|
185
|
+
expect(driver_with_session.instance_variable_get(:@session)[:actions]).to be_empty
|
166
186
|
end
|
167
187
|
|
168
|
-
it 'verifies swipe' do
|
188
|
+
it 'verifies swipe in new session' do
|
169
189
|
driver.boot_simulator
|
170
190
|
duration = 0.5
|
171
191
|
start_coordinates = { x: 1, y: 1 }
|
172
192
|
end_coordinates = { x: 2, y: 2 }
|
173
193
|
expect(Logger).to receive(:info).with("Swipe (#{duration}s):", payload: "#{JSON.pretty_generate(start_coordinates)} => #{JSON.pretty_generate(end_coordinates)}")
|
174
194
|
driver.swipe(start_coordinates: start_coordinates, end_coordinates: end_coordinates, duration: duration)
|
195
|
+
expect(driver.instance_variable_get(:@session)[:actions]).not_to be_empty
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'verifies swipe in old session' do
|
199
|
+
driver_with_session.boot_simulator
|
200
|
+
duration = 0.5
|
201
|
+
start_coordinates = { x: 1, y: 1 }
|
202
|
+
end_coordinates = { x: 2, y: 2 }
|
203
|
+
expect(Logger).to receive(:info).with("Swipe (#{duration}s):", payload: "#{JSON.pretty_generate(start_coordinates)} => #{JSON.pretty_generate(end_coordinates)}")
|
204
|
+
driver_with_session.swipe(start_coordinates: start_coordinates, end_coordinates: end_coordinates, duration: duration)
|
205
|
+
expect(driver_with_session.instance_variable_get(:@session)[:actions]).to be_empty
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'verifies that session can be saved' do
|
209
|
+
expect(File).to receive(:write)
|
210
|
+
driver.instance_variable_set(:@session, { params: {}, actions: [] })
|
211
|
+
driver.save_session
|
175
212
|
end
|
176
213
|
|
177
214
|
it 'verifies that simulator was not booted' do
|
@@ -0,0 +1,52 @@
|
|
1
|
+
describe Repeater do
|
2
|
+
let(:session_path) { 'test/path/session.json' }
|
3
|
+
let(:session_file_content_full) { '{ "params": {"udid": "0", "bundle_id": "0", "enable_simulator_keyboard": true}, "actions": [{ "type": "tap", "x": 0, "y": 0 }] }' }
|
4
|
+
let(:session_file_content_without_params) { '{ "actions": [{ "type": "tap", "x": 0, "y": 0 }] }' }
|
5
|
+
let(:session_file_content_with_empty_actions) { '{ "params": {"udid": "0", "bundle_id": "0", "enable_simulator_keyboard": true}, "actions": [] }' }
|
6
|
+
let(:session_file_content_without_actions) { '{ "params": {"udid": "0", "bundle_id": "0", "enable_simulator_keyboard": true} }' }
|
7
|
+
let(:session_file_content_without_bundle_id) { '{ "params": {"udid": "0", "enable_simulator_keyboard": true}, "actions": [{ "type": "tap", "x": 0, "y": 0 }] }' }
|
8
|
+
let(:session_file_content_without_udid) { '{ "params": {"bundle_id": "0", "enable_simulator_keyboard": true}, "actions": [{ "type": "tap", "x": 0, "y": 0 }] }' }
|
9
|
+
|
10
|
+
# TESTME
|
11
|
+
it 'verifies that session cannot be validated without params' do
|
12
|
+
allow(File).to receive(:exist?).and_return(true)
|
13
|
+
allow(File).to receive(:read).and_return(session_file_content_without_params)
|
14
|
+
expect(Logger).to receive(:error).with('Provided session is not valid: `params` should not be `nil`')
|
15
|
+
described_class.new(session_path: session_path)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'verifies that session cannot be validated without actions' do
|
19
|
+
allow(File).to receive(:exist?).and_return(true)
|
20
|
+
allow(File).to receive(:read).and_return(session_file_content_without_actions)
|
21
|
+
expect(Logger).to receive(:error).with('Provided session is not valid: `actions` should not be `nil` or `empty`')
|
22
|
+
described_class.new(session_path: session_path)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'verifies that session cannot be validated with empty actions' do
|
26
|
+
allow(File).to receive(:exist?).and_return(true)
|
27
|
+
allow(File).to receive(:read).and_return(session_file_content_with_empty_actions)
|
28
|
+
expect(Logger).to receive(:error).with('Provided session is not valid: `actions` should not be `nil` or `empty`')
|
29
|
+
described_class.new(session_path: session_path)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'verifies that session cannot be validated without bundle id' do
|
33
|
+
allow(File).to receive(:exist?).and_return(true)
|
34
|
+
allow(File).to receive(:read).and_return(session_file_content_without_bundle_id)
|
35
|
+
expect(Logger).to receive(:error).with('Provided session is not valid: `bundle_id` should not be `nil`')
|
36
|
+
described_class.new(session_path: session_path)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'verifies that session cannot be validated without udid' do
|
40
|
+
allow(File).to receive(:exist?).and_return(true)
|
41
|
+
allow(File).to receive(:read).and_return(session_file_content_without_udid)
|
42
|
+
expect(Logger).to receive(:error).with('Provided session is not valid: `udid` should not be `nil`')
|
43
|
+
described_class.new(session_path: session_path)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'verifies that session validation can pass' do
|
47
|
+
allow(File).to receive(:exist?).and_return(true)
|
48
|
+
allow(File).to receive(:read).and_return(session_file_content_full)
|
49
|
+
expect(Logger).not_to receive(:error)
|
50
|
+
described_class.new(session_path: session_path)
|
51
|
+
end
|
52
|
+
end
|
data/spec/xcmonkey_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
describe Xcmonkey do
|
2
2
|
describe Xcmonkey::Xcmonkey do
|
3
|
-
let(:params) { { udid: '123', bundle_id: 'example.com.app', duration: 10 } }
|
3
|
+
let(:params) { { udid: '123', bundle_id: 'example.com.app', duration: 10, session_path: Dir.pwd } }
|
4
4
|
let(:duration_error_msg) { 'Duration must be Integer and not less than 1 second' }
|
5
5
|
|
6
6
|
it 'verifies gestures' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xcmonkey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- alteral
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-01-
|
11
|
+
date: 2023-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -217,6 +217,8 @@ files:
|
|
217
217
|
- ".fasterer.yml"
|
218
218
|
- ".github/FUNDING.yml"
|
219
219
|
- ".github/dependabot.yml"
|
220
|
+
- ".github/issue_template/bug_report.md"
|
221
|
+
- ".github/issue_template/feature_request.md"
|
220
222
|
- ".github/pull_request_template.md"
|
221
223
|
- ".github/workflows/test.yml"
|
222
224
|
- ".gitignore"
|
@@ -236,12 +238,14 @@ files:
|
|
236
238
|
- lib/xcmonkey/describer.rb
|
237
239
|
- lib/xcmonkey/driver.rb
|
238
240
|
- lib/xcmonkey/logger.rb
|
241
|
+
- lib/xcmonkey/repeater.rb
|
239
242
|
- lib/xcmonkey/version.rb
|
240
243
|
- requirements.txt
|
241
244
|
- sonar-project.properties
|
242
245
|
- spec/describer_spec.rb
|
243
246
|
- spec/driver_spec.rb
|
244
247
|
- spec/logger_spec.rb
|
248
|
+
- spec/repeater_spec.rb
|
245
249
|
- spec/spec_helper.rb
|
246
250
|
- spec/xcmonkey_spec.rb
|
247
251
|
- xcmonkey.gemspec
|