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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.travis.yml +32 -0
- data/Gemfile +2 -0
- data/Thorfile +33 -1
- data/angular_webdriver.gemspec +10 -3
- data/docs/overview.md +101 -0
- data/docs/sync.md +53 -0
- data/lib/angular_webdriver/protractor/by.rb +331 -0
- data/lib/angular_webdriver/protractor/by_repeater_inner.rb +106 -0
- data/lib/angular_webdriver/protractor/client_side_scripts.rb +1035 -0
- data/lib/angular_webdriver/protractor/protractor.rb +396 -77
- data/lib/angular_webdriver/protractor/protractor_element.rb +33 -0
- data/lib/angular_webdriver/protractor/rspec_helpers.rb +19 -0
- data/lib/angular_webdriver/protractor/watir_patch.rb +209 -0
- data/lib/angular_webdriver/protractor/webdriver_patch.rb +246 -0
- data/lib/angular_webdriver/version.rb +2 -2
- data/lib/angular_webdriver.rb +14 -1
- data/{LICENSE → license/angular_webdriver/LICENSE.txt} +0 -0
- data/{lib/angular_webdriver → license}/protractor/LICENSE.txt +0 -0
- data/{lib/angular_webdriver/protractor/get_url_trace.rb → notes/bootstrap_notes.md} +13 -0
- data/notes/element_by_id/element_by_id_sync_off.txt +12 -0
- data/notes/element_by_id/element_by_id_sync_on.txt +74 -0
- data/notes/element_chaining_debug.txt +94 -0
- data/notes/evaluate/js_evaluate_sync_on.txt +60 -0
- data/notes/evaluate/ruby_evaluate_sync_on.txt +35 -0
- data/notes/get_title/browser_get_title_sync_off.txt +11 -0
- data/notes/get_title/browser_get_title_sync_on.txt +54 -0
- data/notes/phantomjs.md +23 -0
- data/notes/protractor_cli_bugs.txt +39 -0
- data/notes/protractor_get/protractor_get.rb +102 -0
- data/notes/protractor_get/protractor_get_website_sync_off.txt +11 -0
- data/notes/protractor_get/protractor_get_website_sync_on.txt +86 -0
- data/notes/repeater/findAllRepeaterRows_annotated.txt +150 -0
- data/notes/repeater/findAllRepeaterRows_raw.txt +145 -0
- data/notes/repeater/findRepeaterColumn_annotated.txt +317 -0
- data/notes/repeater/findRepeaterColumn_raw.txt +310 -0
- data/notes/repeater/findRepeaterElement_annotated.txt +152 -0
- data/notes/repeater/findRepeaterElement_raw.txt +146 -0
- data/notes/repeater/findRepeaterRows_annotated.txt +156 -0
- data/notes/repeater/findRepeaterRows_raw.txt +152 -0
- data/notes/sync_after.md +46 -0
- data/notes/sync_notes.md +137 -0
- data/notes/synchronize_spec/status_gettext.txt +121 -0
- data/notes/synchronize_spec/status_gettext_x3.txt +451 -0
- data/notes/synchronize_spec/synchronize_spec.js.txt +74 -0
- data/notes/synchronize_spec/watir_gettext.txt +73 -0
- data/readme.md +52 -12
- data/release_notes.md +127 -0
- data/selenium_server/lib/logs.rb +50 -0
- data/selenium_server/lib/selenium_server.rb +21 -0
- data/selenium_server/readme.md +3 -0
- data/selenium_server/spec/logs_spec.rb +18 -0
- data/selenium_server/spec/nodejs_sync_spec_waithttp_annotated.txt +54 -0
- data/selenium_server/spec/nodejs_sync_spec_waithttp_raw.txt +367 -0
- data/selenium_server/spec/nodejs_sync_spec_waithttp_raw_processed.txt +43 -0
- data/selenium_server/spec/ruby_sync_spec_waithttp_annotated.txt +59 -0
- data/selenium_server/spec/ruby_sync_spec_waithttp_raw.txt +267 -0
- data/selenium_server/spec/ruby_sync_spec_waithttp_raw_processed.txt +39 -0
- data/selenium_server/spec/spec_helper.rb +6 -0
- data/selenium_server/spec/status_gettext_x3.txt +429 -0
- data/selenium_server/spec/status_gettext_x3_annotated.txt +86 -0
- metadata +91 -18
- data/lib/angular_webdriver/protractor/clientSideScripts.json +0 -19
- data/lib/angular_webdriver/protractor/clientsidescripts.js +0 -671
- data/lib/angular_webdriver/protractor/scripts.rb +0 -7
- data/lib/angular_webdriver/protractor/scripts_to_json.js +0 -11
- data/spec/protractor_spec.rb +0 -40
- 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
|
-
|
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
|
-
@
|
18
|
-
raise 'Must supply Selenium::WebDriver' unless @driver
|
207
|
+
@watir = opts[:watir]
|
19
208
|
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|