angular_webdriver 0.0.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,671 +0,0 @@
1
- // rev b783dd865dfd16e5099a863d36d497499026b208
2
- /**
3
- * All scripts to be run on the client via executeAsyncScript or
4
- * executeScript should be put here.
5
- *
6
- * NOTE: These scripts are transmitted over the wire as JavaScript text
7
- * constructed using their toString representation, and *cannot*
8
- * reference external variables.
9
- *
10
- * Some implementations seem to have issues with // comments, so use star-style
11
- * inside scripts. (TODO: add issue number / example implementations
12
- * that caused the switch to avoid the // comments.)
13
- */
14
-
15
- // jshint browser: true
16
- // jshint shadow: true
17
- /* global angular */
18
- var functions = {};
19
-
20
- /**
21
- * Wait until Angular has finished rendering and has
22
- * no outstanding $http calls before continuing.
23
- *
24
- * Asynchronous.
25
- *
26
- * @param {string} rootSelector The selector housing an ng-app
27
- * @param {function(string)} callback callback. If a failure occurs, it will
28
- * be passed as a parameter.
29
- */
30
- functions.waitForAngular = function(rootSelector, callback) {
31
- var el = document.querySelector(rootSelector);
32
-
33
- try {
34
- if (!window.angular) {
35
- throw new Error('angular could not be found on the window');
36
- }
37
- if (angular.getTestability) {
38
- angular.getTestability(el).whenStable(callback);
39
- } else {
40
- if (!angular.element(el).injector()) {
41
- throw new Error('root element (' + rootSelector + ') has no injector.' +
42
- ' this may mean it is not inside ng-app.');
43
- }
44
- angular.element(el).injector().get('$browser').
45
- notifyWhenNoOutstandingRequests(callback);
46
- }
47
- } catch (err) {
48
- callback(err.message);
49
- }
50
- };
51
-
52
- /**
53
- * Find a list of elements in the page by their angular binding.
54
- *
55
- * @param {string} binding The binding, e.g. {{cat.name}}.
56
- * @param {boolean} exactMatch Whether the binding needs to be matched exactly
57
- * @param {Element} using The scope of the search.
58
- * @param {string} rootSelector The selector to use for the root app element.
59
- *
60
- * @return {Array.<Element>} The elements containing the binding.
61
- */
62
- functions.findBindings = function(binding, exactMatch, using, rootSelector) {
63
- var root = document.querySelector(rootSelector || 'body');
64
- using = using || document;
65
- if (angular.getTestability) {
66
- return angular.getTestability(root).
67
- findBindings(using, binding, exactMatch);
68
- }
69
- var bindings = using.getElementsByClassName('ng-binding');
70
- var matches = [];
71
- for (var i = 0; i < bindings.length; ++i) {
72
- var dataBinding = angular.element(bindings[i]).data('$binding');
73
- if (dataBinding) {
74
- var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
75
- if (exactMatch) {
76
- var matcher = new RegExp('({|\\s|^|\\|)' + binding + '(}|\\s|$|\\|)');
77
- if (matcher.test(bindingName)) {
78
- matches.push(bindings[i]);
79
- }
80
- } else {
81
- if (bindingName.indexOf(binding) != -1) {
82
- matches.push(bindings[i]);
83
- }
84
- }
85
-
86
- }
87
- }
88
- return matches; /* Return the whole array for webdriver.findElements. */
89
- };
90
-
91
- /**
92
- * Find an array of elements matching a row within an ng-repeat.
93
- * Always returns an array of only one element for plain old ng-repeat.
94
- * Returns an array of all the elements in one segment for ng-repeat-start.
95
- *
96
- * @param {string} repeater The text of the repeater, e.g. 'cat in cats'.
97
- * @param {boolean} exact Whether the repeater needs to be matched exactly
98
- * @param {number} index The row index.
99
- * @param {Element} using The scope of the search.
100
- *
101
- * @return {Array.<Element>} The row of the repeater, or an array of elements
102
- * in the first row in the case of ng-repeat-start.
103
- */
104
- functions.findRepeaterRows = function(repeater, exact, index, using) {
105
- function repeaterMatch(ngRepeat, repeater, exact) {
106
- if (exact) {
107
- return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
108
- trim() == repeater;
109
- } else {
110
- return ngRepeat.indexOf(repeater) != -1;
111
- }
112
- }
113
-
114
- using = using || document;
115
-
116
- var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
117
- var rows = [];
118
- for (var p = 0; p < prefixes.length; ++p) {
119
- var attr = prefixes[p] + 'repeat';
120
- var repeatElems = using.querySelectorAll('[' + attr + ']');
121
- attr = attr.replace(/\\/g, '');
122
- for (var i = 0; i < repeatElems.length; ++i) {
123
- if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
124
- rows.push(repeatElems[i]);
125
- }
126
- }
127
- }
128
- /* multiRows is an array of arrays, where each inner array contains
129
- one row of elements. */
130
- var multiRows = [];
131
- for (var p = 0; p < prefixes.length; ++p) {
132
- var attr = prefixes[p] + 'repeat-start';
133
- var repeatElems = using.querySelectorAll('[' + attr + ']');
134
- attr = attr.replace(/\\/g, '');
135
- for (var i = 0; i < repeatElems.length; ++i) {
136
- if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
137
- var elem = repeatElems[i];
138
- var row = [];
139
- while (elem.nodeType != 8 ||
140
- !repeaterMatch(elem.nodeValue, repeater, exact)) {
141
- if (elem.nodeType == 1) {
142
- row.push(elem);
143
- }
144
- elem = elem.nextSibling;
145
- }
146
- multiRows.push(row);
147
- }
148
- }
149
- }
150
- var row = rows[index] || [], multiRow = multiRows[index] || [];
151
- return [].concat(row, multiRow);
152
- };
153
-
154
- /**
155
- * Find all rows of an ng-repeat.
156
- *
157
- * @param {string} repeater The text of the repeater, e.g. 'cat in cats'.
158
- * @param {boolean} exact Whether the repeater needs to be matched exactly
159
- * @param {Element} using The scope of the search.
160
- *
161
- * @return {Array.<Element>} All rows of the repeater.
162
- */
163
- functions.findAllRepeaterRows = function(repeater, exact, using) {
164
- function repeaterMatch(ngRepeat, repeater, exact) {
165
- if (exact) {
166
- return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
167
- trim() == repeater;
168
- } else {
169
- return ngRepeat.indexOf(repeater) != -1;
170
- }
171
- }
172
-
173
- using = using || document;
174
-
175
- var rows = [];
176
- var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
177
- for (var p = 0; p < prefixes.length; ++p) {
178
- var attr = prefixes[p] + 'repeat';
179
- var repeatElems = using.querySelectorAll('[' + attr + ']');
180
- attr = attr.replace(/\\/g, '');
181
- for (var i = 0; i < repeatElems.length; ++i) {
182
- if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
183
- rows.push(repeatElems[i]);
184
- }
185
- }
186
- }
187
- for (var p = 0; p < prefixes.length; ++p) {
188
- var attr = prefixes[p] + 'repeat-start';
189
- var repeatElems = using.querySelectorAll('[' + attr + ']');
190
- attr = attr.replace(/\\/g, '');
191
- for (var i = 0; i < repeatElems.length; ++i) {
192
- if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
193
- var elem = repeatElems[i];
194
- while (elem.nodeType != 8 ||
195
- !repeaterMatch(elem.nodeValue, repeater, exact)) {
196
- if (elem.nodeType == 1) {
197
- rows.push(elem);
198
- }
199
- elem = elem.nextSibling;
200
- }
201
- }
202
- }
203
- }
204
- return rows;
205
- };
206
-
207
- /**
208
- * Find an element within an ng-repeat by its row and column.
209
- *
210
- * @param {string} repeater The text of the repeater, e.g. 'cat in cats'.
211
- * @param {boolean} exact Whether the repeater needs to be matched exactly
212
- * @param {number} index The row index.
213
- * @param {string} binding The column binding, e.g. '{{cat.name}}'.
214
- * @param {Element} using The scope of the search.
215
- * @param {string} rootSelector The selector to use for the root app element.
216
- *
217
- * @return {Array.<Element>} The element in an array.
218
- */
219
- functions.findRepeaterElement = function(repeater, exact, index, binding, using, rootSelector) {
220
- function repeaterMatch(ngRepeat, repeater, exact) {
221
- if (exact) {
222
- return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
223
- trim() == repeater;
224
- } else {
225
- return ngRepeat.indexOf(repeater) != -1;
226
- }
227
- }
228
-
229
- var matches = [];
230
- var root = document.querySelector(rootSelector || 'body');
231
- using = using || document;
232
-
233
- var rows = [];
234
- var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
235
- for (var p = 0; p < prefixes.length; ++p) {
236
- var attr = prefixes[p] + 'repeat';
237
- var repeatElems = using.querySelectorAll('[' + attr + ']');
238
- attr = attr.replace(/\\/g, '');
239
- for (var i = 0; i < repeatElems.length; ++i) {
240
- if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
241
- rows.push(repeatElems[i]);
242
- }
243
- }
244
- }
245
- /* multiRows is an array of arrays, where each inner array contains
246
- one row of elements. */
247
- var multiRows = [];
248
- for (var p = 0; p < prefixes.length; ++p) {
249
- var attr = prefixes[p] + 'repeat-start';
250
- var repeatElems = using.querySelectorAll('[' + attr + ']');
251
- attr = attr.replace(/\\/g, '');
252
- for (var i = 0; i < repeatElems.length; ++i) {
253
- if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
254
- var elem = repeatElems[i];
255
- var row = [];
256
- while (elem.nodeType != 8 || (elem.nodeValue &&
257
- !repeaterMatch(elem.nodeValue, repeater, exact))) {
258
- if (elem.nodeType == 1) {
259
- row.push(elem);
260
- }
261
- elem = elem.nextSibling;
262
- }
263
- multiRows.push(row);
264
- }
265
- }
266
- }
267
- var row = rows[index];
268
- var multiRow = multiRows[index];
269
- var bindings = [];
270
- if (row) {
271
- if (angular.getTestability) {
272
- matches.push.apply(
273
- matches,
274
- angular.getTestability(root).findBindings(row, binding));
275
- } else {
276
- if (row.className.indexOf('ng-binding') != -1) {
277
- bindings.push(row);
278
- }
279
- var childBindings = row.getElementsByClassName('ng-binding');
280
- for (var i = 0; i < childBindings.length; ++i) {
281
- bindings.push(childBindings[i]);
282
- }
283
- }
284
- }
285
- if (multiRow) {
286
- for (var i = 0; i < multiRow.length; ++i) {
287
- var rowElem = multiRow[i];
288
- if (angular.getTestability) {
289
- matches.push.apply(
290
- matches,
291
- angular.getTestability(root).findBindings(rowElem, binding));
292
- } else {
293
- if (rowElem.className.indexOf('ng-binding') != -1) {
294
- bindings.push(rowElem);
295
- }
296
- var childBindings = rowElem.getElementsByClassName('ng-binding');
297
- for (var j = 0; j < childBindings.length; ++j) {
298
- bindings.push(childBindings[j]);
299
- }
300
- }
301
- }
302
- }
303
- for (var i = 0; i < bindings.length; ++i) {
304
- var dataBinding = angular.element(bindings[i]).data('$binding');
305
- if (dataBinding) {
306
- var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
307
- if (bindingName.indexOf(binding) != -1) {
308
- matches.push(bindings[i]);
309
- }
310
- }
311
- }
312
- return matches;
313
- };
314
-
315
- /**
316
- * Find the elements in a column of an ng-repeat.
317
- *
318
- * @param {string} repeater The text of the repeater, e.g. 'cat in cats'.
319
- * @param {boolean} exact Whether the repeater needs to be matched exactly
320
- * @param {string} binding The column binding, e.g. '{{cat.name}}'.
321
- * @param {Element} using The scope of the search.
322
- * @param {string} rootSelector The selector to use for the root app element.
323
- *
324
- * @return {Array.<Element>} The elements in the column.
325
- */
326
- functions.findRepeaterColumn = function(repeater, exact, binding, using, rootSelector) {
327
- function repeaterMatch(ngRepeat, repeater, exact) {
328
- if (exact) {
329
- return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
330
- trim() == repeater;
331
- } else {
332
- return ngRepeat.indexOf(repeater) != -1;
333
- }
334
- }
335
-
336
- var matches = [];
337
- var root = document.querySelector(rootSelector || 'body');
338
- using = using || document;
339
-
340
- var rows = [];
341
- var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
342
- for (var p = 0; p < prefixes.length; ++p) {
343
- var attr = prefixes[p] + 'repeat';
344
- var repeatElems = using.querySelectorAll('[' + attr + ']');
345
- attr = attr.replace(/\\/g, '');
346
- for (var i = 0; i < repeatElems.length; ++i) {
347
- if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
348
- rows.push(repeatElems[i]);
349
- }
350
- }
351
- }
352
- /* multiRows is an array of arrays, where each inner array contains
353
- one row of elements. */
354
- var multiRows = [];
355
- for (var p = 0; p < prefixes.length; ++p) {
356
- var attr = prefixes[p] + 'repeat-start';
357
- var repeatElems = using.querySelectorAll('[' + attr + ']');
358
- attr = attr.replace(/\\/g, '');
359
- for (var i = 0; i < repeatElems.length; ++i) {
360
- if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
361
- var elem = repeatElems[i];
362
- var row = [];
363
- while (elem.nodeType != 8 || (elem.nodeValue &&
364
- !repeaterMatch(elem.nodeValue, repeater, exact))) {
365
- if (elem.nodeType == 1) {
366
- row.push(elem);
367
- }
368
- elem = elem.nextSibling;
369
- }
370
- multiRows.push(row);
371
- }
372
- }
373
- }
374
- var bindings = [];
375
- for (var i = 0; i < rows.length; ++i) {
376
- if (angular.getTestability) {
377
- matches.push.apply(
378
- matches,
379
- angular.getTestability(root).findBindings(rows[i], binding));
380
- } else {
381
- if (rows[i].className.indexOf('ng-binding') != -1) {
382
- bindings.push(rows[i]);
383
- }
384
- var childBindings = rows[i].getElementsByClassName('ng-binding');
385
- for (var k = 0; k < childBindings.length; ++k) {
386
- bindings.push(childBindings[k]);
387
- }
388
- }
389
- }
390
- for (var i = 0; i < multiRows.length; ++i) {
391
- for (var j = 0; j < multiRows[i].length; ++j) {
392
- if (angular.getTestability) {
393
- matches.push.apply(
394
- matches,
395
- angular.getTestability(root).findBindings(multiRows[i][j], binding));
396
- } else {
397
- var elem = multiRows[i][j];
398
- if (elem.className.indexOf('ng-binding') != -1) {
399
- bindings.push(elem);
400
- }
401
- var childBindings = elem.getElementsByClassName('ng-binding');
402
- for (var k = 0; k < childBindings.length; ++k) {
403
- bindings.push(childBindings[k]);
404
- }
405
- }
406
- }
407
- }
408
- for (var j = 0; j < bindings.length; ++j) {
409
- var dataBinding = angular.element(bindings[j]).data('$binding');
410
- if (dataBinding) {
411
- var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
412
- if (bindingName.indexOf(binding) != -1) {
413
- matches.push(bindings[j]);
414
- }
415
- }
416
- }
417
- return matches;
418
- };
419
-
420
- /**
421
- * Find elements by model name.
422
- *
423
- * @param {string} model The model name.
424
- * @param {Element} using The scope of the search.
425
- * @param {string} rootSelector The selector to use for the root app element.
426
- *
427
- * @return {Array.<Element>} The matching elements.
428
- */
429
- functions.findByModel = function(model, using, rootSelector) {
430
- var root = document.querySelector(rootSelector || 'body');
431
- using = using || document;
432
-
433
- if (angular.getTestability) {
434
- return angular.getTestability(root).
435
- findModels(using, model, true);
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] + 'model="' + model + '"]';
440
- var elements = using.querySelectorAll(selector);
441
- if (elements.length) {
442
- return elements;
443
- }
444
- }
445
- };
446
-
447
- /**
448
- * Find elements by options.
449
- *
450
- * @param {string} optionsDescriptor The descriptor for the option
451
- * (i.e. fruit for fruit in fruits).
452
- * @param {Element} using The scope of the search.
453
- *
454
- * @return {Array.<Element>} The matching elements.
455
- */
456
- functions.findByOptions = function(optionsDescriptor, using) {
457
- using = using || document;
458
-
459
- var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
460
- for (var p = 0; p < prefixes.length; ++p) {
461
- var selector = '[' + prefixes[p] + 'options="' + optionsDescriptor + '"] option';
462
- var elements = using.querySelectorAll(selector);
463
- if (elements.length) {
464
- return elements;
465
- }
466
- }
467
- };
468
-
469
- /**
470
- * Find buttons by textual content.
471
- *
472
- * @param {string} searchText The exact text to match.
473
- * @param {Element} using The scope of the search.
474
- *
475
- * @return {Array.<Element>} The matching elements.
476
- */
477
- functions.findByButtonText = function(searchText, using) {
478
- using = using || document;
479
-
480
- var elements = using.querySelectorAll('button, input[type="button"], input[type="submit"]');
481
- var matches = [];
482
- for (var i = 0; i < elements.length; ++i) {
483
- var element = elements[i];
484
- var elementText;
485
- if (element.tagName.toLowerCase() == 'button') {
486
- elementText = element.textContent || element.innerText || '';
487
- } else {
488
- elementText = element.value;
489
- }
490
- if (elementText.trim() === searchText) {
491
- matches.push(element);
492
- }
493
- }
494
-
495
- return matches;
496
- };
497
-
498
- /**
499
- * Find buttons by textual content.
500
- *
501
- * @param {string} searchText The exact text to match.
502
- * @param {Element} using The scope of the search.
503
- *
504
- * @return {Array.<Element>} The matching elements.
505
- */
506
- functions.findByPartialButtonText = function(searchText, using) {
507
- using = using || document;
508
-
509
- var elements = using.querySelectorAll('button, input[type="button"], input[type="submit"]');
510
- var matches = [];
511
- for (var i = 0; i < elements.length; ++i) {
512
- var element = elements[i];
513
- var elementText;
514
- if (element.tagName.toLowerCase() == 'button') {
515
- elementText = element.textContent || element.innerText || '';
516
- } else {
517
- elementText = element.value;
518
- }
519
- if (elementText.indexOf(searchText) > -1) {
520
- matches.push(element);
521
- }
522
- }
523
-
524
- return matches;
525
- };
526
-
527
- /**
528
- * Find elements by css selector and textual content.
529
- *
530
- * @param {string} cssSelector The css selector to match.
531
- * @param {string} searchText The exact text to match.
532
- * @param {Element} using The scope of the search.
533
- *
534
- * @return {Array.<Element>} An array of matching elements.
535
- */
536
- functions.findByCssContainingText = function(cssSelector, searchText, using) {
537
- using = using || document;
538
-
539
- var elements = using.querySelectorAll(cssSelector);
540
- var matches = [];
541
- for (var i = 0; i < elements.length; ++i) {
542
- var element = elements[i];
543
- var elementText = element.textContent || element.innerText || '';
544
- if (elementText.indexOf(searchText) > -1) {
545
- matches.push(element);
546
- }
547
- }
548
- return matches;
549
- };
550
-
551
- /**
552
- * Tests whether the angular global variable is present on a page. Retries
553
- * in case the page is just loading slowly.
554
- *
555
- * Asynchronous.
556
- *
557
- * @param {number} attempts Number of times to retry.
558
- * @param {function} asyncCallback callback
559
- */
560
- functions.testForAngular = function(attempts, asyncCallback) {
561
- var callback = function(args) {
562
- setTimeout(function() {
563
- asyncCallback(args);
564
- }, 0);
565
- };
566
- var check = function(n) {
567
- try {
568
- if (window.angular && window.angular.resumeBootstrap) {
569
- callback([true, null]);
570
- } else if (n < 1) {
571
- if (window.angular) {
572
- callback([false, 'angular never provided resumeBootstrap']);
573
- } else {
574
- callback([false, 'retries looking for angular exceeded']);
575
- }
576
- } else {
577
- window.setTimeout(function() {check(n - 1);}, 1000);
578
- }
579
- } catch (e) {
580
- callback([false, e]);
581
- }
582
- };
583
- check(attempts);
584
- };
585
-
586
- /**
587
- * Evalute an Angular expression in the context of a given element.
588
- *
589
- * @param {Element} element The element in whose scope to evaluate.
590
- * @param {string} expression The expression to evaluate.
591
- *
592
- * @return {?Object} The result of the evaluation.
593
- */
594
- functions.evaluate = function(element, expression) {
595
- return angular.element(element).scope().$eval(expression);
596
- };
597
-
598
- functions.allowAnimations = function(element, value) {
599
- var ngElement = angular.element(element);
600
- if (ngElement.allowAnimations) {
601
- // AngularDart: $testability API.
602
- return ngElement.allowAnimations(value);
603
- } else {
604
- // AngularJS
605
- var enabledFn = ngElement.injector().get('$animate').enabled;
606
- return (value == null) ? enabledFn() : enabledFn(value);
607
- }
608
- };
609
-
610
- /**
611
- * Return the current url using $location.absUrl().
612
- *
613
- * @param {string} selector The selector housing an ng-app
614
- */
615
- functions.getLocationAbsUrl = function(selector) {
616
- var el = document.querySelector(selector);
617
- if (angular.getTestability) {
618
- return angular.getTestability(el).
619
- getLocation();
620
- }
621
- return angular.element(el).injector().get('$location').absUrl();
622
- };
623
-
624
- /**
625
- * Browse to another page using in-page navigation.
626
- *
627
- * @param {string} selector The selector housing an ng-app
628
- * @param {string} url In page URL using the same syntax as $location.url(),
629
- * /path?search=a&b=c#hash
630
- */
631
- functions.setLocation = function(selector, url) {
632
- var el = document.querySelector(selector);
633
- if (angular.getTestability) {
634
- return angular.getTestability(el).
635
- setLocation(url);
636
- }
637
- var $injector = angular.element(el).injector();
638
- var $location = $injector.get('$location');
639
- var $rootScope = $injector.get('$rootScope');
640
-
641
- if (url !== $location.url()) {
642
- $location.url(url);
643
- $rootScope.$digest();
644
- }
645
- };
646
-
647
- /* Publish all the functions as strings to pass to WebDriver's
648
- * exec[Async]Script. In addition, also include a script that will
649
- * install all the functions on window (for debugging.)
650
- *
651
- * We also wrap any exceptions thrown by a clientSideScripts function
652
- * that is not an instance of the Error type into an Error type. If we
653
- * don't do so, then the resulting stack trace is completely unhelpful
654
- * and the exception message is just "unknown error." These types of
655
- * exceptions are the common case for dart2js code. This wrapping gives
656
- * us the Dart stack trace and exception message.
657
- */
658
- var util = require('util');
659
- var scriptsList = [];
660
- var scriptFmt = (
661
- 'try { return (%s).apply(this, arguments); }\n' +
662
- 'catch(e) { throw (e instanceof Error) ? e : new Error(e); }');
663
- for (var fnName in functions) {
664
- if (functions.hasOwnProperty(fnName)) {
665
- exports[fnName] = util.format(scriptFmt, functions[fnName]);
666
- scriptsList.push(util.format('%s: %s', fnName, functions[fnName]));
667
- }
668
- }
669
-
670
- exports.installInBrowser = (util.format(
671
- 'window.clientSideScripts = {%s};', scriptsList.join(', ')));
@@ -1,7 +0,0 @@
1
- require 'rubygems'
2
- require 'json'
3
- require 'ostruct'
4
-
5
- client_side_scripts = OpenStruct.new JSON.parse File.read 'clientSideScripts.json'
6
-
7
- puts client_side_scripts.waitForAngular
@@ -1,11 +0,0 @@
1
- // run with: node scripts_to_json.js
2
-
3
- var clientSideScripts = require('./clientsidescripts.js'),
4
- fs = require('fs');
5
-
6
- // Serialize client side scripts to JSON for reading into Ruby
7
- var json = JSON.stringify(clientSideScripts, null, 2);
8
-
9
- var fd = fs.openSync('clientSideScripts.json', 'w', '666');
10
- fs.writeSync(fd, json);
11
- fs.closeSync(fd);