xcmonkey 1.2.0 → 1.3.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: c93c94403332c085a393877d88d354b2736788f6e52d118eb8b9faa70c91b1e5
4
- data.tar.gz: ee0f3bfcd014151b4821a6df50f601205581ebd480b5626e33588bda2928981a
3
+ metadata.gz: be0e0b66cbc58704452a6defce61d6bd9f7ba88f7489796f4b7cc6a4f4489a11
4
+ data.tar.gz: 8551a6fd090f89cf20c2cd2e81bc8edc4856b9eb5516a50227db772cb0f013eb
5
5
  SHA512:
6
- metadata.gz: 0ab88db343b0e83363130a9e9c8ed965acbf9d58f56d597b301ff12da4df9d4e79b08c3b2284b870a65c9bfc3d05a8ba9df0d19409631620a28836c9d5785814
7
- data.tar.gz: fe46af5c215273be9210f3c880617457a12c6063e0bd1901d6abbd10750f10935b77a4797ff374926c3f1cac6b1ef79032f210fb705e05917146e4c64cede97c
6
+ metadata.gz: 5f3e1fe8bb0bccfd056c9f7087c32c2cd06adee0d0dca6a7b7ba6b8e038130e8d0f991c1e3bcb8d4b7c6d1c9ad63a5ae1fa718e979baaa8ff8f41ba98ae03b56
7
+ data.tar.gz: 1aabd404928c4cbc3e9d7a3fbe0c9f88ca155c25f745eb7e708cca7330a340740908343af231bc9fd9e5759d380f31816a920a53c40a6be6dbfa1916b50363db
data/.github/stale.yml ADDED
@@ -0,0 +1,18 @@
1
+ # Number of days of inactivity before an issue becomes stale
2
+ daysUntilStale: 14
3
+ # Number of days of inactivity before a stale issue is closed
4
+ daysUntilClose: 7
5
+ # Issues with these labels will never be considered stale
6
+ exemptLabels:
7
+ - important
8
+ # Label to use when marking an issue as stale
9
+ staleLabel: stale
10
+ # Comment to post when marking an issue as stale. Set to `false` to disable
11
+ markComment: >
12
+ This issue has been automatically marked as stale because it has not had
13
+ recent activity. It will be closed if no further activity occurs. Thank you
14
+ for your contributions.
15
+ # Comment to post when closing a stale issue. Set to `false` to disable
16
+ closeComment: >
17
+ This issue has been automatically closed due to inactivity.
18
+ Please open a new issue if it's still valid.
data/CHANGELOG.md ADDED
@@ -0,0 +1,42 @@
1
+ # xcmonkey changelog
2
+
3
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
4
+
5
+ ## [1.3.0](https://github.com/alteral/xcmonkey/releases/tag/1.3.0)
6
+
7
+ _January 29, 2023_
8
+
9
+ ### 🔄 Changed
10
+
11
+ - `duration` option is renamed to `event-count`
12
+
13
+ ### ✅ Added
14
+
15
+ - New test options that allow to
16
+ - specify gestures to exclude from the test
17
+ - set up throttle between events
18
+ - ignore app crashes
19
+
20
+ ## [1.2.0](https://github.com/alteral/xcmonkey/releases/tag/1.2.0)
21
+
22
+ _January 23, 2023_
23
+
24
+ ### ✅ Added
25
+
26
+ - Force keep xcmonkey in the target app
27
+
28
+ ## [1.1.0](https://github.com/alteral/xcmonkey/releases/tag/1.1.0)
29
+
30
+ _January 20, 2023_
31
+
32
+ ### ✅ Added
33
+
34
+ - Support [fastlane](https://github.com/fastlane/fastlane) integration
35
+
36
+ ## [1.0.0](https://github.com/alteral/xcmonkey/releases/tag/1.0.0)
37
+
38
+ _January 09, 2023_
39
+
40
+ ### ✅ Added
41
+
42
+ - xcmonkey `test`, `repeat` and `describe` commands
data/Gemfile CHANGED
@@ -4,3 +4,17 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in xcmonkey.gemspec
6
6
  gemspec
7
+
8
+ gem 'bundler'
9
+ gem 'fasterer', '0.9.0'
10
+ gem 'fastlane'
11
+ gem 'rake'
12
+ gem 'rspec'
13
+ gem 'rspec_junit_formatter'
14
+ gem 'rubocop', '1.44.0'
15
+ gem 'rubocop-performance'
16
+ gem 'rubocop-rake', '0.6.0'
17
+ gem 'rubocop-require_tools'
18
+ gem 'rubocop-rspec', '2.15.0'
19
+ gem 'simplecov'
20
+ gem 'solargraph'
data/README.md CHANGED
@@ -39,7 +39,7 @@ gem 'xcmonkey'
39
39
  ### To run a stress test
40
40
 
41
41
  ```bash
42
- $ xcmonkey test --duration 100 --bundle-id "com.apple.Maps" --udid "413EA256-CFFB-4312-94A6-12592BEE4CBA"
42
+ $ xcmonkey test --event-count 100 --bundle-id "com.apple.Maps" --udid "413EA256-CFFB-4312-94A6-12592BEE4CBA"
43
43
 
44
44
  12:44:19.343: Device info: {
45
45
  "name": "iPhone 14 Pro",
@@ -97,6 +97,26 @@ xcmonkey repeat --session-path "./xcmonkey-session.json"
97
97
  xcmonkey describe -x 20 -y 625 --udid "413EA256-CFFB-4312-94A6-12592BEE4CBA"
98
98
  ```
99
99
 
100
+ ### Test options reference
101
+
102
+ The table below lists all options you can include on the `xcmonkey test` command line.
103
+
104
+ | Category | Option | Description | Default |
105
+ | --- | --- | --- | --- |
106
+ | **General** | `-h, --help` | Display help documentation | |
107
+ | | `-v, --version` | Display version information | |
108
+ | | `-t, --trace` | Display backtrace when an error occurs | |
109
+ | **Events** | `-u, --udid <string>` | Set device UDID | |
110
+ | | `-b, --bundle-id <string>` | Set target bundle identifier | |
111
+ | | `-s, --session-path <string>` | Path where test session should be saved | |
112
+ | | `-e, --event-count <integer>` | Set events count | `60` |
113
+ | | `--exclude-taps` | Exclude taps from gestures list | `false` |
114
+ | | `--exclude-swipes` | Exclude swipes from gestures list | `false` |
115
+ | | `--exclude-presses` | Exclude presses from gestures list | `false` |
116
+ | | `--disable-simulator-keyboard` | Should simulator keyboard be disable? | `false` |
117
+ | **Debugging** | `--ignore-crashes` | Should app crashes be ignored? | `false` |
118
+ | | `--throttle <milliseconds>` | Fixed delay between events | `0` |
119
+
100
120
  ## [fastlane](https://github.com/fastlane/fastlane) integration
101
121
 
102
122
  To run *xcmonkey* from *fastlane*, add the following code to your `Fastfile`:
@@ -106,7 +126,7 @@ require 'xcmonkey'
106
126
 
107
127
  lane :test do
108
128
  Xcmonkey.new(
109
- duration: 100,
129
+ event_count: 100,
110
130
  bundle_id: 'com.apple.Maps',
111
131
  udid: '413EA256-CFFB-4312-94A6-12592BEE4CBA'
112
132
  ).run
data/bin/xcmonkey CHANGED
@@ -17,16 +17,26 @@ class Xcmonkey
17
17
  c.description = 'Runs monkey test'
18
18
  c.option('-u', '--udid STRING', String, 'Set device UDID')
19
19
  c.option('-b', '--bundle-id STRING', String, 'Set target bundle identifier')
20
- c.option('-d', '--duration SECONDS', Integer, 'Test duration in seconds. Defaults to `60`')
21
- c.option('-k', '--enable-simulator-keyboard', 'Should simulator keyboard be enabled? Defaults to `true`')
22
- c.option('-s', '--session-path STRING', String, 'Path where monkey testing session should be saved. Defaults to current directory')
20
+ c.option('-e', '--event-count NUMBER', Integer, 'Set events count. Defaults to `60`')
21
+ c.option('-s', '--session-path STRING', String, 'Path where test session should be saved')
22
+ c.option('--throttle MILLISECONDS', Integer, 'Fixed delay between events in milliseconds. Defaults to `0`')
23
+ c.option('--exclude-taps', 'Exclude taps from gestures list. Defaults to `false`')
24
+ c.option('--exclude-swipes', 'Exclude swipes from gestures list. Defaults to `false`')
25
+ c.option('--exclude-presses', 'Exclude presses from gestures list. Defaults to `false`')
26
+ c.option('--ignore-crashes', 'Should app crashes be ignored? Defaults to `false`')
27
+ c.option('--disable-simulator-keyboard', 'Should simulator keyboard be disable? Defaults to `false`')
23
28
  c.action do |_, options|
24
29
  params = {
25
30
  udid: options.udid,
26
31
  bundle_id: options.bundle_id,
27
- duration: options.duration,
32
+ event_count: options.event_count,
33
+ throttle: options.throttle,
28
34
  session_path: options.session_path,
29
- enable_simulator_keyboard: options.enable_simulator_keyboard
35
+ exclude_taps: options.exclude_taps,
36
+ exclude_swipes: options.exclude_swipes,
37
+ exclude_presses: options.exclude_presses,
38
+ ignore_crashes: options.ignore_crashes,
39
+ disable_simulator_keyboard: options.disable_simulator_keyboard
30
40
  }
31
41
  Xcmonkey.new(params).run
32
42
  end
data/fastlane/Fastfile CHANGED
@@ -8,9 +8,9 @@ lane :release do
8
8
  set_github_release(
9
9
  repository_name: 'alteral/xcmonkey',
10
10
  api_token: ENV.fetch("GITHUB_TOKEN", nil),
11
- name: "xcmonkey v#{version}",
12
- tag_name: "v#{version}",
13
- description: "v#{version}",
11
+ name: version,
12
+ tag_name: version,
13
+ description: "See [CHANGELOG.md](https://github.com/alteral/xcmonkey/blob/main/CHANGELOG.md##{version.delete('.')}})",
14
14
  commitish: git_branch,
15
15
  upload_assets: [gem_path]
16
16
  )
@@ -1,12 +1,14 @@
1
1
  class Driver
2
- attr_accessor :udid, :bundle_id, :enable_simulator_keyboard, :session_duration, :session_path, :session_actions
2
+ attr_accessor :udid, :bundle_id, :disable_simulator_keyboard, :event_count, :session_path, :session_actions, :ignore_crashes, :throttle
3
3
 
4
4
  def initialize(params)
5
5
  self.udid = params[:udid]
6
+ self.throttle = params[:throttle]
6
7
  self.bundle_id = params[:bundle_id]
7
- self.session_duration = params[:duration]
8
+ self.event_count = params[:event_count]
8
9
  self.session_path = params[:session_path]
9
- self.enable_simulator_keyboard = params[:enable_simulator_keyboard]
10
+ self.ignore_crashes = params[:ignore_crashes]
11
+ self.disable_simulator_keyboard = params[:disable_simulator_keyboard]
10
12
  self.session_actions = params[:session_actions]
11
13
  @session = { params: params, actions: [] }
12
14
  ensure_driver_installed
@@ -23,10 +25,8 @@ class Driver
23
25
 
24
26
  def monkey_test(gestures)
25
27
  monkey_test_precondition
26
- app_elements = describe_ui.shuffle
27
- current_time = Time.now
28
- counter = 0
29
- while Time.now < current_time + session_duration
28
+ event_count.times do |counter|
29
+ app_elements = describe_ui.shuffle
30
30
  el1_coordinates = central_coordinates(app_elements.first)
31
31
  el2_coordinates = central_coordinates(app_elements.last)
32
32
  case gestures.sample
@@ -53,18 +53,14 @@ class Driver
53
53
  else
54
54
  next
55
55
  end
56
- detect_app_state_change
57
- track_running_apps if counter % 5 == 0 # Track running apps after every 5th action to speed up the test
58
- counter += 1
59
- app_elements = describe_ui.shuffle
56
+ checkup(counter)
60
57
  end
61
58
  save_session
62
59
  end
63
60
 
64
61
  def repeat_monkey_test
65
62
  monkey_test_precondition
66
- counter = 0
67
- session_actions.each do |action|
63
+ session_actions.each_with_index do |action, counter|
68
64
  case action['type']
69
65
  when 'tap'
70
66
  tap(coordinates: { x: action['x'], y: action['y'] })
@@ -79,10 +75,16 @@ class Driver
79
75
  else
80
76
  next
81
77
  end
82
- detect_app_state_change
83
- track_running_apps if counter % 5 == 0
84
- counter += 1
78
+ checkup(counter)
79
+ end
80
+ end
81
+
82
+ def checkup(counter)
83
+ detect_app_state_change
84
+ if counter % 5 == 0 || throttle.to_i > 0 # Track running apps after every 5th action
85
+ track_running_apps # (unless `throttle` was provided) to speed up the test
85
86
  end
87
+ check_speed_limit
86
88
  end
87
89
 
88
90
  def describe_ui
@@ -115,7 +117,7 @@ class Driver
115
117
 
116
118
  def configure_simulator_keyboard
117
119
  shutdown_simulator
118
- keyboard_status = enable_simulator_keyboard ? 0 : 1
120
+ keyboard_status = disable_simulator_keyboard ? 1 : 0
119
121
  `defaults write com.apple.iphonesimulator ConnectHardwareKeyboard #{keyboard_status}`
120
122
  end
121
123
 
@@ -165,10 +167,8 @@ class Driver
165
167
  end
166
168
 
167
169
  def swipe(start_coordinates:, end_coordinates:, duration:)
168
- Logger.info(
169
- "Swipe (#{duration}s):",
170
- payload: "#{JSON.pretty_generate(start_coordinates)} => #{JSON.pretty_generate(end_coordinates)}"
171
- )
170
+ payload = "#{JSON.pretty_generate(start_coordinates)} => #{JSON.pretty_generate(end_coordinates)}"
171
+ Logger.info("Swipe (#{duration}s):", payload: payload)
172
172
  unless session_actions
173
173
  @session[:actions] << {
174
174
  type: :swipe,
@@ -188,8 +188,8 @@ class Driver
188
188
  x = (frame['x'] + (frame['width'] / 2)).abs.to_i
189
189
  y = (frame['y'] + (frame['height'] / 2)).abs.to_i
190
190
  {
191
- x: x > screen_size[:width].to_i ? rand(0..screen_size[:width].to_i) : x,
192
- y: y > screen_size[:height].to_i ? rand(0..screen_size[:height].to_i) : y
191
+ x: x > screen_size[:width].to_i ? random_coordinates[:x] : x,
192
+ y: y > screen_size[:height].to_i ? random_coordinates[:y] : y
193
193
  }
194
194
  end
195
195
 
@@ -222,6 +222,8 @@ class Driver
222
222
  end
223
223
 
224
224
  def save_session
225
+ return if session_path.nil?
226
+
225
227
  File.write("#{session_path}/xcmonkey-session.json", JSON.pretty_generate(@session))
226
228
  end
227
229
 
@@ -236,6 +238,7 @@ class Driver
236
238
  return if new_apps.empty?
237
239
 
238
240
  launch_app(target_bundle_id: bundle_id)
241
+
239
242
  new_apps.each do |id|
240
243
  Logger.warn("Shutting down: #{id}")
241
244
  terminate_app(id)
@@ -249,7 +252,7 @@ class Driver
249
252
 
250
253
  target_app_is_running = list_running_apps.any? { |app| app['bundle_id'] == bundle_id }
251
254
 
252
- if target_app_is_running
255
+ if target_app_is_running || ignore_crashes
253
256
  launch_app(target_bundle_id: bundle_id)
254
257
  else
255
258
  save_session
@@ -262,6 +265,10 @@ class Driver
262
265
  current_app_label.nil? || current_app_label.strip.empty?
263
266
  end
264
267
 
268
+ def check_speed_limit
269
+ sleep(throttle / 1000.0) if throttle.to_i > 0
270
+ end
271
+
265
272
  private
266
273
 
267
274
  def ensure_driver_installed
@@ -1,5 +1,5 @@
1
1
  class Repeater
2
- attr_accessor :udid, :bundle_id, :enable_simulator_keyboard, :actions
2
+ attr_accessor :udid, :bundle_id, :disable_simulator_keyboard, :ignore_crashes, :actions, :throttle
3
3
 
4
4
  def initialize(params)
5
5
  validate_session(params[:session_path])
@@ -8,8 +8,10 @@ class Repeater
8
8
  def run
9
9
  params = {
10
10
  udid: udid,
11
+ throttle: throttle,
11
12
  bundle_id: bundle_id,
12
- enable_simulator_keyboard: enable_simulator_keyboard,
13
+ ignore_crashes: ignore_crashes,
14
+ disable_simulator_keyboard: disable_simulator_keyboard,
13
15
  session_actions: actions
14
16
  }
15
17
  Driver.new(params).repeat_monkey_test
@@ -34,6 +36,10 @@ class Repeater
34
36
  self.bundle_id = session['params']['bundle_id']
35
37
  Logger.error('Provided session is not valid: `bundle_id` should not be `nil`') if bundle_id.nil?
36
38
 
37
- self.enable_simulator_keyboard = session['params']['enable_simulator_keyboard']
39
+ self.throttle = session['params']['throttle']
40
+
41
+ self.ignore_crashes = session['params']['ignore_crashes']
42
+
43
+ self.disable_simulator_keyboard = session['params']['disable_simulator_keyboard']
38
44
  end
39
45
  end
@@ -1,3 +1,3 @@
1
1
  class Xcmonkey
2
- VERSION = '1.2.0'
2
+ VERSION = '1.3.0'
3
3
  end
data/lib/xcmonkey.rb CHANGED
@@ -7,14 +7,15 @@ require_relative 'xcmonkey/logger'
7
7
  require_relative 'xcmonkey/driver'
8
8
 
9
9
  class Xcmonkey
10
- attr_accessor :driver
10
+ attr_accessor :params, :driver
11
11
 
12
12
  def initialize(params)
13
- params[:session_path] = Dir.pwd if params[:session_path].nil?
14
- params[:duration] = 60 if params[:duration].nil?
15
- params[:enable_simulator_keyboard] = true if params[:enable_simulator_keyboard].nil?
16
- ensure_required_params(params)
13
+ params[:event_count] = 60 if params[:event_count].nil?
14
+ params[:ignore_crashes] = false if params[:ignore_crashes].nil?
15
+ params[:disable_simulator_keyboard] = false if params[:disable_simulator_keyboard].nil?
16
+ self.params = params
17
17
  self.driver = Driver.new(params)
18
+ ensure_required_params
18
19
  end
19
20
 
20
21
  def run
@@ -22,21 +23,21 @@ class Xcmonkey
22
23
  end
23
24
 
24
25
  def gestures
25
- taps = [:precise_tap, :blind_tap] * 10
26
- swipes = [:precise_swipe, :blind_swipe] * 5
27
- presses = [:precise_press, :blind_press]
26
+ taps = params[:exclude_taps] ? [] : [:precise_tap, :blind_tap] * 10
27
+ swipes = params[:exclude_swipes] ? [] : [:precise_swipe, :blind_swipe] * 5
28
+ presses = params[:exclude_presses] ? [] : [:precise_press, :blind_press]
28
29
  taps + swipes + presses
29
30
  end
30
31
 
31
- def ensure_required_params(params)
32
+ def ensure_required_params
32
33
  Logger.error('UDID should be provided') if params[:udid].nil?
33
34
 
34
35
  Logger.error('Bundle identifier should be provided') if params[:bundle_id].nil?
35
36
 
36
- Logger.error('Session path should be a directory') if params[:session_path].nil? || !File.directory?(params[:session_path])
37
+ Logger.error('Session path should be a directory') if params[:session_path] && !File.directory?(params[:session_path])
37
38
 
38
- if params[:duration].nil? || !params[:duration].kind_of?(Integer) || !params[:duration].positive?
39
- Logger.error('Duration must be Integer and not less than 1 second')
39
+ if params[:event_count].nil? || !params[:event_count].kind_of?(Integer) || !params[:event_count].positive?
40
+ Logger.error('Event count must be Integer and not less than 1')
40
41
  end
41
42
  end
42
43
  end
data/spec/driver_spec.rb CHANGED
@@ -1,7 +1,7 @@
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, session_path: Dir.pwd) }
4
+ let(:driver) { described_class.new(udid: udid, bundle_id: bundle_id) }
5
5
  let(:driver_with_session) { described_class.new(udid: udid, bundle_id: bundle_id, session_actions: [{ type: 'tap', x: 0, y: 0 }]) }
6
6
 
7
7
  before do
@@ -109,7 +109,7 @@ describe Driver do
109
109
 
110
110
  it 'verifies that simulator keyboard can be enabled' do
111
111
  allow(driver).to receive(:is_simulator_keyboard_enabled?).and_return(false)
112
- driver = described_class.new(udid: udid, bundle_id: bundle_id, enable_simulator_keyboard: true)
112
+ driver = described_class.new(udid: udid, bundle_id: bundle_id, disable_simulator_keyboard: false)
113
113
  expect(driver).to receive(:shutdown_simulator)
114
114
  driver.configure_simulator_keyboard
115
115
  keyboard_state = `defaults read com.apple.iphonesimulator`.split("\n").grep(/ConnectHardwareKeyboard/)
@@ -119,7 +119,7 @@ describe Driver do
119
119
 
120
120
  it 'verifies that simulator keyboard can be disabled' do
121
121
  allow(driver).to receive(:is_simulator_keyboard_enabled?).and_return(true)
122
- driver = described_class.new(udid: udid, bundle_id: bundle_id, enable_simulator_keyboard: false)
122
+ driver = described_class.new(udid: udid, bundle_id: bundle_id, disable_simulator_keyboard: true)
123
123
  expect(driver).to receive(:shutdown_simulator)
124
124
  driver.configure_simulator_keyboard
125
125
  keyboard_state = `defaults read com.apple.iphonesimulator`.split("\n").grep(/ConnectHardwareKeyboard/)
@@ -192,11 +192,17 @@ describe Driver do
192
192
  end
193
193
 
194
194
  it 'verifies that session can be saved' do
195
+ driver = described_class.new(udid: udid, bundle_id: bundle_id, session_path: Dir.pwd)
195
196
  expect(File).to receive(:write)
196
197
  driver.instance_variable_set(:@session, { params: {}, actions: [] })
197
198
  driver.save_session
198
199
  end
199
200
 
201
+ it "verifies that session won't be saved if path is not provided" do
202
+ expect(File).not_to receive(:write)
203
+ driver.save_session
204
+ end
205
+
200
206
  it 'verifies that monkey_test_precondition works fine' do
201
207
  driver.monkey_test_precondition
202
208
  app_info = driver.list_apps.detect { |app| app['bundle_id'] == bundle_id }
@@ -206,7 +212,7 @@ describe Driver do
206
212
  end
207
213
 
208
214
  it 'verifies that monkey_test works fine' do
209
- params = { udid: udid, bundle_id: bundle_id, duration: 1, session_path: Dir.pwd }
215
+ params = { udid: udid, bundle_id: bundle_id, event_count: 1, session_path: Dir.pwd }
210
216
  driver = described_class.new(params)
211
217
  driver.monkey_test(Xcmonkey.new(params).gestures)
212
218
  expect(driver.instance_variable_get(:@session)[:actions]).not_to be_empty
@@ -272,6 +278,14 @@ describe Driver do
272
278
  expect { driver.detect_app_state_change }.not_to raise_error
273
279
  end
274
280
 
281
+ it 'verifies that app crashes can be ignored' do
282
+ driver = described_class.new(udid: udid, bundle_id: bundle_id, session_path: Dir.pwd, ignore_crashes: true)
283
+ driver.terminate_app(bundle_id)
284
+ expect(driver).not_to receive(:save_session)
285
+ expect(driver).to receive(:launch_app)
286
+ expect { driver.detect_app_state_change }.not_to raise_error
287
+ end
288
+
275
289
  it 'verifies that background state can be determined' do
276
290
  driver.terminate_app(bundle_id)
277
291
  expect(driver.detect_app_in_background).to be(true)
@@ -289,6 +303,29 @@ describe Driver do
289
303
  expect { driver.ensure_device_exists }.to raise_error(SystemExit) { |e| expect(e.status).to eq(1) }
290
304
  end
291
305
 
306
+ it 'verifies that test can be slowed down' do
307
+ throttle = 1000
308
+ driver = described_class.new(udid: udid, bundle_id: bundle_id, session_path: Dir.pwd, throttle: throttle)
309
+ expect(driver).to receive(:sleep).with(throttle / 1000.0)
310
+ driver.check_speed_limit
311
+ end
312
+
313
+ it 'verifies that test ignores throttle by default' do
314
+ expect(driver).not_to receive(:sleep)
315
+ driver.check_speed_limit
316
+ end
317
+
318
+ it 'verifies that running apps are tracked on second entry with throttle' do
319
+ driver = described_class.new(udid: udid, bundle_id: bundle_id, session_path: Dir.pwd, throttle: 1)
320
+ expect(driver).to receive(:track_running_apps)
321
+ driver.checkup(1)
322
+ end
323
+
324
+ it 'verifies that running apps are not tracked on second entry without throttle' do
325
+ expect(driver).not_to receive(:track_running_apps)
326
+ driver.checkup(1)
327
+ end
328
+
292
329
  it 'verifies that simulator was not booted' do
293
330
  driver.shutdown_simulator
294
331
  error_message = "Failed to boot #{udid}"
@@ -1,11 +1,11 @@
1
1
  describe Repeater do
2
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 }] }' }
3
+ let(:session_file_content_full) { '{ "params": {"udid": "0", "bundle_id": "0", "disable_simulator_keyboard": false}, "actions": [{ "type": "tap", "x": 0, "y": 0 }] }' }
4
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 }] }' }
5
+ let(:session_file_content_with_empty_actions) { '{ "params": {"udid": "0", "bundle_id": "0", "disable_simulator_keyboard": false}, "actions": [] }' }
6
+ let(:session_file_content_without_actions) { '{ "params": {"udid": "0", "bundle_id": "0", "disable_simulator_keyboard": false} }' }
7
+ let(:session_file_content_without_bundle_id) { '{ "params": {"udid": "0", "disable_simulator_keyboard": false}, "actions": [{ "type": "tap", "x": 0, "y": 0 }] }' }
8
+ let(:session_file_content_without_udid) { '{ "params": {"bundle_id": "0", "disable_simulator_keyboard": false}, "actions": [{ "type": "tap", "x": 0, "y": 0 }] }' }
9
9
 
10
10
  it 'verifies that session cannot be validated without params' do
11
11
  allow(File).to receive(:exist?).and_return(true)
@@ -1,6 +1,6 @@
1
1
  describe Xcmonkey do
2
- let(:params) { { udid: '123', bundle_id: 'example.com.app', duration: 10, session_path: Dir.pwd } }
3
- let(:duration_error_msg) { 'Duration must be Integer and not less than 1 second' }
2
+ let(:params) { { udid: '123', bundle_id: 'example.com.app', event_count: 10, session_path: Dir.pwd } }
3
+ let(:event_count_error_msg) { 'Event count must be Integer and not less than 1' }
4
4
 
5
5
  before do
6
6
  allow(Logger).to receive(:info)
@@ -14,6 +14,30 @@ describe Xcmonkey do
14
14
  expect(gestures) =~ presses + taps + swipes
15
15
  end
16
16
 
17
+ it 'verifies gestures without taps' do
18
+ params[:exclude_taps] = true
19
+ gestures = described_class.new(params).gestures
20
+ swipes = [:precise_swipe, :blind_swipe] * 5
21
+ presses = [:precise_press, :blind_press]
22
+ expect(gestures) =~ presses + swipes
23
+ end
24
+
25
+ it 'verifies gestures without swipes' do
26
+ params[:exclude_swipes] = true
27
+ gestures = described_class.new(params).gestures
28
+ taps = [:precise_tap, :blind_tap] * 10
29
+ presses = [:precise_press, :blind_press]
30
+ expect(gestures) =~ presses + taps
31
+ end
32
+
33
+ it 'verifies gestures without presses' do
34
+ params[:exclude_presses] = true
35
+ gestures = described_class.new(params).gestures
36
+ taps = [:precise_tap, :blind_tap] * 10
37
+ swipes = [:precise_swipe, :blind_swipe] * 5
38
+ expect(gestures) =~ swipes + taps
39
+ end
40
+
17
41
  it 'verifies required params' do
18
42
  expect(Logger).not_to receive(:error)
19
43
  described_class.new(params)
@@ -31,21 +55,21 @@ describe Xcmonkey do
31
55
  described_class.new(params)
32
56
  end
33
57
 
34
- it 'verifies `duration` param is optional' do
35
- params[:duration] = nil
58
+ it 'verifies `event_count` param is optional' do
59
+ params[:event_count] = nil
36
60
  expect(Logger).not_to receive(:error)
37
61
  described_class.new(params)
38
62
  end
39
63
 
40
- it 'verifies `duration` param cannot be equal to zero' do
41
- params[:duration] = 0
42
- expect(Logger).to receive(:error).with(duration_error_msg)
64
+ it 'verifies `event_count` param cannot be equal to zero' do
65
+ params[:event_count] = 0
66
+ expect(Logger).to receive(:error).with(event_count_error_msg)
43
67
  described_class.new(params)
44
68
  end
45
69
 
46
- it 'verifies `duration` param cannot be negative' do
47
- params[:duration] = -1
48
- expect(Logger).to receive(:error).with(duration_error_msg)
70
+ it 'verifies `event_count` param cannot be negative' do
71
+ params[:event_count] = -1
72
+ expect(Logger).to receive(:error).with(event_count_error_msg)
49
73
  described_class.new(params)
50
74
  end
51
75
 
data/xcmonkey.gemspec CHANGED
@@ -1,42 +1,32 @@
1
1
  lib = File.expand_path('lib', __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require "xcmonkey/version"
3
+ require 'xcmonkey/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "xcmonkey"
6
+ spec.name = 'xcmonkey'
7
7
  spec.version = Xcmonkey::VERSION
8
- spec.authors = ["alteral"]
9
- spec.email = ["a.alterpesotskiy@mail.ru"]
8
+ spec.authors = ['alteral']
9
+ spec.email = ['a.alterpesotskiy@mail.ru']
10
10
 
11
- spec.summary = "xcmonkey is a tool for doing randomised UI testing of iOS apps"
12
- spec.homepage = "https://github.com/alteral/xcmonkey"
13
- spec.license = "MIT"
11
+ spec.summary = 'xcmonkey is a tool for doing randomised UI testing of iOS apps'
12
+ spec.homepage = 'https://github.com/alteral/xcmonkey'
13
+ spec.license = 'MIT'
14
14
 
15
15
  if spec.respond_to?(:metadata)
16
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
16
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
17
17
  else
18
- raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
18
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
19
19
  end
20
20
 
21
- spec.bindir = "bin"
22
- spec.executables = ["xcmonkey"]
21
+ spec.bindir = 'bin'
22
+ spec.executables = ['xcmonkey']
23
23
  spec.files = `git ls-files -z`.split("\x0")
24
24
  spec.require_paths = ['lib']
25
25
 
26
26
  spec.required_ruby_version = '>= 2.4'
27
- spec.add_development_dependency('bundler')
28
- spec.add_development_dependency('fasterer', '0.9.0')
29
- spec.add_development_dependency('fastlane')
30
- spec.add_development_dependency('rake')
31
- spec.add_development_dependency('rspec')
32
- spec.add_development_dependency('rspec_junit_formatter')
33
- spec.add_development_dependency('rubocop', '1.38')
34
- spec.add_development_dependency('rubocop-performance')
35
- spec.add_development_dependency('rubocop-rake', '0.6.0')
36
- spec.add_development_dependency('rubocop-require_tools')
37
- spec.add_development_dependency('rubocop-rspec', '2.15.0')
38
- spec.add_development_dependency('simplecov')
39
- spec.add_dependency("colorize", "~> 0.8.1")
40
- spec.add_dependency("commander")
41
- spec.metadata['rubygems_mfa_required'] = 'true'
27
+
28
+ spec.add_dependency('colorize', '~> 0.8.1')
29
+ spec.add_dependency('commander')
30
+
31
+ spec.metadata['rubygems_mfa_required'] = 'true'
42
32
  end
metadata CHANGED
@@ -1,183 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcmonkey
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.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-23 00:00:00.000000000 Z
11
+ date: 2023-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: fasterer
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '='
32
- - !ruby/object:Gem::Version
33
- version: 0.9.0
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '='
39
- - !ruby/object:Gem::Version
40
- version: 0.9.0
41
- - !ruby/object:Gem::Dependency
42
- name: fastlane
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: rake
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rspec
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rspec_junit_formatter
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rubocop
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - '='
102
- - !ruby/object:Gem::Version
103
- version: '1.38'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - '='
109
- - !ruby/object:Gem::Version
110
- version: '1.38'
111
- - !ruby/object:Gem::Dependency
112
- name: rubocop-performance
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: rubocop-rake
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - '='
130
- - !ruby/object:Gem::Version
131
- version: 0.6.0
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - '='
137
- - !ruby/object:Gem::Version
138
- version: 0.6.0
139
- - !ruby/object:Gem::Dependency
140
- name: rubocop-require_tools
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: rubocop-rspec
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - '='
158
- - !ruby/object:Gem::Version
159
- version: 2.15.0
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - '='
165
- - !ruby/object:Gem::Version
166
- version: 2.15.0
167
- - !ruby/object:Gem::Dependency
168
- name: simplecov
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - ">="
172
- - !ruby/object:Gem::Version
173
- version: '0'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - ">="
179
- - !ruby/object:Gem::Version
180
- version: '0'
181
13
  - !ruby/object:Gem::Dependency
182
14
  name: colorize
183
15
  requirement: !ruby/object:Gem::Requirement
@@ -220,10 +52,12 @@ files:
220
52
  - ".github/ISSUE_TEMPLATE/feature-request.md"
221
53
  - ".github/dependabot.yml"
222
54
  - ".github/pull_request_template.md"
55
+ - ".github/stale.yml"
223
56
  - ".github/workflows/test.yml"
224
57
  - ".gitignore"
225
58
  - ".rspec"
226
59
  - ".rubocop.yml"
60
+ - CHANGELOG.md
227
61
  - CODE_OF_CONDUCT.md
228
62
  - Gemfile
229
63
  - LICENSE