angular_webdriver 0.0.7 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +32 -0
  6. data/Gemfile +2 -0
  7. data/Thorfile +33 -1
  8. data/angular_webdriver.gemspec +10 -3
  9. data/docs/overview.md +101 -0
  10. data/docs/sync.md +53 -0
  11. data/lib/angular_webdriver/protractor/by.rb +331 -0
  12. data/lib/angular_webdriver/protractor/by_repeater_inner.rb +106 -0
  13. data/lib/angular_webdriver/protractor/client_side_scripts.rb +1035 -0
  14. data/lib/angular_webdriver/protractor/protractor.rb +396 -77
  15. data/lib/angular_webdriver/protractor/protractor_element.rb +33 -0
  16. data/lib/angular_webdriver/protractor/rspec_helpers.rb +19 -0
  17. data/lib/angular_webdriver/protractor/watir_patch.rb +209 -0
  18. data/lib/angular_webdriver/protractor/webdriver_patch.rb +246 -0
  19. data/lib/angular_webdriver/version.rb +2 -2
  20. data/lib/angular_webdriver.rb +14 -1
  21. data/{LICENSE → license/angular_webdriver/LICENSE.txt} +0 -0
  22. data/{lib/angular_webdriver → license}/protractor/LICENSE.txt +0 -0
  23. data/{lib/angular_webdriver/protractor/get_url_trace.rb → notes/bootstrap_notes.md} +13 -0
  24. data/notes/element_by_id/element_by_id_sync_off.txt +12 -0
  25. data/notes/element_by_id/element_by_id_sync_on.txt +74 -0
  26. data/notes/element_chaining_debug.txt +94 -0
  27. data/notes/evaluate/js_evaluate_sync_on.txt +60 -0
  28. data/notes/evaluate/ruby_evaluate_sync_on.txt +35 -0
  29. data/notes/get_title/browser_get_title_sync_off.txt +11 -0
  30. data/notes/get_title/browser_get_title_sync_on.txt +54 -0
  31. data/notes/phantomjs.md +23 -0
  32. data/notes/protractor_cli_bugs.txt +39 -0
  33. data/notes/protractor_get/protractor_get.rb +102 -0
  34. data/notes/protractor_get/protractor_get_website_sync_off.txt +11 -0
  35. data/notes/protractor_get/protractor_get_website_sync_on.txt +86 -0
  36. data/notes/repeater/findAllRepeaterRows_annotated.txt +150 -0
  37. data/notes/repeater/findAllRepeaterRows_raw.txt +145 -0
  38. data/notes/repeater/findRepeaterColumn_annotated.txt +317 -0
  39. data/notes/repeater/findRepeaterColumn_raw.txt +310 -0
  40. data/notes/repeater/findRepeaterElement_annotated.txt +152 -0
  41. data/notes/repeater/findRepeaterElement_raw.txt +146 -0
  42. data/notes/repeater/findRepeaterRows_annotated.txt +156 -0
  43. data/notes/repeater/findRepeaterRows_raw.txt +152 -0
  44. data/notes/sync_after.md +46 -0
  45. data/notes/sync_notes.md +137 -0
  46. data/notes/synchronize_spec/status_gettext.txt +121 -0
  47. data/notes/synchronize_spec/status_gettext_x3.txt +451 -0
  48. data/notes/synchronize_spec/synchronize_spec.js.txt +74 -0
  49. data/notes/synchronize_spec/watir_gettext.txt +73 -0
  50. data/readme.md +52 -12
  51. data/release_notes.md +127 -0
  52. data/selenium_server/lib/logs.rb +50 -0
  53. data/selenium_server/lib/selenium_server.rb +21 -0
  54. data/selenium_server/readme.md +3 -0
  55. data/selenium_server/spec/logs_spec.rb +18 -0
  56. data/selenium_server/spec/nodejs_sync_spec_waithttp_annotated.txt +54 -0
  57. data/selenium_server/spec/nodejs_sync_spec_waithttp_raw.txt +367 -0
  58. data/selenium_server/spec/nodejs_sync_spec_waithttp_raw_processed.txt +43 -0
  59. data/selenium_server/spec/ruby_sync_spec_waithttp_annotated.txt +59 -0
  60. data/selenium_server/spec/ruby_sync_spec_waithttp_raw.txt +267 -0
  61. data/selenium_server/spec/ruby_sync_spec_waithttp_raw_processed.txt +39 -0
  62. data/selenium_server/spec/spec_helper.rb +6 -0
  63. data/selenium_server/spec/status_gettext_x3.txt +429 -0
  64. data/selenium_server/spec/status_gettext_x3_annotated.txt +86 -0
  65. metadata +91 -18
  66. data/lib/angular_webdriver/protractor/clientSideScripts.json +0 -19
  67. data/lib/angular_webdriver/protractor/clientsidescripts.js +0 -671
  68. data/lib/angular_webdriver/protractor/scripts.rb +0 -7
  69. data/lib/angular_webdriver/protractor/scripts_to_json.js +0 -11
  70. data/spec/protractor_spec.rb +0 -40
  71. data/spec/spec_helper.rb +0 -5
@@ -0,0 +1,1035 @@
1
+ module ClientSideScripts
2
+
3
+ # class methods
4
+
5
+ def self.scripts
6
+ @@client_side_scripts
7
+ end
8
+
9
+ def self.wait_for_angular
10
+ @@client_side_scripts[:waitForAngular]
11
+ end
12
+
13
+ def self.find_bindings
14
+ @@client_side_scripts[:findBindings]
15
+ end
16
+
17
+ def self.find_repeater_rows
18
+ @@client_side_scripts[:findRepeaterRows]
19
+ end
20
+
21
+ def self.find_all_repeater_rows
22
+ @@client_side_scripts[:findAllRepeaterRows]
23
+ end
24
+
25
+ def self.find_repeater_element
26
+ @@client_side_scripts[:findRepeaterElement]
27
+ end
28
+
29
+ def self.find_repeater_column
30
+ @@client_side_scripts[:findRepeaterColumn]
31
+ end
32
+
33
+ def self.find_by_model
34
+ @@client_side_scripts[:findByModel]
35
+ end
36
+
37
+ def self.find_by_options
38
+ @@client_side_scripts[:findByOptions]
39
+ end
40
+
41
+ def self.find_by_button_text
42
+ @@client_side_scripts[:findByButtonText]
43
+ end
44
+
45
+ def self.find_by_partial_button_text
46
+ @@client_side_scripts[:findByPartialButtonText]
47
+ end
48
+
49
+ def self.find_by_css_containing_text
50
+ @@client_side_scripts[:findByCssContainingText]
51
+ end
52
+
53
+ def self.test_for_angular
54
+ @@client_side_scripts[:testForAngular]
55
+ end
56
+
57
+ def self.evaluate
58
+ @@client_side_scripts[:evaluate]
59
+ end
60
+
61
+ def self.allow_animations
62
+ @@client_side_scripts[:allowAnimations]
63
+ end
64
+
65
+ def self.get_location_abs_url
66
+ @@client_side_scripts[:getLocationAbsUrl]
67
+ end
68
+
69
+ def self.set_location
70
+ @@client_side_scripts[:setLocation]
71
+ end
72
+
73
+ def self.install_in_browser
74
+ @@client_side_scripts[:installInBrowser]
75
+ end
76
+
77
+ @@client_side_scripts = {
78
+ waitForAngular: %q(try { return (function (rootSelector, callback) {
79
+ var el = document.querySelector(rootSelector);
80
+
81
+ try {
82
+ if (!window.angular) {
83
+ throw new Error('angular could not be found on the window');
84
+ }
85
+ if (angular.getTestability) {
86
+ angular.getTestability(el).whenStable(callback);
87
+ } else {
88
+ if (!angular.element(el).injector()) {
89
+ throw new Error('root element (' + rootSelector + ') has no injector.' +
90
+ ' this may mean it is not inside ng-app.');
91
+ }
92
+ angular.element(el).injector().get('$browser').
93
+ notifyWhenNoOutstandingRequests(callback);
94
+ }
95
+ } catch (err) {
96
+ callback(err.message);
97
+ }
98
+ }).apply(this, arguments); }
99
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
100
+ findBindings: %q(try { return (function (binding, exactMatch, using, rootSelector) {
101
+ var root = document.querySelector(rootSelector || 'body');
102
+ using = using || document;
103
+ if (angular.getTestability) {
104
+ return angular.getTestability(root).
105
+ findBindings(using, binding, exactMatch);
106
+ }
107
+ var bindings = using.getElementsByClassName('ng-binding');
108
+ var matches = [];
109
+ for (var i = 0; i < bindings.length; ++i) {
110
+ var dataBinding = angular.element(bindings[i]).data('$binding');
111
+ if (dataBinding) {
112
+ var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
113
+ if (exactMatch) {
114
+ var matcher = new RegExp('({|\\\\s|^|\\\\|)' +
115
+ /* See http://stackoverflow.com/q/3561711 */
116
+ binding.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, '\\\\$&') +
117
+ '(}|\\\\s|$|\\\\|)');
118
+ if (matcher.test(bindingName)) {
119
+ matches.push(bindings[i]);
120
+ }
121
+ } else {
122
+ if (bindingName.indexOf(binding) != -1) {
123
+ matches.push(bindings[i]);
124
+ }
125
+ }
126
+
127
+ }
128
+ }
129
+ return matches; /* Return the whole array for webdriver.findElements. */
130
+ }).apply(this, arguments); }
131
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
132
+ findRepeaterRows: %q(try { return (function (repeater, exact, index, using) {
133
+ function repeaterMatch(ngRepeat, repeater, exact) {
134
+ if (exact) {
135
+ return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
136
+ trim() == repeater;
137
+ } else {
138
+ return ngRepeat.indexOf(repeater) != -1;
139
+ }
140
+ }
141
+
142
+ using = using || document;
143
+
144
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
145
+ var rows = [];
146
+ for (var p = 0; p < prefixes.length; ++p) {
147
+ var attr = prefixes[p] + 'repeat';
148
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
149
+ attr = attr.replace(/\\\\/g, '');
150
+ for (var i = 0; i < repeatElems.length; ++i) {
151
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
152
+ rows.push(repeatElems[i]);
153
+ }
154
+ }
155
+ }
156
+ /* multiRows is an array of arrays, where each inner array contains
157
+ one row of elements. */
158
+ var multiRows = [];
159
+ for (var p = 0; p < prefixes.length; ++p) {
160
+ var attr = prefixes[p] + 'repeat-start';
161
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
162
+ attr = attr.replace(/\\\\/g, '');
163
+ for (var i = 0; i < repeatElems.length; ++i) {
164
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
165
+ var elem = repeatElems[i];
166
+ var row = [];
167
+ while (elem.nodeType != 8 ||
168
+ !repeaterMatch(elem.nodeValue, repeater, exact)) {
169
+ if (elem.nodeType == 1) {
170
+ row.push(elem);
171
+ }
172
+ elem = elem.nextSibling;
173
+ }
174
+ multiRows.push(row);
175
+ }
176
+ }
177
+ }
178
+ var row = rows[index] || [], multiRow = multiRows[index] || [];
179
+ return [].concat(row, multiRow);
180
+ }).apply(this, arguments); }
181
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
182
+ findAllRepeaterRows: %q(try { return (function (repeater, exact, using) {
183
+ function repeaterMatch(ngRepeat, repeater, exact) {
184
+ if (exact) {
185
+ return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
186
+ trim() == repeater;
187
+ } else {
188
+ return ngRepeat.indexOf(repeater) != -1;
189
+ }
190
+ }
191
+
192
+ using = using || document;
193
+
194
+ var rows = [];
195
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
196
+ for (var p = 0; p < prefixes.length; ++p) {
197
+ var attr = prefixes[p] + 'repeat';
198
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
199
+ attr = attr.replace(/\\\\/g, '');
200
+ for (var i = 0; i < repeatElems.length; ++i) {
201
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
202
+ rows.push(repeatElems[i]);
203
+ }
204
+ }
205
+ }
206
+ for (var p = 0; p < prefixes.length; ++p) {
207
+ var attr = prefixes[p] + 'repeat-start';
208
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
209
+ attr = attr.replace(/\\\\/g, '');
210
+ for (var i = 0; i < repeatElems.length; ++i) {
211
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
212
+ var elem = repeatElems[i];
213
+ while (elem.nodeType != 8 ||
214
+ !repeaterMatch(elem.nodeValue, repeater, exact)) {
215
+ if (elem.nodeType == 1) {
216
+ rows.push(elem);
217
+ }
218
+ elem = elem.nextSibling;
219
+ }
220
+ }
221
+ }
222
+ }
223
+ return rows;
224
+ }).apply(this, arguments); }
225
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
226
+ findRepeaterElement: %q(try { return (function (repeater, exact, index, binding, using, rootSelector) {
227
+ function repeaterMatch(ngRepeat, repeater, exact) {
228
+ if (exact) {
229
+ return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
230
+ trim() == repeater;
231
+ } else {
232
+ return ngRepeat.indexOf(repeater) != -1;
233
+ }
234
+ }
235
+
236
+ var matches = [];
237
+ var root = document.querySelector(rootSelector || 'body');
238
+ using = using || document;
239
+
240
+ var rows = [];
241
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
242
+ for (var p = 0; p < prefixes.length; ++p) {
243
+ var attr = prefixes[p] + 'repeat';
244
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
245
+ attr = attr.replace(/\\\\/g, '');
246
+ for (var i = 0; i < repeatElems.length; ++i) {
247
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
248
+ rows.push(repeatElems[i]);
249
+ }
250
+ }
251
+ }
252
+ /* multiRows is an array of arrays, where each inner array contains
253
+ one row of elements. */
254
+ var multiRows = [];
255
+ for (var p = 0; p < prefixes.length; ++p) {
256
+ var attr = prefixes[p] + 'repeat-start';
257
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
258
+ attr = attr.replace(/\\\\/g, '');
259
+ for (var i = 0; i < repeatElems.length; ++i) {
260
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
261
+ var elem = repeatElems[i];
262
+ var row = [];
263
+ while (elem.nodeType != 8 || (elem.nodeValue &&
264
+ !repeaterMatch(elem.nodeValue, repeater, exact))) {
265
+ if (elem.nodeType == 1) {
266
+ row.push(elem);
267
+ }
268
+ elem = elem.nextSibling;
269
+ }
270
+ multiRows.push(row);
271
+ }
272
+ }
273
+ }
274
+ var row = rows[index];
275
+ var multiRow = multiRows[index];
276
+ var bindings = [];
277
+ if (row) {
278
+ if (angular.getTestability) {
279
+ matches.push.apply(
280
+ matches,
281
+ angular.getTestability(root).findBindings(row, binding));
282
+ } else {
283
+ if (row.className.indexOf('ng-binding') != -1) {
284
+ bindings.push(row);
285
+ }
286
+ var childBindings = row.getElementsByClassName('ng-binding');
287
+ for (var i = 0; i < childBindings.length; ++i) {
288
+ bindings.push(childBindings[i]);
289
+ }
290
+ }
291
+ }
292
+ if (multiRow) {
293
+ for (var i = 0; i < multiRow.length; ++i) {
294
+ var rowElem = multiRow[i];
295
+ if (angular.getTestability) {
296
+ matches.push.apply(
297
+ matches,
298
+ angular.getTestability(root).findBindings(rowElem, binding));
299
+ } else {
300
+ if (rowElem.className.indexOf('ng-binding') != -1) {
301
+ bindings.push(rowElem);
302
+ }
303
+ var childBindings = rowElem.getElementsByClassName('ng-binding');
304
+ for (var j = 0; j < childBindings.length; ++j) {
305
+ bindings.push(childBindings[j]);
306
+ }
307
+ }
308
+ }
309
+ }
310
+ for (var i = 0; i < bindings.length; ++i) {
311
+ var dataBinding = angular.element(bindings[i]).data('$binding');
312
+ if (dataBinding) {
313
+ var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
314
+ if (bindingName.indexOf(binding) != -1) {
315
+ matches.push(bindings[i]);
316
+ }
317
+ }
318
+ }
319
+ return matches;
320
+ }).apply(this, arguments); }
321
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
322
+ findRepeaterColumn: %q(try { return (function (repeater, exact, binding, using, rootSelector) {
323
+ function repeaterMatch(ngRepeat, repeater, exact) {
324
+ if (exact) {
325
+ return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
326
+ trim() == repeater;
327
+ } else {
328
+ return ngRepeat.indexOf(repeater) != -1;
329
+ }
330
+ }
331
+
332
+ var matches = [];
333
+ var root = document.querySelector(rootSelector || 'body');
334
+ using = using || document;
335
+
336
+ var rows = [];
337
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
338
+ for (var p = 0; p < prefixes.length; ++p) {
339
+ var attr = prefixes[p] + 'repeat';
340
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
341
+ attr = attr.replace(/\\\\/g, '');
342
+ for (var i = 0; i < repeatElems.length; ++i) {
343
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
344
+ rows.push(repeatElems[i]);
345
+ }
346
+ }
347
+ }
348
+ /* multiRows is an array of arrays, where each inner array contains
349
+ one row of elements. */
350
+ var multiRows = [];
351
+ for (var p = 0; p < prefixes.length; ++p) {
352
+ var attr = prefixes[p] + 'repeat-start';
353
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
354
+ attr = attr.replace(/\\\\/g, '');
355
+ for (var i = 0; i < repeatElems.length; ++i) {
356
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
357
+ var elem = repeatElems[i];
358
+ var row = [];
359
+ while (elem.nodeType != 8 || (elem.nodeValue &&
360
+ !repeaterMatch(elem.nodeValue, repeater, exact))) {
361
+ if (elem.nodeType == 1) {
362
+ row.push(elem);
363
+ }
364
+ elem = elem.nextSibling;
365
+ }
366
+ multiRows.push(row);
367
+ }
368
+ }
369
+ }
370
+ var bindings = [];
371
+ for (var i = 0; i < rows.length; ++i) {
372
+ if (angular.getTestability) {
373
+ matches.push.apply(
374
+ matches,
375
+ angular.getTestability(root).findBindings(rows[i], binding));
376
+ } else {
377
+ if (rows[i].className.indexOf('ng-binding') != -1) {
378
+ bindings.push(rows[i]);
379
+ }
380
+ var childBindings = rows[i].getElementsByClassName('ng-binding');
381
+ for (var k = 0; k < childBindings.length; ++k) {
382
+ bindings.push(childBindings[k]);
383
+ }
384
+ }
385
+ }
386
+ for (var i = 0; i < multiRows.length; ++i) {
387
+ for (var j = 0; j < multiRows[i].length; ++j) {
388
+ if (angular.getTestability) {
389
+ matches.push.apply(
390
+ matches,
391
+ angular.getTestability(root).findBindings(multiRows[i][j], binding));
392
+ } else {
393
+ var elem = multiRows[i][j];
394
+ if (elem.className.indexOf('ng-binding') != -1) {
395
+ bindings.push(elem);
396
+ }
397
+ var childBindings = elem.getElementsByClassName('ng-binding');
398
+ for (var k = 0; k < childBindings.length; ++k) {
399
+ bindings.push(childBindings[k]);
400
+ }
401
+ }
402
+ }
403
+ }
404
+ for (var j = 0; j < bindings.length; ++j) {
405
+ var dataBinding = angular.element(bindings[j]).data('$binding');
406
+ if (dataBinding) {
407
+ var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
408
+ if (bindingName.indexOf(binding) != -1) {
409
+ matches.push(bindings[j]);
410
+ }
411
+ }
412
+ }
413
+ return matches;
414
+ }).apply(this, arguments); }
415
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
416
+ findByModel: %q(try { return (function (model, using, rootSelector) {
417
+ var root = document.querySelector(rootSelector || 'body');
418
+ using = using || document;
419
+
420
+ if (angular.getTestability) {
421
+ return angular.getTestability(root).
422
+ findModels(using, model, true);
423
+ }
424
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
425
+ for (var p = 0; p < prefixes.length; ++p) {
426
+ var selector = '[' + prefixes[p] + 'model="' + model + '"]';
427
+ var elements = using.querySelectorAll(selector);
428
+ if (elements.length) {
429
+ return elements;
430
+ }
431
+ }
432
+ }).apply(this, arguments); }
433
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
434
+ findByOptions: %q(try { return (function (optionsDescriptor, using) {
435
+ using = using || document;
436
+
437
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
438
+ for (var p = 0; p < prefixes.length; ++p) {
439
+ var selector = '[' + prefixes[p] + 'options="' + optionsDescriptor + '"] option';
440
+ var elements = using.querySelectorAll(selector);
441
+ if (elements.length) {
442
+ return elements;
443
+ }
444
+ }
445
+ }).apply(this, arguments); }
446
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
447
+ findByButtonText: %q(try { return (function (searchText, using) {
448
+ using = using || document;
449
+
450
+ var elements = using.querySelectorAll('button, input[type="button"], input[type="submit"]');
451
+ var matches = [];
452
+ for (var i = 0; i < elements.length; ++i) {
453
+ var element = elements[i];
454
+ var elementText;
455
+ if (element.tagName.toLowerCase() == 'button') {
456
+ elementText = element.textContent || element.innerText || '';
457
+ } else {
458
+ elementText = element.value;
459
+ }
460
+ if (elementText.trim() === searchText) {
461
+ matches.push(element);
462
+ }
463
+ }
464
+
465
+ return matches;
466
+ }).apply(this, arguments); }
467
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
468
+ findByPartialButtonText: %q(try { return (function (searchText, using) {
469
+ using = using || document;
470
+
471
+ var elements = using.querySelectorAll('button, input[type="button"], input[type="submit"]');
472
+ var matches = [];
473
+ for (var i = 0; i < elements.length; ++i) {
474
+ var element = elements[i];
475
+ var elementText;
476
+ if (element.tagName.toLowerCase() == 'button') {
477
+ elementText = element.textContent || element.innerText || '';
478
+ } else {
479
+ elementText = element.value;
480
+ }
481
+ if (elementText.indexOf(searchText) > -1) {
482
+ matches.push(element);
483
+ }
484
+ }
485
+
486
+ return matches;
487
+ }).apply(this, arguments); }
488
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
489
+ findByCssContainingText: %q(try { return (function (cssSelector, searchText, using) {
490
+ using = using || document;
491
+
492
+ var elements = using.querySelectorAll(cssSelector);
493
+ var matches = [];
494
+ for (var i = 0; i < elements.length; ++i) {
495
+ var element = elements[i];
496
+ var elementText = element.textContent || element.innerText || '';
497
+ if (elementText.indexOf(searchText) > -1) {
498
+ matches.push(element);
499
+ }
500
+ }
501
+ return matches;
502
+ }).apply(this, arguments); }
503
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
504
+ testForAngular: %q(try { return (function (attempts, asyncCallback) {
505
+ var callback = function(args) {
506
+ setTimeout(function() {
507
+ asyncCallback(args);
508
+ }, 0);
509
+ };
510
+ var check = function(n) {
511
+ try {
512
+ if (window.angular && window.angular.resumeBootstrap) {
513
+ callback([true, null]);
514
+ } else if (n < 1) {
515
+ if (window.angular) {
516
+ callback([false, 'angular never provided resumeBootstrap']);
517
+ } else {
518
+ callback([false, 'retries looking for angular exceeded']);
519
+ }
520
+ } else {
521
+ window.setTimeout(function() {check(n - 1);}, 1000);
522
+ }
523
+ } catch (e) {
524
+ callback([false, e]);
525
+ }
526
+ };
527
+ check(attempts);
528
+ }).apply(this, arguments); }
529
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
530
+ evaluate: %q(try { return (function (element, expression) {
531
+ return angular.element(element).scope().$eval(expression);
532
+ }).apply(this, arguments); }
533
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
534
+ allowAnimations: %q(try { return (function (element, value) {
535
+ var ngElement = angular.element(element);
536
+ if (ngElement.allowAnimations) {
537
+ // AngularDart: $testability API.
538
+ return ngElement.allowAnimations(value);
539
+ } else {
540
+ // AngularJS
541
+ var enabledFn = ngElement.injector().get('$animate').enabled;
542
+ return (value == null) ? enabledFn() : enabledFn(value);
543
+ }
544
+ }).apply(this, arguments); }
545
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
546
+ getLocationAbsUrl: %q(try { return (function (selector) {
547
+ var el = document.querySelector(selector);
548
+ if (angular.getTestability) {
549
+ return angular.getTestability(el).
550
+ getLocation();
551
+ }
552
+ return angular.element(el).injector().get('$location').absUrl();
553
+ }).apply(this, arguments); }
554
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
555
+ setLocation: %q(try { return (function (selector, url) {
556
+ var el = document.querySelector(selector);
557
+ if (angular.getTestability) {
558
+ return angular.getTestability(el).
559
+ setLocation(url);
560
+ }
561
+ var $injector = angular.element(el).injector();
562
+ var $location = $injector.get('$location');
563
+ var $rootScope = $injector.get('$rootScope');
564
+
565
+ if (url !== $location.url()) {
566
+ $location.url(url);
567
+ $rootScope.$digest();
568
+ }
569
+ }).apply(this, arguments); }
570
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }).freeze,
571
+ installInBrowser: %q(window.clientSideScripts = {waitForAngular: function (rootSelector, callback) {
572
+ var el = document.querySelector(rootSelector);
573
+
574
+ try {
575
+ if (!window.angular) {
576
+ throw new Error('angular could not be found on the window');
577
+ }
578
+ if (angular.getTestability) {
579
+ angular.getTestability(el).whenStable(callback);
580
+ } else {
581
+ if (!angular.element(el).injector()) {
582
+ throw new Error('root element (' + rootSelector + ') has no injector.' +
583
+ ' this may mean it is not inside ng-app.');
584
+ }
585
+ angular.element(el).injector().get('$browser').
586
+ notifyWhenNoOutstandingRequests(callback);
587
+ }
588
+ } catch (err) {
589
+ callback(err.message);
590
+ }
591
+ }, findBindings: function (binding, exactMatch, using, rootSelector) {
592
+ var root = document.querySelector(rootSelector || 'body');
593
+ using = using || document;
594
+ if (angular.getTestability) {
595
+ return angular.getTestability(root).
596
+ findBindings(using, binding, exactMatch);
597
+ }
598
+ var bindings = using.getElementsByClassName('ng-binding');
599
+ var matches = [];
600
+ for (var i = 0; i < bindings.length; ++i) {
601
+ var dataBinding = angular.element(bindings[i]).data('$binding');
602
+ if (dataBinding) {
603
+ var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
604
+ if (exactMatch) {
605
+ var matcher = new RegExp('({|\\\\s|^|\\\\|)' +
606
+ /* See http://stackoverflow.com/q/3561711 */
607
+ binding.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, '\\\\$&') +
608
+ '(}|\\\\s|$|\\\\|)');
609
+ if (matcher.test(bindingName)) {
610
+ matches.push(bindings[i]);
611
+ }
612
+ } else {
613
+ if (bindingName.indexOf(binding) != -1) {
614
+ matches.push(bindings[i]);
615
+ }
616
+ }
617
+
618
+ }
619
+ }
620
+ return matches; /* Return the whole array for webdriver.findElements. */
621
+ }, findRepeaterRows: function (repeater, exact, index, using) {
622
+ function repeaterMatch(ngRepeat, repeater, exact) {
623
+ if (exact) {
624
+ return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
625
+ trim() == repeater;
626
+ } else {
627
+ return ngRepeat.indexOf(repeater) != -1;
628
+ }
629
+ }
630
+
631
+ using = using || document;
632
+
633
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
634
+ var rows = [];
635
+ for (var p = 0; p < prefixes.length; ++p) {
636
+ var attr = prefixes[p] + 'repeat';
637
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
638
+ attr = attr.replace(/\\\\/g, '');
639
+ for (var i = 0; i < repeatElems.length; ++i) {
640
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
641
+ rows.push(repeatElems[i]);
642
+ }
643
+ }
644
+ }
645
+ /* multiRows is an array of arrays, where each inner array contains
646
+ one row of elements. */
647
+ var multiRows = [];
648
+ for (var p = 0; p < prefixes.length; ++p) {
649
+ var attr = prefixes[p] + 'repeat-start';
650
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
651
+ attr = attr.replace(/\\\\/g, '');
652
+ for (var i = 0; i < repeatElems.length; ++i) {
653
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
654
+ var elem = repeatElems[i];
655
+ var row = [];
656
+ while (elem.nodeType != 8 ||
657
+ !repeaterMatch(elem.nodeValue, repeater, exact)) {
658
+ if (elem.nodeType == 1) {
659
+ row.push(elem);
660
+ }
661
+ elem = elem.nextSibling;
662
+ }
663
+ multiRows.push(row);
664
+ }
665
+ }
666
+ }
667
+ var row = rows[index] || [], multiRow = multiRows[index] || [];
668
+ return [].concat(row, multiRow);
669
+ }, findAllRepeaterRows: function (repeater, exact, using) {
670
+ function repeaterMatch(ngRepeat, repeater, exact) {
671
+ if (exact) {
672
+ return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
673
+ trim() == repeater;
674
+ } else {
675
+ return ngRepeat.indexOf(repeater) != -1;
676
+ }
677
+ }
678
+
679
+ using = using || document;
680
+
681
+ var rows = [];
682
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
683
+ for (var p = 0; p < prefixes.length; ++p) {
684
+ var attr = prefixes[p] + 'repeat';
685
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
686
+ attr = attr.replace(/\\\\/g, '');
687
+ for (var i = 0; i < repeatElems.length; ++i) {
688
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
689
+ rows.push(repeatElems[i]);
690
+ }
691
+ }
692
+ }
693
+ for (var p = 0; p < prefixes.length; ++p) {
694
+ var attr = prefixes[p] + 'repeat-start';
695
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
696
+ attr = attr.replace(/\\\\/g, '');
697
+ for (var i = 0; i < repeatElems.length; ++i) {
698
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
699
+ var elem = repeatElems[i];
700
+ while (elem.nodeType != 8 ||
701
+ !repeaterMatch(elem.nodeValue, repeater, exact)) {
702
+ if (elem.nodeType == 1) {
703
+ rows.push(elem);
704
+ }
705
+ elem = elem.nextSibling;
706
+ }
707
+ }
708
+ }
709
+ }
710
+ return rows;
711
+ }, findRepeaterElement: function (repeater, exact, index, binding, using, rootSelector) {
712
+ function repeaterMatch(ngRepeat, repeater, exact) {
713
+ if (exact) {
714
+ return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
715
+ trim() == repeater;
716
+ } else {
717
+ return ngRepeat.indexOf(repeater) != -1;
718
+ }
719
+ }
720
+
721
+ var matches = [];
722
+ var root = document.querySelector(rootSelector || 'body');
723
+ using = using || document;
724
+
725
+ var rows = [];
726
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
727
+ for (var p = 0; p < prefixes.length; ++p) {
728
+ var attr = prefixes[p] + 'repeat';
729
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
730
+ attr = attr.replace(/\\\\/g, '');
731
+ for (var i = 0; i < repeatElems.length; ++i) {
732
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
733
+ rows.push(repeatElems[i]);
734
+ }
735
+ }
736
+ }
737
+ /* multiRows is an array of arrays, where each inner array contains
738
+ one row of elements. */
739
+ var multiRows = [];
740
+ for (var p = 0; p < prefixes.length; ++p) {
741
+ var attr = prefixes[p] + 'repeat-start';
742
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
743
+ attr = attr.replace(/\\\\/g, '');
744
+ for (var i = 0; i < repeatElems.length; ++i) {
745
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
746
+ var elem = repeatElems[i];
747
+ var row = [];
748
+ while (elem.nodeType != 8 || (elem.nodeValue &&
749
+ !repeaterMatch(elem.nodeValue, repeater, exact))) {
750
+ if (elem.nodeType == 1) {
751
+ row.push(elem);
752
+ }
753
+ elem = elem.nextSibling;
754
+ }
755
+ multiRows.push(row);
756
+ }
757
+ }
758
+ }
759
+ var row = rows[index];
760
+ var multiRow = multiRows[index];
761
+ var bindings = [];
762
+ if (row) {
763
+ if (angular.getTestability) {
764
+ matches.push.apply(
765
+ matches,
766
+ angular.getTestability(root).findBindings(row, binding));
767
+ } else {
768
+ if (row.className.indexOf('ng-binding') != -1) {
769
+ bindings.push(row);
770
+ }
771
+ var childBindings = row.getElementsByClassName('ng-binding');
772
+ for (var i = 0; i < childBindings.length; ++i) {
773
+ bindings.push(childBindings[i]);
774
+ }
775
+ }
776
+ }
777
+ if (multiRow) {
778
+ for (var i = 0; i < multiRow.length; ++i) {
779
+ var rowElem = multiRow[i];
780
+ if (angular.getTestability) {
781
+ matches.push.apply(
782
+ matches,
783
+ angular.getTestability(root).findBindings(rowElem, binding));
784
+ } else {
785
+ if (rowElem.className.indexOf('ng-binding') != -1) {
786
+ bindings.push(rowElem);
787
+ }
788
+ var childBindings = rowElem.getElementsByClassName('ng-binding');
789
+ for (var j = 0; j < childBindings.length; ++j) {
790
+ bindings.push(childBindings[j]);
791
+ }
792
+ }
793
+ }
794
+ }
795
+ for (var i = 0; i < bindings.length; ++i) {
796
+ var dataBinding = angular.element(bindings[i]).data('$binding');
797
+ if (dataBinding) {
798
+ var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
799
+ if (bindingName.indexOf(binding) != -1) {
800
+ matches.push(bindings[i]);
801
+ }
802
+ }
803
+ }
804
+ return matches;
805
+ }, findRepeaterColumn: function (repeater, exact, binding, using, rootSelector) {
806
+ function repeaterMatch(ngRepeat, repeater, exact) {
807
+ if (exact) {
808
+ return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
809
+ trim() == repeater;
810
+ } else {
811
+ return ngRepeat.indexOf(repeater) != -1;
812
+ }
813
+ }
814
+
815
+ var matches = [];
816
+ var root = document.querySelector(rootSelector || 'body');
817
+ using = using || document;
818
+
819
+ var rows = [];
820
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
821
+ for (var p = 0; p < prefixes.length; ++p) {
822
+ var attr = prefixes[p] + 'repeat';
823
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
824
+ attr = attr.replace(/\\\\/g, '');
825
+ for (var i = 0; i < repeatElems.length; ++i) {
826
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
827
+ rows.push(repeatElems[i]);
828
+ }
829
+ }
830
+ }
831
+ /* multiRows is an array of arrays, where each inner array contains
832
+ one row of elements. */
833
+ var multiRows = [];
834
+ for (var p = 0; p < prefixes.length; ++p) {
835
+ var attr = prefixes[p] + 'repeat-start';
836
+ var repeatElems = using.querySelectorAll('[' + attr + ']');
837
+ attr = attr.replace(/\\\\/g, '');
838
+ for (var i = 0; i < repeatElems.length; ++i) {
839
+ if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
840
+ var elem = repeatElems[i];
841
+ var row = [];
842
+ while (elem.nodeType != 8 || (elem.nodeValue &&
843
+ !repeaterMatch(elem.nodeValue, repeater, exact))) {
844
+ if (elem.nodeType == 1) {
845
+ row.push(elem);
846
+ }
847
+ elem = elem.nextSibling;
848
+ }
849
+ multiRows.push(row);
850
+ }
851
+ }
852
+ }
853
+ var bindings = [];
854
+ for (var i = 0; i < rows.length; ++i) {
855
+ if (angular.getTestability) {
856
+ matches.push.apply(
857
+ matches,
858
+ angular.getTestability(root).findBindings(rows[i], binding));
859
+ } else {
860
+ if (rows[i].className.indexOf('ng-binding') != -1) {
861
+ bindings.push(rows[i]);
862
+ }
863
+ var childBindings = rows[i].getElementsByClassName('ng-binding');
864
+ for (var k = 0; k < childBindings.length; ++k) {
865
+ bindings.push(childBindings[k]);
866
+ }
867
+ }
868
+ }
869
+ for (var i = 0; i < multiRows.length; ++i) {
870
+ for (var j = 0; j < multiRows[i].length; ++j) {
871
+ if (angular.getTestability) {
872
+ matches.push.apply(
873
+ matches,
874
+ angular.getTestability(root).findBindings(multiRows[i][j], binding));
875
+ } else {
876
+ var elem = multiRows[i][j];
877
+ if (elem.className.indexOf('ng-binding') != -1) {
878
+ bindings.push(elem);
879
+ }
880
+ var childBindings = elem.getElementsByClassName('ng-binding');
881
+ for (var k = 0; k < childBindings.length; ++k) {
882
+ bindings.push(childBindings[k]);
883
+ }
884
+ }
885
+ }
886
+ }
887
+ for (var j = 0; j < bindings.length; ++j) {
888
+ var dataBinding = angular.element(bindings[j]).data('$binding');
889
+ if (dataBinding) {
890
+ var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
891
+ if (bindingName.indexOf(binding) != -1) {
892
+ matches.push(bindings[j]);
893
+ }
894
+ }
895
+ }
896
+ return matches;
897
+ }, findByModel: function (model, using, rootSelector) {
898
+ var root = document.querySelector(rootSelector || 'body');
899
+ using = using || document;
900
+
901
+ if (angular.getTestability) {
902
+ return angular.getTestability(root).
903
+ findModels(using, model, true);
904
+ }
905
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
906
+ for (var p = 0; p < prefixes.length; ++p) {
907
+ var selector = '[' + prefixes[p] + 'model="' + model + '"]';
908
+ var elements = using.querySelectorAll(selector);
909
+ if (elements.length) {
910
+ return elements;
911
+ }
912
+ }
913
+ }, findByOptions: function (optionsDescriptor, using) {
914
+ using = using || document;
915
+
916
+ var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
917
+ for (var p = 0; p < prefixes.length; ++p) {
918
+ var selector = '[' + prefixes[p] + 'options="' + optionsDescriptor + '"] option';
919
+ var elements = using.querySelectorAll(selector);
920
+ if (elements.length) {
921
+ return elements;
922
+ }
923
+ }
924
+ }, findByButtonText: function (searchText, using) {
925
+ using = using || document;
926
+
927
+ var elements = using.querySelectorAll('button, input[type="button"], input[type="submit"]');
928
+ var matches = [];
929
+ for (var i = 0; i < elements.length; ++i) {
930
+ var element = elements[i];
931
+ var elementText;
932
+ if (element.tagName.toLowerCase() == 'button') {
933
+ elementText = element.textContent || element.innerText || '';
934
+ } else {
935
+ elementText = element.value;
936
+ }
937
+ if (elementText.trim() === searchText) {
938
+ matches.push(element);
939
+ }
940
+ }
941
+
942
+ return matches;
943
+ }, findByPartialButtonText: function (searchText, using) {
944
+ using = using || document;
945
+
946
+ var elements = using.querySelectorAll('button, input[type="button"], input[type="submit"]');
947
+ var matches = [];
948
+ for (var i = 0; i < elements.length; ++i) {
949
+ var element = elements[i];
950
+ var elementText;
951
+ if (element.tagName.toLowerCase() == 'button') {
952
+ elementText = element.textContent || element.innerText || '';
953
+ } else {
954
+ elementText = element.value;
955
+ }
956
+ if (elementText.indexOf(searchText) > -1) {
957
+ matches.push(element);
958
+ }
959
+ }
960
+
961
+ return matches;
962
+ }, findByCssContainingText: function (cssSelector, searchText, using) {
963
+ using = using || document;
964
+
965
+ var elements = using.querySelectorAll(cssSelector);
966
+ var matches = [];
967
+ for (var i = 0; i < elements.length; ++i) {
968
+ var element = elements[i];
969
+ var elementText = element.textContent || element.innerText || '';
970
+ if (elementText.indexOf(searchText) > -1) {
971
+ matches.push(element);
972
+ }
973
+ }
974
+ return matches;
975
+ }, testForAngular: function (attempts, asyncCallback) {
976
+ var callback = function(args) {
977
+ setTimeout(function() {
978
+ asyncCallback(args);
979
+ }, 0);
980
+ };
981
+ var check = function(n) {
982
+ try {
983
+ if (window.angular && window.angular.resumeBootstrap) {
984
+ callback([true, null]);
985
+ } else if (n < 1) {
986
+ if (window.angular) {
987
+ callback([false, 'angular never provided resumeBootstrap']);
988
+ } else {
989
+ callback([false, 'retries looking for angular exceeded']);
990
+ }
991
+ } else {
992
+ window.setTimeout(function() {check(n - 1);}, 1000);
993
+ }
994
+ } catch (e) {
995
+ callback([false, e]);
996
+ }
997
+ };
998
+ check(attempts);
999
+ }, evaluate: function (element, expression) {
1000
+ return angular.element(element).scope().$eval(expression);
1001
+ }, allowAnimations: function (element, value) {
1002
+ var ngElement = angular.element(element);
1003
+ if (ngElement.allowAnimations) {
1004
+ // AngularDart: $testability API.
1005
+ return ngElement.allowAnimations(value);
1006
+ } else {
1007
+ // AngularJS
1008
+ var enabledFn = ngElement.injector().get('$animate').enabled;
1009
+ return (value == null) ? enabledFn() : enabledFn(value);
1010
+ }
1011
+ }, getLocationAbsUrl: function (selector) {
1012
+ var el = document.querySelector(selector);
1013
+ if (angular.getTestability) {
1014
+ return angular.getTestability(el).
1015
+ getLocation();
1016
+ }
1017
+ return angular.element(el).injector().get('$location').absUrl();
1018
+ }, setLocation: function (selector, url) {
1019
+ var el = document.querySelector(selector);
1020
+ if (angular.getTestability) {
1021
+ return angular.getTestability(el).
1022
+ setLocation(url);
1023
+ }
1024
+ var $injector = angular.element(el).injector();
1025
+ var $location = $injector.get('$location');
1026
+ var $rootScope = $injector.get('$rootScope');
1027
+
1028
+ if (url !== $location.url()) {
1029
+ $location.url(url);
1030
+ $rootScope.$digest();
1031
+ }
1032
+ }};).freeze,
1033
+
1034
+ }.freeze
1035
+ end