xcmonkey 0.1.2 → 0.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 +4 -4
- data/.github/FUNDING.yml +0 -1
- data/.github/workflows/test.yml +1 -1
- data/README.md +31 -23
- data/assets/images/xcmonkey.png +0 -0
- data/bin/xcmonkey +5 -3
- data/lib/xcmonkey/driver.rb +76 -20
- data/lib/xcmonkey/version.rb +1 -1
- data/lib/xcmonkey.rb +5 -2
- data/spec/driver_spec.rb +86 -4
- data/spec/logger_spec.rb +20 -0
- data/spec/xcmonkey_spec.rb +13 -1
- 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: 48bd9b79b2370e4f20366973e689af344f6c75729b361658fbc5bb2c02c38253
|
4
|
+
data.tar.gz: c207e8dbe7c820623f60a9c0b9e8ea8a7e5bce18bfe10f9d5c27e8928829889d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c0f1f52ad5e8118799556e4e1ba3a49574c504cf2a840fe0369e06c6dbab260fd0a9c275ada9efb789a865759ac48f7d46f9348cde5b2cb53a44969b5189cf9
|
7
|
+
data.tar.gz: 761ffee247c8646bc24dee5fd3f473414402033d3c9a773fe87623579aef93155ecbafc3d412111396945ae485d74b28d6916e5e287754a82b15fcfc792b0c47
|
data/.github/FUNDING.yml
CHANGED
data/.github/workflows/test.yml
CHANGED
data/README.md
CHANGED
@@ -9,9 +9,13 @@
|
|
9
9
|
<a href="/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg?style=flat" /></a>
|
10
10
|
</p>
|
11
11
|
|
12
|
-
|
12
|
+
## Description
|
13
13
|
|
14
|
-
|
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.
|
15
|
+
|
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
|
+
|
18
|
+
## Prerequisites
|
15
19
|
|
16
20
|
```bash
|
17
21
|
brew install facebook/fb/idb-companion
|
@@ -24,22 +28,28 @@ pip3.6 install fb-idb
|
|
24
28
|
gem install xcmonkey
|
25
29
|
```
|
26
30
|
|
31
|
+
If you prefer to use [*bundler*](https://bundler.io/), add the following line to your `Gemfile`:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
gem 'xcmonkey'
|
35
|
+
```
|
36
|
+
|
27
37
|
## Usage
|
28
38
|
|
29
|
-
###
|
39
|
+
### To run a stress test
|
30
40
|
|
31
41
|
```bash
|
32
|
-
$ xcmonkey test --udid "413EA256-CFFB-4312-94A6-12592BEE4CBA" --bundle-id "com.apple.
|
42
|
+
$ xcmonkey test --udid "413EA256-CFFB-4312-94A6-12592BEE4CBA" --bundle-id "com.apple.Maps" --duration 100
|
33
43
|
12:44:19.343: 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
|
34
44
|
|
35
|
-
12:44:22.550: App info: com.apple.
|
45
|
+
12:44:22.550: App info: com.apple.Maps | Maps | system | arm64, x86_64 | Running | Not Debuggable | pid=74636
|
36
46
|
|
37
47
|
12:44:23.203: Tap: {
|
38
48
|
"x": 53,
|
39
49
|
"y": 749
|
40
50
|
}
|
41
51
|
|
42
|
-
12:44:23.511: Swipe: {
|
52
|
+
12:44:23.511: Swipe (0.5s): {
|
43
53
|
"x": 196,
|
44
54
|
"y": 426
|
45
55
|
} => {
|
@@ -47,39 +57,37 @@ $ xcmonkey test --udid "413EA256-CFFB-4312-94A6-12592BEE4CBA" --bundle-id "com.a
|
|
47
57
|
"y": 447
|
48
58
|
}
|
49
59
|
|
50
|
-
12:44:24.355:
|
60
|
+
12:44:24.355: Press (1.2s): {
|
51
61
|
"x": 143,
|
52
62
|
"y": 323
|
53
63
|
}
|
54
64
|
```
|
55
65
|
|
56
|
-
###
|
66
|
+
### To describe the required point
|
57
67
|
|
58
68
|
```bash
|
59
|
-
$ xcmonkey describe -x
|
60
|
-
|
69
|
+
$ xcmonkey describe -x 20 -y 625 --udid "413EA256-CFFB-4312-94A6-12592BEE4CBA"
|
70
|
+
20:05:20.212: 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
|
61
71
|
|
62
|
-
|
63
|
-
"AXFrame": "{{
|
64
|
-
"AXUniqueId": "
|
72
|
+
20:05:21.713: x:20 y:625 point info: {
|
73
|
+
"AXFrame": "{{19, 624.3}, {86, 130.6}}",
|
74
|
+
"AXUniqueId": "ShortcutsRowCell",
|
65
75
|
"frame": {
|
66
|
-
"y":
|
67
|
-
"x":
|
68
|
-
"width":
|
69
|
-
"height":
|
76
|
+
"y": 624.3,
|
77
|
+
"x": 19,
|
78
|
+
"width": 86,
|
79
|
+
"height": 130.6
|
70
80
|
},
|
71
81
|
"role_description": "button",
|
72
|
-
"AXLabel": "
|
82
|
+
"AXLabel": "Home",
|
73
83
|
"content_required": false,
|
74
84
|
"type": "Button",
|
75
85
|
"title": null,
|
76
|
-
"help":
|
86
|
+
"help": null,
|
77
87
|
"custom_actions": [
|
78
|
-
|
79
|
-
"Today",
|
80
|
-
"App Library"
|
88
|
+
|
81
89
|
],
|
82
|
-
"AXValue": "",
|
90
|
+
"AXValue": "Add",
|
83
91
|
"enabled": true,
|
84
92
|
"role": "AXButton",
|
85
93
|
"subrole": null
|
data/assets/images/xcmonkey.png
CHANGED
Binary file
|
data/bin/xcmonkey
CHANGED
@@ -16,13 +16,15 @@ module Xcmonkey
|
|
16
16
|
c.description = 'Runs monkey test'
|
17
17
|
c.option('-u', '--udid STRING', String, 'Set device UDID')
|
18
18
|
c.option('-b', '--bundle-id STRING', String, 'Set target bundle identifier')
|
19
|
-
c.option('-d', '--duration SECONDS', Integer, 'Test duration in seconds')
|
19
|
+
c.option('-d', '--duration SECONDS', Integer, 'Test duration in seconds. Defaults to `60`')
|
20
|
+
c.option('-k', '--enable-simulator-keyboard', 'Should simulator keyboard be enabled? Defaults to `true`')
|
20
21
|
c.action do |args, options|
|
21
|
-
options.default(duration: 60)
|
22
|
+
options.default(duration: 60, enable_simulator_keyboard: true)
|
22
23
|
params = {
|
23
24
|
udid: options.udid,
|
24
25
|
bundle_id: options.bundle_id,
|
25
|
-
duration: options.duration
|
26
|
+
duration: options.duration,
|
27
|
+
simulator_keyboard: options.enable_simulator_keyboard
|
26
28
|
}
|
27
29
|
Xcmonkey.new(params).run
|
28
30
|
end
|
data/lib/xcmonkey/driver.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
class Driver
|
2
|
-
attr_accessor :udid, :bundle_id, :duration
|
2
|
+
attr_accessor :udid, :bundle_id, :duration, :enable_simulator_keyboard
|
3
3
|
|
4
4
|
def initialize(params)
|
5
5
|
self.udid = params[:udid]
|
6
6
|
self.bundle_id = params[:bundle_id]
|
7
7
|
self.duration = params[:duration]
|
8
|
+
self.enable_simulator_keyboard = params[:enable_simulator_keyboard]
|
8
9
|
ensure_driver_installed
|
9
10
|
end
|
10
11
|
|
@@ -18,11 +19,23 @@ class Driver
|
|
18
19
|
when :precise_tap
|
19
20
|
tap(coordinates: el1_coordinates)
|
20
21
|
when :blind_tap
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
when :
|
25
|
-
|
22
|
+
tap(coordinates: random_coordinates)
|
23
|
+
when :precise_press
|
24
|
+
press(coordinates: el1_coordinates, duration: press_duration)
|
25
|
+
when :blind_press
|
26
|
+
press(coordinates: random_coordinates, duration: press_duration)
|
27
|
+
when :precise_swipe
|
28
|
+
swipe(
|
29
|
+
start_coordinates: el1_coordinates,
|
30
|
+
end_coordinates: el2_coordinates,
|
31
|
+
duration: swipe_duration
|
32
|
+
)
|
33
|
+
when :blind_swipe
|
34
|
+
swipe(
|
35
|
+
start_coordinates: random_coordinates,
|
36
|
+
end_coordinates: random_coordinates,
|
37
|
+
duration: swipe_duration
|
38
|
+
)
|
26
39
|
else
|
27
40
|
next
|
28
41
|
end
|
@@ -31,9 +44,9 @@ class Driver
|
|
31
44
|
end
|
32
45
|
end
|
33
46
|
|
34
|
-
def open_home_screen(
|
47
|
+
def open_home_screen(with_tracker: false)
|
35
48
|
`idb ui button --udid #{udid} HOME`
|
36
|
-
detect_home_unique_element if
|
49
|
+
detect_home_unique_element if with_tracker
|
37
50
|
end
|
38
51
|
|
39
52
|
def describe_ui
|
@@ -57,13 +70,19 @@ class Driver
|
|
57
70
|
|
58
71
|
def boot_simulator
|
59
72
|
`idb boot #{udid}`
|
60
|
-
|
73
|
+
Logger.error("Failed to boot #{udid}") if device_info['state'] != 'Booted'
|
61
74
|
end
|
62
75
|
|
63
76
|
def shutdown_simulator
|
64
77
|
`idb shutdown #{udid}`
|
65
78
|
end
|
66
79
|
|
80
|
+
def configure_simulator_keyboard
|
81
|
+
shutdown_simulator
|
82
|
+
keyboard_status = enable_simulator_keyboard ? 0 : 1
|
83
|
+
`defaults write com.apple.iphonesimulator ConnectHardwareKeyboard #{keyboard_status}`
|
84
|
+
end
|
85
|
+
|
67
86
|
def list_targets
|
68
87
|
@list_targets ||= `idb list-targets`.split("\n")
|
69
88
|
@list_targets
|
@@ -80,13 +99,12 @@ class Driver
|
|
80
99
|
def ensure_device_exists
|
81
100
|
device = list_targets.detect { |target| target.include?(udid) }
|
82
101
|
Logger.error("Can't find device #{udid}") if device.nil?
|
83
|
-
Logger.info('Device info:', payload: device)
|
84
|
-
boot_simulator if device.include?('simulator')
|
85
|
-
end
|
86
102
|
|
87
|
-
|
88
|
-
|
89
|
-
|
103
|
+
Logger.info('Device info:', payload: device)
|
104
|
+
if device.include?('simulator')
|
105
|
+
configure_simulator_keyboard
|
106
|
+
boot_simulator
|
107
|
+
end
|
90
108
|
end
|
91
109
|
|
92
110
|
def list_apps
|
@@ -98,20 +116,58 @@ class Driver
|
|
98
116
|
`idb ui tap --udid #{udid} #{coordinates[:x]} #{coordinates[:y]}`
|
99
117
|
end
|
100
118
|
|
101
|
-
def
|
102
|
-
Logger.info(
|
119
|
+
def press(coordinates:, duration:)
|
120
|
+
Logger.info("Press (#{duration}s):", payload: JSON.pretty_generate(coordinates))
|
121
|
+
`idb ui tap --udid #{udid} --duration #{duration} #{coordinates[:x]} #{coordinates[:y]}`
|
122
|
+
end
|
123
|
+
|
124
|
+
def swipe(start_coordinates:, end_coordinates:, duration:)
|
125
|
+
Logger.info(
|
126
|
+
"Swipe (#{duration}s):",
|
127
|
+
payload: "#{JSON.pretty_generate(start_coordinates)} => #{JSON.pretty_generate(end_coordinates)}"
|
128
|
+
)
|
103
129
|
coordinates = "#{start_coordinates[:x]} #{start_coordinates[:y]} #{end_coordinates[:x]} #{end_coordinates[:y]}"
|
104
|
-
`idb ui swipe --udid #{udid} --duration
|
130
|
+
`idb ui swipe --udid #{udid} --duration #{duration} #{coordinates}`
|
105
131
|
end
|
106
132
|
|
107
133
|
def central_coordinates(element)
|
108
134
|
frame = element['frame']
|
135
|
+
x = (frame['x'] + (frame['width'] / 2)).abs.to_i
|
136
|
+
y = (frame['y'] + (frame['height'] / 2)).abs.to_i
|
137
|
+
{
|
138
|
+
x: x > screen_size[:width].to_i ? rand(0..screen_size[:width].to_i) : x,
|
139
|
+
y: y > screen_size[:height].to_i ? rand(0..screen_size[:height].to_i) : y
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
def random_coordinates
|
109
144
|
{
|
110
|
-
x: (
|
111
|
-
y: (
|
145
|
+
x: rand(0..screen_size[:width].to_i),
|
146
|
+
y: rand(0..screen_size[:height].to_i)
|
112
147
|
}
|
113
148
|
end
|
114
149
|
|
150
|
+
def device_info
|
151
|
+
@device_info ||= JSON.parse(`idb describe --udid #{udid} --json`)
|
152
|
+
@device_info
|
153
|
+
end
|
154
|
+
|
155
|
+
def screen_size
|
156
|
+
screen_dimensions = device_info['screen_dimensions']
|
157
|
+
{
|
158
|
+
width: screen_dimensions['width_points'],
|
159
|
+
height: screen_dimensions['height_points']
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
def swipe_duration
|
164
|
+
rand(0.1..0.7).ceil(1)
|
165
|
+
end
|
166
|
+
|
167
|
+
def press_duration
|
168
|
+
rand(0.5..1.5).ceil(1)
|
169
|
+
end
|
170
|
+
|
115
171
|
private
|
116
172
|
|
117
173
|
def ensure_driver_installed
|
data/lib/xcmonkey/version.rb
CHANGED
data/lib/xcmonkey.rb
CHANGED
@@ -21,13 +21,16 @@ module Xcmonkey
|
|
21
21
|
driver.ensure_device_exists
|
22
22
|
driver.ensure_app_installed
|
23
23
|
driver.terminate_app
|
24
|
-
driver.open_home_screen(
|
24
|
+
driver.open_home_screen(with_tracker: true)
|
25
25
|
driver.launch_app
|
26
26
|
driver.monkey_test(gestures)
|
27
27
|
end
|
28
28
|
|
29
29
|
def gestures
|
30
|
-
[:precise_tap, :blind_tap
|
30
|
+
taps = [:precise_tap, :blind_tap] * 10
|
31
|
+
swipes = [:precise_swipe, :blind_swipe] * 5
|
32
|
+
presses = [:precise_press, :blind_press]
|
33
|
+
taps + swipes + presses
|
31
34
|
end
|
32
35
|
|
33
36
|
def ensure_required_params(params)
|
data/spec/driver_spec.rb
CHANGED
@@ -6,8 +6,7 @@ describe Driver do
|
|
6
6
|
it 'verifies that sumulator was booted' do
|
7
7
|
error_message = "Failed to boot #{udid}"
|
8
8
|
expect(Logger).not_to receive(:error).with(error_message, payload: nil)
|
9
|
-
expect
|
10
|
-
driver.boot_simulator
|
9
|
+
expect { driver.boot_simulator }.not_to raise_error
|
11
10
|
end
|
12
11
|
|
13
12
|
it 'verifies that there are booted simulators' do
|
@@ -24,10 +23,16 @@ describe Driver do
|
|
24
23
|
|
25
24
|
it 'verifies that home screen can be opened' do
|
26
25
|
driver.boot_simulator
|
27
|
-
home_tracker = driver.open_home_screen(
|
26
|
+
home_tracker = driver.open_home_screen(with_tracker: true)
|
28
27
|
expect(home_tracker).not_to be_empty
|
29
28
|
end
|
30
29
|
|
30
|
+
it 'verifies that home screen can be opened without tracker' do
|
31
|
+
driver.boot_simulator
|
32
|
+
home_tracker = driver.open_home_screen(with_tracker: false)
|
33
|
+
expect(home_tracker).to be_nil
|
34
|
+
end
|
35
|
+
|
31
36
|
it 'verifies that list of targets can be showed' do
|
32
37
|
list_targets = driver.list_targets
|
33
38
|
expect(list_targets).not_to be_empty
|
@@ -85,6 +90,58 @@ describe Driver do
|
|
85
90
|
expect(actual_coordinates).to eq(expected_coordinates)
|
86
91
|
end
|
87
92
|
|
93
|
+
it 'verifies that device info can be for booted simulator' do
|
94
|
+
driver.boot_simulator
|
95
|
+
expect(driver.device_info).not_to be_empty
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'verifies that device info can be for not booted simulator' do
|
99
|
+
driver.shutdown_simulator
|
100
|
+
expect(driver.device_info).not_to be_empty
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'verifies that screen size can be found' do
|
104
|
+
driver.boot_simulator
|
105
|
+
screen_size = driver.screen_size
|
106
|
+
expect(screen_size[:width]).to be > 0
|
107
|
+
expect(screen_size[:height]).to be > 0
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'verifies that random coordinates can be found' do
|
111
|
+
driver.boot_simulator
|
112
|
+
coordinates = driver.random_coordinates
|
113
|
+
expect(coordinates[:x]).to be > 0
|
114
|
+
expect(coordinates[:y]).to be > 0
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'verifies swipe duration' do
|
118
|
+
expect(driver.swipe_duration).to be_between(0.1, 0.7)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'verifies press duration' do
|
122
|
+
expect(driver.press_duration).to be_between(0.5, 1.5)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'verifies that simulator keyboard can be enabled' do
|
126
|
+
allow(driver).to receive(:is_simulator_keyboard_enabled?).and_return(false)
|
127
|
+
driver = described_class.new(udid: udid, bundle_id: bundle_id, enable_simulator_keyboard: true)
|
128
|
+
expect(driver).to receive(:shutdown_simulator)
|
129
|
+
driver.configure_simulator_keyboard
|
130
|
+
keyboard_state = `defaults read com.apple.iphonesimulator`.split("\n").grep(/ConnectHardwareKeyboard/)
|
131
|
+
expect(keyboard_state).not_to be_empty
|
132
|
+
expect(keyboard_state.first).to include('0')
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'verifies that simulator keyboard can be disabled' do
|
136
|
+
allow(driver).to receive(:is_simulator_keyboard_enabled?).and_return(true)
|
137
|
+
driver = described_class.new(udid: udid, bundle_id: bundle_id, enable_simulator_keyboard: false)
|
138
|
+
expect(driver).to receive(:shutdown_simulator)
|
139
|
+
driver.configure_simulator_keyboard
|
140
|
+
keyboard_state = `defaults read com.apple.iphonesimulator`.split("\n").grep(/ConnectHardwareKeyboard/)
|
141
|
+
expect(keyboard_state).not_to be_empty
|
142
|
+
expect(keyboard_state.first).to include('1')
|
143
|
+
end
|
144
|
+
|
88
145
|
it 'verifies that app can be launched' do
|
89
146
|
expect(Logger).not_to receive(:error)
|
90
147
|
expect(Logger).to receive(:info)
|
@@ -93,10 +150,35 @@ describe Driver do
|
|
93
150
|
expect { driver.launch_app }.not_to raise_error
|
94
151
|
end
|
95
152
|
|
153
|
+
it 'verifies tap' do
|
154
|
+
driver.boot_simulator
|
155
|
+
coordinates = { x: 1, y: 1 }
|
156
|
+
expect(Logger).to receive(:info).with('Tap:', payload: JSON.pretty_generate(coordinates))
|
157
|
+
driver.tap(coordinates: coordinates)
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'verifies press' do
|
161
|
+
driver.boot_simulator
|
162
|
+
duration = 0.5
|
163
|
+
coordinates = { x: 1, y: 1 }
|
164
|
+
expect(Logger).to receive(:info).with("Press (#{duration}s):", payload: JSON.pretty_generate(coordinates))
|
165
|
+
driver.press(coordinates: coordinates, duration: duration)
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'verifies swipe' do
|
169
|
+
driver.boot_simulator
|
170
|
+
duration = 0.5
|
171
|
+
start_coordinates = { x: 1, y: 1 }
|
172
|
+
end_coordinates = { x: 2, y: 2 }
|
173
|
+
expect(Logger).to receive(:info).with("Swipe (#{duration}s):", payload: "#{JSON.pretty_generate(start_coordinates)} => #{JSON.pretty_generate(end_coordinates)}")
|
174
|
+
driver.swipe(start_coordinates: start_coordinates, end_coordinates: end_coordinates, duration: duration)
|
175
|
+
end
|
176
|
+
|
96
177
|
it 'verifies that simulator was not booted' do
|
97
178
|
driver.shutdown_simulator
|
98
179
|
error_message = "Failed to boot #{udid}"
|
180
|
+
allow(driver).to receive(:device_info).and_return({ 'state' => 'Unknown' })
|
99
181
|
expect(Logger).to receive(:log).with(error_message, color: :light_red, payload: nil)
|
100
|
-
expect { driver.
|
182
|
+
expect { driver.boot_simulator }.to raise_error(SystemExit) { |e| expect(e.status).to eq(1) }
|
101
183
|
end
|
102
184
|
end
|
data/spec/logger_spec.rb
CHANGED
@@ -33,4 +33,24 @@ describe Logger do
|
|
33
33
|
expect { described_class.error(message, payload: payload) }
|
34
34
|
.to raise_error(SystemExit) { |e| expect(e.status).to eq(1) }
|
35
35
|
end
|
36
|
+
|
37
|
+
it 'verifies custom log without payload' do
|
38
|
+
color = :blue
|
39
|
+
time = Time.now
|
40
|
+
allow(Time).to receive(:now).and_return(time)
|
41
|
+
expected_output = "#{time.strftime('%k:%M:%S.%L')}: #{message}".colorize(color)
|
42
|
+
expect do
|
43
|
+
described_class.log(message, color: color, payload: nil)
|
44
|
+
end.to output("#{expected_output}\n\n").to_stdout
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'verifies custom log with payload' do
|
48
|
+
color = :blue
|
49
|
+
time = Time.now
|
50
|
+
allow(Time).to receive(:now).and_return(time)
|
51
|
+
expected_output = "#{time.strftime('%k:%M:%S.%L')}: #{message}".colorize(color)
|
52
|
+
expect do
|
53
|
+
described_class.log(message, color: color, payload: payload)
|
54
|
+
end.to output("#{expected_output} #{payload.colorize(:light_green)}\n\n").to_stdout
|
55
|
+
end
|
36
56
|
end
|
data/spec/xcmonkey_spec.rb
CHANGED
@@ -5,7 +5,10 @@ describe Xcmonkey do
|
|
5
5
|
|
6
6
|
it 'verifies gestures' do
|
7
7
|
gestures = described_class.new(params).gestures
|
8
|
-
|
8
|
+
taps = [:precise_tap, :blind_tap] * 10
|
9
|
+
swipes = [:precise_swipe, :blind_swipe] * 5
|
10
|
+
presses = [:precise_press, :blind_press]
|
11
|
+
expect(gestures) =~ presses + taps + swipes
|
9
12
|
end
|
10
13
|
|
11
14
|
it 'verifies required params' do
|
@@ -42,5 +45,14 @@ describe Xcmonkey do
|
|
42
45
|
expect(Logger).to receive(:error).with(duration_error_msg)
|
43
46
|
described_class.new(params)
|
44
47
|
end
|
48
|
+
|
49
|
+
it 'verifies version' do
|
50
|
+
current_version = Gem::Version.new(Xcmonkey::VERSION)
|
51
|
+
expect(current_version).to be > Gem::Version.new('0.1.0')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'verifies gem name' do
|
55
|
+
expect(Xcmonkey::GEM_NAME).to eq('xcmonkey')
|
56
|
+
end
|
45
57
|
end
|
46
58
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xcmonkey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.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:
|
11
|
+
date: 2023-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|