smart_monkey 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +1 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +21 -0
- data/README.md +77 -0
- data/Rakefile +57 -0
- data/Troubleshooting.md +61 -0
- data/VERSION +1 -0
- data/bin/smart_monkey +53 -0
- data/lib/bootstrap/css/bootstrap-responsive.css +1109 -0
- data/lib/bootstrap/css/bootstrap-responsive.min.css +9 -0
- data/lib/bootstrap/css/bootstrap.css +6167 -0
- data/lib/bootstrap/css/bootstrap.min.css +9 -0
- data/lib/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/lib/bootstrap/img/glyphicons-halflings.png +0 -0
- data/lib/bootstrap/js/bootstrap.js +2280 -0
- data/lib/bootstrap/js/bootstrap.min.js +6 -0
- data/lib/ios_device_log/deviceconsole +0 -0
- data/lib/smart_monkey.rb +2 -0
- data/lib/smart_monkey/command_helper.rb +71 -0
- data/lib/smart_monkey/monkey_runner.rb +549 -0
- data/lib/smart_monkey/templates/automation_result.xsl +61 -0
- data/lib/smart_monkey/templates/index.html.erb +77 -0
- data/lib/smart_monkey/templates/result.html.erb +110 -0
- data/lib/smart_monkey/templates/result_view.coffee +160 -0
- data/lib/smart_monkey/templates/result_view.js +250 -0
- data/lib/ui-auto-monkey/UIAutoMonkey.js +470 -0
- data/lib/ui-auto-monkey/custom.js +73 -0
- data/lib/ui-auto-monkey/handler/buttonHandler.js +111 -0
- data/lib/ui-auto-monkey/handler/wbScrollViewButtonHandler.js +114 -0
- data/lib/ui-auto-monkey/tuneup/LICENSE +20 -0
- data/lib/ui-auto-monkey/tuneup/assertions.js +402 -0
- data/lib/ui-auto-monkey/tuneup/image_asserter +26 -0
- data/lib/ui-auto-monkey/tuneup/image_assertion.js +65 -0
- data/lib/ui-auto-monkey/tuneup/image_assertion.rb +102 -0
- data/lib/ui-auto-monkey/tuneup/lang-ext.js +76 -0
- data/lib/ui-auto-monkey/tuneup/screen.js +11 -0
- data/lib/ui-auto-monkey/tuneup/test.js +71 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/abbreviated_console_output.rb +38 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/colored_console_output.rb +27 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/console_output.rb +17 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/preprocessor.rb +25 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/run +343 -0
- data/lib/ui-auto-monkey/tuneup/test_runner/xunit_output.rb +114 -0
- data/lib/ui-auto-monkey/tuneup/tuneup.js +6 -0
- data/lib/ui-auto-monkey/tuneup/tuneup_js.podspec +52 -0
- data/lib/ui-auto-monkey/tuneup/uiautomation-ext.js +965 -0
- data/smart_monkey.gemspec +112 -0
- data/spec/spec_helper.rb +12 -0
- metadata +192 -0
@@ -0,0 +1,470 @@
|
|
1
|
+
// Copyright (c) 2013 Jonathan Penn (http://cocoamanifest.net/)
|
2
|
+
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
// of this software and associated documentation files (the "Software"), to deal
|
5
|
+
// in the Software without restriction, including without limitation the rights
|
6
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
// copies of the Software, and to permit persons to whom the Software is
|
8
|
+
// furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
// The above copyright notice and this permission notice shall be included in
|
11
|
+
// all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
// THE SOFTWARE.
|
20
|
+
|
21
|
+
"use strict";
|
22
|
+
|
23
|
+
function UIAutoMonkey() {
|
24
|
+
|
25
|
+
|
26
|
+
this.config = {
|
27
|
+
//run either by minutesToRun or numberOfEvents. Only one of these can set. (To use minutes you can use config.numberOfEvents = 0)
|
28
|
+
//minutesToRun = 60 * 8; //sample to run for 8 hours.
|
29
|
+
//checkTimeEvery = 60; //how often to check (in events) if minutesToRun has is used.
|
30
|
+
numberOfEvents: 100000,
|
31
|
+
delayBetweenEvents: 0.05, // In seconds
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Sometimes the monkey can fall into UI Holes from which it it is hard to escape. The monkey may then spend an inordinate
|
35
|
+
* amount of time in such holes, neglecting other parts of the application.
|
36
|
+
*
|
37
|
+
* For example, if a parent Window P has a large image
|
38
|
+
* and clicking on the image opens a child window C from which one exits by tapping a small X on the top right, then until that small X is
|
39
|
+
* tapped we will reamin in C. conditionHandlers offer the developer the option to periodically recognize that we are in C and press the X.
|
40
|
+
*
|
41
|
+
* See buttonHandler.js for a specialized conditionHandler useful when a top level button can be used to escape from a UI hole.
|
42
|
+
*
|
43
|
+
* conditionHandlers are objects that respond to the following methods:
|
44
|
+
* isTrue(target, eventNumber): returns True if the condition is true given target and event number eventNumber.
|
45
|
+
* checkEvery(): How many events should pass before we check.
|
46
|
+
* handle(target, mainWindow) handle the condition.
|
47
|
+
* isExclusive() if true then if this condition's handler is invoked then processing subsequent conditions is skipped for this particular event. This
|
48
|
+
* is usually set to true as it allows the condition to exit a UI hole and at that point there may be no point executing other conditions
|
49
|
+
* logStats() log statics using UIALogger;
|
50
|
+
* condition handers must have the following property
|
51
|
+
* statsHandleInvokedCount - the count of the number of times we were invoked
|
52
|
+
*/
|
53
|
+
|
54
|
+
conditionHandlers: [],
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Unfortunately if the application is not responsive "ANR", the monkey may not notice and continue to fire events not realizing that
|
58
|
+
* the application is stuck. When run via continuous integration users may not notice that "successful" monkey runs in fact were in an
|
59
|
+
* ANR state.
|
60
|
+
*
|
61
|
+
* To deal with this the monkey supports ANR detection. Using an anrFingerprint function it periodically takes a fingerprint and if these
|
62
|
+
* are identical for a specificed interval then an ANR exception is thrown.
|
63
|
+
*
|
64
|
+
*
|
65
|
+
*/
|
66
|
+
anrSettings: {
|
67
|
+
//fingerprintFunction defaults to false which will disable ANR fingerprinting. Otherwise set to a function that will return
|
68
|
+
//a string. One useful idiom using tuneup.js is
|
69
|
+
//#import tuneup.js
|
70
|
+
//config.anrSettings.fingerprintFunction = function() {return logVisibleElementTreeJSON(false)};
|
71
|
+
fingerprintFunction: false,
|
72
|
+
eventsBeforeANRDeclared: 1500, //throw exception if the fingerprint hasn't changed within this number of events
|
73
|
+
eventsBetweenSnapshots: 150, //how often (in events) to take a snapshot using the fingerprintFunction
|
74
|
+
debug: false //if true extra logging is made
|
75
|
+
},
|
76
|
+
|
77
|
+
// If the following line is uncommented, then screenshots are taken
|
78
|
+
// every "n" seconds.
|
79
|
+
screenshotInterval: 5,
|
80
|
+
|
81
|
+
// Events are triggered based on the relative weights here. The event
|
82
|
+
// with this highest number gets triggered the most.
|
83
|
+
//
|
84
|
+
// If you want to add your own "events", check out the event method
|
85
|
+
// definitions below.
|
86
|
+
eventWeights: {
|
87
|
+
tap: 500,
|
88
|
+
drag: 10,
|
89
|
+
flick: 1,
|
90
|
+
orientation: 1,
|
91
|
+
clickVolumeUp: 1,
|
92
|
+
clickVolumeDown: 1,
|
93
|
+
lock: 1,
|
94
|
+
pinchClose: 10,
|
95
|
+
pinchOpen: 10,
|
96
|
+
shake: 1
|
97
|
+
},
|
98
|
+
|
99
|
+
// Probability that touch events will have these different properties
|
100
|
+
touchProbability: {
|
101
|
+
multipleTaps: 0.05,
|
102
|
+
multipleTouches: 0.05,
|
103
|
+
longPress: 0.05
|
104
|
+
}
|
105
|
+
|
106
|
+
|
107
|
+
// Uncomment the following to restrict events to a rectangluar area of
|
108
|
+
// the screen
|
109
|
+
/*
|
110
|
+
frame: {
|
111
|
+
origin: {x: 0, y: 0},
|
112
|
+
size: {width: 100, height: 50}
|
113
|
+
}
|
114
|
+
*/
|
115
|
+
|
116
|
+
};
|
117
|
+
|
118
|
+
// Dismiss alerts
|
119
|
+
UIATarget.onAlert = function onAlert(alert) {
|
120
|
+
var title = alert.name();
|
121
|
+
UIALogger.logMessage('On Alert: ' + title);
|
122
|
+
return true;
|
123
|
+
}
|
124
|
+
|
125
|
+
}
|
126
|
+
|
127
|
+
// --- --- --- ---
|
128
|
+
// Event Methods
|
129
|
+
//
|
130
|
+
// Any event probability in the hash above corresponds to a related event
|
131
|
+
// method below. So, a "tap" probability will trigger a "tap" method.
|
132
|
+
//
|
133
|
+
// If you want to add your own events, just add a probability to the hash
|
134
|
+
// above and then add a corresponding method below. Boom!
|
135
|
+
//
|
136
|
+
// Each event method can call any other method on this UIAutoMonkey object.
|
137
|
+
// All the methods at the end are helpers at your disposal and feel free to
|
138
|
+
// add your own.
|
139
|
+
|
140
|
+
UIAutoMonkey.prototype.allEvents = {
|
141
|
+
tap: function() {
|
142
|
+
this.target().tapWithOptions(
|
143
|
+
{ x: this.randomX(), y: this.randomY() },
|
144
|
+
{
|
145
|
+
tapCount: this.randomTapCount(),
|
146
|
+
touchCount: this.randomTouchCount(),
|
147
|
+
duration: this.randomTapDuration()
|
148
|
+
}
|
149
|
+
);
|
150
|
+
},
|
151
|
+
|
152
|
+
drag: function() {
|
153
|
+
this.target().dragFromToForDuration(
|
154
|
+
{ x: this.randomX(), y: this.randomY() },
|
155
|
+
{ x: this.randomX(), y: this.randomY() },
|
156
|
+
0.5
|
157
|
+
);
|
158
|
+
},
|
159
|
+
|
160
|
+
flick: function() {
|
161
|
+
this.target().flickFromTo(
|
162
|
+
{ x: this.randomX(), y: this.randomY() },
|
163
|
+
{ x: this.randomX(), y: this.randomY() }
|
164
|
+
);
|
165
|
+
},
|
166
|
+
|
167
|
+
orientation: function() {
|
168
|
+
var orientations = [
|
169
|
+
UIA_DEVICE_ORIENTATION_PORTRAIT,
|
170
|
+
UIA_DEVICE_ORIENTATION_PORTRAIT_UPSIDEDOWN,
|
171
|
+
UIA_DEVICE_ORIENTATION_LANDSCAPELEFT,
|
172
|
+
UIA_DEVICE_ORIENTATION_LANDSCAPERIGHT
|
173
|
+
];
|
174
|
+
|
175
|
+
var i = Math.floor(Math.random() * 10) % orientations.length;
|
176
|
+
var newOrientation = orientations[i];
|
177
|
+
this.target().setDeviceOrientation(newOrientation);
|
178
|
+
this.delay(0.9);
|
179
|
+
},
|
180
|
+
|
181
|
+
clickVolumeUp: function() {
|
182
|
+
this.target().clickVolumeUp();
|
183
|
+
},
|
184
|
+
|
185
|
+
clickVolumeDown: function() {
|
186
|
+
this.target().clickVolumeUp();
|
187
|
+
},
|
188
|
+
|
189
|
+
lock: function() {
|
190
|
+
this.target().lockForDuration(Math.random() * 3);
|
191
|
+
},
|
192
|
+
|
193
|
+
pinchClose: function () {
|
194
|
+
this.target().pinchCloseFromToForDuration(
|
195
|
+
{ x: this.randomX(), y: this.randomY() },
|
196
|
+
{ x: this.randomX(), y: this.randomY() },
|
197
|
+
0.5
|
198
|
+
);
|
199
|
+
},
|
200
|
+
|
201
|
+
pinchOpen: function () {
|
202
|
+
this.target().pinchOpenFromToForDuration(
|
203
|
+
{ x: this.randomX(), y: this.randomY() },
|
204
|
+
{ x: this.randomX(), y: this.randomY() },
|
205
|
+
0.5
|
206
|
+
);
|
207
|
+
},
|
208
|
+
|
209
|
+
shake: function() {
|
210
|
+
this.target().shake();
|
211
|
+
}
|
212
|
+
};
|
213
|
+
|
214
|
+
// --- --- --- ---
|
215
|
+
// Helper methods
|
216
|
+
//
|
217
|
+
UIAutoMonkey.prototype.RELEASE_THE_MONKEY = function() {
|
218
|
+
// Called at the bottom of this script to, you know...
|
219
|
+
//
|
220
|
+
// RELEASE THE MONKEY!
|
221
|
+
try{
|
222
|
+
if (this.config.minutesToRun && this.config.numberOfEvents) {
|
223
|
+
throw "invalid configuration. You cannot define both minutesToRun and numberOfEvents"
|
224
|
+
}
|
225
|
+
var conditionHandlers = this.config.conditionHandlers || []; //For legacy configs, if not present default to empty.
|
226
|
+
var useConditionHandlers = conditionHandlers.length > 0;
|
227
|
+
var checkTime = false;
|
228
|
+
var localNumberOfEvents = this.config.numberOfEvents; //we may modify so we want to leave config untouched
|
229
|
+
if (this.config.minutesToRun) {
|
230
|
+
checkTime = true;
|
231
|
+
localNumberOfEvents = 2000000000;
|
232
|
+
var startTime = new Date().getTime();
|
233
|
+
var checkTimeEvery = this.config.checkTimeEvery || 60; //number of events to pass before we check the time
|
234
|
+
}
|
235
|
+
//setup anr parameters as needed
|
236
|
+
var anrFingerprintFunction = this.config.anrSettings ? this.config.anrSettings.fingerprintFunction : false; //handle legacy settings missing this
|
237
|
+
if (anrFingerprintFunction) {
|
238
|
+
this.anrSnapshot = "Initial snapshot-nothing should match this!!";
|
239
|
+
this.anrSnapshotTakenAtIndex = -1;
|
240
|
+
var anrEventsBetweenSnapshots = this.config.anrSettings.eventsBetweenSnapshots || 300;
|
241
|
+
var anrDebug = this.config.anrSettings.debug;
|
242
|
+
this.anrMaxElapsedCount = -1;
|
243
|
+
}
|
244
|
+
|
245
|
+
UIALogger.logMessage(JSON.stringify(UIATarget.localTarget().rect().size));
|
246
|
+
|
247
|
+
for (var i = 0; i < localNumberOfEvents; i++) {
|
248
|
+
if (checkTime && (i % checkTimeEvery == 0)) { //check the time if needed
|
249
|
+
var currTime = new Date().getTime();
|
250
|
+
var elapsedMinutes = (currTime-startTime) / 60000;
|
251
|
+
if (elapsedMinutes >= this.config.minutesToRun) {
|
252
|
+
UIALogger.logDebug("Ending monkey after " + elapsedMinutes + " minutes run time.");
|
253
|
+
break;
|
254
|
+
} else {
|
255
|
+
UIALogger.logDebug(this.config.minutesToRun - elapsedMinutes + " minutes left to run.")
|
256
|
+
}
|
257
|
+
}
|
258
|
+
this.triggerRandomEvent();
|
259
|
+
if (anrFingerprintFunction && (i % anrEventsBetweenSnapshots == 0)) this.anrCheck(i, anrFingerprintFunction, anrDebug);
|
260
|
+
// if (this.config.screenshotInterval) this.takeScreenShotIfItIsTime();
|
261
|
+
// this.takeScreenShotIfItIsTime();
|
262
|
+
if (useConditionHandlers) this.processConditionHandlers(conditionHandlers, i+1, this.target());
|
263
|
+
this.delay();
|
264
|
+
}
|
265
|
+
// publish stats if warranted
|
266
|
+
if (anrFingerprintFunction) {
|
267
|
+
UIALogger.logDebug("ANR Statistics");
|
268
|
+
UIALogger.logDebug("ANR max event count for identical fingerprint snapshots :: events before ANR declared: " + this.anrMaxElapsedCount + " :: " + this.config.anrSettings.eventsBeforeANRDeclared);
|
269
|
+
}
|
270
|
+
|
271
|
+
if (useConditionHandlers) {
|
272
|
+
UIALogger.logDebug("ConditionHandler Statistics")
|
273
|
+
conditionHandlers.forEach(function(aHandler) {aHandler.logStats()});
|
274
|
+
conditionHandlers.sort(function(aHandler, bHandler) {return aHandler.statsHandleInvokedCount - bHandler.statsHandleInvokedCount});
|
275
|
+
UIALogger.logDebug("sorted by HandleInvokedCount");
|
276
|
+
conditionHandlers.forEach(function(aHandler) {UIALogger.logDebug(aHandler + ": " + aHandler.statsHandleInvokedCount)});
|
277
|
+
}
|
278
|
+
}finally{
|
279
|
+
UIALogger.logDebug("MonkeyTest finish.");
|
280
|
+
}
|
281
|
+
};
|
282
|
+
|
283
|
+
|
284
|
+
UIAutoMonkey.prototype.anrCheck = function(i, fingerprintFunction, debugFlag){
|
285
|
+
|
286
|
+
var newSnapshot = fingerprintFunction();
|
287
|
+
if (newSnapshot != this.anrSnapshot) {
|
288
|
+
//all is good, we're moving along
|
289
|
+
if (debugFlag) UIALogger.logDebug("UIAutoMonkey:anrCheck(): snapshot != for event " + i);
|
290
|
+
this.anrSnapshot = newSnapshot;
|
291
|
+
this.anrSnapshotTakenAtIndex = i;
|
292
|
+
}
|
293
|
+
else {
|
294
|
+
//have a match
|
295
|
+
//for how many counts?
|
296
|
+
var elapsedCount = i - this.anrSnapshotTakenAtIndex;
|
297
|
+
this.anrMaxElapsedCount = Math.max(this.anrMaxElapsedCount, elapsedCount);
|
298
|
+
UIALogger.logDebug("UIAutoMonkey:anrCheck(): snapshot == with elapsed count=" + elapsedCount);
|
299
|
+
if (elapsedCount > this.config.anrSettings.eventsBeforeANRDeclared) {
|
300
|
+
UIALogger.logDebug("duplicate snapshot detected" + this.anrSnapshot);
|
301
|
+
throw "anr exception-identical after " + elapsedCount + " events";
|
302
|
+
};
|
303
|
+
};
|
304
|
+
};
|
305
|
+
|
306
|
+
|
307
|
+
UIAutoMonkey.prototype.processConditionHandlers = function(conditionHandlers, eventNumberPlus1, target) {
|
308
|
+
var mainWindow = target.frontMostApp().mainWindow(); //optimization to let handlers do less work. Assumes isTrue() doesn't alter the mainWindow.
|
309
|
+
for (var i = 0; i < conditionHandlers.length; i++) {
|
310
|
+
var aCondition = conditionHandlers[i];
|
311
|
+
if ((eventNumberPlus1 % aCondition.checkEvery()) != 0) {
|
312
|
+
continue; //not yet time to process aCondition.
|
313
|
+
}
|
314
|
+
try {
|
315
|
+
UIATarget.localTarget().pushTimeout(0);
|
316
|
+
var isConditionTrue = aCondition.isTrue(target, eventNumberPlus1, mainWindow);
|
317
|
+
}
|
318
|
+
finally {
|
319
|
+
UIATarget.localTarget().popTimeout();
|
320
|
+
}
|
321
|
+
if (isConditionTrue) {
|
322
|
+
aCondition.handle(target, mainWindow);
|
323
|
+
if (aCondition.isExclusive()) {
|
324
|
+
break;
|
325
|
+
} else {
|
326
|
+
mainWindow = target.frontMostApp().mainWindow(); //could be stale
|
327
|
+
}
|
328
|
+
};
|
329
|
+
};
|
330
|
+
};
|
331
|
+
|
332
|
+
UIAutoMonkey.prototype.triggerRandomEvent = function() {
|
333
|
+
var name = this.chooseEventName();
|
334
|
+
// Find the event method based on the name of the event
|
335
|
+
var event = this.allEvents[name];
|
336
|
+
event.apply(this);
|
337
|
+
this.takeScreenShotIfItIsTime();
|
338
|
+
};
|
339
|
+
|
340
|
+
UIAutoMonkey.prototype.target = function() {
|
341
|
+
// Return the local target.
|
342
|
+
return UIATarget.localTarget();
|
343
|
+
};
|
344
|
+
|
345
|
+
UIAutoMonkey.prototype.delay = function(seconds) {
|
346
|
+
// Delay the target by `seconds` (can be a fraction)
|
347
|
+
// Defaults to setting in configuration
|
348
|
+
seconds = seconds || this.config.delayBetweenEvents;
|
349
|
+
this.target().delay(seconds);
|
350
|
+
};
|
351
|
+
|
352
|
+
UIAutoMonkey.prototype.chooseEventName = function() {
|
353
|
+
// Randomly chooses an event name from the `eventsWeight` dictionary
|
354
|
+
// based on the given weights.
|
355
|
+
var calculatedEventWeights = [];
|
356
|
+
var totalWeight = 0;
|
357
|
+
var events = this.config.eventWeights;
|
358
|
+
for (var event in events) {
|
359
|
+
if (events.hasOwnProperty(event)) {
|
360
|
+
calculatedEventWeights.push({
|
361
|
+
weight: events[event]+totalWeight,
|
362
|
+
event: event
|
363
|
+
});
|
364
|
+
totalWeight += events[event];
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
var chosenWeight = Math.random() * 1000 % totalWeight;
|
369
|
+
|
370
|
+
for (var i = 0; i < calculatedEventWeights.length; i++) {
|
371
|
+
if (chosenWeight < calculatedEventWeights[i].weight) {
|
372
|
+
return calculatedEventWeights[i].event;
|
373
|
+
}
|
374
|
+
}
|
375
|
+
|
376
|
+
throw "No event was chosen!";
|
377
|
+
};
|
378
|
+
|
379
|
+
UIAutoMonkey.prototype.screenWidth = function() {
|
380
|
+
// Need to adjust by one to stay within rectangle
|
381
|
+
return this.target().rect().size.width - 1;
|
382
|
+
};
|
383
|
+
|
384
|
+
UIAutoMonkey.prototype.screenHeight = function() {
|
385
|
+
// Need to adjust by one to stay within rectangle
|
386
|
+
return this.target().rect().size.height - 1;
|
387
|
+
};
|
388
|
+
|
389
|
+
UIAutoMonkey.prototype.randomX = function() {
|
390
|
+
var min, max;
|
391
|
+
var r = Math.random();
|
392
|
+
|
393
|
+
if (this.config.frame){
|
394
|
+
// Limits coordinates to given frame if set in config
|
395
|
+
min = this.config.frame.origin.x;
|
396
|
+
max = this.config.frame.size.width + min;
|
397
|
+
} else {
|
398
|
+
// Returns a random X coordinate within the screen rectangle
|
399
|
+
min = 0;
|
400
|
+
max = this.screenWidth();
|
401
|
+
}
|
402
|
+
return r == 0 ? 1 : r * (max - min) + min;
|
403
|
+
};
|
404
|
+
|
405
|
+
UIAutoMonkey.prototype.randomY = function() {
|
406
|
+
var min, max;
|
407
|
+
var r = Math.random();
|
408
|
+
|
409
|
+
if (this.config.frame){
|
410
|
+
// Limits coordinates to given frame if set in config
|
411
|
+
min = this.config.frame.origin.y;
|
412
|
+
max = this.config.frame.size.height + min;
|
413
|
+
} else {
|
414
|
+
// Returns a random Y coordinate within the screen rectangle
|
415
|
+
min = 0;
|
416
|
+
max = this.screenHeight();
|
417
|
+
}
|
418
|
+
return r == 0 ? 1 : r * (max - min) + min;
|
419
|
+
};
|
420
|
+
|
421
|
+
UIAutoMonkey.prototype.randomTapCount = function() {
|
422
|
+
// Calculates a tap count for tap events based on touch probabilities
|
423
|
+
if (this.config.touchProbability.multipleTaps > Math.random()) {
|
424
|
+
return Math.floor(Math.random() * 10) % 3 + 1;
|
425
|
+
}
|
426
|
+
else return 1;
|
427
|
+
};
|
428
|
+
|
429
|
+
UIAutoMonkey.prototype.randomTouchCount = function() {
|
430
|
+
// Calculates a touch count for tap events based on touch probabilities
|
431
|
+
if (this.config.touchProbability.multipleTouches > Math.random()) {
|
432
|
+
return Math.floor(Math.random() * 10) % 3 + 1;
|
433
|
+
}
|
434
|
+
else return 1;
|
435
|
+
};
|
436
|
+
|
437
|
+
UIAutoMonkey.prototype.randomTapDuration = function() {
|
438
|
+
// Calculates whether or not a tap should be a long press based on
|
439
|
+
// touch probabilities
|
440
|
+
if (this.config.touchProbability.longPress > Math.random()) {
|
441
|
+
return 0.5;
|
442
|
+
}
|
443
|
+
else return 0;
|
444
|
+
};
|
445
|
+
|
446
|
+
UIAutoMonkey.prototype.randomRadians = function() {
|
447
|
+
// Returns a random radian value
|
448
|
+
return Math.random() * 10 % (3.14159 * 2);
|
449
|
+
};
|
450
|
+
|
451
|
+
UIAutoMonkey.prototype.takeScreenShotIfItIsTime = function() {
|
452
|
+
// var now = (new Date()).valueOf();
|
453
|
+
// if (!this._lastScreenshotTime) this._lastScreenshotTime = 0;
|
454
|
+
|
455
|
+
// if (now - this._lastScreenshotTime > this.config.screenshotInterval * 1000) {
|
456
|
+
// var filename = "monkey-" + (new Date()).toISOString().replace(/[:\.]+/g, "-");
|
457
|
+
// this.target().captureScreenWithName(filename);
|
458
|
+
// this._lastScreenshotTime = now;
|
459
|
+
// }
|
460
|
+
var filename = "monkey-" + (new Date()).toISOString().replace(/[:\.]+/g, "-");
|
461
|
+
this.target().captureScreenWithName(filename);
|
462
|
+
};
|
463
|
+
|
464
|
+
// Commodity function to call RELEASE_THE_MONKEY directly on UIAutoMonkey
|
465
|
+
// if you don't need to customize your instance
|
466
|
+
UIAutoMonkey.RELEASE_THE_MONKEY = function() {
|
467
|
+
(new UIAutoMonkey()).RELEASE_THE_MONKEY();
|
468
|
+
};
|
469
|
+
|
470
|
+
// UIAutoMonkey.RELEASE_THE_MONKEY();
|