run_loop_tcc 2.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/bin/run-loop +19 -0
- data/lib/run_loop/abstract.rb +18 -0
- data/lib/run_loop/app.rb +372 -0
- data/lib/run_loop/cache/cache.rb +68 -0
- data/lib/run_loop/cli/cli.rb +48 -0
- data/lib/run_loop/cli/codesign.rb +24 -0
- data/lib/run_loop/cli/errors.rb +11 -0
- data/lib/run_loop/cli/instruments.rb +160 -0
- data/lib/run_loop/cli/locale.rb +31 -0
- data/lib/run_loop/cli/simctl.rb +257 -0
- data/lib/run_loop/cli/tcc.rb +139 -0
- data/lib/run_loop/codesign.rb +76 -0
- data/lib/run_loop/core.rb +902 -0
- data/lib/run_loop/core_simulator.rb +960 -0
- data/lib/run_loop/detect_aut/detect.rb +185 -0
- data/lib/run_loop/detect_aut/errors.rb +126 -0
- data/lib/run_loop/detect_aut/xamarin_studio.rb +46 -0
- data/lib/run_loop/detect_aut/xcode.rb +157 -0
- data/lib/run_loop/device.rb +722 -0
- data/lib/run_loop/device_agent/app/CBX-Runner.app.zip +0 -0
- data/lib/run_loop/device_agent/bin/xctestctl +0 -0
- data/lib/run_loop/device_agent/cbxrunner.rb +156 -0
- data/lib/run_loop/device_agent/frameworks/Frameworks.zip +0 -0
- data/lib/run_loop/device_agent/frameworks.rb +65 -0
- data/lib/run_loop/device_agent/ipa/CBX-Runner.app.zip +0 -0
- data/lib/run_loop/device_agent/launcher.rb +51 -0
- data/lib/run_loop/device_agent/xcodebuild.rb +91 -0
- data/lib/run_loop/device_agent/xctestctl.rb +109 -0
- data/lib/run_loop/directory.rb +179 -0
- data/lib/run_loop/dnssd.rb +148 -0
- data/lib/run_loop/dot_dir.rb +87 -0
- data/lib/run_loop/dylib_injector.rb +145 -0
- data/lib/run_loop/encoding.rb +56 -0
- data/lib/run_loop/environment.rb +361 -0
- data/lib/run_loop/fifo.rb +40 -0
- data/lib/run_loop/host_cache.rb +128 -0
- data/lib/run_loop/http/error.rb +15 -0
- data/lib/run_loop/http/request.rb +44 -0
- data/lib/run_loop/http/retriable_client.rb +166 -0
- data/lib/run_loop/http/server.rb +17 -0
- data/lib/run_loop/instruments.rb +436 -0
- data/lib/run_loop/ipa.rb +142 -0
- data/lib/run_loop/l10n.rb +93 -0
- data/lib/run_loop/language.rb +63 -0
- data/lib/run_loop/lipo.rb +132 -0
- data/lib/run_loop/lldb.rb +52 -0
- data/lib/run_loop/locale.rb +101 -0
- data/lib/run_loop/logging.rb +111 -0
- data/lib/run_loop/otool.rb +76 -0
- data/lib/run_loop/patches/awesome_print.rb +17 -0
- data/lib/run_loop/physical_device/life_cycle.rb +268 -0
- data/lib/run_loop/plist_buddy.rb +189 -0
- data/lib/run_loop/process_terminator.rb +128 -0
- data/lib/run_loop/process_waiter.rb +117 -0
- data/lib/run_loop/regex.rb +19 -0
- data/lib/run_loop/shell.rb +103 -0
- data/lib/run_loop/sim_control.rb +1264 -0
- data/lib/run_loop/simctl.rb +275 -0
- data/lib/run_loop/sqlite.rb +61 -0
- data/lib/run_loop/strings.rb +88 -0
- data/lib/run_loop/tcc/TCC.db +0 -0
- data/lib/run_loop/tcc/tcc.rb +240 -0
- data/lib/run_loop/template.rb +61 -0
- data/lib/run_loop/version.rb +182 -0
- data/lib/run_loop/xcode.rb +318 -0
- data/lib/run_loop/xcrun.rb +107 -0
- data/lib/run_loop/xcuitest.rb +550 -0
- data/lib/run_loop.rb +230 -0
- data/plists/simctl/com.apple.UIAutomation.plist +0 -0
- data/plists/simctl/com.apple.UIAutomationPlugIn.plist +0 -0
- data/scripts/calabash_script_uia.js +28184 -0
- data/scripts/lib/json2.min.js +26 -0
- data/scripts/lib/log.js +26 -0
- data/scripts/lib/on_alert.js +224 -0
- data/scripts/read-cmd.sh +2 -0
- data/scripts/run_dismiss_location.js +89 -0
- data/scripts/run_loop_basic.js +34 -0
- data/scripts/run_loop_fast_uia.js +188 -0
- data/scripts/run_loop_host.js +117 -0
- data/scripts/run_loop_shared_element.js +125 -0
- data/scripts/timeout3 +23 -0
- data/scripts/udidetect +0 -0
- data/vendor-licenses/FBSimulatorControl.LICENSE +30 -0
- data/vendor-licenses/xctestctl.LICENSE +32 -0
- metadata +443 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
if(typeof JSON!=='object'){JSON={};}
|
3
|
+
(function(){'use strict';function f(n){return n<10?'0'+n:n;}
|
4
|
+
if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+
|
5
|
+
f(this.getUTCMonth()+1)+'-'+
|
6
|
+
f(this.getUTCDate())+'T'+
|
7
|
+
f(this.getUTCHours())+':'+
|
8
|
+
f(this.getUTCMinutes())+':'+
|
9
|
+
f(this.getUTCSeconds())+'Z':null;};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}
|
10
|
+
var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}
|
11
|
+
function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
|
12
|
+
if(typeof rep==='function'){value=rep.call(holder,key,value);}
|
13
|
+
switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
|
14
|
+
gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}
|
15
|
+
v=partial.length===0?'[]':gap?'[\n'+gap+partial.join(',\n'+gap)+'\n'+mind+']':'['+partial.join(',')+']';gap=mind;return v;}
|
16
|
+
if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){if(typeof rep[i]==='string'){k=rep[i];v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}
|
17
|
+
v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}
|
18
|
+
if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}
|
19
|
+
rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}
|
20
|
+
return str('',{'':value});};}
|
21
|
+
if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}
|
22
|
+
return reviver.call(holder,key,value);}
|
23
|
+
text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+
|
24
|
+
('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}
|
25
|
+
if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}
|
26
|
+
throw new SyntaxError('JSON.parse');};}}());
|
data/scripts/lib/log.js
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
var Log = (function () {
|
2
|
+
var forceFlush = [];
|
3
|
+
var N = "$FLUSH_LOGS" == "FLUSH_LOGS" ? 16384 : 0;
|
4
|
+
var i = N;
|
5
|
+
while (i--) {
|
6
|
+
forceFlush[i] = "*";
|
7
|
+
}
|
8
|
+
forceFlush = forceFlush.join('');
|
9
|
+
|
10
|
+
function log_json(object)
|
11
|
+
{
|
12
|
+
UIALogger.logMessage("OUTPUT_JSON:\n"+JSON.stringify(object)+"\nEND_OUTPUT");
|
13
|
+
if (forceFlush.length > 0) {
|
14
|
+
UIALogger.logMessage(forceFlush);
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
return {
|
19
|
+
result: function (status, data) {
|
20
|
+
log_json({"status": status, "value": data, "index":_actualIndex});
|
21
|
+
},
|
22
|
+
output: function (msg) {
|
23
|
+
log_json({"output": msg,"last_index":_actualIndex});
|
24
|
+
}
|
25
|
+
};
|
26
|
+
})();
|
@@ -0,0 +1,224 @@
|
|
1
|
+
function findAlertTitle(alert) {
|
2
|
+
if (!alert) {
|
3
|
+
return false;
|
4
|
+
}
|
5
|
+
var title = alert.name();
|
6
|
+
var staticTexts;
|
7
|
+
|
8
|
+
if (title === null) {
|
9
|
+
staticTexts = alert.staticTexts();
|
10
|
+
if (staticTexts !== null && staticTexts.length > 0) {
|
11
|
+
|
12
|
+
title = staticText[0].name();
|
13
|
+
}
|
14
|
+
|
15
|
+
}
|
16
|
+
return title;
|
17
|
+
}
|
18
|
+
|
19
|
+
function findAlertButtonNames(alert) {
|
20
|
+
if (!alert) {
|
21
|
+
return false;
|
22
|
+
}
|
23
|
+
|
24
|
+
var buttons = alert.buttons();
|
25
|
+
var leftButton = buttons[0].name();
|
26
|
+
var rightButton = buttons[1].name();
|
27
|
+
|
28
|
+
return leftButton + "," + rightButton;
|
29
|
+
}
|
30
|
+
|
31
|
+
function englishLocalizations() {
|
32
|
+
return [
|
33
|
+
["OK", /Would Like to Use Your Current Location/],
|
34
|
+
["OK", /Location Accuracy/],
|
35
|
+
["Allow", /access your location/],
|
36
|
+
["OK", /Would Like to Access Your Photos/],
|
37
|
+
["OK", /Would Like to Access Your Contacts/],
|
38
|
+
["OK", /Access the Microphone/],
|
39
|
+
["OK", /Would Like to Access Your Calendar/],
|
40
|
+
["OK", /Would Like to Access Your Reminders/],
|
41
|
+
["OK", /Would Like to Access Your Motion Activity/],
|
42
|
+
["OK", /Would Like to Access the Camera/],
|
43
|
+
["OK", /Would Like to Access Your Motion & Fitness Activity/],
|
44
|
+
["OK", /Would Like Access to Twitter Accounts/],
|
45
|
+
["OK", /data available to nearby bluetooth devices/],
|
46
|
+
["OK", /[Ww]ould [Ll]ike to [Ss]end [Yy]ou( Push)? Notifications/]
|
47
|
+
];
|
48
|
+
}
|
49
|
+
|
50
|
+
function danishLocalizations() {
|
51
|
+
return [
|
52
|
+
["Tillad", /bruge din lokalitet, når du bruger appen/],
|
53
|
+
["Tillad", /også når du ikke bruger appen/],
|
54
|
+
["OK", /vil bruge din aktuelle placering/],
|
55
|
+
["OK", /vil bruge dine kontakter/],
|
56
|
+
["OK", /vil bruge mikrofonen/],
|
57
|
+
["OK", /vil bruge din kalender/],
|
58
|
+
["OK", /vil bruge dine påmindelser/],
|
59
|
+
["OK", /vil bruge dine fotos/],
|
60
|
+
["OK", /ønsker adgang til Twitter-konti/],
|
61
|
+
["OK", /vil bruge din fysiske aktivitet og din træningsaktivitet/],
|
62
|
+
["OK", /vil bruge kameraet/],
|
63
|
+
["OK", /vil gerne sende dig meddelelser/]
|
64
|
+
];
|
65
|
+
}
|
66
|
+
|
67
|
+
function euSpanishLocalizations() {
|
68
|
+
return [
|
69
|
+
["Permitir", /acceder a tu ubicación mientras utilizas la aplicación/],
|
70
|
+
["Permitir", /acceder a tu ubicación aunque no estés utilizando la aplicación/],
|
71
|
+
["OK", /quiere acceder a tus contactos/],
|
72
|
+
["OK", /quiere acceder a tu calendario/],
|
73
|
+
["OK", /quiere acceder a tus recordatorios/],
|
74
|
+
["OK", /quiere acceder a tus fotos/],
|
75
|
+
["OK", /quiere obtener acceso a cuentas Twitter/],
|
76
|
+
["OK", /quiere acceder al micrófono/],
|
77
|
+
["OK", /desea acceder a tu actividad física y deportiva/],
|
78
|
+
["OK", /quiere acceder a la cámara/],
|
79
|
+
["OK", /quiere enviarte notificaciones/]
|
80
|
+
];
|
81
|
+
}
|
82
|
+
|
83
|
+
function es419SpanishLocalizations() {
|
84
|
+
return [
|
85
|
+
["Permitir", /acceda a tu ubicación mientras la app está en uso/],
|
86
|
+
["Permitir", /acceda a tu ubicación incluso cuando la app no está en uso/],
|
87
|
+
["OK", /quiere acceder a tu condición y actividad física/]
|
88
|
+
];
|
89
|
+
}
|
90
|
+
|
91
|
+
function spanishLocalizations() {
|
92
|
+
return [].concat(
|
93
|
+
euSpanishLocalizations(),
|
94
|
+
es419SpanishLocalizations()
|
95
|
+
);
|
96
|
+
}
|
97
|
+
|
98
|
+
function germanLocalizations() {
|
99
|
+
return [
|
100
|
+
["Ja", /Darf (?:.)+ Ihren aktuellen Ort verwenden/],
|
101
|
+
["Erlauben", /auf Ihren Standort zugreifen, wenn Sie die App benutzen/],
|
102
|
+
["Erlauben", /auch auf Ihren Standort zugreifen, wenn Sie die App nicht benutzen/],
|
103
|
+
["Erlauben", /auf Ihren Standort zugreifen, selbst wenn Sie die App nicht benutzen/],
|
104
|
+
["Ja", /auf Ihre Kontakte zugreifen/],
|
105
|
+
["Ja", /auf Ihren Kalender zugreifen/],
|
106
|
+
["Ja", /auf Ihre Erinnerungen zugreifen/],
|
107
|
+
["Ja", /auf Ihre Fotos zugreifen/],
|
108
|
+
["Erlauben", /möchte auf Twitter-Accounts zugreifen/],
|
109
|
+
["Ja", /auf das Mikrofon zugreifen/],
|
110
|
+
["Ja", /möchte auf Ihre Bewegungs- und Fitnessdaten zugreifen/],
|
111
|
+
["Ja", /auf Ihre Kamera zugreifen/],
|
112
|
+
["OK", /Ihnen Mitteilungen senden/]
|
113
|
+
];
|
114
|
+
}
|
115
|
+
|
116
|
+
function dutchLocalizations() {
|
117
|
+
return [
|
118
|
+
["Sta toe", /tot uw locatie toestaan terwijl u de app gebruikt/],
|
119
|
+
["Sta toe", /toegang tot uw locatie toestaan terwijl u de app gebruikt/],
|
120
|
+
["Sta toe", /ook toegang tot uw locatie toestaan, zelfs als u de app niet gebruikt/],
|
121
|
+
["Sta toe", /toegang tot uw locatie toestaan, zelfs als u de app niet gebruikt/],
|
122
|
+
["OK", /wil toegang tot uw contacten/],
|
123
|
+
["OK", /wil toegang tot uw agenda/],
|
124
|
+
["OK", /wil toegang tot uw herinneringen/],
|
125
|
+
["OK", /wil toegang tot uw foto's/],
|
126
|
+
["OK", /wil toegang tot Twitter-accounts/],
|
127
|
+
["OK", /wil toegang tot de microfoon/],
|
128
|
+
["OK", /wil toegang tot uw bewegings- en fitnessactiviteit/],
|
129
|
+
["OK", /wil toegang tot de camera/],
|
130
|
+
["OK", /wil u berichten sturen/]
|
131
|
+
];
|
132
|
+
}
|
133
|
+
|
134
|
+
function russianLocalizations() {
|
135
|
+
return [
|
136
|
+
// Location
|
137
|
+
["OK", /запрашивает разрешение на использование Ващей текущей пгеопозиции/]
|
138
|
+
];
|
139
|
+
}
|
140
|
+
|
141
|
+
function frenchLocalizations() {
|
142
|
+
return [
|
143
|
+
["OK", /vous envoyer des notifications/],
|
144
|
+
["Autoriser", /à accéder à vos données de localisation lorsque vous utilisez l’app/],
|
145
|
+
["Autoriser", /à accéder à vos données de localisation même lorsque vous n’utilisez pas l’app/],
|
146
|
+
["Autoriser", /à accéder aussi à vos données de localisation lorsque vous n’utilisez pas l’app/],
|
147
|
+
["OK", /souhaite accéder à vos contacts/],
|
148
|
+
["OK", /souhaite accéder à votre calendrier/],
|
149
|
+
["OK", /souhaite accéder à vos rappels/],
|
150
|
+
["OK", /souhaite accéder à vos mouvements et vos activités physiques/],
|
151
|
+
["OK", /souhaite accéder à vos photos/],
|
152
|
+
["OK", /souhaite accéder à l’appareil photo/],
|
153
|
+
["OK", /souhaite accéder aux comptes Twitter/],
|
154
|
+
["OK", /souhaite accéder au micro/]
|
155
|
+
];
|
156
|
+
}
|
157
|
+
|
158
|
+
function localizations() {
|
159
|
+
return [].concat(
|
160
|
+
danishLocalizations(),
|
161
|
+
dutchLocalizations(),
|
162
|
+
englishLocalizations(),
|
163
|
+
germanLocalizations(),
|
164
|
+
russianLocalizations(),
|
165
|
+
spanishLocalizations(),
|
166
|
+
frenchLocalizations()
|
167
|
+
);
|
168
|
+
}
|
169
|
+
|
170
|
+
function isPrivacyAlert(alert) {
|
171
|
+
|
172
|
+
var expressions = localizations();
|
173
|
+
|
174
|
+
var title = findAlertTitle(alert);
|
175
|
+
|
176
|
+
// Comment this out when capturing new regexes. See the comment below.
|
177
|
+
Log.output({"alert":title});
|
178
|
+
|
179
|
+
// When debugging or trying to capture the regexes for a new
|
180
|
+
// localization, uncomment the logging below.
|
181
|
+
//
|
182
|
+
// Notes:
|
183
|
+
// * Microphone alerts only appear on physical devices.
|
184
|
+
// * You have to click through the Health alert; it is completely blocking -
|
185
|
+
// tests will not proceed.
|
186
|
+
// * Generating bluetooth alerts is NYI.
|
187
|
+
// * In general, there will be a different alert on device for using location
|
188
|
+
// in background mode.
|
189
|
+
// * Alerts vary by iOS.
|
190
|
+
// * To reset notifications on devices:
|
191
|
+
// General > Settings > Reset > Reset Location + Privacy
|
192
|
+
// - These are the last table rows
|
193
|
+
// - APNS permissions are reset once a day.
|
194
|
+
// * On devices, set the device language in Settings.
|
195
|
+
//
|
196
|
+
// Use the Permission.app.
|
197
|
+
//
|
198
|
+
// * Alert text is printed at the end of every test.
|
199
|
+
// * Alert text is written to a file in Permissions/tmp.
|
200
|
+
//
|
201
|
+
// Examples:
|
202
|
+
//
|
203
|
+
// # Simulator running Mexican Spanish
|
204
|
+
// $ APP_LANG="es-MX" APP_LOCALE="es_MX" be cucumber -t @supported
|
205
|
+
//
|
206
|
+
// # Device running Dutch
|
207
|
+
// $ APP_LANG="nl" APP_LOCALE="nl" be cucumber -t @supported -p macmini
|
208
|
+
|
209
|
+
// This is very slow, so only do this if you are trying to capture regexes.
|
210
|
+
//var buttonNames = findAlertButtonNames(alert);
|
211
|
+
//Log.output({"alert":{"title":title, "buttons":buttonNames, "capture":"YES"}});
|
212
|
+
|
213
|
+
var answer;
|
214
|
+
var expression;
|
215
|
+
for (var i = 0; i < expressions.length; i++) {
|
216
|
+
answer = expressions[i][0];
|
217
|
+
expression = expressions[i][1];
|
218
|
+
if (expression.test(title)) {
|
219
|
+
return answer;
|
220
|
+
}
|
221
|
+
}
|
222
|
+
return false;
|
223
|
+
}
|
224
|
+
|
data/scripts/read-cmd.sh
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
var target = UIATarget.localTarget(),
|
2
|
+
screenshot_count = 0;
|
3
|
+
|
4
|
+
<%= render_template("lib/on_alert.js") %>
|
5
|
+
|
6
|
+
var alertHandlers = [//run in reverse order of this:
|
7
|
+
isLocationPrompt
|
8
|
+
];
|
9
|
+
|
10
|
+
|
11
|
+
UIATarget.onAlert = function (alert) {
|
12
|
+
var N = alertHandlers.length;
|
13
|
+
while (N--) {
|
14
|
+
if (alertHandlers[i]) {
|
15
|
+
break;
|
16
|
+
}
|
17
|
+
}
|
18
|
+
return true;
|
19
|
+
};
|
20
|
+
|
21
|
+
function performAction(action, data) {
|
22
|
+
UIALogger.logMessage("perform action:" + action);
|
23
|
+
var actionTaken = true,
|
24
|
+
res = null;
|
25
|
+
switch (action) {
|
26
|
+
case "setLocation":
|
27
|
+
target.setLocation({"latitude":data.latitude, "longitude":data.longitude});
|
28
|
+
break;
|
29
|
+
case "background":
|
30
|
+
target.deactivateAppForDuration(data.duration);
|
31
|
+
break;
|
32
|
+
case "registerAlertHandler":
|
33
|
+
alertHandlers.push(eval(data.handler));
|
34
|
+
break;
|
35
|
+
case "screenshot":
|
36
|
+
screenshot_count += 1;
|
37
|
+
target.captureScreenWithName(data.name || ("screenshot_" + screenshot_count));
|
38
|
+
break;
|
39
|
+
case "eval":
|
40
|
+
try {
|
41
|
+
res = eval(data);
|
42
|
+
} catch (e) {
|
43
|
+
if (e) {
|
44
|
+
UIALogger.logMessage(e.toString());
|
45
|
+
}
|
46
|
+
}
|
47
|
+
break;
|
48
|
+
}
|
49
|
+
if (actionTaken && !data.preserve) {
|
50
|
+
target.frontMostApp().setPreferencesValueForKey(null, "__run_loop_action");
|
51
|
+
}
|
52
|
+
return res;
|
53
|
+
|
54
|
+
}
|
55
|
+
|
56
|
+
UIALogger.logStart("RunLoop");
|
57
|
+
|
58
|
+
var app = target.frontMostApp(),
|
59
|
+
val,
|
60
|
+
res,
|
61
|
+
count = 0,
|
62
|
+
action = null;
|
63
|
+
while (true) {
|
64
|
+
target.delay(1);
|
65
|
+
val = target.frontMostApp().preferencesValueForKey("__run_loop_action");
|
66
|
+
if (val)
|
67
|
+
UIALogger.logMessage(val);
|
68
|
+
else {
|
69
|
+
UIALogger.logMessage("null");
|
70
|
+
val = target.frontMostApp().preferencesValueForKey("x");
|
71
|
+
if (val)
|
72
|
+
UIALogger.logMessage(val.toString());
|
73
|
+
}
|
74
|
+
|
75
|
+
if (val && typeof val == 'object') {
|
76
|
+
action = val.action;
|
77
|
+
performAction(action, val);
|
78
|
+
}
|
79
|
+
else if (val && typeof val == 'string') {
|
80
|
+
res = performAction("eval", val);
|
81
|
+
if (res) {
|
82
|
+
UIALogger.logMessage(res.toString());
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
count += 1;
|
87
|
+
}
|
88
|
+
|
89
|
+
UIALogger.logPass("RunLoop");
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<%= render_template("lib/json2.min.js") %>
|
2
|
+
<%= render_template("lib/log.js"); %>
|
3
|
+
<%= render_template("lib/on_alert.js"); %>
|
4
|
+
|
5
|
+
UIATarget.onAlert = function (alert) {
|
6
|
+
Log.output({"output":"on alert"});
|
7
|
+
var target = UIATarget.localTarget();
|
8
|
+
target.pushTimeout(10);
|
9
|
+
function dismissPrivacyAlert(retry_count) {
|
10
|
+
retry_count = retry_count || 0;
|
11
|
+
if (retry_count >= 5) {
|
12
|
+
Log.output("Maxed out retry (5) - unable to dismiss privacy alert.");
|
13
|
+
return;
|
14
|
+
}
|
15
|
+
try {
|
16
|
+
var answer = isPrivacyAlert(alert);
|
17
|
+
if (answer) {
|
18
|
+
alert.buttons()[answer].tap();
|
19
|
+
}
|
20
|
+
}
|
21
|
+
catch (e) {
|
22
|
+
Log.output("Exception while trying to touch alert. Retrying...");
|
23
|
+
if (e && typeof e.toString == 'function') {
|
24
|
+
Log.output(e.toString());
|
25
|
+
}
|
26
|
+
target.delay(1);
|
27
|
+
dismissPrivacyAlert(retry_count + 1);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
dismissPrivacyAlert(0);
|
32
|
+
target.popTimeout();
|
33
|
+
return true;
|
34
|
+
};
|
@@ -0,0 +1,188 @@
|
|
1
|
+
<% render_template("lib/json2.min.js") %>
|
2
|
+
|
3
|
+
_RUN_LOOP_MAX_RETRY_AFTER_HANDLER = 10;
|
4
|
+
var _expectedIndex = 0,//expected index of next command
|
5
|
+
_actualIndex=0,//actual index of next command by reading commandPath
|
6
|
+
_exp,//expression to be eval'ed
|
7
|
+
_result,
|
8
|
+
_lastResponse=null;
|
9
|
+
|
10
|
+
<%= render_template("lib/log.js"); %>
|
11
|
+
<%= render_template("lib/on_alert.js"); %>
|
12
|
+
|
13
|
+
UIATarget.onAlert = function (alert) {
|
14
|
+
var target = UIATarget.localTarget(),
|
15
|
+
app = target.frontMostApp(),
|
16
|
+
req = null,
|
17
|
+
rsp = null,
|
18
|
+
actualIndex = null;
|
19
|
+
target.pushTimeout(10);
|
20
|
+
function dismissPrivacyAlert(retry_count) {
|
21
|
+
retry_count = retry_count || 0;
|
22
|
+
if (retry_count >= 5) {
|
23
|
+
Log.output("Maxed out retry (5) - unable to dismiss privacy alert.");
|
24
|
+
return;
|
25
|
+
}
|
26
|
+
try {
|
27
|
+
var answer = isPrivacyAlert(alert);
|
28
|
+
if (answer) {
|
29
|
+
alert.buttons()[answer].tap();
|
30
|
+
}
|
31
|
+
}
|
32
|
+
catch (e) {
|
33
|
+
Log.output("Exception while trying to touch privacy alert. Retrying...");
|
34
|
+
if (e && typeof e.toString == 'function') {
|
35
|
+
Log.output(e.toString());
|
36
|
+
}
|
37
|
+
target.delay(1);
|
38
|
+
dismissPrivacyAlert(retry_count + 1);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
dismissPrivacyAlert(0);
|
43
|
+
target.popTimeout();
|
44
|
+
|
45
|
+
for (var i=0;i<_RUN_LOOP_MAX_RETRY_AFTER_HANDLER;i++) {
|
46
|
+
req = app.preferencesValueForKey(__calabashRequest);
|
47
|
+
rsp = app.preferencesValueForKey(__calabashResponse);
|
48
|
+
actualIndex = req && req['index'];
|
49
|
+
if (req && !isNaN(actualIndex) && actualIndex <= _lastResponse['index']) {
|
50
|
+
UIALogger.logMessage("Deleting previous response: "+(rsp && rsp['index']));
|
51
|
+
app.setPreferencesValueForKey(0, __calabashRequest);
|
52
|
+
app.setPreferencesValueForKey(null, __calabashRequest);
|
53
|
+
}
|
54
|
+
if (_lastResponse) {
|
55
|
+
UIALogger.logMessage("Re-Writing response: "+_lastResponse['value']);
|
56
|
+
_response(_lastResponse);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
return true;
|
60
|
+
};
|
61
|
+
|
62
|
+
var target = null,
|
63
|
+
failureMessage = null,
|
64
|
+
preferences = null,
|
65
|
+
__calabashRequest = "__calabashRequest",
|
66
|
+
__calabashResponse = "__calabashResponse",
|
67
|
+
_sanitize = function(val) {
|
68
|
+
if (typeof val === 'undefined' || val === null || val instanceof UIAElementNil) {
|
69
|
+
return ":nil";
|
70
|
+
}
|
71
|
+
if (typeof val === 'string' || val instanceof String) {
|
72
|
+
return val;
|
73
|
+
}
|
74
|
+
var arrVal = null, i, N;
|
75
|
+
if (val instanceof Array || val instanceof UIAElementArray) {
|
76
|
+
arrVal = [];
|
77
|
+
for (i=0,N=val.length;i<N;i++) {
|
78
|
+
arrVal[i] = _sanitize(val[i]);
|
79
|
+
}
|
80
|
+
return arrVal;
|
81
|
+
}
|
82
|
+
if (val instanceof UIAElement) {
|
83
|
+
return val.toString();
|
84
|
+
}
|
85
|
+
var objVal = null, p;
|
86
|
+
if (typeof val == 'object') {
|
87
|
+
objVal = {};
|
88
|
+
for (p in val) {
|
89
|
+
objVal[p] = _sanitize(val[p]);
|
90
|
+
}
|
91
|
+
return objVal;
|
92
|
+
}
|
93
|
+
return val;
|
94
|
+
},
|
95
|
+
_response = function(response) {
|
96
|
+
var sanitized = _sanitize(response),
|
97
|
+
i = 0,
|
98
|
+
MAX_TRIES=120,
|
99
|
+
res,
|
100
|
+
tmp;
|
101
|
+
|
102
|
+
for (i=0; i<MAX_TRIES; i+=1) {
|
103
|
+
tmp = target.frontMostApp().preferencesValueForKey(__calabashResponse);
|
104
|
+
UIALogger.logMessage("Last response..."+(tmp && tmp['index']+"->"+tmp['value']));
|
105
|
+
target.frontMostApp().setPreferencesValueForKey(sanitized, __calabashResponse);
|
106
|
+
res = target.frontMostApp().preferencesValueForKey(__calabashRequest);
|
107
|
+
res = target.frontMostApp().preferencesValueForKey(__calabashResponse);
|
108
|
+
UIALogger.logMessage("Next response..."+(res && res['value']));
|
109
|
+
target.delay(0.1);
|
110
|
+
res = target.frontMostApp().preferencesValueForKey(__calabashResponse);
|
111
|
+
UIALogger.logMessage("Post delay response..."+(res && res['value']));
|
112
|
+
if (res && res['index'] == sanitized['index']) {
|
113
|
+
UIALogger.logMessage("Storage succeeded: "+ res['index']);
|
114
|
+
return;
|
115
|
+
} else {
|
116
|
+
UIALogger.logMessage("Storage failed: "+ res + " Retrying...");
|
117
|
+
target.delay(0.2);
|
118
|
+
}
|
119
|
+
}
|
120
|
+
throw new Error("Unable to write to preferences");
|
121
|
+
},
|
122
|
+
_success = function(result,index) {
|
123
|
+
_lastResponse = {"status":'success', "value":result, "index": index};
|
124
|
+
_response(_lastResponse);
|
125
|
+
|
126
|
+
},
|
127
|
+
_failure = function(err, index) {
|
128
|
+
_lastResponse = {"status":'error',
|
129
|
+
"value":err.toString(),
|
130
|
+
"backtrace":(err.stack ? err.stack.toString() : ""),
|
131
|
+
"index":index};
|
132
|
+
_response(_lastResponse);
|
133
|
+
},
|
134
|
+
_resetCalabashPreferences = function () {
|
135
|
+
//Implementation is weird but reading pref values seems to have side effects
|
136
|
+
//also deleting a key seemed to require writing 0 and then null :)
|
137
|
+
var app = UIATarget.localTarget().frontMostApp();
|
138
|
+
app.preferencesValueForKey(__calabashRequest);
|
139
|
+
app.preferencesValueForKey(__calabashResponse);
|
140
|
+
app.setPreferencesValueForKey(0, __calabashResponse);
|
141
|
+
app.setPreferencesValueForKey(null, __calabashResponse);
|
142
|
+
app.setPreferencesValueForKey(0, __calabashRequest);
|
143
|
+
app.setPreferencesValueForKey(null, __calabashRequest);
|
144
|
+
};
|
145
|
+
|
146
|
+
_resetCalabashPreferences();
|
147
|
+
Log.result('success', true);
|
148
|
+
target = UIATarget.localTarget();
|
149
|
+
while (true) {
|
150
|
+
try {
|
151
|
+
preferences = target.frontMostApp().preferencesValueForKey(__calabashRequest);
|
152
|
+
} catch (e) {
|
153
|
+
Log.output("Unable to read preferences..."+ e.toString());
|
154
|
+
target.delay(0.5);
|
155
|
+
continue;
|
156
|
+
}
|
157
|
+
|
158
|
+
if (!preferences) {
|
159
|
+
target.delay(0.2);
|
160
|
+
continue;
|
161
|
+
}
|
162
|
+
|
163
|
+
_actualIndex = preferences['index'];
|
164
|
+
if (!isNaN(_actualIndex) && _actualIndex >= _expectedIndex) {
|
165
|
+
UIATarget.localTarget().frontMostApp().setPreferencesValueForKey(null, __calabashResponse);
|
166
|
+
_exp = preferences['command'];
|
167
|
+
UIALogger.logMessage("index " + _actualIndex + " is command: "+ _exp);
|
168
|
+
try {
|
169
|
+
if (_exp == 'break;') {
|
170
|
+
_success("OK", _actualIndex);
|
171
|
+
break;
|
172
|
+
}
|
173
|
+
_result = eval(_exp);
|
174
|
+
UIALogger.logMessage("Success: "+ _result);
|
175
|
+
_success(_result, _actualIndex);
|
176
|
+
}
|
177
|
+
catch(err) {
|
178
|
+
failureMessage = "Failure: "+ err.toString() + " " + (err.stack ? err.stack.toString() : "");
|
179
|
+
Log.output({"output":failureMessage});
|
180
|
+
_failure(err, _actualIndex);
|
181
|
+
}
|
182
|
+
}
|
183
|
+
else {//likely old command is lingering...
|
184
|
+
continue;
|
185
|
+
}
|
186
|
+
_expectedIndex = Math.max(_actualIndex+1, _expectedIndex+1);
|
187
|
+
target.delay(0.2);
|
188
|
+
}
|