angular_webdriver 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,215 @@
1
+ =begin
2
+
3
+ executeAsyncScript_ & executeScript_ wrappers not required. The description
4
+ is visible only at the node.js level using a debugger,
5
+ it's not sent to the selenium server.
6
+
7
+ Server trace from executing browser.get('http://www.angularjs.org')
8
+
9
+ Protractor.prototype.get // protractor.js
10
+
11
+ clientSideScripts.testForAngular
12
+
13
+ pause angular bootstrap
14
+ Protractor.prototype.addBaseMockModules_
15
+ resume angular bootstrap
16
+
17
+ ---
18
+
19
+ 14:05:23.286 INFO - Executing: [get: data:text/html,<html></html>])
20
+ 14:05:23.369 INFO - Done: [get: data:text/html,<html></html>]
21
+ 14:05:23.391 INFO - Executing: [execute script: window.name = "NG_DEFER_BOOTSTRAP!" + window.name;window.location.replace("http://www.angularjs.org/");, []])
22
+ 14:05:23.439 INFO - Done: [execute script: window.name = "NG_DEFER_BOOTSTRAP!" + window.name;window.location.replace("http://www.angularjs.org/");, []]
23
+ 14:05:23.451 INFO - Executing: [execute script: return window.location.href;, []])
24
+ 14:05:25.223 INFO - Done: [execute script: return window.location.href;, []]
25
+ 14:05:25.234 INFO - Executing: [execute async script: try { return (function (attempts, asyncCallback) {
26
+ var callback = function(args) {
27
+ setTimeout(function() {
28
+ asyncCallback(args);
29
+ }, 0);
30
+ };
31
+ var check = function(n) {
32
+ try {
33
+ if (window.angular && window.angular.resumeBootstrap) {
34
+ callback([true, null]);
35
+ } else if (n < 1) {
36
+ if (window.angular) {
37
+ callback([false, 'angular never provided resumeBootstrap']);
38
+ } else {
39
+ callback([false, 'retries looking for angular exceeded']);
40
+ }
41
+ } else {
42
+ window.setTimeout(function() {check(n - 1);}, 1000);
43
+ }
44
+ } catch (e) {
45
+ callback([false, e]);
46
+ }
47
+ };
48
+ check(attempts);
49
+ }).apply(this, arguments); }
50
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [10]])
51
+ 14:05:25.298 INFO - Done: [execute async script: try { return (function (attempts, asyncCallback) {
52
+ var callback = function(args) {
53
+ setTimeout(function() {
54
+ asyncCallback(args);
55
+ }, 0);
56
+ };
57
+ var check = function(n) {
58
+ try {
59
+ if (window.angular && window.angular.resumeBootstrap) {
60
+ callback([true, null]);
61
+ } else if (n < 1) {
62
+ if (window.angular) {
63
+ callback([false, 'angular never provided resumeBootstrap']);
64
+ } else {
65
+ callback([false, 'retries looking for angular exceeded']);
66
+ }
67
+ } else {
68
+ window.setTimeout(function() {check(n - 1);}, 1000);
69
+ }
70
+ } catch (e) {
71
+ callback([false, e]);
72
+ }
73
+ };
74
+ check(attempts);
75
+ }).apply(this, arguments); }
76
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [10]]
77
+ 14:05:25.308 INFO - Executing: [execute script: return (function () {
78
+ angular.module('protractorBaseModule_', []).
79
+ config(['$compileProvider', function($compileProvider) {
80
+ if ($compileProvider.debugInfoEnabled) {
81
+ $compileProvider.debugInfoEnabled(true);
82
+ }
83
+ }]);
84
+ }).apply(null, arguments);, []])
85
+ 14:05:25.367 INFO - Done: [execute script: return (function () {
86
+ angular.module('protractorBaseModule_', []).
87
+ config(['$compileProvider', function($compileProvider) {
88
+ if ($compileProvider.debugInfoEnabled) {
89
+ $compileProvider.debugInfoEnabled(true);
90
+ }
91
+ }]);
92
+ }).apply(null, arguments);, []]
93
+ 14:05:25.375 INFO - Executing: [execute script: angular.resumeBootstrap(arguments[0]);, [[protractorBaseModule_]]])
94
+ 14:05:26.553 INFO - Done: [execute script: angular.resumeBootstrap(arguments[0]);, [[protractorBaseModule_]]]
95
+ =end
96
+
97
+
98
+ =begin
99
+
100
+ trace for list(by.binding(''))
101
+
102
+ * execute async script functions.waitForAngular with default rootSelector body
103
+ * execute script (not async) functions.findBindings
104
+
105
+ 14:20:14.396 INFO - Executing: [execute script: , []])
106
+ 14:20:14.396 INFO - Executing: [execute async script: try { return (function (rootSelector, callback) {
107
+ var el = document.querySelector(rootSelector);
108
+
109
+ try {
110
+ if (!window.angular) {
111
+ throw new Error('angular could not be found on the window');
112
+ }
113
+ if (angular.getTestability) {
114
+ angular.getTestability(el).whenStable(callback);
115
+ } else {
116
+ if (!angular.element(el).injector()) {
117
+ throw new Error('root element (' + rootSelector + ') has no injector.' +
118
+ ' this may mean it is not inside ng-app.');
119
+ }
120
+ angular.element(el).injector().get('$browser').
121
+ notifyWhenNoOutstandingRequests(callback);
122
+ }
123
+ } catch (err) {
124
+ callback(err.message);
125
+ }
126
+ }).apply(this, arguments); }
127
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]])
128
+ 14:20:14.482 INFO - Done: [execute script: , []]
129
+ 14:20:14.669 INFO - Done: [execute async script: try { return (function (rootSelector, callback) {
130
+ var el = document.querySelector(rootSelector);
131
+
132
+ try {
133
+ if (!window.angular) {
134
+ throw new Error('angular could not be found on the window');
135
+ }
136
+ if (angular.getTestability) {
137
+ angular.getTestability(el).whenStable(callback);
138
+ } else {
139
+ if (!angular.element(el).injector()) {
140
+ throw new Error('root element (' + rootSelector + ') has no injector.' +
141
+ ' this may mean it is not inside ng-app.');
142
+ }
143
+ angular.element(el).injector().get('$browser').
144
+ notifyWhenNoOutstandingRequests(callback);
145
+ }
146
+ } catch (err) {
147
+ callback(err.message);
148
+ }
149
+ }).apply(this, arguments); }
150
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]]
151
+ 14:20:14.697 INFO - Executing: [execute script: try { return (function (binding, exactMatch, using, rootSelector) {
152
+ var root = document.querySelector(rootSelector || 'body');
153
+ using = using || document;
154
+ if (angular.getTestability) {
155
+ return angular.getTestability(root).
156
+ findBindings(using, binding, exactMatch);
157
+ }
158
+ var bindings = using.getElementsByClassName('ng-binding');
159
+ var matches = [];
160
+ for (var i = 0; i < bindings.length; ++i) {
161
+ var dataBinding = angular.element(bindings[i]).data('$binding');
162
+ if (dataBinding) {
163
+ var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
164
+ if (exactMatch) {
165
+ var matcher = new RegExp('({|\\s|^|\\|)' + binding + '(}|\\s|$|\\|)');
166
+ if (matcher.test(bindingName)) {
167
+ matches.push(bindings[i]);
168
+ }
169
+ } else {
170
+ if (bindingName.indexOf(binding) != -1) {
171
+ matches.push(bindings[i]);
172
+ }
173
+ }
174
+
175
+ }
176
+ }
177
+ return matches; /* Return the whole array for webdriver.findElements. */
178
+ }).apply(this, arguments); }
179
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [, false, null, body]])
180
+ 14:20:14.850 INFO - Done: [execute script: try { return (function (binding, exactMatch, using, rootSelector) {
181
+ var root = document.querySelector(rootSelector || 'body');
182
+ using = using || document;
183
+ if (angular.getTestability) {
184
+ return angular.getTestability(root).
185
+ findBindings(using, binding, exactMatch);
186
+ }
187
+ var bindings = using.getElementsByClassName('ng-binding');
188
+ var matches = [];
189
+ for (var i = 0; i < bindings.length; ++i) {
190
+ var dataBinding = angular.element(bindings[i]).data('$binding');
191
+ if (dataBinding) {
192
+ var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;
193
+ if (exactMatch) {
194
+ var matcher = new RegExp('({|\\s|^|\\|)' + binding + '(}|\\s|$|\\|)');
195
+ if (matcher.test(bindingName)) {
196
+ matches.push(bindings[i]);
197
+ }
198
+ } else {
199
+ if (bindingName.indexOf(binding) != -1) {
200
+ matches.push(bindings[i]);
201
+ }
202
+ }
203
+
204
+ }
205
+ }
206
+ return matches; /* Return the whole array for webdriver.findElements. */
207
+ }).apply(this, arguments); }
208
+ catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [, false, null, body]]
209
+ 14:20:14.972 INFO - Executing: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@540378f1 -> unknown locator]])
210
+ 14:20:15.006 INFO - Done: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@540378f1 -> unknown locator]]
211
+ 14:20:15.019 INFO - Executing: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@540378f1 -> unknown locator]])
212
+ 14:20:15.078 INFO - Done: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@540378f1 -> unknown locator]]
213
+ 14:20:15.086 INFO - Executing: [get text: 1 [org.openqa.selenium.remote.RemoteWebElement@dee620f8 -> unknown locator]])
214
+ ...
215
+ =end
@@ -0,0 +1,124 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+ require 'ostruct'
4
+ require 'selenium-webdriver'
5
+ require 'selenium/webdriver/common/error'
6
+
7
+ class Protractor
8
+ # code/comments from protractor/lib/protractor.js
9
+ attr_accessor :root_element, :ignore_sync
10
+
11
+ attr_reader :client_side_scripts, :driver
12
+
13
+ # @param [Hash] opts the options to initialize with
14
+ # @option opts [String] :root_element the root element on which to find Angular
15
+ # @option opts [Boolean] :ignore_sync if true, Protractor won't auto sync the page
16
+ def initialize opts={}
17
+ @driver = opts[:driver]
18
+ raise 'Must supply Selenium::WebDriver' unless @driver
19
+
20
+ # The css selector for an element on which to find Angular. This is usually
21
+ # 'body' but if your ng-app is on a subsection of the page it may be
22
+ # a subelement.
23
+ #
24
+ # @return [String]
25
+ @root_element = opts.fetch :root_element, 'body'
26
+
27
+ # If true, Protractor will not attempt to synchronize with the page before
28
+ # performing actions. This can be harmful because Protractor will not wait
29
+ # until $timeouts and $http calls have been processed, which can cause
30
+ # tests to become flaky. This should be used only when necessary, such as
31
+ # when a page continuously polls an API using $timeout.
32
+ #
33
+ # @return [Boolean]
34
+ @ignore_sync = !!opts.fetch(:ignore_sync, false)
35
+
36
+ scripts_file = File.expand_path '../clientSideScripts.json', __FILE__
37
+ @client_side_scripts = OpenStruct.new JSON.parse File.read scripts_file
38
+ end
39
+
40
+ # Instruct webdriver to wait until Angular has finished rendering and has
41
+ # no outstanding $http or $timeout calls before continuing.
42
+ # Note that Protractor automatically applies this command before every
43
+ # WebDriver action.
44
+ #
45
+ # @param [String] opt_description An optional description to be added
46
+ # to webdriver logs.
47
+ # @return [WebDriver::Element, Integer, Float, Boolean, NilClass, String, Array]
48
+ def waitForAngular opt_description='' # Protractor.prototype.waitForAngular
49
+ return if ignore_sync
50
+
51
+ begin
52
+ # the client side script will return a string on error
53
+ # the string won't be raised as an error unless we explicitly do so here
54
+ error = executeAsyncScript_(client_side_scripts.waitForAngular,
55
+ "Protractor.waitForAngular() #{opt_description}",
56
+ root_element)
57
+ raise Selenium::WebDriver::Error::JavascriptError, error if error
58
+ rescue Exception => e
59
+ raise e.class, "Error while waiting for Protractor to sync with the page: #{e}"
60
+ end
61
+ end
62
+
63
+ def executeAsyncScript_ script, description, args
64
+ # ensure description is exactly one line that ends in a newline
65
+ description = description ? '// ' + description.split.join(' ') : ''
66
+ description = description.strip + "\n"
67
+
68
+ # add description as comment to script so it shows up in server logs
69
+ script = description + script
70
+
71
+ # puts "Evaluating:\n#{script}"
72
+
73
+ driver.execute_async_script script, args
74
+ end
75
+
76
+ =begin
77
+ /**
78
+ * Instruct webdriver to wait until Angular has finished rendering and has
79
+ * no outstanding $http or $timeout calls before continuing.
80
+ * Note that Protractor automatically applies this command before every
81
+ * WebDriver action.
82
+ *
83
+ * @param {string=} opt_description An optional description to be added
84
+ * to webdriver logs.
85
+ * @return {!webdriver.promise.Promise} A promise that will resolve to the
86
+ * scripts return value.
87
+ */
88
+ Protractor.prototype.waitForAngular = function(opt_description) {
89
+ var description = opt_description ? ' - ' + opt_description : '';
90
+ if (this.ignoreSynchronization) {
91
+ return webdriver.promise.fulfilled();
92
+ }
93
+ return this.executeAsyncScript_(
94
+ clientSideScripts.waitForAngular,
95
+ 'Protractor.waitForAngular()' + description,
96
+ this.rootEl).
97
+ then(function(browserErr) {
98
+ if (browserErr) {
99
+ throw 'Error while waiting for Protractor to ' +
100
+ 'sync with the page: ' + JSON.stringify(browserErr);
101
+ }
102
+ }).then(null, function(err) {
103
+ var timeout;
104
+ if (/asynchronous script timeout/.test(err.message)) {
105
+ // Timeout on Chrome
106
+ timeout = /-?[\d\.]*\ seconds/.exec(err.message);
107
+ } else if (/Timed out waiting for async script/.test(err.message)) {
108
+ // Timeout on Firefox
109
+ timeout = /-?[\d\.]*ms/.exec(err.message);
110
+ } else if (/Timed out waiting for an asynchronous script/.test(err.message)) {
111
+ // Timeout on Safari
112
+ timeout = /-?[\d\.]*\ ms/.exec(err.message);
113
+ }
114
+ if (timeout) {
115
+ throw 'Timed out waiting for Protractor to synchronize with ' +
116
+ 'the page after ' + timeout + '. Please see ' +
117
+ 'https://github.com/angular/protractor/blob/master/docs/faq.md';
118
+ } else {
119
+ throw err;
120
+ }
121
+ });
122
+ };
123
+ =end
124
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+ require 'ostruct'
4
+
5
+ client_side_scripts = OpenStruct.new JSON.parse File.read 'clientSideScripts.json'
6
+
7
+ puts client_side_scripts.waitForAngular
@@ -0,0 +1,11 @@
1
+ // run with: node scripts_to_json.js
2
+
3
+ var clientSideScripts = require('./clientsidescripts.js'),
4
+ fs = require('fs');
5
+
6
+ // Serialize client side scripts to JSON for reading into Ruby
7
+ var json = JSON.stringify(clientSideScripts, null, 2);
8
+
9
+ var fd = fs.openSync('clientSideScripts.json', 'w', '666');
10
+ fs.writeSync(fd, json);
11
+ fs.closeSync(fd);
@@ -0,0 +1,4 @@
1
+ module AngularWebdriver
2
+ VERSION = '0.0.2' unless defined? ::AngularWebdriver::VERSION
3
+ DATE = '2015-05-04' unless defined? ::AngularWebdriver::DATE
4
+ end
File without changes
data/readme.md ADDED
@@ -0,0 +1,39 @@
1
+ # angular_webdriver
2
+
3
+ Angular enhancements to the Ruby webdriver bindings based on [protractor](https://github.com/angular/protractor).
4
+
5
+ ## Testing
6
+
7
+ Tests run against protractor's [testapp](https://github.com/angular/protractor/blob/19b4bf21525a683c8cc3ba21018c194cac9b6426/testapp/index.html).
8
+
9
+ - `git clone git@github.com:angular/protractor.git`
10
+ - `cd testapp; npm install`
11
+ - `npm start` Test app will start on `http://localhost:8081/`
12
+
13
+ ## Protractor CLI
14
+
15
+ Notes about protractor / angular testing.
16
+
17
+ --
18
+
19
+ [Protractor's Element Explorer](https://github.com/angular/protractor/blob/master/docs/debugging.md)
20
+
21
+ - `webdriver-manager update` Install webdriver jar
22
+ - `protractor --elementExplorer` Start protractor repl
23
+ - `.exit` Exit REPL session
24
+
25
+ View server logs
26
+
27
+ - `java -jar selenium-server-standalone-2.45.0.jar` Startup selenium server
28
+ - `nvm use v0.10.30`
29
+ - `protractor --elementExplorer --seleniumAddress 127.0.0.1:4444 --browser firefox` Tell protractor to connect to it
30
+
31
+ Known Issues:
32
+
33
+ - [protractor element explorer requires node v0.10.30](https://github.com/angular/protractor/issues/1890)
34
+ - [node >0.10.30 is broken and 0.12 doesn't work at all](https://github.com/angular/protractor/issues/1970#issuecomment-89371944)
35
+
36
+ Use [nvm](https://github.com/creationix/nvm) to manage node versions
37
+
38
+ - `brew install nvm` now update `~/.bash_profile` as instructed
39
+ - `nvm install v0.10.30` Install proper version of node
@@ -0,0 +1,24 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe 'client side scripts' do
4
+
5
+ before {
6
+ @driver = Selenium::WebDriver.for :firefox
7
+ @protractor = Protractor.new driver: @driver
8
+ }
9
+
10
+ after {
11
+ @driver.quit
12
+ }
13
+
14
+ it 'waitForAngular should error on non-angular pages' do
15
+ error_class = Selenium::WebDriver::Error::JavascriptError
16
+ error_message = /angular could not be found on the window/
17
+ expect { @protractor.waitForAngular }.to raise_error(error_class, error_message)
18
+ end
19
+
20
+ it 'waitForAngular should succeed on angular pages' do
21
+ @driver.get 'http://localhost:8081/' # use protractor's testapp
22
+ @protractor.waitForAngular
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'selenium-webdriver'
4
+ require_relative '../lib/angular_webdriver/protractor/protractor'
5
+ require 'pry'
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: angular_webdriver
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - code@bootstraponline.com
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: selenium-webdriver
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.45.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.45.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: appium_thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.0'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 0.0.7
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '0.0'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 0.0.7
61
+ description: Angular webdriver.
62
+ email:
63
+ - code@bootstraponline.com
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - ".gitignore"
69
+ - Gemfile
70
+ - LICENSE
71
+ - Thorfile
72
+ - angular_webdriver.gemspec
73
+ - lib/angular_webdriver.rb
74
+ - lib/angular_webdriver/protractor/LICENSE.txt
75
+ - lib/angular_webdriver/protractor/clientSideScripts.json
76
+ - lib/angular_webdriver/protractor/clientsidescripts.js
77
+ - lib/angular_webdriver/protractor/get_url_trace.rb
78
+ - lib/angular_webdriver/protractor/protractor.rb
79
+ - lib/angular_webdriver/protractor/scripts.rb
80
+ - lib/angular_webdriver/protractor/scripts_to_json.js
81
+ - lib/angular_webdriver/version.rb
82
+ - readme.md
83
+ - spec/protractor_spec.rb
84
+ - spec/spec_helper.rb
85
+ homepage: https://github.com/bootstraponline/angular_webdriver
86
+ licenses:
87
+ - http://www.apache.org/licenses/LICENSE-2.0.txt
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 1.9.3
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.4.6
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Angular webdriver
109
+ test_files: []
110
+ has_rdoc: