angular_webdriver 0.0.7 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +32 -0
  6. data/Gemfile +2 -0
  7. data/Thorfile +33 -1
  8. data/angular_webdriver.gemspec +10 -3
  9. data/docs/overview.md +101 -0
  10. data/docs/sync.md +53 -0
  11. data/lib/angular_webdriver/protractor/by.rb +331 -0
  12. data/lib/angular_webdriver/protractor/by_repeater_inner.rb +106 -0
  13. data/lib/angular_webdriver/protractor/client_side_scripts.rb +1035 -0
  14. data/lib/angular_webdriver/protractor/protractor.rb +396 -77
  15. data/lib/angular_webdriver/protractor/protractor_element.rb +33 -0
  16. data/lib/angular_webdriver/protractor/rspec_helpers.rb +19 -0
  17. data/lib/angular_webdriver/protractor/watir_patch.rb +209 -0
  18. data/lib/angular_webdriver/protractor/webdriver_patch.rb +246 -0
  19. data/lib/angular_webdriver/version.rb +2 -2
  20. data/lib/angular_webdriver.rb +14 -1
  21. data/{LICENSE → license/angular_webdriver/LICENSE.txt} +0 -0
  22. data/{lib/angular_webdriver → license}/protractor/LICENSE.txt +0 -0
  23. data/{lib/angular_webdriver/protractor/get_url_trace.rb → notes/bootstrap_notes.md} +13 -0
  24. data/notes/element_by_id/element_by_id_sync_off.txt +12 -0
  25. data/notes/element_by_id/element_by_id_sync_on.txt +74 -0
  26. data/notes/element_chaining_debug.txt +94 -0
  27. data/notes/evaluate/js_evaluate_sync_on.txt +60 -0
  28. data/notes/evaluate/ruby_evaluate_sync_on.txt +35 -0
  29. data/notes/get_title/browser_get_title_sync_off.txt +11 -0
  30. data/notes/get_title/browser_get_title_sync_on.txt +54 -0
  31. data/notes/phantomjs.md +23 -0
  32. data/notes/protractor_cli_bugs.txt +39 -0
  33. data/notes/protractor_get/protractor_get.rb +102 -0
  34. data/notes/protractor_get/protractor_get_website_sync_off.txt +11 -0
  35. data/notes/protractor_get/protractor_get_website_sync_on.txt +86 -0
  36. data/notes/repeater/findAllRepeaterRows_annotated.txt +150 -0
  37. data/notes/repeater/findAllRepeaterRows_raw.txt +145 -0
  38. data/notes/repeater/findRepeaterColumn_annotated.txt +317 -0
  39. data/notes/repeater/findRepeaterColumn_raw.txt +310 -0
  40. data/notes/repeater/findRepeaterElement_annotated.txt +152 -0
  41. data/notes/repeater/findRepeaterElement_raw.txt +146 -0
  42. data/notes/repeater/findRepeaterRows_annotated.txt +156 -0
  43. data/notes/repeater/findRepeaterRows_raw.txt +152 -0
  44. data/notes/sync_after.md +46 -0
  45. data/notes/sync_notes.md +137 -0
  46. data/notes/synchronize_spec/status_gettext.txt +121 -0
  47. data/notes/synchronize_spec/status_gettext_x3.txt +451 -0
  48. data/notes/synchronize_spec/synchronize_spec.js.txt +74 -0
  49. data/notes/synchronize_spec/watir_gettext.txt +73 -0
  50. data/readme.md +52 -12
  51. data/release_notes.md +127 -0
  52. data/selenium_server/lib/logs.rb +50 -0
  53. data/selenium_server/lib/selenium_server.rb +21 -0
  54. data/selenium_server/readme.md +3 -0
  55. data/selenium_server/spec/logs_spec.rb +18 -0
  56. data/selenium_server/spec/nodejs_sync_spec_waithttp_annotated.txt +54 -0
  57. data/selenium_server/spec/nodejs_sync_spec_waithttp_raw.txt +367 -0
  58. data/selenium_server/spec/nodejs_sync_spec_waithttp_raw_processed.txt +43 -0
  59. data/selenium_server/spec/ruby_sync_spec_waithttp_annotated.txt +59 -0
  60. data/selenium_server/spec/ruby_sync_spec_waithttp_raw.txt +267 -0
  61. data/selenium_server/spec/ruby_sync_spec_waithttp_raw_processed.txt +39 -0
  62. data/selenium_server/spec/spec_helper.rb +6 -0
  63. data/selenium_server/spec/status_gettext_x3.txt +429 -0
  64. data/selenium_server/spec/status_gettext_x3_annotated.txt +86 -0
  65. metadata +91 -18
  66. data/lib/angular_webdriver/protractor/clientSideScripts.json +0 -19
  67. data/lib/angular_webdriver/protractor/clientsidescripts.js +0 -671
  68. data/lib/angular_webdriver/protractor/scripts.rb +0 -7
  69. data/lib/angular_webdriver/protractor/scripts_to_json.js +0 -11
  70. data/spec/protractor_spec.rb +0 -40
  71. data/spec/spec_helper.rb +0 -5
@@ -0,0 +1,209 @@
1
+ require 'watir-webdriver/elements/element'
2
+
3
+ # match protractor semantics
4
+ # unfortunately setting always locate doesn't always locate.
5
+ Watir.always_locate = true
6
+
7
+ #
8
+ # This patch serves a few purposes. The first is matching Protractor semantics
9
+ # of lazy finding elements and always relocating elements (ex: element.text)
10
+ #
11
+ # The second is removing unnecessary bloatware from Watir which has a number
12
+ # of checks that don't make sense for angular.js testing. The specifics
13
+ # of this patch will change in the next Watir release. Currently version
14
+ # 0.7.0 is targeted.
15
+ #
16
+ # The third is teaching Watir about angular specific locators
17
+ #
18
+ # Design goal: element.all(by.binding('slowHttpStatus'))
19
+ # should not make any server requests
20
+ #
21
+
22
+ module Watir
23
+
24
+ class HTMLElementCollection
25
+ # Return original selector.
26
+ # Method added for protractor compatibility
27
+ def locator
28
+ @selector
29
+ end
30
+ end
31
+
32
+ module Container
33
+ #
34
+ # Alias of elements for Protractor
35
+ #
36
+
37
+ def all(*args)
38
+ elements(*args)
39
+ end
40
+
41
+ # Redefine extract_selector to wrap find by repeater
42
+ upstream_extract_selector = instance_method(:extract_selector)
43
+ define_method(:extract_selector) do |selectors|
44
+ selectors = AngularWebdriver::ByRepeaterInner.wrap_repeater selectors
45
+
46
+ upstream_extract_selector.bind(self).call selectors
47
+ end
48
+
49
+ end # module Container
50
+
51
+ #
52
+ # Base class for HTML elements.
53
+ #
54
+
55
+ # Note the element class is different on master.
56
+
57
+ class Element
58
+
59
+ # Always raise on stale element ref error. Prevents infinite retry loop.
60
+ def element_call
61
+ yield
62
+ rescue Selenium::WebDriver::Error::StaleElementReferenceError
63
+ raise
64
+ end
65
+
66
+ def selected?
67
+ assert_exists
68
+ element_call { @element.selected? }
69
+ end
70
+
71
+ # required for watir otherwise execute_script will fail
72
+ #
73
+ # e = browser.element(tag_name: 'div')
74
+ # driver.execute_script 'return arguments[0].tagName', e
75
+ # {"script":"return arguments[0].tagName","args":[{"ELEMENT":"0"}]}
76
+ #
77
+ # Convert to a WebElement JSON Object for transmission over the wire.
78
+ # @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#basic-terms-and-concepts
79
+ #
80
+ # @api private
81
+ #
82
+ def to_json(*args)
83
+ assert_exists
84
+ { ELEMENT: @element.ref }.to_json
85
+ end
86
+
87
+ # Ensure that the element exists by always relocating it
88
+ # Required to trigger waitForAngular. Caching the element here will
89
+ # break the Protractor sync feature so this must be @element = locate.
90
+ def assert_exists
91
+ @element = locate
92
+ end
93
+
94
+ def assert_not_stale
95
+ nil
96
+ end
97
+
98
+ def assert_enabled
99
+ nil
100
+ end
101
+
102
+ # Return original selector.
103
+ # Method added for protractor compatibility
104
+ def locator
105
+ @selector
106
+ end
107
+
108
+ # avoid context lookup
109
+ def locate
110
+ locator_class.new(@parent.wd, @selector, self.class.attribute_list).locate
111
+ end
112
+
113
+ # Invoke protractor.allowAnimations with freshly located element and
114
+ # optional value.
115
+ def allowAnimations value=nil
116
+ assert_exists
117
+ driver.protractor.allowAnimations @element, value
118
+ end
119
+
120
+ # Watir doesn't define a clear method on element so we have to provide one.
121
+ def clear
122
+ assert_exists
123
+ element_call { @element.clear }
124
+ end
125
+
126
+ # Evaluate an Angular expression as if it were on the scope
127
+ # of the current element.
128
+ #
129
+ # @param expression <String> The expression to evaluate.
130
+ #
131
+ # @return <Object> The result of the evaluation.
132
+ def evaluate expression
133
+ assert_exists
134
+ driver.protractor.evaluate @element, expression
135
+ end
136
+
137
+ #
138
+ # Returns true if the element exists and is visible on the page.
139
+ #
140
+ # @return [Boolean]
141
+ # @see Watir::Wait
142
+ #
143
+ #
144
+ # rescue element not found
145
+ def present?
146
+ exists? && visible?
147
+ rescue Selenium::WebDriver::Error::NoSuchElementError, Selenium::WebDriver::Error::StaleElementReferenceError, UnknownObjectException
148
+ # if the element disappears between the exists? and visible? calls,
149
+ # consider it not present.
150
+ false
151
+ end
152
+ end
153
+
154
+
155
+ #
156
+ # The main class through which you control the browser.
157
+ #
158
+
159
+ class Browser
160
+ def assert_exists
161
+ # remove expensive window check
162
+ raise Exception::Error, 'browser was closed' if @closed
163
+ end
164
+
165
+ def inspect
166
+ nil # avoid expensive browser url and title lookup
167
+ end
168
+ end
169
+
170
+ class ElementLocator
171
+ def validate_element(element)
172
+ tn = @selector[:tag_name]
173
+ return element unless tn # don't validate nil tag names
174
+ element_tag_name = element.tag_name.downcase
175
+
176
+ return if tn && !tag_name_matches?(element_tag_name, tn)
177
+
178
+ if element_tag_name == 'input'
179
+ return if @selector[:type] && @selector[:type] != element.attribute(:type)
180
+ end
181
+
182
+ element
183
+ end
184
+
185
+ # always raise element not found / stale reference error
186
+ def locate
187
+ # element.all(by.partialButtonText('text')).to_a[0].value creates the
188
+ # selector {:element=>#<Selenium::WebDriver::Element ...>}
189
+ # in that case we've already located the element.
190
+ #
191
+ # see 'should find multiple buttons containing "text"' in locators_spec.rb
192
+ return @selector[:element] if @selector.is_a?(Hash) && @selector[:element].is_a?(Selenium::WebDriver::Element)
193
+
194
+ e = by_id and return e # short-circuit if :id is given
195
+
196
+ if @selector.size == 1
197
+ element = find_first_by_one
198
+ else
199
+ element = find_first_by_multiple
200
+ end
201
+
202
+ # This actually only applies when finding by xpath/css - browser.text_field(:xpath, "//input[@type='radio']")
203
+ # We don't need to validate the element if we built the xpath ourselves.
204
+ # It is also used to alter behavior of methods locating more than one type of element
205
+ # (e.g. text_field locates both input and textarea)
206
+ validate_element(element) if element
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,246 @@
1
+ # https://github.com/SeleniumHQ/selenium/blob/1221ea539d92a46f392b00abccb9f48886415d26/rb/lib/selenium/webdriver/remote/bridge.rb#L576
2
+
3
+ require 'selenium/webdriver/common/search_context'
4
+ require 'selenium/webdriver/remote'
5
+ require 'selenium/webdriver/remote/bridge'
6
+
7
+ module Selenium
8
+ module WebDriver
9
+
10
+ class Driver
11
+ def protractor
12
+ @bridge.protractor
13
+ end
14
+
15
+ def protractor= protractor_object
16
+ @bridge.protractor = protractor_object
17
+ end
18
+
19
+ def bridge
20
+ @bridge
21
+ end
22
+
23
+ #
24
+ # Sets the wait time in seconds used when locating elements and
25
+ # waiting for angular tohttps://www.youtube.com/watch?v=o9c3U5_8tGY load.
26
+ #
27
+ # @param value [Numeric] the amount of time to wait in seconds
28
+ #
29
+ # @return [Numeric] the wait time in seconds
30
+ #
31
+ def set_max_wait value
32
+ @bridge.set_max_wait value
33
+ end
34
+
35
+ #
36
+ # Returns the wait time in seconds used when locating elements and
37
+ # waiting for angular to load.
38
+ #
39
+ def max_wait_seconds
40
+ @bridge.max_wait_seconds
41
+ end
42
+ end
43
+
44
+ module Remote
45
+ class Bridge
46
+ attr_accessor :protractor
47
+
48
+ def set_max_wait value
49
+ fail 'set_max_wait value must be a number' unless value.is_a?(Numeric)
50
+ # ensure no negative values
51
+ @max_wait_seconds = value >= 0 ? value : 0
52
+ end
53
+
54
+ def max_wait_seconds
55
+ # default to 0
56
+ @max_wait_seconds ||= 0
57
+ end
58
+
59
+ # execute_script requires a JSON representation of the element id
60
+ # otherwise the element will not be sent correctly to the browser
61
+ class WrappedParent
62
+ def initialize id
63
+ @id = id
64
+ end
65
+
66
+ def to_json *args
67
+ { ELEMENT: @id }.to_json
68
+ end
69
+ end
70
+
71
+ def protractor_find(many, how, what, parent = nil)
72
+ timeout = max_wait_seconds
73
+
74
+ # we have to waitForAngular here. unlike selenium locators,
75
+ # protractor locators don't go through execute. execute uses
76
+ # protractor.sync to run waitForAngular when finding elements.
77
+ wait(timeout: timeout, bubble: true) { protractor.waitForAngular }
78
+
79
+ # execute_script will invoke to_json on the parent, WrappedParent
80
+ # ensures that the JSON produces the expected result.
81
+ using = parent ? WrappedParent.new(parent) : false
82
+ root_selector = protractor.root_element
83
+ comment = "Protractor find by.#{how}"
84
+
85
+ # args order from locators.js
86
+ case how
87
+ when 'binding', 'exactBinding'
88
+ exact = how == 'exactBinding'
89
+ binding_descriptor = what
90
+ args = [binding_descriptor, exact, using, root_selector]
91
+ protractor_js = protractor.client_side_scripts.find_bindings
92
+ when 'partialButtonText'
93
+ search_text = what
94
+ args = [search_text, using, root_selector]
95
+ protractor_js = protractor.client_side_scripts.find_by_partial_button_text
96
+ when 'buttonText'
97
+ search_text = what
98
+ args = [search_text, using, root_selector]
99
+ protractor_js = protractor.client_side_scripts.find_by_button_text
100
+ when 'model'
101
+ model = what
102
+ args = [model, using, root_selector]
103
+ protractor_js = protractor.client_side_scripts.find_by_model
104
+ when 'options'
105
+ options_descriptor = what
106
+ args = [options_descriptor, using, root_selector]
107
+ protractor_js = protractor.client_side_scripts.find_by_options
108
+ when 'cssContainingText'
109
+ json = JSON.parse what
110
+ css_selector = json['cssSelector']
111
+ search_text = json['searchText']
112
+ args = [css_selector, search_text, using, root_selector]
113
+ protractor_js = protractor.client_side_scripts.find_by_css_containing_text
114
+ when 'repeater' # includes 'exactRepeater'
115
+ json = JSON.parse what
116
+ repeater_args = json['args'].values # json args is a hash
117
+ # using and root_selector are always passed to repeater even
118
+ # if the script doesn't use them.
119
+ args = repeater_args + [using, root_selector]
120
+
121
+ # findRepeaterElement, findRepeaterRows, findRepeaterColumn, findAllRepeaterRows
122
+ script_name = json['script'].intern
123
+
124
+ protractor_js = protractor.client_side_scripts.scripts[script_name]
125
+ end
126
+
127
+ finder = lambda { protractor.executeScript_(protractor_js, comment, *args) }
128
+
129
+ result = []
130
+
131
+ # Ignore any exceptions here because find_elements returns
132
+ # an empty array when there are no values found, not an error.
133
+ ignore do
134
+ wait_true(timeout) do
135
+ result = finder.call
136
+ result.length > 0
137
+ end
138
+ end
139
+
140
+ result ||= []
141
+
142
+ if many
143
+ return result
144
+ else
145
+ result = result.first
146
+ return result if result
147
+ fail ::Selenium::WebDriver::Error::NoSuchElementError
148
+ end
149
+ end
150
+
151
+ def find_element_by(how, what, parent = nil)
152
+ if protractor.finder? how
153
+ return protractor_find(false, how, what, parent)
154
+ end
155
+
156
+ if parent
157
+ id = execute :findChildElement, { :id => parent }, { :using => how, :value => what }
158
+ else
159
+ id = execute :findElement, {}, { :using => how, :value => what }
160
+ end
161
+
162
+ Element.new self, element_id_from(id)
163
+ end
164
+
165
+ def find_elements_by(how, what, parent = nil)
166
+ if protractor.finder? how
167
+ return protractor_find(true, how, what, parent)
168
+ end
169
+
170
+ if parent
171
+ ids = execute :findChildElements, { :id => parent }, { :using => how, :value => what }
172
+ else
173
+ ids = execute :findElements, {}, { :using => how, :value => what }
174
+ end
175
+
176
+ ids.map { |id| Element.new self, element_id_from(id) }
177
+ end
178
+
179
+ #
180
+ # driver.get uses execute which invokes protractor.get
181
+ # protractor.get needs to call driver.get without invoking
182
+ # protractor.get.
183
+ #
184
+ # this is accomplished by using driver_get and raw_execute
185
+ #
186
+
187
+ def driver_get(url)
188
+ raw_execute(:get, {}, :url => url)['value']
189
+ end
190
+
191
+ FIND_ELEMENT_METHODS = [:findElement, :findChildElement].freeze
192
+ FIND_ELEMENTS_METHODS = [:findElements, :findChildElements].freeze
193
+
194
+ #
195
+ # executes a command on the remote server.
196
+ #
197
+ #
198
+ # Returns the 'value' of the returned payload
199
+ #
200
+
201
+ def execute(*args)
202
+ raise 'Must initialize protractor' unless protractor
203
+ method_symbol = args.first
204
+ unless protractor.ignore_sync
205
+ # override get method which has special sync logic
206
+ # (not handled via sync method)
207
+ if method_symbol == :get
208
+ url = args.last[:url]
209
+ return protractor.get url
210
+ end
211
+
212
+ protractor.sync method_symbol
213
+ end
214
+
215
+ timeout = max_wait_seconds
216
+ finder = lambda { raw_execute(*args)['value'] }
217
+ find_one_element = FIND_ELEMENT_METHODS.include?(method_symbol)
218
+ find_many_elements = FIND_ELEMENTS_METHODS.include?(method_symbol)
219
+
220
+ if find_one_element
221
+ wait(timeout: timeout, bubble: true) do
222
+ finder.call
223
+ end
224
+ elsif find_many_elements
225
+ result = []
226
+
227
+ # Ignore any exceptions here because find_elements returns
228
+ # an empty array when there are no values found, not an error.
229
+ ignore do
230
+ wait_true(timeout) do
231
+ result = finder.call
232
+ result.length > 0
233
+ end
234
+ end
235
+
236
+ result ||= []
237
+ result
238
+ else # all other commands
239
+ finder.call
240
+ end
241
+ end
242
+
243
+ end # class Bridge
244
+ end # module Remote
245
+ end # module WebDriver
246
+ end # module Selenium
@@ -1,4 +1,4 @@
1
1
  module AngularWebdriver
2
- VERSION = '0.0.7' unless defined? ::AngularWebdriver::VERSION
3
- DATE = '2015-05-12' unless defined? ::AngularWebdriver::DATE
2
+ VERSION = '1.0.0' unless defined? ::AngularWebdriver::VERSION
3
+ DATE = '2015-06-06' unless defined? ::AngularWebdriver::DATE
4
4
  end
@@ -1 +1,14 @@
1
- require_relative 'angular_webdriver/protractor/protractor'
1
+ require_relative 'angular_webdriver/version'
2
+
3
+ require 'rubygems'
4
+ require 'selenium-webdriver'
5
+ require 'watir-webdriver'
6
+
7
+ require_relative 'angular_webdriver/protractor/by'
8
+ require_relative 'angular_webdriver/protractor/by_repeater_inner'
9
+ require_relative 'angular_webdriver/protractor/client_side_scripts'
10
+ require_relative 'angular_webdriver/protractor/protractor'
11
+ require_relative 'angular_webdriver/protractor/protractor_element'
12
+ require_relative 'angular_webdriver/protractor/rspec_helpers'
13
+ require_relative 'angular_webdriver/protractor/webdriver_patch'
14
+ require_relative 'angular_webdriver/protractor/watir_patch'
File without changes
@@ -1,3 +1,15 @@
1
+ # https://github.com/SeleniumHQ/selenium/blob/51fd82ec9cb1ebe7596bf7bb3fb8290113466a9a/rb/lib/selenium/webdriver/common/search_context.rb#L23
2
+ # protractor/lib/locators.js
3
+ #
4
+ # ProtractorBy.prototype.binding = function(bindingDescriptor) {
5
+ # return {
6
+ # findElementsOverride: function(driver, using, rootSelector) {
7
+ # return driver.findElements(
8
+ # webdriver.By.js(clientSideScripts.findBindings,
9
+ # bindingDescriptor, false, using, rootSelector));
10
+ # },
11
+
12
+ ```
1
13
  =begin
2
14
 
3
15
  executeAsyncScript_ & executeScript_ wrappers not required. The description
@@ -213,3 +225,4 @@ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [, false, null, bod
213
225
  14:20:15.086 INFO - Executing: [get text: 1 [org.openqa.selenium.remote.RemoteWebElement@dee620f8 -> unknown locator]])
214
226
  ...
215
227
  =end
228
+ ```
@@ -0,0 +1,12 @@
1
+ browser.get('https://angularjs.org/')
2
+ element(by.id('the-basics')).getText()
3
+ The Basics
4
+
5
+ 13:06:18.990 INFO - Executing: [execute script: , []])
6
+ 13:06:18.990 INFO - Executing: [execute script: , []])
7
+ 13:06:18.990 INFO - Executing: [find elements: By.id: the-basics])
8
+ 13:06:19.704 INFO - Done: [execute script: , []]
9
+ 13:06:19.799 INFO - Done: [find elements: By.id: the-basics]
10
+ 13:06:19.815 INFO - Executing: [get text: 0 [[FirefoxDriver: firefox on MAC (6e728ccc-09cf-0b47-a80e-44bdfdbb8a1b)] -> id: the-basics]])
11
+ 13:06:19.865 INFO - Done: [execute script: , []]
12
+ 13:06:19.930 INFO - Done: [get text: 0 [[FirefoxDriver: firefox on MAC (6e728ccc-09cf-0b47-a80e-44bdfdbb8a1b)] -> id: the-basics]]
@@ -0,0 +1,74 @@
1
+ browser.get('https://angularjs.org/')
2
+ element(by.id('the-basics')).getText()
3
+ The Basics
4
+
5
+
6
+ the waitForAngular method is called before the get by id method.
7
+
8
+
9
+ 13:04:57.684 INFO - Executing: [execute script: , []])
10
+ 13:04:57.684 INFO - Executing: [execute script: , []])
11
+
12
+ waitForAngular - clientsidescript
13
+
14
+ 13:04:57.684 INFO - Executing: [execute async script: try { return (function (rootSelector, callback) {
15
+ var el = document.querySelector(rootSelector);
16
+
17
+ try {
18
+ if (!window.angular) {
19
+ throw new Error('angular could not be found on the window');
20
+ }
21
+ if (angular.getTestability) {
22
+ angular.getTestability(el).whenStable(callback);
23
+ } else {
24
+ if (!angular.element(el).injector()) {
25
+ throw new Error('root element (' + rootSelector + ') has no injector.' +
26
+ ' this may mean it is not inside ng-app.');
27
+ }
28
+ angular.element(el).injector().get('$browser').
29
+ notifyWhenNoOutstandingRequests(callback);
30
+ }
31
+ } catch (err) {
32
+ callback(err.message);
33
+ }
34
+ }).apply(this, arguments); }
35
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]])
36
+ 13:04:57.684 INFO - Executing: [execute script: , []])
37
+ 13:04:57.685 INFO - Executing: [execute script: , []])
38
+ 13:04:58.617 INFO - Done: [execute script: , []]
39
+ 13:04:58.694 INFO - Done: [execute script: , []]
40
+
41
+ waitForAngular - clientsidescript
42
+
43
+ 13:04:58.771 INFO - Done: [execute async script: try { return (function (rootSelector, callback) {
44
+ var el = document.querySelector(rootSelector);
45
+
46
+ try {
47
+ if (!window.angular) {
48
+ throw new Error('angular could not be found on the window');
49
+ }
50
+ if (angular.getTestability) {
51
+ angular.getTestability(el).whenStable(callback);
52
+ } else {
53
+ if (!angular.element(el).injector()) {
54
+ throw new Error('root element (' + rootSelector + ') has no injector.' +
55
+ ' this may mean it is not inside ng-app.');
56
+ }
57
+ angular.element(el).injector().get('$browser').
58
+ notifyWhenNoOutstandingRequests(callback);
59
+ }
60
+ } catch (err) {
61
+ callback(err.message);
62
+ }
63
+ }).apply(this, arguments); }
64
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]]
65
+ 13:04:58.792 INFO - Executing: [find elements: By.id: the-basics])
66
+
67
+ 13:04:59.019 INFO - Done: [execute script: , []]
68
+ 13:04:59.085 INFO - Done: [execute script: , []]
69
+ 13:04:59.218 INFO - Done: [find elements: By.id: the-basics]
70
+ 13:04:59.240 INFO - Executing: [get text: 0 [[FirefoxDriver: firefox on MAC (6e728ccc-09cf-0b47-a80e-44bdfdbb8a1b)] -> id: the-basics]])
71
+ 13:04:59.286 INFO - Done: [get text: 0 [[FirefoxDriver: firefox on MAC (6e728ccc-09cf-0b47-a80e-44bdfdbb8a1b)] -> id: the-basics]]
72
+
73
+
74
+
@@ -0,0 +1,94 @@
1
+ debugging 'should allow chaining while returning a single column'
2
+
3
+ ["allinfo in days", false, 2, "name", "{ebfdf19b-a4a8-be46-8118-6f313da550fd}", nil]
4
+
5
+
6
+
7
+ The element reference isn't being sent properly.
8
+
9
+
10
+ Ruby server output:
11
+
12
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [allinfo in days, false, 2, name, 0, body]])
13
+
14
+
15
+ element.ref is 0
16
+
17
+
18
+ Protractor server output:
19
+
20
+ [allinfo in days, false, 2, name, [[FirefoxDriver: firefox on MAC (7f28005d-8e97-024e-86aa-879ee42d9e76)] -> css selector: .allinfo], body]]
21
+
22
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [allinfo in days, false, 2, name, [[FirefoxDriver: firefox on MAC (7f28005d-8e97-024e-86aa-879ee42d9e76)] -> css selector: .allinfo], body]]
23
+
24
+ ---
25
+
26
+ browser.get('http://localhost:8081/#/repeater')
27
+
28
+
29
+ var secondName = element(by.css('.allinfo')).element(by.repeater('allinfo in days').column('name').row(2))
30
+
31
+ ---
32
+
33
+ > e.ref
34
+ => "2"
35
+
36
+
37
+ driver.execute_script 'return arguments[0].tagName', e
38
+ > DIV
39
+ driver.execute_script 'return arguments[0].tagName', e.ref
40
+ > nil
41
+
42
+ driver.execute_script 'return arguments[0].tagName', 2
43
+ => nil
44
+
45
+ driver.execute_script 'return arguments[0].tagName', '2'
46
+ => nil
47
+
48
+
49
+ driver.execute_script 'return arguments[0].tagName', '{7c79f087-b7a2-dd43-be77-2a4076cb5959}'
50
+ => nil
51
+
52
+
53
+ e = browser.element(tag_name: 'div')
54
+
55
+
56
+ ---
57
+
58
+ > command_hash
59
+ => {:script=>"return arguments[0].tagName", :args=>[#<Selenium::WebDriver::Element:0x..fea95b8c7217851b0 id="0">]}
60
+
61
+ ---
62
+
63
+ e = browser.element(tag_name: 'div')
64
+ driver.execute_script 'return arguments[0].tagName', e
65
+
66
+ Requesting: {"script":"return arguments[0].tagName","args":["#<Watir::HTMLElement:0x007f8a6d098ae0>"]}
67
+
68
+ patched webdriver http default to output request body
69
+
70
+ def new_request_for(verb, url, headers, payload)
71
+ puts "Requesting: #{req.body}"
72
+
73
+ ---
74
+
75
+ e = driver.find_element(tag_name: 'div')
76
+ driver.execute_script 'return arguments[0].tagName', e
77
+ Requesting: {"script":"return arguments[0].tagName","args":[{"ELEMENT":"0"}]}
78
+
79
+ ----
80
+
81
+ > puts e.to_json
82
+ {"ELEMENT":"0"}
83
+
84
+ ---
85
+
86
+
87
+ element id changes depending on if a remote bridge or a firefox bridge is used.
88
+ remote bridges start at 0 and go up by one.
89
+
90
+ firefox bridge uses hashes.
91
+
92
+ ---
93
+
94
+ driver.execute_script 'return arguments[0].tagName', WrappedParent.new('0')