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
@@ -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);