capybara-ng 0.0.3
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 +7 -0
- data/.gitignore +22 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +85 -0
- data/Rakefile +2 -0
- data/capybara-ng.gemspec +25 -0
- data/lib/angular/client_script.rb +669 -0
- data/lib/angular/driver.rb +354 -0
- data/lib/angular/dsl.rb +143 -0
- data/lib/angular/element_helper.rb +896 -0
- data/lib/angular/locator.rb +347 -0
- data/lib/angular/setup.rb +79 -0
- data/lib/angular/version.rb +3 -0
- data/lib/angular/waiter.rb +58 -0
- data/lib/angular.rb +11 -0
- data/lib/capybara-ng.rb +1 -0
- data/test/Gemfile +3 -0
- data/test/test.rb +6 -0
- metadata +108 -0
@@ -0,0 +1,347 @@
|
|
1
|
+
module Angular
|
2
|
+
module Locator
|
3
|
+
def binding
|
4
|
+
<<-FN
|
5
|
+
/**
|
6
|
+
* Find an element by binding.
|
7
|
+
*
|
8
|
+
* @view
|
9
|
+
* <span>{{person.name}}</span>
|
10
|
+
* <span ng-bind="person.email"></span>
|
11
|
+
*
|
12
|
+
* @example
|
13
|
+
* var span1 = element(by.binding('person.name'));
|
14
|
+
* expect(span1.getText()).toBe('Foo');
|
15
|
+
*
|
16
|
+
* var span2 = element(by.binding('person.email'));
|
17
|
+
* expect(span2.getText()).toBe('foo@bar.com');
|
18
|
+
*
|
19
|
+
* @param {string} bindingDescriptor
|
20
|
+
* @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
|
21
|
+
*/
|
22
|
+
function(bindingDescriptor) {
|
23
|
+
return {
|
24
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
25
|
+
return driver.findElements(
|
26
|
+
webdriver.By.js(clientSideScripts.findBindings,
|
27
|
+
bindingDescriptor, false, using, rootSelector));
|
28
|
+
},
|
29
|
+
toString: function toString() {
|
30
|
+
return 'by.binding("' + bindingDescriptor + '")';
|
31
|
+
}
|
32
|
+
};
|
33
|
+
};
|
34
|
+
FN
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def exactBinding
|
39
|
+
<<-FN
|
40
|
+
/**
|
41
|
+
* Find an element by exact binding.
|
42
|
+
*
|
43
|
+
* @view
|
44
|
+
* <span>{{ person.name }}</span>
|
45
|
+
* <span ng-bind="person-email"></span>
|
46
|
+
* <span>{{person_phone|uppercase}}</span>
|
47
|
+
*
|
48
|
+
* @example
|
49
|
+
* expect(element(by.exactBinding('person.name')).isPresent()).toBe(true);
|
50
|
+
* expect(element(by.exactBinding('person-email')).isPresent()).toBe(true);
|
51
|
+
* expect(element(by.exactBinding('person')).isPresent()).toBe(false);
|
52
|
+
* expect(element(by.exactBinding('person_phone')).isPresent()).toBe(true);
|
53
|
+
* expect(element(by.exactBinding('person_phone|uppercase')).isPresent()).toBe(true);
|
54
|
+
* expect(element(by.exactBinding('phone')).isPresent()).toBe(false);
|
55
|
+
*
|
56
|
+
* @param {string} bindingDescriptor
|
57
|
+
* @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
|
58
|
+
*/
|
59
|
+
function(bindingDescriptor) {
|
60
|
+
return {
|
61
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
62
|
+
return driver.findElements(
|
63
|
+
webdriver.By.js(clientSideScripts.findBindings,
|
64
|
+
bindingDescriptor, true, using, rootSelector));
|
65
|
+
},
|
66
|
+
toString: function toString() {
|
67
|
+
return 'by.exactBinding("' + bindingDescriptor + '")';
|
68
|
+
}
|
69
|
+
};
|
70
|
+
};
|
71
|
+
FN
|
72
|
+
end
|
73
|
+
|
74
|
+
def model
|
75
|
+
<<-FN
|
76
|
+
/**
|
77
|
+
* Find an element by ng-model expression.
|
78
|
+
*
|
79
|
+
* @alias by.model(modelName)
|
80
|
+
* @view
|
81
|
+
* <input type="text" ng-model="person.name"/>
|
82
|
+
*
|
83
|
+
* @example
|
84
|
+
* var input = element(by.model('person.name'));
|
85
|
+
* input.sendKeys('123');
|
86
|
+
* expect(input.getAttribute('value')).toBe('Foo123');
|
87
|
+
*
|
88
|
+
* @param {string} model ng-model expression.
|
89
|
+
*/
|
90
|
+
function(model) {
|
91
|
+
return {
|
92
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
93
|
+
return driver.findElements(
|
94
|
+
webdriver.By.js(
|
95
|
+
clientSideScripts.findByModel, model, using, rootSelector));
|
96
|
+
},
|
97
|
+
toString: function toString() {
|
98
|
+
return 'by.model("' + model + '")';
|
99
|
+
}
|
100
|
+
};
|
101
|
+
};
|
102
|
+
FN
|
103
|
+
end
|
104
|
+
|
105
|
+
def buttonText
|
106
|
+
<<-FN
|
107
|
+
/**
|
108
|
+
* Find a button by text.
|
109
|
+
*
|
110
|
+
* @view
|
111
|
+
* <button>Save</button>
|
112
|
+
*
|
113
|
+
* @example
|
114
|
+
* element(by.buttonText('Save'));
|
115
|
+
*
|
116
|
+
* @param {string} searchText
|
117
|
+
* @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
|
118
|
+
*/
|
119
|
+
function(searchText) {
|
120
|
+
return {
|
121
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
122
|
+
return driver.findElements(
|
123
|
+
webdriver.By.js(clientSideScripts.findByButtonText,
|
124
|
+
searchText, using, rootSelector));
|
125
|
+
},
|
126
|
+
toString: function toString() {
|
127
|
+
return 'by.buttonText("' + searchText + '")';
|
128
|
+
}
|
129
|
+
};
|
130
|
+
};
|
131
|
+
FN
|
132
|
+
end
|
133
|
+
|
134
|
+
def partialButtonText
|
135
|
+
<<-FN
|
136
|
+
/**
|
137
|
+
* Find a button by partial text.
|
138
|
+
*
|
139
|
+
* @view
|
140
|
+
* <button>Save my file</button>
|
141
|
+
*
|
142
|
+
* @example
|
143
|
+
* element(by.partialButtonText('Save'));
|
144
|
+
*
|
145
|
+
* @param {string} searchText
|
146
|
+
* @return {{findElementsOverride: findElementsOverride, toString: Function|string}}
|
147
|
+
*/
|
148
|
+
function(searchText) {
|
149
|
+
return {
|
150
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
151
|
+
return driver.findElements(
|
152
|
+
webdriver.By.js(clientSideScripts.findByPartialButtonText,
|
153
|
+
searchText, using, rootSelector));
|
154
|
+
},
|
155
|
+
toString: function toString() {
|
156
|
+
return 'by.partialButtonText("' + searchText + '")';
|
157
|
+
}
|
158
|
+
};
|
159
|
+
};
|
160
|
+
FN
|
161
|
+
end
|
162
|
+
|
163
|
+
def repeater
|
164
|
+
<<-FN
|
165
|
+
/**
|
166
|
+
* Find elements inside an ng-repeat.
|
167
|
+
*
|
168
|
+
* @view
|
169
|
+
* <div ng-repeat="cat in pets">
|
170
|
+
* <span>{{cat.name}}</span>
|
171
|
+
* <span>{{cat.age}}</span>
|
172
|
+
* </div>
|
173
|
+
*
|
174
|
+
* <div class="book-img" ng-repeat-start="book in library">
|
175
|
+
* <span>{{$index}}</span>
|
176
|
+
* </div>
|
177
|
+
* <div class="book-info" ng-repeat-end>
|
178
|
+
* <h4>{{book.name}}</h4>
|
179
|
+
* <p>{{book.blurb}}</p>
|
180
|
+
* </div>
|
181
|
+
*
|
182
|
+
* @example
|
183
|
+
* // Returns the DIV for the second cat.
|
184
|
+
* var secondCat = element(by.repeater('cat in pets').row(1));
|
185
|
+
*
|
186
|
+
* // Returns the SPAN for the first cat's name.
|
187
|
+
* var firstCatName = element(by.repeater('cat in pets').
|
188
|
+
* row(0).column('{{cat.name}}'));
|
189
|
+
*
|
190
|
+
* // Returns a promise that resolves to an array of WebElements from a column
|
191
|
+
* var ages = element.all(
|
192
|
+
* by.repeater('cat in pets').column('{{cat.age}}'));
|
193
|
+
*
|
194
|
+
* // Returns a promise that resolves to an array of WebElements containing
|
195
|
+
* // all top level elements repeated by the repeater. For 2 pets rows resolves
|
196
|
+
* // to an array of 2 elements.
|
197
|
+
* var rows = element.all(by.repeater('cat in pets'));
|
198
|
+
*
|
199
|
+
* // Returns a promise that resolves to an array of WebElements containing all
|
200
|
+
* // the elements with a binding to the book's name.
|
201
|
+
* var divs = element.all(by.repeater('book in library').column('book.name'));
|
202
|
+
*
|
203
|
+
* // Returns a promise that resolves to an array of WebElements containing
|
204
|
+
* // the DIVs for the second book.
|
205
|
+
* var bookInfo = element.all(by.repeater('book in library').row(1));
|
206
|
+
*
|
207
|
+
* // Returns the H4 for the first book's name.
|
208
|
+
* var firstBookName = element(by.repeater('book in library').
|
209
|
+
* row(0).column('{{book.name}}'));
|
210
|
+
*
|
211
|
+
* // Returns a promise that resolves to an array of WebElements containing
|
212
|
+
* // all top level elements repeated by the repeater. For 2 books divs
|
213
|
+
* // resolves to an array of 4 elements.
|
214
|
+
* var divs = element.all(by.repeater('book in library'));
|
215
|
+
*/
|
216
|
+
function(repeatDescriptor) {
|
217
|
+
return {
|
218
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
219
|
+
return driver.findElements(
|
220
|
+
webdriver.By.js(clientSideScripts.findAllRepeaterRows,
|
221
|
+
repeatDescriptor, using, rootSelector));
|
222
|
+
},
|
223
|
+
toString: function toString() {
|
224
|
+
return 'by.repeater("' + repeatDescriptor + '")';
|
225
|
+
},
|
226
|
+
row: function(index) {
|
227
|
+
return {
|
228
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
229
|
+
return driver.findElements(
|
230
|
+
webdriver.By.js(clientSideScripts.findRepeaterRows,
|
231
|
+
repeatDescriptor, index, using, rootSelector));
|
232
|
+
},
|
233
|
+
toString: function toString() {
|
234
|
+
return 'by.repeater(' + repeatDescriptor + '").row("' + index + '")"';
|
235
|
+
},
|
236
|
+
column: function(binding) {
|
237
|
+
return {
|
238
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
239
|
+
return driver.findElements(
|
240
|
+
webdriver.By.js(clientSideScripts.findRepeaterElement,
|
241
|
+
repeatDescriptor, index, binding, using, rootSelector));
|
242
|
+
},
|
243
|
+
toString: function toString() {
|
244
|
+
return 'by.repeater("' + repeatDescriptor + '").row("' + index +
|
245
|
+
'").column("' + binding + '")';
|
246
|
+
}
|
247
|
+
};
|
248
|
+
}
|
249
|
+
};
|
250
|
+
},
|
251
|
+
column: function(binding) {
|
252
|
+
return {
|
253
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
254
|
+
return driver.findElements(
|
255
|
+
webdriver.By.js(clientSideScripts.findRepeaterColumn,
|
256
|
+
repeatDescriptor, binding, using, rootSelector));
|
257
|
+
},
|
258
|
+
toString: function toString() {
|
259
|
+
return 'by.repeater("' + repeatDescriptor + '").column("' +
|
260
|
+
binding + '")';
|
261
|
+
},
|
262
|
+
row: function(index) {
|
263
|
+
return {
|
264
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
265
|
+
return driver.findElements(
|
266
|
+
webdriver.By.js(clientSideScripts.findRepeaterElement,
|
267
|
+
repeatDescriptor, index, binding, using, rootSelector));
|
268
|
+
},
|
269
|
+
toString: function toString() {
|
270
|
+
return 'by.repeater("' + repeatDescriptor + '").column("' +
|
271
|
+
binding + '").row("' + index + '")';
|
272
|
+
}
|
273
|
+
};
|
274
|
+
}
|
275
|
+
};
|
276
|
+
}
|
277
|
+
};
|
278
|
+
};
|
279
|
+
FN
|
280
|
+
end
|
281
|
+
|
282
|
+
def cssContainingText
|
283
|
+
<<-FN
|
284
|
+
/**
|
285
|
+
* Find elements by CSS which contain a certain string.
|
286
|
+
*
|
287
|
+
* @view
|
288
|
+
* <ul>
|
289
|
+
* <li class="pet">Dog</li>
|
290
|
+
* <li class="pet">Cat</li>
|
291
|
+
* </ul>
|
292
|
+
*
|
293
|
+
* @example
|
294
|
+
* // Returns the DIV for the dog, but not cat.
|
295
|
+
* var dog = element(by.cssContainingText('.pet', 'Dog'));
|
296
|
+
*/
|
297
|
+
function(cssSelector, searchText) {
|
298
|
+
return {
|
299
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
300
|
+
return driver.findElements(
|
301
|
+
webdriver.By.js(clientSideScripts.findByCssContainingText,
|
302
|
+
cssSelector, searchText, using, rootSelector));
|
303
|
+
},
|
304
|
+
toString: function toString() {
|
305
|
+
return 'by.cssContainingText("' + cssSelector + '", "' + searchText + '")';
|
306
|
+
}
|
307
|
+
};
|
308
|
+
};
|
309
|
+
FN
|
310
|
+
end
|
311
|
+
|
312
|
+
def options
|
313
|
+
<<-FN
|
314
|
+
/**
|
315
|
+
* Find an element by ng-options expression.
|
316
|
+
*
|
317
|
+
* @alias by.options(optionsDescriptor)
|
318
|
+
* @view
|
319
|
+
* <select ng-model="color" ng-options="c for c in colors">
|
320
|
+
* <option value="0" selected="selected">red</option>
|
321
|
+
* <option value="1">green</option>
|
322
|
+
* </select>
|
323
|
+
*
|
324
|
+
* @example
|
325
|
+
* var allOptions = element.all(by.options('c for c in colors'));
|
326
|
+
* expect(allOptions.count()).toEqual(2);
|
327
|
+
* var firstOption = allOptions.first();
|
328
|
+
* expect(firstOption.getText()).toEqual('red');
|
329
|
+
*
|
330
|
+
* @param {string} optionsDescriptor ng-options expression.
|
331
|
+
*/
|
332
|
+
function(optionsDescriptor) {
|
333
|
+
return {
|
334
|
+
findElementsOverride: function(driver, using, rootSelector) {
|
335
|
+
return driver.findElements(
|
336
|
+
webdriver.By.js(clientSideScripts.findByOptions, optionsDescriptor,
|
337
|
+
using, rootSelector));
|
338
|
+
},
|
339
|
+
toString: function toString() {
|
340
|
+
return 'by.option("' + optionsDescriptor + '")';
|
341
|
+
}
|
342
|
+
};
|
343
|
+
};
|
344
|
+
FN
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Angular
|
2
|
+
class Setup
|
3
|
+
attr_reader :page
|
4
|
+
|
5
|
+
def initialize(page)
|
6
|
+
@page = page
|
7
|
+
end
|
8
|
+
|
9
|
+
def ng_wait
|
10
|
+
install
|
11
|
+
Waiter.new(self).wait_until_ready
|
12
|
+
end
|
13
|
+
|
14
|
+
def make_call(method, params, nodes)
|
15
|
+
ng_wait
|
16
|
+
|
17
|
+
js_params = params.map do |p|
|
18
|
+
if p.nil?
|
19
|
+
'null'
|
20
|
+
elsif p.is_a? String
|
21
|
+
escaped = p.gsub(/'/, "\\\\'").gsub(/"/, '\\\\"')
|
22
|
+
"'#{escaped}'"
|
23
|
+
else
|
24
|
+
p.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
js = "#{method}(#{js_params.join(', ')});"
|
29
|
+
logger.info js
|
30
|
+
|
31
|
+
js_result = page.evaluate_script(js);
|
32
|
+
logger.info js_result
|
33
|
+
|
34
|
+
if nodes
|
35
|
+
make_result method, params, js_result
|
36
|
+
else
|
37
|
+
js_result
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
def make_result(method, params, js_result)
|
43
|
+
if js_result.nil? || js_result.empty?
|
44
|
+
raise NotFound.new("#{method}: #{params.inspect}")
|
45
|
+
end
|
46
|
+
|
47
|
+
js_result.map do |el|
|
48
|
+
el ? Capybara::Selenium::Node.new(page.driver, el) : nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def angular_app?
|
53
|
+
begin
|
54
|
+
js = "(typeof angular !== 'undefined') && "
|
55
|
+
js += "angular.element(document.querySelector('[ng-app], [data-ng-app]')).length > 0"
|
56
|
+
@page.evaluate_script js
|
57
|
+
rescue Capybara::NotSupportedByDriverError
|
58
|
+
false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def page_reloaded?
|
63
|
+
@page.evaluate_script("window.ngInstalled === undefined")
|
64
|
+
end
|
65
|
+
|
66
|
+
def mark_installed
|
67
|
+
@page.evaluate_script("window.ngInstalled = true")
|
68
|
+
end
|
69
|
+
|
70
|
+
def install
|
71
|
+
if page_reloaded?
|
72
|
+
ClientScript.window_scripts.each do |f|
|
73
|
+
@page.evaluate_script(f)
|
74
|
+
end
|
75
|
+
mark_installed
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Angular
|
2
|
+
class Waiter
|
3
|
+
def initialize(setup)
|
4
|
+
@setup = setup
|
5
|
+
@page = @setup.page
|
6
|
+
end
|
7
|
+
|
8
|
+
def wait_until_ready
|
9
|
+
return unless @setup.angular_app?
|
10
|
+
|
11
|
+
setup_waiter
|
12
|
+
start = Time.now
|
13
|
+
until ready?
|
14
|
+
timeout! if timeout?(start)
|
15
|
+
setup_waiter if @setup.page_reloaded?
|
16
|
+
sleep(0.01)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def timeout?(start)
|
23
|
+
Time.now - start > Capybara.default_wait_time
|
24
|
+
end
|
25
|
+
|
26
|
+
def timeout!
|
27
|
+
raise TimeoutError.new("timeout while waiting for angular")
|
28
|
+
end
|
29
|
+
|
30
|
+
def ready?
|
31
|
+
@page.evaluate_script("window.ngReady")
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup_waiter
|
35
|
+
script = <<-JS
|
36
|
+
window.ngReady = false;
|
37
|
+
(function() {
|
38
|
+
var app = angular.element(document.querySelector('[ng-app], [data-ng-app]'));
|
39
|
+
var injector = app.injector();
|
40
|
+
var callback = function() {
|
41
|
+
window.ngReady = true;
|
42
|
+
};
|
43
|
+
|
44
|
+
try {
|
45
|
+
if (angular.getTestability) {
|
46
|
+
angular.getTestability(el).whenStable(callback);
|
47
|
+
} else {
|
48
|
+
injector.get('$browser').notifyWhenNoOutstandingRequests(callback);
|
49
|
+
}
|
50
|
+
} catch (e) {
|
51
|
+
callback(e);
|
52
|
+
}
|
53
|
+
})();
|
54
|
+
JS
|
55
|
+
@page.execute_script script
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/angular.rb
ADDED
data/lib/capybara-ng.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'angular'
|
data/test/Gemfile
ADDED
data/test/test.rb
ADDED
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capybara-ng
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- kari
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: awesome_print
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.2.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.2.0
|
55
|
+
description: AngularJS bindings for capybara.
|
56
|
+
email:
|
57
|
+
- mr.kari.ikonen@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".ruby-gemset"
|
64
|
+
- ".ruby-version"
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- capybara-ng.gemspec
|
70
|
+
- lib/angular.rb
|
71
|
+
- lib/angular/client_script.rb
|
72
|
+
- lib/angular/driver.rb
|
73
|
+
- lib/angular/dsl.rb
|
74
|
+
- lib/angular/element_helper.rb
|
75
|
+
- lib/angular/locator.rb
|
76
|
+
- lib/angular/setup.rb
|
77
|
+
- lib/angular/version.rb
|
78
|
+
- lib/angular/waiter.rb
|
79
|
+
- lib/capybara-ng.rb
|
80
|
+
- test/Gemfile
|
81
|
+
- test/test.rb
|
82
|
+
homepage: https://github.com/kikonen/capybara-ng
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.2.2
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: AngularJS for capybara.
|
106
|
+
test_files:
|
107
|
+
- test/Gemfile
|
108
|
+
- test/test.rb
|