run_loop 1.1.1.pre3 → 1.1.1.pre4
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/lib/run_loop/core.rb +31 -8
- data/lib/run_loop/device.rb +34 -2
- data/lib/run_loop/version.rb +1 -1
- data/lib/run_loop/xctools.rb +27 -2
- data/scripts/calabash_script_uia.js +19425 -14792
- data/scripts/run_loop_shared_element.js +338 -0
- metadata +17 -2
@@ -0,0 +1,338 @@
|
|
1
|
+
if (typeof JSON !== 'object') {
|
2
|
+
JSON = {};
|
3
|
+
}
|
4
|
+
(function () {
|
5
|
+
'use strict';
|
6
|
+
function f(n) {
|
7
|
+
return n < 10 ? '0' + n : n;
|
8
|
+
}
|
9
|
+
|
10
|
+
if (typeof Date.prototype.toJSON !== 'function') {
|
11
|
+
Date.prototype.toJSON = function (key) {
|
12
|
+
return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' +
|
13
|
+
f(this.getUTCMonth() + 1) + '-' +
|
14
|
+
f(this.getUTCDate()) + 'T' +
|
15
|
+
f(this.getUTCHours()) + ':' +
|
16
|
+
f(this.getUTCMinutes()) + ':' +
|
17
|
+
f(this.getUTCSeconds()) + 'Z' : null;
|
18
|
+
};
|
19
|
+
String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) {
|
20
|
+
return this.valueOf();
|
21
|
+
};
|
22
|
+
}
|
23
|
+
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;
|
24
|
+
|
25
|
+
function quote(string) {
|
26
|
+
escapable.lastIndex = 0;
|
27
|
+
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
|
28
|
+
var c = meta[a];
|
29
|
+
return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
30
|
+
}) + '"' : '"' + string + '"';
|
31
|
+
}
|
32
|
+
|
33
|
+
function str(key, holder) {
|
34
|
+
var i, k, v, length, mind = gap, partial, value = holder[key];
|
35
|
+
if (value && typeof value === 'object' && typeof value.toJSON === 'function') {
|
36
|
+
value = value.toJSON(key);
|
37
|
+
}
|
38
|
+
if (typeof rep === 'function') {
|
39
|
+
value = rep.call(holder, key, value);
|
40
|
+
}
|
41
|
+
switch (typeof value) {
|
42
|
+
case'string':
|
43
|
+
return quote(value);
|
44
|
+
case'number':
|
45
|
+
return isFinite(value) ? String(value) : 'null';
|
46
|
+
case'boolean':
|
47
|
+
case'null':
|
48
|
+
return String(value);
|
49
|
+
case'object':
|
50
|
+
if (!value) {
|
51
|
+
return'null';
|
52
|
+
}
|
53
|
+
gap += indent;
|
54
|
+
partial = [];
|
55
|
+
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
56
|
+
length = value.length;
|
57
|
+
for (i = 0; i < length; i += 1) {
|
58
|
+
partial[i] = str(i, value) || 'null';
|
59
|
+
}
|
60
|
+
v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']';
|
61
|
+
gap = mind;
|
62
|
+
return v;
|
63
|
+
}
|
64
|
+
if (rep && typeof rep === 'object') {
|
65
|
+
length = rep.length;
|
66
|
+
for (i = 0; i < length; i += 1) {
|
67
|
+
if (typeof rep[i] === 'string') {
|
68
|
+
k = rep[i];
|
69
|
+
v = str(k, value);
|
70
|
+
if (v) {
|
71
|
+
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
} else {
|
76
|
+
for (k in value) {
|
77
|
+
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
78
|
+
v = str(k, value);
|
79
|
+
if (v) {
|
80
|
+
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}';
|
86
|
+
gap = mind;
|
87
|
+
return v;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
if (typeof JSON.stringify !== 'function') {
|
92
|
+
JSON.stringify = function (value, replacer, space) {
|
93
|
+
var i;
|
94
|
+
gap = '';
|
95
|
+
indent = '';
|
96
|
+
if (typeof space === 'number') {
|
97
|
+
for (i = 0; i < space; i += 1) {
|
98
|
+
indent += ' ';
|
99
|
+
}
|
100
|
+
} else if (typeof space === 'string') {
|
101
|
+
indent = space;
|
102
|
+
}
|
103
|
+
rep = replacer;
|
104
|
+
if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
|
105
|
+
throw new Error('JSON.stringify');
|
106
|
+
}
|
107
|
+
return str('', {'': value});
|
108
|
+
};
|
109
|
+
}
|
110
|
+
if (typeof JSON.parse !== 'function') {
|
111
|
+
JSON.parse = function (text, reviver) {
|
112
|
+
var j;
|
113
|
+
|
114
|
+
function walk(holder, key) {
|
115
|
+
var k, v, value = holder[key];
|
116
|
+
if (value && typeof value === 'object') {
|
117
|
+
for (k in value) {
|
118
|
+
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
119
|
+
v = walk(value, k);
|
120
|
+
if (v !== undefined) {
|
121
|
+
value[k] = v;
|
122
|
+
} else {
|
123
|
+
delete value[k];
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|
128
|
+
return reviver.call(holder, key, value);
|
129
|
+
}
|
130
|
+
|
131
|
+
text = String(text);
|
132
|
+
cx.lastIndex = 0;
|
133
|
+
if (cx.test(text)) {
|
134
|
+
text = text.replace(cx, function (a) {
|
135
|
+
return'\\u' +
|
136
|
+
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
137
|
+
});
|
138
|
+
}
|
139
|
+
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, ''))) {
|
140
|
+
j = eval('(' + text + ')');
|
141
|
+
return typeof reviver === 'function' ? walk({'': j}, '') : j;
|
142
|
+
}
|
143
|
+
throw new SyntaxError('JSON.parse');
|
144
|
+
};
|
145
|
+
}
|
146
|
+
}());
|
147
|
+
|
148
|
+
|
149
|
+
_RUN_LOOP_MAX_RETRY_AFTER_HANDLER = 10;
|
150
|
+
var _expectedIndex = 0,//expected index of next command
|
151
|
+
_actualIndex=0,//actual index of next command by reading commandPath
|
152
|
+
_exp,//expression to be eval'ed
|
153
|
+
_result,
|
154
|
+
_lastResponse=null;
|
155
|
+
|
156
|
+
var Log = (function () {
|
157
|
+
var forceFlush = [],
|
158
|
+
N = 16384,
|
159
|
+
i = N;
|
160
|
+
while (i--) {
|
161
|
+
forceFlush[i] = "*";
|
162
|
+
}
|
163
|
+
forceFlush = forceFlush.join('');
|
164
|
+
|
165
|
+
function log_json(object, flush)
|
166
|
+
{
|
167
|
+
UIALogger.logMessage("OUTPUT_JSON:\n"+JSON.stringify(object)+"\nEND_OUTPUT");
|
168
|
+
if (flush) {
|
169
|
+
UIALogger.logMessage(forceFlush);
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
return {
|
174
|
+
result: function (status, data, flush) {
|
175
|
+
log_json({"status": status, "value": data, "index":_actualIndex}, flush)
|
176
|
+
},
|
177
|
+
output: function (msg, flush) {
|
178
|
+
log_json({"output": msg,"last_index":_actualIndex}, flush);
|
179
|
+
}
|
180
|
+
};
|
181
|
+
})();
|
182
|
+
|
183
|
+
|
184
|
+
function findAlertViewText(alert) {
|
185
|
+
if (!alert) {
|
186
|
+
return false;
|
187
|
+
}
|
188
|
+
var txt = alert.name(),
|
189
|
+
txts;
|
190
|
+
if (txt == null) {
|
191
|
+
txts = alert.staticTexts();
|
192
|
+
if (txts != null && txts.length > 0) {
|
193
|
+
txt = txts[0].name();
|
194
|
+
}
|
195
|
+
}
|
196
|
+
return txt;
|
197
|
+
}
|
198
|
+
|
199
|
+
function isLocationPrompt(alert) {
|
200
|
+
var exps = [
|
201
|
+
["OK", /vil bruge din aktuelle placering/],
|
202
|
+
["OK", /Would Like to Use Your Current Location/],
|
203
|
+
["Ja", /Darf (?:.)+ Ihren aktuellen Ort verwenden/],
|
204
|
+
["OK", /Would Like to Send You Notifications/],
|
205
|
+
["Allow", /access your location/],
|
206
|
+
["OK", /Would Like to Access Your Photos/],
|
207
|
+
["OK", /Would Like to Access Your Contacts/],
|
208
|
+
["OK", /запрашивает разрешение на использование Ващей текущей пгеопозиции/]
|
209
|
+
],
|
210
|
+
ans, exp,
|
211
|
+
txt;
|
212
|
+
|
213
|
+
txt = findAlertViewText(alert);
|
214
|
+
Log.output({"output":"alert: "+txt}, true);
|
215
|
+
for (var i = 0; i < exps.length; i++) {
|
216
|
+
ans = exps[i][0];
|
217
|
+
exp = exps[i][1];
|
218
|
+
if (exp.test(txt)) {
|
219
|
+
return ans;
|
220
|
+
}
|
221
|
+
}
|
222
|
+
return false;
|
223
|
+
}
|
224
|
+
|
225
|
+
UIATarget.onAlert = function (alert) {
|
226
|
+
var target = UIATarget.localTarget(),
|
227
|
+
app = target.frontMostApp(),
|
228
|
+
req = null,
|
229
|
+
rsp = null,
|
230
|
+
actualIndex = null;
|
231
|
+
target.pushTimeout(10);
|
232
|
+
function attemptTouchOKOnLocation(retry_count) {
|
233
|
+
retry_count = retry_count || 0;
|
234
|
+
if (retry_count >= 5) {
|
235
|
+
Log.output("Maxed out retry (5) - unable to dismiss location dialog.");
|
236
|
+
return;
|
237
|
+
}
|
238
|
+
try {
|
239
|
+
var answer = isLocationPrompt(alert);
|
240
|
+
if (answer) {
|
241
|
+
alert.buttons()[answer].tap();
|
242
|
+
}
|
243
|
+
}
|
244
|
+
catch (e) {
|
245
|
+
Log.output("Exception while trying to touch alert dialog. Retrying...");
|
246
|
+
if (e && typeof e.toString == 'function') {
|
247
|
+
Log.output(e.toString());
|
248
|
+
}
|
249
|
+
target.delay(1);
|
250
|
+
attemptTouchOKOnLocation(retry_count + 1);
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
254
|
+
attemptTouchOKOnLocation(0);
|
255
|
+
target.popTimeout();
|
256
|
+
return true;
|
257
|
+
};
|
258
|
+
|
259
|
+
|
260
|
+
Log.result('success',true,true);
|
261
|
+
|
262
|
+
var _calabashSharedTextField = null,
|
263
|
+
__calabashSharedTextFieldName = '__calabash_uia_channel',
|
264
|
+
_firstElement,
|
265
|
+
target = null,
|
266
|
+
failureMessage = null,
|
267
|
+
_request = null,
|
268
|
+
_response = function(response) {
|
269
|
+
response.type = 'response';
|
270
|
+
var jsonResponse = JSON.stringify(response);
|
271
|
+
UIALogger.logMessage("Response: "+ jsonResponse);
|
272
|
+
_calabashSharedTextField.setValue(jsonResponse);
|
273
|
+
},
|
274
|
+
_success = function(result,index) {
|
275
|
+
_lastResponse = {"status":'success', "value":result, "index": index};
|
276
|
+
_response(_lastResponse);
|
277
|
+
},
|
278
|
+
_failure = function(err, index) {
|
279
|
+
_lastResponse = {"status":'error',
|
280
|
+
"value":err.toString(),
|
281
|
+
"backtrace":(err.stack ? err.stack.toString() : ""),
|
282
|
+
"index":index};
|
283
|
+
_response(_lastResponse);
|
284
|
+
},
|
285
|
+
_syncDoneJSON='{"type":"syncDone"}';
|
286
|
+
|
287
|
+
target = UIATarget.localTarget();
|
288
|
+
while (!_calabashSharedTextField) {
|
289
|
+
UIALogger.logMessage("Waiting for shared element...");
|
290
|
+
_firstElement = target.frontMostApp().mainWindow().elements()[0];
|
291
|
+
target.frontMostApp().mainWindow().logElementTree();
|
292
|
+
if (_firstElement instanceof UIATextField) {
|
293
|
+
if (_firstElement.name() == __calabashSharedTextFieldName) {
|
294
|
+
_calabashSharedTextField = _firstElement;
|
295
|
+
UIALogger.logMessage("Found shared element... Responding: syncDone");
|
296
|
+
_calabashSharedTextField.setValue(_syncDoneJSON);
|
297
|
+
target.delay(0.5);
|
298
|
+
break;
|
299
|
+
}
|
300
|
+
}
|
301
|
+
target.delay(0.5);
|
302
|
+
}
|
303
|
+
|
304
|
+
while (true) {
|
305
|
+
_request = _calabashSharedTextField.value();
|
306
|
+
|
307
|
+
if (!_request || _request === _syncDoneJSON) {
|
308
|
+
target.delay(0.2);
|
309
|
+
continue;
|
310
|
+
}
|
311
|
+
|
312
|
+
UIALogger.logMessage("index " + _actualIndex + " is request: "+ _request);
|
313
|
+
_request = JSON.parse(_request);
|
314
|
+
|
315
|
+
_actualIndex = _request['index'];
|
316
|
+
if (!isNaN(_actualIndex) && _actualIndex >= _expectedIndex) {
|
317
|
+
_exp = _request['command'];
|
318
|
+
UIALogger.logMessage("index " + _actualIndex + " is command: "+ _exp);
|
319
|
+
try {
|
320
|
+
if (_exp == 'break;') {
|
321
|
+
_success("OK", _actualIndex);
|
322
|
+
break;
|
323
|
+
}
|
324
|
+
_result = eval(_exp);
|
325
|
+
UIALogger.logMessage("Success: "+ _result);
|
326
|
+
_success(_result, _actualIndex);
|
327
|
+
}
|
328
|
+
catch(err) {
|
329
|
+
failureMessage = "Failure: "+ err.toString() + " " + (err.stack ? err.stack.toString() : "");
|
330
|
+
Log.output({"output":failureMessage}, true);
|
331
|
+
_failure(err, _actualIndex);
|
332
|
+
}
|
333
|
+
}
|
334
|
+
else {//likely old command is lingering...
|
335
|
+
continue;
|
336
|
+
}
|
337
|
+
_expectedIndex = Math.max(_actualIndex+1, _expectedIndex+1);
|
338
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: run_loop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.1.
|
4
|
+
version: 1.1.1.pre4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Krukow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -192,6 +192,20 @@ dependencies:
|
|
192
192
|
- - ~>
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '0.5'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: stub_env
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ~>
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0.2'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ~>
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0.2'
|
195
209
|
description: calabash-cucumber drives tests for native iOS apps. RunLoop provides
|
196
210
|
a number of tools associated with running Calabash tests.
|
197
211
|
email:
|
@@ -222,6 +236,7 @@ files:
|
|
222
236
|
- scripts/run_loop_basic.js
|
223
237
|
- scripts/run_loop_fast_uia.js
|
224
238
|
- scripts/run_loop_host.js
|
239
|
+
- scripts/run_loop_shared_element.js
|
225
240
|
- scripts/udidetect
|
226
241
|
homepage: http://calaba.sh
|
227
242
|
licenses:
|