angular_webdriver 0.0.2

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.
@@ -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: