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,31 +1,235 @@
1
- require 'rubygems'
2
- require 'json'
3
- require 'ostruct'
4
- require 'selenium-webdriver'
5
1
  require 'selenium/webdriver/common/error'
6
2
 
7
3
  class Protractor
4
+
5
+ NEW_FINDERS_KEYS = %i(
6
+ binding
7
+ exactBinding
8
+ partialButtonText
9
+ buttonText
10
+ model
11
+ options
12
+ cssContainingText
13
+ repeater
14
+ ).freeze # [:binding]
15
+ NEW_FINDERS_HASH = NEW_FINDERS_KEYS.map { |e| [e, e.to_s] }.to_h.freeze # {binding: 'binding'}
16
+
17
+ # Return true if given finder is a protractor finder.
18
+ #
19
+ # @param finder_name [Symbol|String] the name of the finder
20
+ #
21
+ # @return [boolean]
22
+ def finder? finder_name
23
+ NEW_FINDERS_KEYS.include? finder_name.intern
24
+ end
25
+
8
26
  # code/comments from protractor/lib/protractor.js
9
- attr_accessor :root_element, :ignore_sync
10
27
 
11
- attr_reader :client_side_scripts, :driver
28
+ # The css selector for an element on which to find Angular. This is usually
29
+ # 'body' but if your ng-app is on a subsection of the page it may be
30
+ # a subelement.
31
+ #
32
+ # @return [String]
33
+ #
34
+ attr_accessor :root_element
35
+
36
+ # If true, Protractor will not attempt to synchronize with the page before
37
+ # performing actions. This can be harmful because Protractor will not wait
38
+ # until $timeouts and $http calls have been processed, which can cause
39
+ # tests to become flaky. This should be used only when necessary, such as
40
+ # when a page continuously polls an API using $timeout.
41
+ #
42
+ # @return [Boolean]
43
+ #
44
+ attr_accessor :ignore_sync
45
+
46
+ # File.join(base_url, destination) when using driver.get and
47
+ # protractor.get (if sync is on, base_url is set, and destination
48
+ # is not absolute).
49
+ #
50
+ # @return [String] Default nil.
51
+ #
52
+ attr_accessor :base_url
53
+
54
+ # All scripts to be run on the client via executeAsyncScript or
55
+ # executeScript should be put here.
56
+ #
57
+ # NOTE: These scripts are transmitted over the wire as JavaScript text
58
+ # constructed using their toString representation, and# cannot*
59
+ # reference external variables.
60
+ #
61
+ # Some implementations seem to have issues with // comments, so use star-style
62
+ # inside scripts. that caused the switch to avoid the // comments.)
63
+ #
64
+ attr_reader :client_side_scripts
65
+
66
+ # The Selenium::WebDriver driver object
67
+ attr_reader :driver
68
+
69
+ # URL to a blank page. Differs depending on the browser.
70
+ # @see reset_url_for_browser
71
+ #
72
+ attr_reader :reset_url
73
+
74
+ # @see webdriver.WebDriver.get
75
+ #
76
+ # Navigate to the given destination. Assumes that the page being loaded uses Angular.
77
+ # If you need to access a page which does not have Angular on load,
78
+ # use driver_get.
79
+ #
80
+ # @example
81
+ # browser.get('https://angularjs.org/');
82
+ # expect(browser.getCurrentUrl()).toBe('https://angularjs.org/');
83
+ #
84
+ # @param destination [String] The destination URL to load, can be relative if base_url is set
85
+ # @param opt_timeout [Integer] Number of seconds to wait for Angular to start. Default 30.
86
+ #
87
+ def get destination, opt_timeout=30
88
+ # do not use driver.get because that redirects to this method
89
+ # instead driver_get is provided.
90
+
91
+ timeout = opt_timeout
92
+
93
+ raise "Invalid timeout #{timeout}" unless timeout.is_a?(Numeric)
94
+
95
+ unless destination.is_a?(String) || destination.is_a?(URI)
96
+ raise "Invalid destination #{destination}"
97
+ end
98
+
99
+ # URI.join doesn't allow for http://localhost:8081/#/ as a base_url
100
+ # so this departs from the Protractor behavior and favors File.join instead.
101
+ #
102
+ # In protractor: url.resolve('http://localhost:8081/#/', 'async')
103
+ # => http://localhost:8081/async
104
+ # In Ruby: File.join('http://localhost:8081/#/', 'async')
105
+ # => http://localhost:8081/#/async
106
+ #
107
+ base_url_exists = base_url && !base_url.empty?
108
+ no_scheme = !URI.parse(destination).scheme rescue true
109
+
110
+ if base_url_exists && no_scheme
111
+ destination = File.join(base_url, destination.to_s)
112
+ end
113
+
114
+ msg = lambda { |str| 'Protractor.get(' + destination + ') - ' + str }
115
+
116
+ return driver_get(destination) if ignore_sync
117
+
118
+ driver_get(reset_url)
119
+ executeScript_(
120
+ 'window.location.replace("' + destination + '");',
121
+ msg.call('reset url'))
122
+
123
+ wait(timeout) do
124
+ url = executeScript_('return window.location.href;', msg.call('get url'))
125
+ not_on_reset_url = url != reset_url
126
+ destination_is_reset = destination == reset_url
127
+ raise 'still on reset url' unless not_on_reset_url || destination_is_reset
128
+ end
129
+
130
+ # now that the url has changed, make sure Angular has loaded
131
+ # note that the mock module logic is omitted.
132
+ #
133
+ waitForAngular
134
+ end
135
+
136
+ # Invokes the underlying driver.get. Does not wait for angular.
137
+ # Does not use base_url or reset_url logic.
138
+ #
139
+ def driver_get url
140
+ driver.bridge.driver_get url
141
+ end
142
+
143
+ # @see webdriver.WebDriver.refresh
144
+ #
145
+ # Makes a full reload of the current page. Assumes that the page being loaded uses Angular.
146
+ # If you need to access a page which does not have Angular on load, use
147
+ # driver_get.
148
+ #
149
+ # @param opt_timeout [Integer] Number of seconds to wait for Angular to start.
150
+ #
151
+ def refresh opt_timeout
152
+ timeout = opt_timeout || 10
12
153
 
154
+ return driver.navigate.refresh if ignore_sync
155
+
156
+ executeScript_('return window.location.href;',
157
+ 'Protractor.refresh() - getUrl')
158
+
159
+ get(href, timeout)
160
+ end
161
+
162
+ # Browse to another page using in-page navigation.
163
+ # Assumes that the page being loaded uses Angular.
164
+ #
165
+ # @example
166
+ # browser.get('http://angular.github.io/protractor/#/tutorial');
167
+ # browser.setLocation('api');
168
+ # expect(browser.getCurrentUrl())
169
+ # .toBe('http://angular.github.io/protractor/#/api');
170
+ #
171
+ # @param url [String] In page URL using the same syntax as $location.url()
172
+ #
173
+ def setLocation url
174
+ waitForAngular
175
+
176
+ begin
177
+ executeScript_(client_side_scripts.set_location,
178
+ 'Protractor.setLocation()', root_element, url)
179
+ rescue Exception => e
180
+ raise e.class, "Error while navigating to '#{url}' : #{e}"
181
+ end
182
+ end
183
+
184
+ # Returns the current absolute url from AngularJS.
185
+ # Waits for Angular.
186
+ #
187
+ # @example
188
+ # browser.get('http://angular.github.io/protractor/#/api');
189
+ # expect(browser.getLocationAbsUrl())
190
+ # .toBe('/api');
191
+ #
192
+ def getLocationAbsUrl
193
+ waitForAngular
194
+ executeScript_(client_side_scripts.get_location_abs_url,
195
+ 'Protractor.getLocationAbsUrl()', root_element)
196
+ end
197
+
198
+ # Creates a new protractor instance and dynamically patches the provided
199
+ # driver.
200
+ #
13
201
  # @param [Hash] opts the options to initialize with
202
+ # @option opts [Watir::Browser] :watir the watir instance used for automation
14
203
  # @option opts [String] :root_element the root element on which to find Angular
15
204
  # @option opts [Boolean] :ignore_sync if true, Protractor won't auto sync the page
205
+ #
16
206
  def initialize opts={}
17
- @driver = opts[:driver]
18
- raise 'Must supply Selenium::WebDriver' unless @driver
207
+ @watir = opts[:watir]
19
208
 
20
- watir = defined?(Watir::Browser) && @driver.is_a?(Watir::Browser)
21
- @driver = watir ? @driver.driver : @driver
209
+ valid_watir = defined?(Watir::Browser) && @watir.is_a?(Watir::Browser)
210
+ raise "Driver must be a Watir::Browser not #{@driver.class}" unless valid_watir
211
+ @driver = @watir.driver
212
+
213
+ unless Selenium::WebDriver::SearchContext::FINDERS.keys.include?(NEW_FINDERS_KEYS)
214
+ Selenium::WebDriver::SearchContext::FINDERS.merge!(NEW_FINDERS_HASH)
215
+ end
216
+
217
+ unless Watir::ElementLocator::WD_FINDERS.include? NEW_FINDERS_KEYS
218
+ old = Watir::ElementLocator::WD_FINDERS
219
+ # avoid const redefinition warning
220
+ Watir::ElementLocator.send :remove_const, :WD_FINDERS
221
+ Watir::ElementLocator.send :const_set, :WD_FINDERS, old + NEW_FINDERS_KEYS
222
+ end
223
+
224
+ @driver.protractor = self
22
225
 
23
226
  # The css selector for an element on which to find Angular. This is usually
24
227
  # 'body' but if your ng-app is on a subsection of the page it may be
25
228
  # a subelement.
26
229
  #
27
230
  # @return [String]
28
- @root_element = opts.fetch :root_element, 'body'
231
+ #
232
+ @root_element = opts.fetch :root_element, 'body'
29
233
 
30
234
  # If true, Protractor will not attempt to synchronize with the page before
31
235
  # performing actions. This can be harmful because Protractor will not wait
@@ -34,10 +238,87 @@ class Protractor
34
238
  # when a page continuously polls an API using $timeout.
35
239
  #
36
240
  # @return [Boolean]
37
- @ignore_sync = !!opts.fetch(:ignore_sync, false)
241
+ #
242
+ @ignore_sync = !!opts.fetch(:ignore_sync, false)
243
+
244
+ @client_side_scripts = ClientSideScripts
245
+
246
+ browser_name = driver.capabilities[:browser_name].to_s.strip
247
+ @reset_url = reset_url_for_browser browser_name
248
+
249
+ @base_url = opts.fetch(:base_url, nil)
250
+
251
+ # must be local var for use with define element below.
252
+ protractor_element = AngularWebdriver::ProtractorElement.new @watir
253
+
254
+ # Top level element method to enable protractor syntax.
255
+ # redefine element to point to the new protractor element instance.
256
+ #
257
+ # toplevel self enables by/element from within pry. rspec helpers enables
258
+ # by/element within rspec tests when used with install_rspec_helpers.
259
+ [eval('self', TOPLEVEL_BINDING), AngularWebdriver::RSpecHelpers].each do |obj|
260
+ obj.send :define_singleton_method, :element do |*args|
261
+ protractor_element.element *args
262
+ end
263
+
264
+ obj.send :define_singleton_method, :by do
265
+ AngularWebdriver::By
266
+ end
267
+ end
268
+
269
+ self
270
+ end
271
+
272
+ # Reset URL used on IE & Safari since they don't work well with data URLs
273
+ ABOUT_BLANK = 'about:blank'.freeze
274
+
275
+ # Reset URL used by non-IE/Safari browsers
276
+ DEFAULT_RESET_URL = 'data:text/html,<html></html>'.freeze
277
+
278
+ # IE and Safari require about:blank because they don't work well with
279
+ # data urls (flaky). For other browsers, data urls are stable.
280
+ #
281
+ # browser_name [String] the browser name from driver caps. Must be 'safari'
282
+ # or 'internet explorer'
283
+ # @return reset_url [String] the reset URL
284
+ #
285
+ def reset_url_for_browser browser_name
286
+ if ['internet explorer', 'safari'].include?(browser_name)
287
+ ABOUT_BLANK
288
+ else
289
+ DEFAULT_RESET_URL
290
+ end
291
+ end
292
+
293
+ # @private
294
+ #
295
+ # Syncs the webdriver command if it's white listed
296
+ #
297
+ # @param webdriver_command [Symbol] the webdriver command to check for syncing
298
+ #
299
+ def sync webdriver_command
300
+ return unless webdriver_command
301
+ webdriver_command = webdriver_command.intern
302
+ # Note get must not sync here because the get command is redirected to
303
+ # protractor.get which already has the sync logic built in.
304
+ #
305
+ # also don't sync set location (protractor custom command already waits
306
+ # for angular). the selenium set location is for latitude/longitude/altitude
307
+ # and that doesn't require syncing
308
+ #
309
+ sync_whitelist = %i(
310
+ getCurrentUrl
311
+ refresh
312
+ getPageSource
313
+ getTitle
314
+ findElement
315
+ findElements
316
+ findChildElement
317
+ findChildElements
318
+ )
319
+ must_sync = sync_whitelist.include? webdriver_command
38
320
 
39
- scripts_file = File.expand_path '../clientSideScripts.json', __FILE__
40
- @client_side_scripts = OpenStruct.new JSON.parse File.read scripts_file
321
+ self.waitForAngular if must_sync
41
322
  end
42
323
 
43
324
  # Instruct webdriver to wait until Angular has finished rendering and has
@@ -48,80 +329,118 @@ class Protractor
48
329
  # @param [String] opt_description An optional description to be added
49
330
  # to webdriver logs.
50
331
  # @return [WebDriver::Element, Integer, Float, Boolean, NilClass, String, Array]
332
+ #
51
333
  def waitForAngular opt_description='' # Protractor.prototype.waitForAngular
52
334
  return if ignore_sync
53
335
 
54
336
  begin
55
337
  # the client side script will return a string on error
56
338
  # the string won't be raised as an error unless we explicitly do so here
57
- error = executeAsyncScript_(client_side_scripts.waitForAngular,
58
- "Protractor.waitForAngular() #{opt_description}",
59
- root_element)
60
- raise Selenium::WebDriver::Error::JavascriptError, error if error
339
+ error = executeAsyncScript_(client_side_scripts.wait_for_angular,
340
+ "Protractor.waitForAngular() #{opt_description}",
341
+ root_element)
342
+ raise Selenium::WebDriver::Error::JavascriptError, error if error
61
343
  rescue Exception => e
344
+ # https://github.com/angular/protractor/blob/master/docs/faq.md
62
345
  raise e.class, "Error while waiting for Protractor to sync with the page: #{e}"
63
346
  end
64
347
  end
65
348
 
66
- def executeAsyncScript_ script, description, args
67
- # ensure description is exactly one line that ends in a newline
68
- description = description ? '// ' + description.split.join(' ') : ''
69
- description = description.strip + "\n"
349
+ # Ensure description is exactly one line that ends in a newline
350
+ # must use /* */ not // due to some browsers having problems
351
+ # with // comments when used with execute script
352
+ #
353
+ def _js_comment description
354
+ description = description ? '/* ' + description.gsub(/\s+/, ' ').strip + ' */' : ''
355
+ description.strip + "\n"
356
+ end
357
+
358
+ # The same as {@code webdriver.WebDriver.prototype.executeAsyncScript},
359
+ # but with a customized description for debugging.
360
+ #
361
+ # @private
362
+ # @param script [String] The javascript to execute.
363
+ # @param description [String] A description of the command for debugging.
364
+ # @param args [var_args] The arguments to pass to the script.
365
+ # @return The scripts return value.
366
+ #
367
+ def executeAsyncScript_ script, description, *args
368
+ # add description as comment to script so it shows up in server logs
369
+ script = _js_comment(description) + script
370
+
371
+ driver.execute_async_script script, *args
372
+ end
70
373
 
374
+ # The same as {@code webdriver.WebDriver.prototype.executeScript},
375
+ # but with a customized description for debugging.
376
+ #
377
+ # @private
378
+ # @param script [String] The javascript to execute.
379
+ # @param description [String] A description of the command for debugging.
380
+ # @param args [var_args] The arguments to pass to the script.
381
+ # @return The scripts return value.
382
+ #
383
+ def executeScript_ script, description, *args
71
384
  # add description as comment to script so it shows up in server logs
72
- script = description + script
73
-
74
- # puts "Evaluating:\n#{script}"
75
-
76
- driver.execute_async_script script, args
77
- end
78
-
79
- =begin
80
- /**
81
- * Instruct webdriver to wait until Angular has finished rendering and has
82
- * no outstanding $http or $timeout calls before continuing.
83
- * Note that Protractor automatically applies this command before every
84
- * WebDriver action.
85
- *
86
- * @param {string=} opt_description An optional description to be added
87
- * to webdriver logs.
88
- * @return {!webdriver.promise.Promise} A promise that will resolve to the
89
- * scripts return value.
90
- */
91
- Protractor.prototype.waitForAngular = function(opt_description) {
92
- var description = opt_description ? ' - ' + opt_description : '';
93
- if (this.ignoreSynchronization) {
94
- return webdriver.promise.fulfilled();
95
- }
96
- return this.executeAsyncScript_(
97
- clientSideScripts.waitForAngular,
98
- 'Protractor.waitForAngular()' + description,
99
- this.rootEl).
100
- then(function(browserErr) {
101
- if (browserErr) {
102
- throw 'Error while waiting for Protractor to ' +
103
- 'sync with the page: ' + JSON.stringify(browserErr);
104
- }
105
- }).then(null, function(err) {
106
- var timeout;
107
- if (/asynchronous script timeout/.test(err.message)) {
108
- // Timeout on Chrome
109
- timeout = /-?[\d\.]*\ seconds/.exec(err.message);
110
- } else if (/Timed out waiting for async script/.test(err.message)) {
111
- // Timeout on Firefox
112
- timeout = /-?[\d\.]*ms/.exec(err.message);
113
- } else if (/Timed out waiting for an asynchronous script/.test(err.message)) {
114
- // Timeout on Safari
115
- timeout = /-?[\d\.]*\ ms/.exec(err.message);
116
- }
117
- if (timeout) {
118
- throw 'Timed out waiting for Protractor to synchronize with ' +
119
- 'the page after ' + timeout + '. Please see ' +
120
- 'https://github.com/angular/protractor/blob/master/docs/faq.md';
121
- } else {
122
- throw err;
123
- }
124
- });
125
- };
126
- =end
385
+ script = _js_comment(description) + script
386
+
387
+ driver.execute_script script, *args
388
+ end
389
+
390
+ # Injects client side scripts into window.clientSideScripts for debugging.
391
+ #
392
+ # Example:
393
+ #
394
+ # ```ruby
395
+ # # inject the scripts
396
+ # protractor.debugger
397
+ #
398
+ # # now that the scripts are injected, they can be used via execute_script
399
+ # driver.execute_script "window.clientSideScripts.getLocationAbsUrl('body')"
400
+ # ```
401
+ #
402
+ # This should be used under Pry. The window client side scripts can be
403
+ # invoked using chrome dev tools after calling debugger.
404
+ #
405
+ def debugger
406
+ executeScript_ client_side_scripts.install_in_browser, 'Protractor.debugger()'
407
+ end
408
+
409
+ # Determine if animation is allowed on the current underlying elements.
410
+ # @param <Element> web_element - the web element to act upon
411
+ # @param <Boolean> value - turn on/off ng-animate animations.
412
+ #
413
+ # @example
414
+ # // Turns off ng-animate animations for all elements in the <body>
415
+ # element(by.css('body')).allowAnimations(false);
416
+ #
417
+ # @return <Boolean> whether animation is allowed.
418
+ def allowAnimations web_element, value=nil
419
+ executeScript_ client_side_scripts.allow_animations, 'Protractor.allow_animations()', web_element, value
420
+ end
421
+
422
+ # Evaluate an Angular expression as if it were on the scope
423
+ # of the given element.
424
+ #
425
+ # @param element <Element> The element in whose scope to evaluate.
426
+ # @param expression <String> The expression to evaluate.
427
+ #
428
+ # @return <Object> The result of the evaluation.
429
+ def evaluate element, expression
430
+ # angular.element(element).scope().$eval(expression);
431
+ executeScript_ client_side_scripts.evaluate, 'Protractor.evaluate()', element, expression
432
+ end
433
+
434
+ private
435
+
436
+ # @private
437
+ # Internal function only useful as part of Protractor's custom get logic
438
+ # which pauses then resumes the bootstrap. Currently not used at all.
439
+ #
440
+ # Do not use!
441
+ def testForAngular timeout_seconds=10
442
+ # [false, "retries looking for angular exceeded"]
443
+ # [false, "angular never provided resumeBootstrap"]
444
+ executeAsyncScript_ client_side_scripts.test_for_angular, 'Protractor.testForAngular', timeout_seconds
445
+ end
127
446
  end
@@ -0,0 +1,33 @@
1
+ module AngularWebdriver
2
+ class ProtractorElement
3
+ attr_reader :watir
4
+
5
+ def initialize watir
6
+ is_watir = watir.is_a?(Watir::Browser)
7
+ raise 'Must init with a Watir::Browser' unless is_watir
8
+
9
+ @watir = watir
10
+ end
11
+
12
+ # Protractor element
13
+ #
14
+ # Example:
15
+ # element(by.css('bar'))
16
+ #
17
+ # @return Watir::HTMLElement
18
+ def element *args
19
+ return self unless args.length > 0
20
+ watir.element *args
21
+ end
22
+
23
+ # Protractor all method.
24
+ #
25
+ # Example:
26
+ # element.all(by.css('bar'))
27
+ #
28
+ # @return Watir::HTMLElementCollection
29
+ def all *args
30
+ watir.elements *args
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module AngularWebdriver
2
+ # dynamically populated upon protractor init
3
+ # provides by and element methods as top level singleton methods
4
+ # in addition to being defined within the rspechelpers module
5
+ module RSpecHelpers
6
+ end
7
+
8
+ # call within before(:all) in rspec config after invoking Protractor.new
9
+ def self.install_rspec_helpers
10
+ context = RSpec::Core::ExampleGroup
11
+ helpers = AngularWebdriver::RSpecHelpers
12
+ helpers.singleton_methods.each do |method_symbol|
13
+ context.send(:define_method, method_symbol) do |*args|
14
+ args.length == 0 ? helpers.send(method_symbol) :
15
+ helpers.send(method_symbol, *args)
16
+ end
17
+ end
18
+ end
19
+ end