xcmonkey 0.3.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48bd9b79b2370e4f20366973e689af344f6c75729b361658fbc5bb2c02c38253
4
- data.tar.gz: c207e8dbe7c820623f60a9c0b9e8ea8a7e5bce18bfe10f9d5c27e8928829889d
3
+ metadata.gz: be5b38b4ec7977038ba4f739a4516a376bc79652447a0cc52c10465ea85657d2
4
+ data.tar.gz: 97d3eefd65f8a438bfb2ed2919bdaa6bf42e0324235d10a7f7df5b0ede316d88
5
5
  SHA512:
6
- metadata.gz: 9c0f1f52ad5e8118799556e4e1ba3a49574c504cf2a840fe0369e06c6dbab260fd0a9c275ada9efb789a865759ac48f7d46f9348cde5b2cb53a44969b5189cf9
7
- data.tar.gz: 761ffee247c8646bc24dee5fd3f473414402033d3c9a773fe87623579aef93155ecbafc3d412111396945ae485d74b28d6916e5e287754a82b15fcfc792b0c47
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
@@ -1,9 +1,14 @@
1
1
  # Changes
2
2
 
3
3
  ## References
4
+
4
5
  - https://github.com/alteral/xcmonkey/issues/XXX
5
6
 
7
+ ## Description
8
+
9
+
6
10
  ## Risks
11
+
7
12
  - [ ] None
8
13
  - [ ] Low
9
14
  - [ ] High
data/.gitignore CHANGED
@@ -39,3 +39,6 @@ DerivedData
39
39
 
40
40
  # Sonar
41
41
  .scannerwork
42
+
43
+ # Cache
44
+ xcmonkey-session.json
data/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  ## Description
13
13
 
14
- *xcmonkey* is a tool for doing randomised UI testing of iOS apps. It's inspired by and has similar goals to [*monkey*](https://developer.android.com/studio/test/monkey) on Android.
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.action do |args, options|
22
- options.default(duration: 60, enable_simulator_keyboard: true)
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
- simulator_keyboard: options.enable_simulator_keyboard
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 |args, options|
56
+ c.action do |_, options|
40
57
  params = {
41
58
  udid: options.udid,
42
59
  x: options.x,
@@ -1,9 +1,8 @@
1
1
  class Describer
2
- attr_accessor :udid, :x, :y, :driver
2
+ attr_accessor :x, :y, :driver
3
3
 
4
4
  def initialize(params)
5
5
  ensure_required_params(params)
6
- self.udid = params[:udid]
7
6
  self.x = params[:x]
8
7
  self.y = params[:y]
9
8
  self.driver = Driver.new(params)
@@ -1,18 +1,30 @@
1
1
  class Driver
2
- attr_accessor :udid, :bundle_id, :duration, :enable_simulator_keyboard
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.duration = params[:duration]
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 + duration
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
- Logger.error('App lost') if app_elements.include?(@home_tracker)
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
@@ -1,4 +1,4 @@
1
1
  module Xcmonkey
2
- VERSION = '0.3.0'
2
+ VERSION = '1.0.0'
3
3
  GEM_NAME = 'xcmonkey'
4
4
  end
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 :udid, :bundle_id, :duration, :driver
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 press' do
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
@@ -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.3.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-08 00:00:00.000000000 Z
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