xcmonkey 1.1.0 → 1.2.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 +4 -4
- data/README.md +3 -3
- data/lib/xcmonkey/driver.rb +63 -29
- data/lib/xcmonkey/version.rb +1 -1
- data/spec/describer_spec.rb +4 -2
- data/spec/driver_spec.rb +70 -28
- data/spec/xcmonkey_spec.rb +4 -0
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c93c94403332c085a393877d88d354b2736788f6e52d118eb8b9faa70c91b1e5
         | 
| 4 | 
            +
              data.tar.gz: ee0f3bfcd014151b4821a6df50f601205581ebd480b5626e33588bda2928981a
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 0ab88db343b0e83363130a9e9c8ed965acbf9d58f56d597b301ff12da4df9d4e79b08c3b2284b870a65c9bfc3d05a8ba9df0d19409631620a28836c9d5785814
         | 
| 7 | 
            +
              data.tar.gz: fe46af5c215273be9210f3c880617457a12c6063e0bd1901d6abbd10750f10935b77a4797ff374926c3f1cac6b1ef79032f210fb705e05917146e4c64cede97c
         | 
    
        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 -- | 
| 42 | 
            +
            $ xcmonkey test --duration 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",
         | 
| @@ -106,9 +106,9 @@ require 'xcmonkey' | |
| 106 106 |  | 
| 107 107 | 
             
            lane :test do
         | 
| 108 108 | 
             
              Xcmonkey.new(
         | 
| 109 | 
            -
                 | 
| 109 | 
            +
                duration: 100,
         | 
| 110 110 | 
             
                bundle_id: 'com.apple.Maps',
         | 
| 111 | 
            -
                 | 
| 111 | 
            +
                udid: '413EA256-CFFB-4312-94A6-12592BEE4CBA'
         | 
| 112 112 | 
             
              ).run
         | 
| 113 113 | 
             
            end
         | 
| 114 114 | 
             
            ```
         | 
    
        data/lib/xcmonkey/driver.rb
    CHANGED
    
    | @@ -16,15 +16,16 @@ class Driver | |
| 16 16 | 
             
                puts
         | 
| 17 17 | 
             
                ensure_device_exists
         | 
| 18 18 | 
             
                ensure_app_installed
         | 
| 19 | 
            -
                terminate_app
         | 
| 20 | 
            -
                 | 
| 21 | 
            -
                 | 
| 19 | 
            +
                terminate_app(bundle_id)
         | 
| 20 | 
            +
                launch_app(target_bundle_id: bundle_id, wait_for_state_update: true)
         | 
| 21 | 
            +
                @running_apps = list_running_apps
         | 
| 22 22 | 
             
              end
         | 
| 23 23 |  | 
| 24 24 | 
             
              def monkey_test(gestures)
         | 
| 25 25 | 
             
                monkey_test_precondition
         | 
| 26 26 | 
             
                app_elements = describe_ui.shuffle
         | 
| 27 27 | 
             
                current_time = Time.now
         | 
| 28 | 
            +
                counter = 0
         | 
| 28 29 | 
             
                while Time.now < current_time + session_duration
         | 
| 29 30 | 
             
                  el1_coordinates = central_coordinates(app_elements.first)
         | 
| 30 31 | 
             
                  el2_coordinates = central_coordinates(app_elements.last)
         | 
| @@ -52,17 +53,17 @@ class Driver | |
| 52 53 | 
             
                  else
         | 
| 53 54 | 
             
                    next
         | 
| 54 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
         | 
| 55 59 | 
             
                  app_elements = describe_ui.shuffle
         | 
| 56 | 
            -
                  next unless app_elements.include?(@home_tracker)
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                  save_session
         | 
| 59 | 
            -
                  Logger.error('App lost')
         | 
| 60 60 | 
             
                end
         | 
| 61 61 | 
             
                save_session
         | 
| 62 62 | 
             
              end
         | 
| 63 63 |  | 
| 64 64 | 
             
              def repeat_monkey_test
         | 
| 65 65 | 
             
                monkey_test_precondition
         | 
| 66 | 
            +
                counter = 0
         | 
| 66 67 | 
             
                session_actions.each do |action|
         | 
| 67 68 | 
             
                  case action['type']
         | 
| 68 69 | 
             
                  when 'tap'
         | 
| @@ -78,15 +79,12 @@ class Driver | |
| 78 79 | 
             
                  else
         | 
| 79 80 | 
             
                    next
         | 
| 80 81 | 
             
                  end
         | 
| 81 | 
            -
                   | 
| 82 | 
            +
                  detect_app_state_change
         | 
| 83 | 
            +
                  track_running_apps if counter % 5 == 0
         | 
| 84 | 
            +
                  counter += 1
         | 
| 82 85 | 
             
                end
         | 
| 83 86 | 
             
              end
         | 
| 84 87 |  | 
| 85 | 
            -
              def open_home_screen(with_tracker: false)
         | 
| 86 | 
            -
                `idb ui button --udid #{udid} HOME`
         | 
| 87 | 
            -
                detect_home_unique_element if with_tracker
         | 
| 88 | 
            -
              end
         | 
| 89 | 
            -
             | 
| 90 88 | 
             
              def describe_ui
         | 
| 91 89 | 
             
                JSON.parse(`idb ui describe-all --udid #{udid}`)
         | 
| 92 90 | 
             
              end
         | 
| @@ -97,13 +95,13 @@ class Driver | |
| 97 95 | 
             
                point_info
         | 
| 98 96 | 
             
              end
         | 
| 99 97 |  | 
| 100 | 
            -
              def launch_app
         | 
| 101 | 
            -
                `idb launch --udid #{udid} #{ | 
| 102 | 
            -
                wait_until_app_launched
         | 
| 98 | 
            +
              def launch_app(target_bundle_id:, wait_for_state_update: false)
         | 
| 99 | 
            +
                `idb launch --udid #{udid} #{target_bundle_id}`
         | 
| 100 | 
            +
                wait_until_app_launched(target_bundle_id) if wait_for_state_update
         | 
| 103 101 | 
             
              end
         | 
| 104 102 |  | 
| 105 | 
            -
              def terminate_app
         | 
| 106 | 
            -
                `idb terminate --udid #{udid} #{ | 
| 103 | 
            +
              def terminate_app(target_bundle_id)
         | 
| 104 | 
            +
                `idb terminate --udid #{udid} #{target_bundle_id} 2>/dev/null`
         | 
| 107 105 | 
             
              end
         | 
| 108 106 |  | 
| 109 107 | 
             
              def boot_simulator
         | 
| @@ -130,6 +128,10 @@ class Driver | |
| 130 128 | 
             
                `idb list-apps --udid #{udid} --json`.split("\n").map! { |app| JSON.parse(app) }
         | 
| 131 129 | 
             
              end
         | 
| 132 130 |  | 
| 131 | 
            +
              def list_running_apps
         | 
| 132 | 
            +
                list_apps.select { |app| app['process_state'] == 'Running' }
         | 
| 133 | 
            +
              end
         | 
| 134 | 
            +
             | 
| 133 135 | 
             
              def ensure_app_installed
         | 
| 134 136 | 
             
                return if list_apps.any? { |app| app['bundle_id'] == bundle_id }
         | 
| 135 137 |  | 
| @@ -144,6 +146,9 @@ class Driver | |
| 144 146 | 
             
                if device['type'] == 'simulator'
         | 
| 145 147 | 
             
                  configure_simulator_keyboard
         | 
| 146 148 | 
             
                  boot_simulator
         | 
| 149 | 
            +
                else
         | 
| 150 | 
            +
                  Logger.error('xcmonkey does not support real devices yet. ' \
         | 
| 151 | 
            +
                               'For more information see https://github.com/alteral/xcmonkey/issues/7')
         | 
| 147 152 | 
             
                end
         | 
| 148 153 | 
             
              end
         | 
| 149 154 |  | 
| @@ -220,28 +225,57 @@ class Driver | |
| 220 225 | 
             
                File.write("#{session_path}/xcmonkey-session.json", JSON.pretty_generate(@session))
         | 
| 221 226 | 
             
              end
         | 
| 222 227 |  | 
| 223 | 
            -
               | 
| 228 | 
            +
              # This function takes ≈200ms
         | 
| 229 | 
            +
              def track_running_apps
         | 
| 230 | 
            +
                current_list_of_running_apps = list_running_apps
         | 
| 231 | 
            +
                if @running_apps != current_list_of_running_apps
         | 
| 232 | 
            +
                  currently_running_bundle_ids = current_list_of_running_apps.map { |app| app['bundle_id'] }
         | 
| 233 | 
            +
                  previously_running_bundle_ids = @running_apps.map { |app| app['bundle_id'] }
         | 
| 234 | 
            +
                  new_apps = currently_running_bundle_ids - previously_running_bundle_ids
         | 
| 224 235 |  | 
| 225 | 
            -
             | 
| 226 | 
            -
             | 
| 236 | 
            +
                  return if new_apps.empty?
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                  launch_app(target_bundle_id: bundle_id)
         | 
| 239 | 
            +
                  new_apps.each do |id|
         | 
| 240 | 
            +
                    Logger.warn("Shutting down: #{id}")
         | 
| 241 | 
            +
                    terminate_app(id)
         | 
| 242 | 
            +
                  end
         | 
| 243 | 
            +
                end
         | 
| 227 244 | 
             
              end
         | 
| 228 245 |  | 
| 229 | 
            -
               | 
| 230 | 
            -
             | 
| 231 | 
            -
             | 
| 232 | 
            -
             | 
| 246 | 
            +
              # This function takes ≈300ms
         | 
| 247 | 
            +
              def detect_app_state_change
         | 
| 248 | 
            +
                return unless detect_app_in_background
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                target_app_is_running = list_running_apps.any? { |app| app['bundle_id'] == bundle_id }
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                if target_app_is_running
         | 
| 253 | 
            +
                  launch_app(target_bundle_id: bundle_id)
         | 
| 254 | 
            +
                else
         | 
| 255 | 
            +
                  save_session
         | 
| 256 | 
            +
                  Logger.error("Target app has crashed or been terminated")
         | 
| 233 257 | 
             
                end
         | 
| 234 | 
            -
                @home_tracker
         | 
| 235 258 | 
             
              end
         | 
| 236 259 |  | 
| 237 | 
            -
              def  | 
| 260 | 
            +
              def detect_app_in_background
         | 
| 261 | 
            +
                current_app_label = describe_ui.detect { |el| el['type'] == 'Application' }['AXLabel']
         | 
| 262 | 
            +
                current_app_label.nil? || current_app_label.strip.empty?
         | 
| 263 | 
            +
              end
         | 
| 264 | 
            +
             | 
| 265 | 
            +
              private
         | 
| 266 | 
            +
             | 
| 267 | 
            +
              def ensure_driver_installed
         | 
| 268 | 
            +
                Logger.error("'idb' doesn't seem to be installed") if `which idb`.strip.empty?
         | 
| 269 | 
            +
              end
         | 
| 270 | 
            +
             | 
| 271 | 
            +
              def wait_until_app_launched(target_bundle_id)
         | 
| 238 272 | 
             
                app_is_running = false
         | 
| 239 273 | 
             
                current_time = Time.now
         | 
| 240 274 | 
             
                while !app_is_running && Time.now < current_time + 5
         | 
| 241 | 
            -
                  app_info = list_apps.detect { |app| app['bundle_id'] ==  | 
| 275 | 
            +
                  app_info = list_apps.detect { |app| app['bundle_id'] == target_bundle_id }
         | 
| 242 276 | 
             
                  app_is_running = app_info && app_info['process_state'] == 'Running'
         | 
| 243 277 | 
             
                end
         | 
| 244 | 
            -
                Logger.error("Can't run the app #{ | 
| 278 | 
            +
                Logger.error("Can't run the app #{target_bundle_id}") unless app_is_running
         | 
| 245 279 | 
             
                Logger.info('App info:', payload: JSON.pretty_generate(app_info))
         | 
| 246 280 | 
             
              end
         | 
| 247 281 | 
             
            end
         | 
    
        data/lib/xcmonkey/version.rb
    CHANGED
    
    
    
        data/spec/describer_spec.rb
    CHANGED
    
    | @@ -2,15 +2,17 @@ describe Describer do | |
| 2 2 | 
             
              let(:udid) { `xcrun simctl list | grep " iPhone 14 Pro Max"`.split("\n")[0].split('(')[1].split(')')[0] }
         | 
| 3 3 | 
             
              let(:driver) { Driver.new(udid: udid) }
         | 
| 4 4 |  | 
| 5 | 
            -
               | 
| 5 | 
            +
              before do
         | 
| 6 6 | 
             
                allow(Logger).to receive(:info)
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              it 'verifies that point can be described (integer)' do
         | 
| 7 10 | 
             
                driver.boot_simulator
         | 
| 8 11 | 
             
                point_info = described_class.new(udid: udid, x: 10, y: 10).run
         | 
| 9 12 | 
             
                expect(point_info).not_to be_empty
         | 
| 10 13 | 
             
              end
         | 
| 11 14 |  | 
| 12 15 | 
             
              it 'verifies that point can be described (string)' do
         | 
| 13 | 
            -
                allow(Logger).to receive(:info)
         | 
| 14 16 | 
             
                driver.boot_simulator
         | 
| 15 17 | 
             
                point_info = described_class.new(udid: udid, x: '10', y: '10').run
         | 
| 16 18 | 
             
                expect(point_info).not_to be_empty
         | 
    
        data/spec/driver_spec.rb
    CHANGED
    
    | @@ -4,6 +4,10 @@ describe Driver do | |
| 4 4 | 
             
              let(:driver) { described_class.new(udid: udid, bundle_id: bundle_id, session_path: Dir.pwd) }
         | 
| 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 | 
            +
              before do
         | 
| 8 | 
            +
                allow(Logger).to receive(:info)
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 7 11 | 
             
              it 'verifies that sumulator was booted' do
         | 
| 8 12 | 
             
                error_message = "Failed to boot #{udid}"
         | 
| 9 13 | 
             
                expect(Logger).not_to receive(:error).with(error_message, payload: nil)
         | 
| @@ -16,18 +20,6 @@ describe Driver do | |
| 16 20 | 
             
                expect(ui).not_to be_empty
         | 
| 17 21 | 
             
              end
         | 
| 18 22 |  | 
| 19 | 
            -
              it 'verifies that home screen can be opened' do
         | 
| 20 | 
            -
                driver.boot_simulator
         | 
| 21 | 
            -
                home_tracker = driver.open_home_screen(with_tracker: true)
         | 
| 22 | 
            -
                expect(home_tracker).not_to be_empty
         | 
| 23 | 
            -
              end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
              it 'verifies that home screen can be opened without tracker' do
         | 
| 26 | 
            -
                driver.boot_simulator
         | 
| 27 | 
            -
                home_tracker = driver.open_home_screen(with_tracker: false)
         | 
| 28 | 
            -
                expect(home_tracker).to be_nil
         | 
| 29 | 
            -
              end
         | 
| 30 | 
            -
             | 
| 31 23 | 
             
              it 'verifies that list of targets can be showed' do
         | 
| 32 24 | 
             
                list_targets = driver.list_targets
         | 
| 33 25 | 
             
                expect(list_targets).not_to be_empty
         | 
| @@ -56,9 +48,7 @@ describe Driver do | |
| 56 48 | 
             
              end
         | 
| 57 49 |  | 
| 58 50 | 
             
              it 'verifies that device exists' do
         | 
| 59 | 
            -
                payload = driver.list_targets.detect { |target| target['udid'] == udid }
         | 
| 60 51 | 
             
                expect(Logger).not_to receive(:error)
         | 
| 61 | 
            -
                expect(Logger).to receive(:info).with('Device info:', payload: JSON.pretty_generate(payload))
         | 
| 62 52 | 
             
                expect(driver).to receive(:boot_simulator)
         | 
| 63 53 | 
             
                expect(driver).to receive(:configure_simulator_keyboard)
         | 
| 64 54 | 
             
                expect { driver.ensure_device_exists }.not_to raise_error
         | 
| @@ -137,18 +127,25 @@ describe Driver do | |
| 137 127 | 
             
                expect(keyboard_state.first).to include('1')
         | 
| 138 128 | 
             
              end
         | 
| 139 129 |  | 
| 140 | 
            -
              it 'verifies that app can be launched' do
         | 
| 130 | 
            +
              it 'verifies that app can be launched with waiting' do
         | 
| 131 | 
            +
                expect(Logger).not_to receive(:error)
         | 
| 132 | 
            +
                expect(driver).to receive(:wait_until_app_launched)
         | 
| 133 | 
            +
                driver.boot_simulator
         | 
| 134 | 
            +
                driver.terminate_app(bundle_id)
         | 
| 135 | 
            +
                expect { driver.launch_app(target_bundle_id: bundle_id, wait_for_state_update: true) }.not_to raise_error
         | 
| 136 | 
            +
              end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
              it 'verifies that app can be launched without waiting' do
         | 
| 141 139 | 
             
                expect(Logger).not_to receive(:error)
         | 
| 142 | 
            -
                expect( | 
| 140 | 
            +
                expect(driver).not_to receive(:wait_until_app_launched)
         | 
| 143 141 | 
             
                driver.boot_simulator
         | 
| 144 | 
            -
                driver.terminate_app
         | 
| 145 | 
            -
                expect { driver.launch_app }.not_to raise_error
         | 
| 142 | 
            +
                driver.terminate_app(bundle_id)
         | 
| 143 | 
            +
                expect { driver.launch_app(target_bundle_id: bundle_id) }.not_to raise_error
         | 
| 146 144 | 
             
              end
         | 
| 147 145 |  | 
| 148 146 | 
             
              it 'verifies tap in new session' do
         | 
| 149 147 | 
             
                driver.boot_simulator
         | 
| 150 148 | 
             
                coordinates = { x: 1, y: 1 }
         | 
| 151 | 
            -
                expect(Logger).to receive(:info).with('Tap:', payload: JSON.pretty_generate(coordinates))
         | 
| 152 149 | 
             
                driver.tap(coordinates: coordinates)
         | 
| 153 150 | 
             
                expect(driver.instance_variable_get(:@session)[:actions]).not_to be_empty
         | 
| 154 151 | 
             
              end
         | 
| @@ -156,7 +153,6 @@ describe Driver do | |
| 156 153 | 
             
              it 'verifies tap in old session' do
         | 
| 157 154 | 
             
                driver_with_session.boot_simulator
         | 
| 158 155 | 
             
                coordinates = { x: 1, y: 1 }
         | 
| 159 | 
            -
                expect(Logger).to receive(:info).with('Tap:', payload: JSON.pretty_generate(coordinates))
         | 
| 160 156 | 
             
                driver_with_session.tap(coordinates: coordinates)
         | 
| 161 157 | 
             
                expect(driver_with_session.instance_variable_get(:@session)[:actions]).to be_empty
         | 
| 162 158 | 
             
              end
         | 
| @@ -165,7 +161,6 @@ describe Driver do | |
| 165 161 | 
             
                driver.boot_simulator
         | 
| 166 162 | 
             
                duration = 0.5
         | 
| 167 163 | 
             
                coordinates = { x: 1, y: 1 }
         | 
| 168 | 
            -
                expect(Logger).to receive(:info).with("Press (#{duration}s):", payload: JSON.pretty_generate(coordinates))
         | 
| 169 164 | 
             
                driver.press(coordinates: coordinates, duration: duration)
         | 
| 170 165 | 
             
                expect(driver.instance_variable_get(:@session)[:actions]).not_to be_empty
         | 
| 171 166 | 
             
              end
         | 
| @@ -174,7 +169,6 @@ describe Driver do | |
| 174 169 | 
             
                driver_with_session.boot_simulator
         | 
| 175 170 | 
             
                duration = 0.5
         | 
| 176 171 | 
             
                coordinates = { x: 1, y: 1 }
         | 
| 177 | 
            -
                expect(Logger).to receive(:info).with("Press (#{duration}s):", payload: JSON.pretty_generate(coordinates))
         | 
| 178 172 | 
             
                driver_with_session.press(coordinates: coordinates, duration: duration)
         | 
| 179 173 | 
             
                expect(driver_with_session.instance_variable_get(:@session)[:actions]).to be_empty
         | 
| 180 174 | 
             
              end
         | 
| @@ -184,7 +178,6 @@ describe Driver do | |
| 184 178 | 
             
                duration = 0.5
         | 
| 185 179 | 
             
                start_coordinates = { x: 1, y: 1 }
         | 
| 186 180 | 
             
                end_coordinates = { x: 2, y: 2 }
         | 
| 187 | 
            -
                expect(Logger).to receive(:info).with("Swipe (#{duration}s):", payload: "#{JSON.pretty_generate(start_coordinates)} => #{JSON.pretty_generate(end_coordinates)}")
         | 
| 188 181 | 
             
                driver.swipe(start_coordinates: start_coordinates, end_coordinates: end_coordinates, duration: duration)
         | 
| 189 182 | 
             
                expect(driver.instance_variable_get(:@session)[:actions]).not_to be_empty
         | 
| 190 183 | 
             
              end
         | 
| @@ -194,7 +187,6 @@ describe Driver do | |
| 194 187 | 
             
                duration = 0.5
         | 
| 195 188 | 
             
                start_coordinates = { x: 1, y: 1 }
         | 
| 196 189 | 
             
                end_coordinates = { x: 2, y: 2 }
         | 
| 197 | 
            -
                expect(Logger).to receive(:info).with("Swipe (#{duration}s):", payload: "#{JSON.pretty_generate(start_coordinates)} => #{JSON.pretty_generate(end_coordinates)}")
         | 
| 198 190 | 
             
                driver_with_session.swipe(start_coordinates: start_coordinates, end_coordinates: end_coordinates, duration: duration)
         | 
| 199 191 | 
             
                expect(driver_with_session.instance_variable_get(:@session)[:actions]).to be_empty
         | 
| 200 192 | 
             
              end
         | 
| @@ -210,12 +202,12 @@ describe Driver do | |
| 210 202 | 
             
                app_info = driver.list_apps.detect { |app| app['bundle_id'] == bundle_id }
         | 
| 211 203 | 
             
                app_is_running = app_info && app_info['process_state'] == 'Running'
         | 
| 212 204 | 
             
                expect(app_is_running).to be(true)
         | 
| 205 | 
            +
                expect(driver.instance_variable_get(:@running_apps)).not_to be_nil
         | 
| 213 206 | 
             
              end
         | 
| 214 207 |  | 
| 215 208 | 
             
              it 'verifies that monkey_test works fine' do
         | 
| 216 209 | 
             
                params = { udid: udid, bundle_id: bundle_id, duration: 1, session_path: Dir.pwd }
         | 
| 217 210 | 
             
                driver = described_class.new(params)
         | 
| 218 | 
            -
                expect(driver).to receive(:monkey_test_precondition)
         | 
| 219 211 | 
             
                driver.monkey_test(Xcmonkey.new(params).gestures)
         | 
| 220 212 | 
             
                expect(driver.instance_variable_get(:@session)[:actions]).not_to be_empty
         | 
| 221 213 | 
             
              end
         | 
| @@ -227,8 +219,6 @@ describe Driver do | |
| 227 219 | 
             
                  { 'type' => 'swipe', 'x' => 12, 'y' => 12, 'endX' => 15, 'endY' => 15, 'duration' => 0.3 }
         | 
| 228 220 | 
             
                ]
         | 
| 229 221 | 
             
                driver = described_class.new(udid: udid, bundle_id: bundle_id, session_actions: session_actions)
         | 
| 230 | 
            -
                allow(Logger).to receive(:info).twice
         | 
| 231 | 
            -
                expect(driver).to receive(:monkey_test_precondition)
         | 
| 232 222 | 
             
                expect(driver).to receive(:tap).with(coordinates: { x: 10, y: 10 })
         | 
| 233 223 | 
             
                expect(driver).to receive(:press).with(coordinates: { x: 11, y: 11 }, duration: 1.4)
         | 
| 234 224 | 
             
                expect(driver).to receive(:swipe).with(start_coordinates: { x: 12, y: 12 }, end_coordinates: { x: 15, y: 15 }, duration: 0.3)
         | 
| @@ -238,7 +228,6 @@ describe Driver do | |
| 238 228 |  | 
| 239 229 | 
             
              it 'verifies that unknown actions does not break repeat_monkey_test' do
         | 
| 240 230 | 
             
                driver = described_class.new(udid: udid, bundle_id: bundle_id, session_actions: [{ 'type' => 'test', 'x' => 10, 'y' => 10 }])
         | 
| 241 | 
            -
                allow(Logger).to receive(:info).twice
         | 
| 242 231 | 
             
                expect(driver).to receive(:monkey_test_precondition)
         | 
| 243 232 | 
             
                expect(driver).not_to receive(:tap)
         | 
| 244 233 | 
             
                expect(driver).not_to receive(:press)
         | 
| @@ -247,6 +236,59 @@ describe Driver do | |
| 247 236 | 
             
                expect(driver.instance_variable_get(:@session)[:actions]).to be_empty
         | 
| 248 237 | 
             
              end
         | 
| 249 238 |  | 
| 239 | 
            +
              it 'verifies that running apps are tracked' do
         | 
| 240 | 
            +
                new_app_bundle_id = 'com.apple.Preferences'
         | 
| 241 | 
            +
                driver.terminate_app(new_app_bundle_id)
         | 
| 242 | 
            +
                driver.monkey_test_precondition
         | 
| 243 | 
            +
                driver.launch_app(target_bundle_id: new_app_bundle_id, wait_for_state_update: true)
         | 
| 244 | 
            +
                expect(driver).to receive(:launch_app).with(target_bundle_id: bundle_id)
         | 
| 245 | 
            +
                expect(driver).to receive(:terminate_app).with(new_app_bundle_id)
         | 
| 246 | 
            +
                driver.track_running_apps
         | 
| 247 | 
            +
              end
         | 
| 248 | 
            +
             | 
| 249 | 
            +
              it 'verifies that running apps can be determined' do
         | 
| 250 | 
            +
                driver.terminate_app(bundle_id)
         | 
| 251 | 
            +
                sum = driver.list_running_apps.size
         | 
| 252 | 
            +
                driver.launch_app(target_bundle_id: bundle_id)
         | 
| 253 | 
            +
                expect(driver.list_running_apps.size).to eq(sum + 1)
         | 
| 254 | 
            +
              end
         | 
| 255 | 
            +
             | 
| 256 | 
            +
              it 'verifies that app state change can be determined' do
         | 
| 257 | 
            +
                driver.launch_app(target_bundle_id: bundle_id)
         | 
| 258 | 
            +
                allow(driver).to receive(:detect_app_in_background).and_return(true)
         | 
| 259 | 
            +
                expect(driver).not_to receive(:save_session)
         | 
| 260 | 
            +
                expect(driver).to receive(:launch_app)
         | 
| 261 | 
            +
                expect { driver.detect_app_state_change }.not_to raise_error
         | 
| 262 | 
            +
              end
         | 
| 263 | 
            +
             | 
| 264 | 
            +
              it 'verifies that background is the invalid app state' do
         | 
| 265 | 
            +
                driver.terminate_app(bundle_id)
         | 
| 266 | 
            +
                expect(driver).to receive(:save_session)
         | 
| 267 | 
            +
                expect { driver.detect_app_state_change }.to raise_error(SystemExit) { |e| expect(e.status).to eq(1) }
         | 
| 268 | 
            +
              end
         | 
| 269 | 
            +
             | 
| 270 | 
            +
              it 'verifies that foreground is the valid app state' do
         | 
| 271 | 
            +
                driver.launch_app(target_bundle_id: bundle_id, wait_for_state_update: true)
         | 
| 272 | 
            +
                expect { driver.detect_app_state_change }.not_to raise_error
         | 
| 273 | 
            +
              end
         | 
| 274 | 
            +
             | 
| 275 | 
            +
              it 'verifies that background state can be determined' do
         | 
| 276 | 
            +
                driver.terminate_app(bundle_id)
         | 
| 277 | 
            +
                expect(driver.detect_app_in_background).to be(true)
         | 
| 278 | 
            +
              end
         | 
| 279 | 
            +
             | 
| 280 | 
            +
              it 'verifies that foregroung state can be determined' do
         | 
| 281 | 
            +
                driver.monkey_test_precondition
         | 
| 282 | 
            +
                expect(driver.detect_app_in_background).to be(false)
         | 
| 283 | 
            +
              end
         | 
| 284 | 
            +
             | 
| 285 | 
            +
              it 'verifies that xcmonkey behaves as expected on real devices' do
         | 
| 286 | 
            +
                udid = '1234-5678'
         | 
| 287 | 
            +
                driver = described_class.new(udid: udid, bundle_id: bundle_id)
         | 
| 288 | 
            +
                allow(driver).to receive(:list_targets).and_return([{ 'udid' => udid, 'type' => 'device' }])
         | 
| 289 | 
            +
                expect { driver.ensure_device_exists }.to raise_error(SystemExit) { |e| expect(e.status).to eq(1) }
         | 
| 290 | 
            +
              end
         | 
| 291 | 
            +
             | 
| 250 292 | 
             
              it 'verifies that simulator was not booted' do
         | 
| 251 293 | 
             
                driver.shutdown_simulator
         | 
| 252 294 | 
             
                error_message = "Failed to boot #{udid}"
         | 
    
        data/spec/xcmonkey_spec.rb
    CHANGED
    
    | @@ -2,6 +2,10 @@ describe Xcmonkey do | |
| 2 2 | 
             
              let(:params) { { udid: '123', bundle_id: 'example.com.app', duration: 10, session_path: Dir.pwd } }
         | 
| 3 3 | 
             
              let(:duration_error_msg) { 'Duration must be Integer and not less than 1 second' }
         | 
| 4 4 |  | 
| 5 | 
            +
              before do
         | 
| 6 | 
            +
                allow(Logger).to receive(:info)
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 5 9 | 
             
              it 'verifies gestures' do
         | 
| 6 10 | 
             
                gestures = described_class.new(params).gestures
         | 
| 7 11 | 
             
                taps = [:precise_tap, :blind_tap] * 10
         | 
    
        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: 1. | 
| 4 | 
            +
              version: 1.2.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-23 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         |