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.
- 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
@@ -0,0 +1,156 @@
|
|
1
|
+
browser.get('http://localhost:8081/#/repeater')
|
2
|
+
element(by.repeater('baz in days').row(0)).getText();
|
3
|
+
|
4
|
+
|
5
|
+
16:14:10.375 INFO - Executing: [execute script: , []])
|
6
|
+
16:14:10.375 INFO - Executing: [execute async script: try { return (function (rootSelector, callback) {
|
7
|
+
var el = document.querySelector(rootSelector);
|
8
|
+
|
9
|
+
try {
|
10
|
+
if (!window.angular) {
|
11
|
+
throw new Error('angular could not be found on the window');
|
12
|
+
}
|
13
|
+
if (angular.getTestability) {
|
14
|
+
angular.getTestability(el).whenStable(callback);
|
15
|
+
} else {
|
16
|
+
if (!angular.element(el).injector()) {
|
17
|
+
throw new Error('root element (' + rootSelector + ') has no injector.' +
|
18
|
+
' this may mean it is not inside ng-app.');
|
19
|
+
}
|
20
|
+
angular.element(el).injector().get('$browser').
|
21
|
+
notifyWhenNoOutstandingRequests(callback);
|
22
|
+
}
|
23
|
+
} catch (err) {
|
24
|
+
callback(err.message);
|
25
|
+
}
|
26
|
+
}).apply(this, arguments); }
|
27
|
+
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]])
|
28
|
+
16:14:10.390 INFO - Done: [execute script: , []]
|
29
|
+
16:14:10.450 INFO - Done: [execute async script: try { return (function (rootSelector, callback) {
|
30
|
+
var el = document.querySelector(rootSelector);
|
31
|
+
|
32
|
+
try {
|
33
|
+
if (!window.angular) {
|
34
|
+
throw new Error('angular could not be found on the window');
|
35
|
+
}
|
36
|
+
if (angular.getTestability) {
|
37
|
+
angular.getTestability(el).whenStable(callback);
|
38
|
+
} else {
|
39
|
+
if (!angular.element(el).injector()) {
|
40
|
+
throw new Error('root element (' + rootSelector + ') has no injector.' +
|
41
|
+
' this may mean it is not inside ng-app.');
|
42
|
+
}
|
43
|
+
angular.element(el).injector().get('$browser').
|
44
|
+
notifyWhenNoOutstandingRequests(callback);
|
45
|
+
}
|
46
|
+
} catch (err) {
|
47
|
+
callback(err.message);
|
48
|
+
}
|
49
|
+
}).apply(this, arguments); }
|
50
|
+
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]]
|
51
|
+
|
52
|
+
// -- function (repeater, exact, index, using)
|
53
|
+
// -- [baz in days, false, 0, null, body]
|
54
|
+
// -- findRepeaterRows
|
55
|
+
16:14:10.466 INFO - Executing: [execute script: try { return (function (repeater, exact, index, using) {
|
56
|
+
function repeaterMatch(ngRepeat, repeater, exact) {
|
57
|
+
if (exact) {
|
58
|
+
return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
|
59
|
+
trim() == repeater;
|
60
|
+
} else {
|
61
|
+
return ngRepeat.indexOf(repeater) != -1;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
using = using || document;
|
66
|
+
|
67
|
+
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
|
68
|
+
var rows = [];
|
69
|
+
for (var p = 0; p < prefixes.length; ++p) {
|
70
|
+
var attr = prefixes[p] + 'repeat';
|
71
|
+
var repeatElems = using.querySelectorAll('[' + attr + ']');
|
72
|
+
attr = attr.replace(/\\/g, '');
|
73
|
+
for (var i = 0; i < repeatElems.length; ++i) {
|
74
|
+
if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
|
75
|
+
rows.push(repeatElems[i]);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
/* multiRows is an array of arrays, where each inner array contains
|
80
|
+
one row of elements. */
|
81
|
+
var multiRows = [];
|
82
|
+
for (var p = 0; p < prefixes.length; ++p) {
|
83
|
+
var attr = prefixes[p] + 'repeat-start';
|
84
|
+
var repeatElems = using.querySelectorAll('[' + attr + ']');
|
85
|
+
attr = attr.replace(/\\/g, '');
|
86
|
+
for (var i = 0; i < repeatElems.length; ++i) {
|
87
|
+
if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
|
88
|
+
var elem = repeatElems[i];
|
89
|
+
var row = [];
|
90
|
+
while (elem.nodeType != 8 ||
|
91
|
+
!repeaterMatch(elem.nodeValue, repeater, exact)) {
|
92
|
+
if (elem.nodeType == 1) {
|
93
|
+
row.push(elem);
|
94
|
+
}
|
95
|
+
elem = elem.nextSibling;
|
96
|
+
}
|
97
|
+
multiRows.push(row);
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
var row = rows[index] || [], multiRow = multiRows[index] || [];
|
102
|
+
return [].concat(row, multiRow);
|
103
|
+
}).apply(this, arguments); }
|
104
|
+
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [baz in days, false, 0, null, body]])
|
105
|
+
16:14:10.553 INFO - Done: [execute script: try { return (function (repeater, exact, index, using) {
|
106
|
+
function repeaterMatch(ngRepeat, repeater, exact) {
|
107
|
+
if (exact) {
|
108
|
+
return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
|
109
|
+
trim() == repeater;
|
110
|
+
} else {
|
111
|
+
return ngRepeat.indexOf(repeater) != -1;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
using = using || document;
|
116
|
+
|
117
|
+
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
|
118
|
+
var rows = [];
|
119
|
+
for (var p = 0; p < prefixes.length; ++p) {
|
120
|
+
var attr = prefixes[p] + 'repeat';
|
121
|
+
var repeatElems = using.querySelectorAll('[' + attr + ']');
|
122
|
+
attr = attr.replace(/\\/g, '');
|
123
|
+
for (var i = 0; i < repeatElems.length; ++i) {
|
124
|
+
if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
|
125
|
+
rows.push(repeatElems[i]);
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
129
|
+
/* multiRows is an array of arrays, where each inner array contains
|
130
|
+
one row of elements. */
|
131
|
+
var multiRows = [];
|
132
|
+
for (var p = 0; p < prefixes.length; ++p) {
|
133
|
+
var attr = prefixes[p] + 'repeat-start';
|
134
|
+
var repeatElems = using.querySelectorAll('[' + attr + ']');
|
135
|
+
attr = attr.replace(/\\/g, '');
|
136
|
+
for (var i = 0; i < repeatElems.length; ++i) {
|
137
|
+
if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
|
138
|
+
var elem = repeatElems[i];
|
139
|
+
var row = [];
|
140
|
+
while (elem.nodeType != 8 ||
|
141
|
+
!repeaterMatch(elem.nodeValue, repeater, exact)) {
|
142
|
+
if (elem.nodeType == 1) {
|
143
|
+
row.push(elem);
|
144
|
+
}
|
145
|
+
elem = elem.nextSibling;
|
146
|
+
}
|
147
|
+
multiRows.push(row);
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
var row = rows[index] || [], multiRow = multiRows[index] || [];
|
152
|
+
return [].concat(row, multiRow);
|
153
|
+
}).apply(this, arguments); }
|
154
|
+
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [baz in days, false, 0, null, body]]
|
155
|
+
16:14:10.570 INFO - Executing: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@fa534d6b -> unknown locator]])
|
156
|
+
16:14:10.616 INFO - Done: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@fa534d6b -> unknown locator]]
|
@@ -0,0 +1,152 @@
|
|
1
|
+
browser.get('http://localhost:8081/#/repeater')
|
2
|
+
element(by.repeater('baz in days').row(0)).getText();
|
3
|
+
|
4
|
+
|
5
|
+
16:14:10.375 INFO - Executing: [execute script: , []])
|
6
|
+
16:14:10.375 INFO - Executing: [execute async script: try { return (function (rootSelector, callback) {
|
7
|
+
var el = document.querySelector(rootSelector);
|
8
|
+
|
9
|
+
try {
|
10
|
+
if (!window.angular) {
|
11
|
+
throw new Error('angular could not be found on the window');
|
12
|
+
}
|
13
|
+
if (angular.getTestability) {
|
14
|
+
angular.getTestability(el).whenStable(callback);
|
15
|
+
} else {
|
16
|
+
if (!angular.element(el).injector()) {
|
17
|
+
throw new Error('root element (' + rootSelector + ') has no injector.' +
|
18
|
+
' this may mean it is not inside ng-app.');
|
19
|
+
}
|
20
|
+
angular.element(el).injector().get('$browser').
|
21
|
+
notifyWhenNoOutstandingRequests(callback);
|
22
|
+
}
|
23
|
+
} catch (err) {
|
24
|
+
callback(err.message);
|
25
|
+
}
|
26
|
+
}).apply(this, arguments); }
|
27
|
+
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]])
|
28
|
+
16:14:10.390 INFO - Done: [execute script: , []]
|
29
|
+
16:14:10.450 INFO - Done: [execute async script: try { return (function (rootSelector, callback) {
|
30
|
+
var el = document.querySelector(rootSelector);
|
31
|
+
|
32
|
+
try {
|
33
|
+
if (!window.angular) {
|
34
|
+
throw new Error('angular could not be found on the window');
|
35
|
+
}
|
36
|
+
if (angular.getTestability) {
|
37
|
+
angular.getTestability(el).whenStable(callback);
|
38
|
+
} else {
|
39
|
+
if (!angular.element(el).injector()) {
|
40
|
+
throw new Error('root element (' + rootSelector + ') has no injector.' +
|
41
|
+
' this may mean it is not inside ng-app.');
|
42
|
+
}
|
43
|
+
angular.element(el).injector().get('$browser').
|
44
|
+
notifyWhenNoOutstandingRequests(callback);
|
45
|
+
}
|
46
|
+
} catch (err) {
|
47
|
+
callback(err.message);
|
48
|
+
}
|
49
|
+
}).apply(this, arguments); }
|
50
|
+
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]]
|
51
|
+
16:14:10.466 INFO - Executing: [execute script: try { return (function (repeater, exact, index, using) {
|
52
|
+
function repeaterMatch(ngRepeat, repeater, exact) {
|
53
|
+
if (exact) {
|
54
|
+
return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
|
55
|
+
trim() == repeater;
|
56
|
+
} else {
|
57
|
+
return ngRepeat.indexOf(repeater) != -1;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
using = using || document;
|
62
|
+
|
63
|
+
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
|
64
|
+
var rows = [];
|
65
|
+
for (var p = 0; p < prefixes.length; ++p) {
|
66
|
+
var attr = prefixes[p] + 'repeat';
|
67
|
+
var repeatElems = using.querySelectorAll('[' + attr + ']');
|
68
|
+
attr = attr.replace(/\\/g, '');
|
69
|
+
for (var i = 0; i < repeatElems.length; ++i) {
|
70
|
+
if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
|
71
|
+
rows.push(repeatElems[i]);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
/* multiRows is an array of arrays, where each inner array contains
|
76
|
+
one row of elements. */
|
77
|
+
var multiRows = [];
|
78
|
+
for (var p = 0; p < prefixes.length; ++p) {
|
79
|
+
var attr = prefixes[p] + 'repeat-start';
|
80
|
+
var repeatElems = using.querySelectorAll('[' + attr + ']');
|
81
|
+
attr = attr.replace(/\\/g, '');
|
82
|
+
for (var i = 0; i < repeatElems.length; ++i) {
|
83
|
+
if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
|
84
|
+
var elem = repeatElems[i];
|
85
|
+
var row = [];
|
86
|
+
while (elem.nodeType != 8 ||
|
87
|
+
!repeaterMatch(elem.nodeValue, repeater, exact)) {
|
88
|
+
if (elem.nodeType == 1) {
|
89
|
+
row.push(elem);
|
90
|
+
}
|
91
|
+
elem = elem.nextSibling;
|
92
|
+
}
|
93
|
+
multiRows.push(row);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
var row = rows[index] || [], multiRow = multiRows[index] || [];
|
98
|
+
return [].concat(row, multiRow);
|
99
|
+
}).apply(this, arguments); }
|
100
|
+
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [baz in days, false, 0, null, body]])
|
101
|
+
16:14:10.553 INFO - Done: [execute script: try { return (function (repeater, exact, index, using) {
|
102
|
+
function repeaterMatch(ngRepeat, repeater, exact) {
|
103
|
+
if (exact) {
|
104
|
+
return ngRepeat.split(' track by ')[0].split(' as ')[0].split('|')[0].
|
105
|
+
trim() == repeater;
|
106
|
+
} else {
|
107
|
+
return ngRepeat.indexOf(repeater) != -1;
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
using = using || document;
|
112
|
+
|
113
|
+
var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\:'];
|
114
|
+
var rows = [];
|
115
|
+
for (var p = 0; p < prefixes.length; ++p) {
|
116
|
+
var attr = prefixes[p] + 'repeat';
|
117
|
+
var repeatElems = using.querySelectorAll('[' + attr + ']');
|
118
|
+
attr = attr.replace(/\\/g, '');
|
119
|
+
for (var i = 0; i < repeatElems.length; ++i) {
|
120
|
+
if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
|
121
|
+
rows.push(repeatElems[i]);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
/* multiRows is an array of arrays, where each inner array contains
|
126
|
+
one row of elements. */
|
127
|
+
var multiRows = [];
|
128
|
+
for (var p = 0; p < prefixes.length; ++p) {
|
129
|
+
var attr = prefixes[p] + 'repeat-start';
|
130
|
+
var repeatElems = using.querySelectorAll('[' + attr + ']');
|
131
|
+
attr = attr.replace(/\\/g, '');
|
132
|
+
for (var i = 0; i < repeatElems.length; ++i) {
|
133
|
+
if (repeaterMatch(repeatElems[i].getAttribute(attr), repeater, exact)) {
|
134
|
+
var elem = repeatElems[i];
|
135
|
+
var row = [];
|
136
|
+
while (elem.nodeType != 8 ||
|
137
|
+
!repeaterMatch(elem.nodeValue, repeater, exact)) {
|
138
|
+
if (elem.nodeType == 1) {
|
139
|
+
row.push(elem);
|
140
|
+
}
|
141
|
+
elem = elem.nextSibling;
|
142
|
+
}
|
143
|
+
multiRows.push(row);
|
144
|
+
}
|
145
|
+
}
|
146
|
+
}
|
147
|
+
var row = rows[index] || [], multiRow = multiRows[index] || [];
|
148
|
+
return [].concat(row, multiRow);
|
149
|
+
}).apply(this, arguments); }
|
150
|
+
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [baz in days, false, 0, null, body]]
|
151
|
+
16:14:10.570 INFO - Executing: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@fa534d6b -> unknown locator]])
|
152
|
+
16:14:10.616 INFO - Done: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@fa534d6b -> unknown locator]]
|
data/notes/sync_after.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
Due to protractors design (lazy loading of elements and always refinding elements)
|
2
|
+
there's no need for syncing after an element action. This is because every
|
3
|
+
element action causes the element to be refound which triggers wait for angular.
|
4
|
+
|
5
|
+
These are some notes about sync_after which ended up not being used.
|
6
|
+
Instead the protractor semantics are matched by adopting watir-webdriver.
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
# do not use. will be removed
|
10
|
+
def sync_after webdriver_command
|
11
|
+
# https://github.com/angular/protractor/blob/8743d5cdf4c6b1337f5a4bd376336911cf62b856/lib/element.js#L5
|
12
|
+
# var WEB_ELEMENT_FUNCTIONS
|
13
|
+
#
|
14
|
+
# 'click', # :clickElement,
|
15
|
+
# 'sendKeys', # :sendKeysToElement, :sendKeysToActiveElement, :sendModifierKeyToActiveElement
|
16
|
+
# 'getTagName', # :getElementTagName
|
17
|
+
# 'getCssValue', # getElementValueOfCssProperty
|
18
|
+
# 'getAttribute', # :getElementAttribute
|
19
|
+
# 'getText', # :getElementText
|
20
|
+
# 'getSize', # :getElementSize,
|
21
|
+
# 'getLocation', # :getElementLocation, :getElementLocationOnceScrolledIntoView
|
22
|
+
# 'isEnabled', # :isElementEnabled
|
23
|
+
# 'isSelected', # :isElementSelected
|
24
|
+
# 'submit', # :submitElement
|
25
|
+
# 'clear', # :clearElement
|
26
|
+
# 'isDisplayed', # :isElementDisplayed
|
27
|
+
# 'getOuterHtml', -- JS binding exclusive. not available in Ruby bindings.
|
28
|
+
# 'getInnerHtml', -- JS binding exclusive. not available in Ruby bindings.
|
29
|
+
# 'getId', # :describeElement
|
30
|
+
# 'getRawId']; # same as element.ref however in Ruby this is purely client side.
|
31
|
+
|
32
|
+
|
33
|
+
# todo: audit all web element functions (protractor element.js)
|
34
|
+
# so that the sync test can pass.
|
35
|
+
# commdands.rb
|
36
|
+
|
37
|
+
|
38
|
+
# todo: evaluate these
|
39
|
+
# :getElementValue
|
40
|
+
# :dragElement
|
41
|
+
# :getActiveElement
|
42
|
+
# elementEquals
|
43
|
+
|
44
|
+
|
45
|
+
end
|
46
|
+
```
|
data/notes/sync_notes.md
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
sync on find element(s) calls
|
2
|
+
browser.get('https://angularjs.org/')
|
3
|
+
element(by.id('the-basics')).getText()
|
4
|
+
|
5
|
+
|
6
|
+
protractor.js
|
7
|
+
|
8
|
+
var methodsToSync = ['getCurrentUrl', 'getPageSource', 'getTitle']; -- all of these wait for angular
|
9
|
+
|
10
|
+
Protractor.prototype.findElement -- waits for angular
|
11
|
+
Protractor.prototype.findElements -- waits for angular
|
12
|
+
|
13
|
+
Protractor.prototype.isElementPresent -- does **not** trigger wait for angular
|
14
|
+
|
15
|
+
Protractor.prototype.get -- custom protractor method, waits for angular
|
16
|
+
Protractor.prototype.refresh -- custom protractor method, waits for angular
|
17
|
+
Protractor.prototype.navigate -- does not trigger wait for angular
|
18
|
+
|
19
|
+
Protractor.prototype.setLocation -- custom protractor method -- client side script that already checks for angular.
|
20
|
+
Protractor.prototype.getLocationAbsUrl -- custom protractor method -- client side script that already checks for angular.
|
21
|
+
Protractor.prototype.debugger -- custom protractor method -- client side script. doesn't wait.
|
22
|
+
|
23
|
+
|
24
|
+
todo: port custom protractor methods
|
25
|
+
todo: auto sync / use protractor replacements when ignore sync is false
|
26
|
+
|
27
|
+
|
28
|
+
redefine core selenium methods to auto sync before execution
|
29
|
+
to use commands (for example get) on non-angular pages, people can disable synchronization.
|
30
|
+
|
31
|
+
# ---
|
32
|
+
|
33
|
+
Selenium::WebDriver::Remote::COMMANDS.keys
|
34
|
+
=> [:newSession,
|
35
|
+
:getCapabilities,
|
36
|
+
:status,
|
37
|
+
:getCurrentUrl, -- must sync
|
38
|
+
:get, -- must sync
|
39
|
+
:goForward, -- does not sync
|
40
|
+
:goBack, -- does not sync
|
41
|
+
:refresh, -- must sync
|
42
|
+
:quit,
|
43
|
+
:close,
|
44
|
+
:getPageSource, -- must sync
|
45
|
+
:getTitle, -- must sync
|
46
|
+
:findElement, -- must sync
|
47
|
+
:findElements, -- must sync
|
48
|
+
:getActiveElement, -- does not sync
|
49
|
+
:getCurrentWindowHandle, -- does not sync
|
50
|
+
:getWindowHandles,
|
51
|
+
:setWindowSize,
|
52
|
+
:setWindowPosition,
|
53
|
+
:getWindowSize, -- does not sync
|
54
|
+
:getWindowPosition, -- does not sync
|
55
|
+
:maximizeWindow,
|
56
|
+
:executeScript, -- does not sync
|
57
|
+
:executeAsyncScript, -- does not sync
|
58
|
+
:screenshot,
|
59
|
+
:dismissAlert,
|
60
|
+
:acceptAlert,
|
61
|
+
:getAlertText, -- does not sync
|
62
|
+
:setAlertValue,
|
63
|
+
:switchToFrame,
|
64
|
+
:switchToParentFrame,
|
65
|
+
:switchToWindow,
|
66
|
+
:getCookies,
|
67
|
+
:addCookie,
|
68
|
+
:deleteAllCookies,
|
69
|
+
:deleteCookie,
|
70
|
+
:implicitlyWait,
|
71
|
+
:setScriptTimeout,
|
72
|
+
:setTimeout,
|
73
|
+
:describeElement,
|
74
|
+
:findChildElement, -- sync
|
75
|
+
:findChildElements, -- sync
|
76
|
+
:clickElement,
|
77
|
+
:submitElement,
|
78
|
+
:getElementValue,
|
79
|
+
:sendKeysToElement,
|
80
|
+
:uploadFile,
|
81
|
+
:getElementTagName,
|
82
|
+
:clearElement,
|
83
|
+
:isElementSelected,
|
84
|
+
:isElementEnabled,
|
85
|
+
:getElementAttribute,
|
86
|
+
:elementEquals,
|
87
|
+
:isElementDisplayed, -- does not sync
|
88
|
+
:getElementLocation,
|
89
|
+
:getElementLocationOnceScrolledIntoView,
|
90
|
+
:getElementSize,
|
91
|
+
:dragElement,
|
92
|
+
:getElementValueOfCssProperty,
|
93
|
+
:getElementText, -- does not sync
|
94
|
+
:getScreenOrientation,
|
95
|
+
:setScreenOrientation,
|
96
|
+
:click, -- does not sync
|
97
|
+
:doubleClick,
|
98
|
+
:mouseDown,
|
99
|
+
:mouseUp,
|
100
|
+
:mouseMoveTo,
|
101
|
+
:sendModifierKeyToActiveElement,
|
102
|
+
:sendKeysToActiveElement,
|
103
|
+
:executeSql,
|
104
|
+
:getLocation,
|
105
|
+
:setLocation, -- must sync (custom protractor method only, not the selenium setLocation)
|
106
|
+
:getAppCache,
|
107
|
+
:getAppCacheStatus,
|
108
|
+
:clearAppCache,
|
109
|
+
:isBrowserOnline,
|
110
|
+
:setBrowserOnline,
|
111
|
+
:getLocalStorageItem,
|
112
|
+
:removeLocalStorageItem,
|
113
|
+
:getLocalStorageKeys,
|
114
|
+
:setLocalStorageItem,
|
115
|
+
:clearLocalStorage,
|
116
|
+
:getLocalStorageSize,
|
117
|
+
:getSessionStorageItem,
|
118
|
+
:removeSessionStorageItem,
|
119
|
+
:getSessionStorageKeys,
|
120
|
+
:setSessionStorageItem,
|
121
|
+
:clearSessionStorage,
|
122
|
+
:getSessionStorageSize,
|
123
|
+
:imeGetAvailableEngines,
|
124
|
+
:imeGetActiveEngine,
|
125
|
+
:imeIsActivated,
|
126
|
+
:imeDeactivate,
|
127
|
+
:imeActivateEngine,
|
128
|
+
:touchSingleTap,
|
129
|
+
:touchDoubleTap,
|
130
|
+
:touchLongPress,
|
131
|
+
:touchDown,
|
132
|
+
:touchUp,
|
133
|
+
:touchMove,
|
134
|
+
:touchScroll,
|
135
|
+
:touchFlick,
|
136
|
+
:getAvailableLogTypes,
|
137
|
+
:getLog]
|
@@ -0,0 +1,121 @@
|
|
1
|
+
var status = element(by.binding('slowHttpStatus'));
|
2
|
+
|
3
|
+
expect(status.getText()).toEqual('not started');
|
4
|
+
expect(status.getText()).toEqual('not started');
|
5
|
+
expect(status.getText()).toEqual('not started');
|
6
|
+
|
7
|
+
|
8
|
+
In protractor, the element will be refound before getting the text.
|
9
|
+
in Ruby webdriver, the element will be referenced by id (instead of issuing a find command)
|
10
|
+
and the text will be retrieved directly.
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
---
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
11:43:37.983 INFO - Executing: [new session: Capabilities [{count=1, browserName=firefox, version=ANY}]])
|
22
|
+
11:43:37.984 INFO - Creating a new session for Capabilities [{count=1, browserName=firefox, version=ANY}]
|
23
|
+
11:43:42.013 INFO - Done: [new session: Capabilities [{count=1, browserName=firefox, version=ANY}]]
|
24
|
+
11:43:42.051 INFO - Executing: [set script timeoutt: 11000])
|
25
|
+
11:43:42.090 INFO - Done: [set script timeoutt: 11000]
|
26
|
+
11:43:42.241 INFO - Executing: [get: data:text/html,<html></html>])
|
27
|
+
11:43:42.330 INFO - Done: [get: data:text/html,<html></html>]
|
28
|
+
11:43:42.341 INFO - Executing: [execute script: window.name = "NG_DEFER_BOOTSTRAP!" + window.name;window.location.replace("http://localhost:8081/index.html#/async");, []])
|
29
|
+
11:43:42.424 INFO - Done: [execute script: window.name = "NG_DEFER_BOOTSTRAP!" + window.name;window.location.replace("http://localhost:8081/index.html#/async");, []]
|
30
|
+
11:43:42.464 INFO - Executing: [execute script: return window.location.href;, []])
|
31
|
+
11:43:42.562 INFO - Done: [execute script: return window.location.href;, []]
|
32
|
+
11:43:42.584 INFO - Executing: [execute async script: try { return (function (attempts, asyncCallback) {
|
33
|
+
var callback = function(args) {
|
34
|
+
setTimeout(function() {
|
35
|
+
asyncCallback(args);
|
36
|
+
}, 0);
|
37
|
+
};
|
38
|
+
var check = function(n) {
|
39
|
+
try {
|
40
|
+
if (window.angular && window.angular.resumeBootstrap) {
|
41
|
+
callback([true, null]);
|
42
|
+
} else if (n < 1) {
|
43
|
+
if (window.angular) {
|
44
|
+
callback([false, 'angular never provided resumeBootstrap']);
|
45
|
+
} else {
|
46
|
+
callback([false, 'retries looking for angular exceeded']);
|
47
|
+
}
|
48
|
+
} else {
|
49
|
+
window.setTimeout(function() {check(n - 1);}, 1000);
|
50
|
+
}
|
51
|
+
} catch (e) {
|
52
|
+
callback([false, e]);
|
53
|
+
}
|
54
|
+
};
|
55
|
+
check(attempts);
|
56
|
+
}).apply(this, arguments); }
|
57
|
+
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [10]])
|
58
|
+
11:43:42.621 INFO - Done: [execute async script: try { return (function (attempts, asyncCallback) {
|
59
|
+
var callback = function(args) {
|
60
|
+
setTimeout(function() {
|
61
|
+
asyncCallback(args);
|
62
|
+
}, 0);
|
63
|
+
};
|
64
|
+
var check = function(n) {
|
65
|
+
try {
|
66
|
+
if (window.angular && window.angular.resumeBootstrap) {
|
67
|
+
callback([true, null]);
|
68
|
+
} else if (n < 1) {
|
69
|
+
if (window.angular) {
|
70
|
+
callback([false, 'angular never provided resumeBootstrap']);
|
71
|
+
} else {
|
72
|
+
callback([false, 'retries looking for angular exceeded']);
|
73
|
+
}
|
74
|
+
} else {
|
75
|
+
window.setTimeout(function() {check(n - 1);}, 1000);
|
76
|
+
}
|
77
|
+
} catch (e) {
|
78
|
+
callback([false, e]);
|
79
|
+
}
|
80
|
+
};
|
81
|
+
check(attempts);
|
82
|
+
}).apply(this, arguments); }
|
83
|
+
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [10]]
|
84
|
+
11:43:42.632 INFO - Executing: [execute script: return (function () {
|
85
|
+
angular.module('protractorBaseModule_', []).
|
86
|
+
config(['$compileProvider', function($compileProvider) {
|
87
|
+
if ($compileProvider.debugInfoEnabled) {
|
88
|
+
$compileProvider.debugInfoEnabled(true);
|
89
|
+
}
|
90
|
+
}]);
|
91
|
+
}).apply(null, arguments);, []])
|
92
|
+
11:43:42.677 INFO - Done: [execute script: return (function () {
|
93
|
+
angular.module('protractorBaseModule_', []).
|
94
|
+
config(['$compileProvider', function($compileProvider) {
|
95
|
+
if ($compileProvider.debugInfoEnabled) {
|
96
|
+
$compileProvider.debugInfoEnabled(true);
|
97
|
+
}
|
98
|
+
}]);
|
99
|
+
}).apply(null, arguments);, []]
|
100
|
+
11:43:42.690 INFO - Executing: [execute script: angular.resumeBootstrap(arguments[0]);, [[protractorBaseModule_]]])
|
101
|
+
11:43:42.778 INFO - Done: [execute script: angular.resumeBootstrap(arguments[0]);, [[protractorBaseModule_]]]
|
102
|
+
11:43:42.840 INFO - Executing: [waitForAngular, [body]])
|
103
|
+
11:43:42.908 INFO - Done: [waitForAngular, [body]]
|
104
|
+
11:43:42.923 INFO - Executing: [findByBinding, [slowHttpStatus, false, null, body]])
|
105
|
+
11:43:43.019 INFO - Done: [findByBinding, [slowHttpStatus, false, null, body]]
|
106
|
+
11:43:43.032 INFO - Executing: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@8f818cf5 -> unknown locator]])
|
107
|
+
11:43:43.082 INFO - Done: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@8f818cf5 -> unknown locator]]
|
108
|
+
11:43:43.095 INFO - Executing: [waitForAngular, [body]])
|
109
|
+
11:43:43.144 INFO - Done: [waitForAngular, [body]]
|
110
|
+
11:43:43.164 INFO - Executing: [findByBinding, [slowHttpStatus, false, null, body]])
|
111
|
+
11:43:43.220 INFO - Done: [findByBinding, [slowHttpStatus, false, null, body]]
|
112
|
+
11:43:43.258 INFO - Executing: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@8f818cf5 -> unknown locator]])
|
113
|
+
11:43:43.356 INFO - Done: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@8f818cf5 -> unknown locator]]
|
114
|
+
11:43:43.373 INFO - Executing: [waitForAngular, [body]])
|
115
|
+
11:43:43.422 INFO - Done: [waitForAngular, [body]]
|
116
|
+
11:43:43.444 INFO - Executing: [findByBinding, [slowHttpStatus, false, null, body]])
|
117
|
+
11:43:43.497 INFO - Done: [findByBinding, [slowHttpStatus, false, null, body]]
|
118
|
+
11:43:43.511 INFO - Executing: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@8f818cf5 -> unknown locator]])
|
119
|
+
11:43:43.567 INFO - Done: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@8f818cf5 -> unknown locator]]
|
120
|
+
11:43:43.588 INFO - Executing: [delete session: 85df60d0-1d35-492b-a346-6c1b2cf8725d])
|
121
|
+
11:43:43.697 INFO - Done: [delete session: 85df60d0-1d35-492b-a346-6c1b2cf8725d]
|