run_loop_tcc 2.1.3
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 +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
|
+
}
|