capybara-ng 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d0fd3873f9fff7e7552e5a62b0a16a12cb8e960f
4
- data.tar.gz: 03011c29b2d399748ca090482395bb0fb47e4820
3
+ metadata.gz: 4751f5d1b3319c7ffdc1524119db8ae2af4ad77b
4
+ data.tar.gz: 8eb230d62a078b284fa5f04108f2fd26c229d754
5
5
  SHA512:
6
- metadata.gz: 42bc6bbfb546dd007a27308146e4bec2e914ae99cb47a167bbfbf3a8bd35c0ca61d0676a68af1d456129eb2e312d21790145ac03b5e8f8ddf43f81b99624c51f
7
- data.tar.gz: 2154e49664ff9d9a06c616b019383d0e14fff13755d95623f07aa69a6ff638180b57175b1963f6ec376e8c3e18fadb896fdef2c0bcd07da6979af8947606e103
6
+ metadata.gz: 7693856f13f3b8488998226acb849b265ae0e03b905ea8cde880a5fc3aa3424a7f430e6942304624b4c1c19e6ae200ba6152b066831e0c4c0652cb2d1f68912c
7
+ data.tar.gz: 7c2f25c8bb781d417e3b4011fa5356be4171253526394931609b203c1508cba3e4be18d933fb6e7d799a7cc54d3a1bb7d969761a1b134777474c34bee3b5c98e
data/README.md CHANGED
@@ -3,9 +3,17 @@
3
3
  Basic bindings for AngularJS to be used with Capybara. Implementation is based into
4
4
  logic copied from Protractor.
5
5
 
6
- NOTE: At this point of development, I would classify DSL API "unstable". This means that
6
+ *NOTE* At this point of development, I would classify DSL API "unstable". This means that
7
7
  DSL language may change in incompatible ways.
8
8
 
9
+ ## Supported drivers
10
+
11
+ Based into testing following drivers should work.
12
+
13
+ - chrome
14
+ - poltergeist
15
+ - webkit
16
+
9
17
  ## Related Projects
10
18
 
11
19
  - https://github.com/jnicklas/capybara
@@ -5,4 +5,9 @@ class Capybara::Session
5
5
  def ng_session_options
6
6
  @ng_session_options ||= {}
7
7
  end
8
+
9
+ def ng
10
+ opt = ng_session_options
11
+ opt[:ng] ||= ::Angular::Setup.new(self)
12
+ end
8
13
  end
@@ -40,10 +40,12 @@ FN
40
40
  function(binding, exactMatch, using, rootSelector) {
41
41
  rootSelector = rootSelector || 'body';
42
42
  using = using || document.querySelector(rootSelector);
43
+
43
44
  if (angular.getTestability) {
44
45
  return angular.getTestability(using).
45
46
  findBindings(using, binding, exactMatch);
46
47
  }
48
+
47
49
  var bindings = using.getElementsByClassName('ng-binding');
48
50
  var matches = [];
49
51
  for (var i = 0; i < bindings.length; ++i) {
@@ -67,6 +69,23 @@ function(binding, exactMatch, using, rootSelector) {
67
69
  };
68
70
  FN
69
71
 
72
+ # /**
73
+ # * Find a list of element Ids in the page by their angular binding.
74
+ # *
75
+ # * @param {string} binding The binding, e.g. {{cat.name}}.
76
+ # * @param {boolean} exactMatch Whether the binding needs to be matched exactly
77
+ # * @param {Element} using The scope of the search.
78
+ # * @param {string} rootSelector The selector to use for the root app element.
79
+ # *
80
+ # * @return {Array.<Element>} The elements containing the binding.
81
+ # */
82
+ FN_findBindingsIds = <<-FN
83
+ function(binding, exactMatch, using, rootSelector) {
84
+ var elements = findBindings(binding, exactMatch, using, rootSelector);
85
+ return createCapybaraNgMatches(elements);
86
+ };
87
+ FN
88
+
70
89
  # /**
71
90
  # * Find an array of elements matching a row within an ng-repeat.
72
91
  # * Always returns an array of only one element for plain old ng-repeat.
@@ -120,7 +139,27 @@ function(repeater, index, using, rootSelector) {
120
139
  }
121
140
  }
122
141
  return [rows[index]].concat(multiRows[index]);
123
- };
142
+ };
143
+ FN
144
+
145
+ # /**
146
+ # * Find an array of element ids matching a row within an ng-repeat.
147
+ # * Always returns an array of only one element for plain old ng-repeat.
148
+ # * Returns an array of all the elements in one segment for ng-repeat-start.
149
+ # *
150
+ # * @param {string} repeater The text of the repeater, e.g. 'cat in cats'.
151
+ # * @param {number} index The row index.
152
+ # * @param {Element} using The scope of the search.
153
+ # * @param {string} rootSelector The selector to use for the root app element.
154
+ # *
155
+ # * @return {Array.<Element>} The row of the repeater, or an array of elements
156
+ # * in the first row in the case of ng-repeat-start.
157
+ # */
158
+ FN_findRepeaterRowsIds = <<-FN
159
+ function(repeater, index, using, rootSelector) {
160
+ var elements = findRepeaterRows(repeater, index, using, rootSelector);
161
+ return createCapybaraNgMatches(elements);
162
+ };
124
163
  FN
125
164
 
126
165
  # /**
@@ -167,7 +206,23 @@ function(repeater, using, rootSelector) {
167
206
  }
168
207
  }
169
208
  return rows;
170
- };
209
+ };
210
+ FN
211
+
212
+ # /**
213
+ # * Find all rows ids of an ng-repeat.
214
+ # *
215
+ # * @param {string} repeater The text of the repeater, e.g. 'cat in cats'.
216
+ # * @param {Element} using The scope of the search.
217
+ # * @param {string} rootSelector The selector to use for the root app element.
218
+ # *
219
+ # * @return {Array.<Element>} All rows of the repeater.
220
+ # */
221
+ FN_findAllRepeaterRowsIds = <<-FN
222
+ function(repeater, using, rootSelector) {
223
+ var elements = findAllRepeaterRows(repeater, using, rootSelector);
224
+ return createCapybaraNgMatches(elements);
225
+ };
171
226
  FN
172
227
 
173
228
  # /**
@@ -270,6 +325,24 @@ function(repeater, index, binding, using, rootSelector) {
270
325
  };
271
326
  FN
272
327
 
328
+ # /**
329
+ # * Find an element ids within an ng-repeat by its row and column.
330
+ # *
331
+ # * @param {string} repeater The text of the repeater, e.g. 'cat in cats'.
332
+ # * @param {number} index The row index.
333
+ # * @param {string} binding The column binding, e.g. '{{cat.name}}'.
334
+ # * @param {Element} using The scope of the search.
335
+ # * @param {string} rootSelector The selector to use for the root app element.
336
+ # *
337
+ # * @return {Array.<Element>} The element in an array.
338
+ # */
339
+ FN_findRepeaterElementIds = <<-FN
340
+ function(repeater, index, binding, using, rootSelector) {
341
+ var elements = findRepeaterElement(repeater, index, binding, using, rootSelector);
342
+ return createCapybaraNgMatches(elements);
343
+ };
344
+ FN
345
+
273
346
  # /**
274
347
  # * Find the elements in a column of an ng-repeat.
275
348
  # *
@@ -367,6 +440,23 @@ function(repeater, binding, using, rootSelector) {
367
440
  };
368
441
  FN
369
442
 
443
+ # /**
444
+ # * Find the elements in a column of an ng-repeat.
445
+ # *
446
+ # * @param {string} repeater The text of the repeater, e.g. 'cat in cats'.
447
+ # * @param {string} binding The column binding, e.g. '{{cat.name}}'.
448
+ # * @param {Element} using The scope of the search.
449
+ # * @param {string} rootSelector The selector to use for the root app element.
450
+ # *
451
+ # * @return {Array.<Element>} The elements in the column.
452
+ # */
453
+ FN_findRepeaterColumnIds = <<-FN
454
+ function(repeater, binding, using, rootSelector) {
455
+ var elements = findRepeaterColumn(repeater, binding, using, rootSelector);
456
+ return createCapybaraNgMatches(elements);
457
+ };
458
+ FN
459
+
370
460
  # /**
371
461
  # * Find elements by model name.
372
462
  # *
@@ -385,6 +475,7 @@ function(model, using, rootSelector) {
385
475
  return angular.getTestability(using).
386
476
  findModels(using, model, true);
387
477
  }
478
+
388
479
  var prefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-', 'ng\\\\:'];
389
480
  for (var p = 0; p < prefixes.length; ++p) {
390
481
  var selector = '[' + prefixes[p] + 'model="' + model + '"]';
@@ -396,6 +487,22 @@ function(model, using, rootSelector) {
396
487
  };
397
488
  FN
398
489
 
490
+ # /**
491
+ # * Find element ids by model name.
492
+ # *
493
+ # * @param {string} model The model name.
494
+ # * @param {Element} using The scope of the search.
495
+ # * @param {string} rootSelector The selector to use for the root app element.
496
+ # *
497
+ # * @return {Array.<Element>} The matching elements.
498
+ # */
499
+ FN_findByModelIds = <<-FN
500
+ function(model, using, rootSelector) {
501
+ var elements = findByModel(model, using, rootSelector);
502
+ return createCapybaraNgMatches(elements);
503
+ };
504
+ FN
505
+
399
506
  # /**
400
507
  # * Find elements by options.
401
508
  # *
@@ -422,6 +529,23 @@ function(optionsDescriptor, using, rootSelector) {
422
529
  };
423
530
  FN
424
531
 
532
+ # /**
533
+ # * Find elements by options.
534
+ # *
535
+ # * @param {string} optionsDescriptor The descriptor for the option
536
+ # * (i.e. fruit for fruit in fruits).
537
+ # * @param {Element} using The scope of the search.
538
+ # * @param {string} rootSelector The selector to use for the root app element.
539
+ # *
540
+ # * @return {Array.<Element>} The matching elements.
541
+ # */
542
+ FN_findByOptionsIds = <<-FN
543
+ function(optionsDescriptor, using, rootSelector) {
544
+ var elements = findByOptions(optionsDescriptor, using, rootSelector);
545
+ return createCapybaraNgMatches(elements);
546
+ };
547
+ FN
548
+
425
549
  # /**
426
550
  # * Find buttons by textual content.
427
551
  # *
@@ -1,7 +1,7 @@
1
1
  module Angular
2
2
  module DSL
3
3
  def ng
4
- @ng ||= ::Angular::Setup.new(Capybara.current_session)
4
+ Capybara.current_session.ng
5
5
  end
6
6
 
7
7
  def ng_root_selector(root_selector = nil)
@@ -100,7 +100,7 @@ module DSL
100
100
  #
101
101
  def ng_bindings(binding, opt = {})
102
102
  opt[:root_selector] ||= ng_root_selector
103
- ng.get_nodes :findBindings, [binding, opt[:exact] == true], opt
103
+ ng.get_nodes_2 :findBindingsIds, [binding, opt[:exact] == true], opt
104
104
  end
105
105
 
106
106
  #
@@ -118,6 +118,18 @@ module DSL
118
118
  rescue NotFound
119
119
  false
120
120
  end
121
+ #
122
+ # Does model not exist
123
+ #
124
+ # @param opt
125
+ # - :using
126
+ # - :root_selector
127
+ # - :wait
128
+ # @return true | false
129
+ #
130
+ def has_no_ng_model?(model, opt = {})
131
+ !has_ng_model?(model, opt)
132
+ end
121
133
 
122
134
  #
123
135
  # Node for nth model match
@@ -146,7 +158,7 @@ module DSL
146
158
  #
147
159
  def ng_models(model, opt = {})
148
160
  opt[:root_selector] ||= ng_root_selector
149
- ng.get_nodes :findByModel, [model], opt
161
+ ng.get_nodes_2 :findByModelIds, [model], opt
150
162
  end
151
163
 
152
164
  #
@@ -158,7 +170,7 @@ module DSL
158
170
  # - :wait
159
171
  # @return true | false
160
172
  #
161
- def has_ng_option?(options, opt = {})
173
+ def has_ng_options?(options, opt = {})
162
174
  opt[:root_selector] ||= ng_root_selector
163
175
  ng_options(options, opt)
164
176
  true
@@ -166,6 +178,19 @@ module DSL
166
178
  false
167
179
  end
168
180
 
181
+ #
182
+ # Does option not exist
183
+ #
184
+ # @param opt
185
+ # - :using
186
+ # - :root_selector
187
+ # - :wait
188
+ # @return true | false
189
+ #
190
+ def has_no_ng_options?(options, opt = {})
191
+ !has_ng_options?(options, opt)
192
+ end
193
+
169
194
  #
170
195
  # Node for nth option
171
196
  #
@@ -193,7 +218,7 @@ module DSL
193
218
  #
194
219
  def ng_options(options, opt = {})
195
220
  opt[:root_selector] ||= ng_root_selector
196
- ng.get_nodes :findByOptions, [options], opt
221
+ ng.get_nodes_2(:findByOptionsIds, [options], opt)
197
222
  end
198
223
 
199
224
  #
@@ -206,13 +231,25 @@ module DSL
206
231
  # @return true | false
207
232
  #
208
233
  def has_ng_repeater_row?(repeater, opt = {})
209
- opt[:root_selector] ||= ng_root_selector
210
- ng.get_nodes(:findRepeaterRows, [repeater, 0], opt)
234
+ ng_repeater_row(repeater, opt)
211
235
  true
212
236
  rescue NotFound
213
237
  false
214
238
  end
215
239
 
240
+ #
241
+ # Does row not exist
242
+ #
243
+ # @param opt
244
+ # - :using
245
+ # - :root_selector
246
+ # - :wait
247
+ # @return true | false
248
+ #
249
+ def has_no_ng_repeater_row?(repeater, opt = {})
250
+ !has_ng_repeater_rows?(repeater, opt)
251
+ end
252
+
216
253
  #
217
254
  # Node for nth repeater row
218
255
  #
@@ -226,7 +263,7 @@ module DSL
226
263
  def ng_repeater_row(repeater, opt = {})
227
264
  opt[:root_selector] ||= ng_root_selector
228
265
  row = ng.row(opt)
229
- data = ng.get_nodes(:findRepeaterRows, [repeater, row], opt)
266
+ data = ng.get_nodes_2(:findRepeaterRowsIds, [repeater, row], opt)
230
267
  data.first
231
268
  end
232
269
 
@@ -241,7 +278,7 @@ module DSL
241
278
  #
242
279
  def ng_repeater_rows(repeater, opt = {})
243
280
  opt[:root_selector] ||= ng_root_selector
244
- ng.get_nodes :findAllRepeaterRows, [repeater], opt
281
+ ng.get_nodes_2 :findAllRepeaterRowsIds, [repeater], opt
245
282
  end
246
283
 
247
284
  #
@@ -271,7 +308,7 @@ module DSL
271
308
  #
272
309
  def ng_repeater_columns(repeater, binding, opt = {})
273
310
  opt[:root_selector] ||= ng_root_selector
274
- ng.get_nodes :findRepeaterColumn, [repeater, binding], opt
311
+ ng.get_nodes_2 :findRepeaterColumnIds, [repeater, binding], opt
275
312
  end
276
313
 
277
314
  #
@@ -297,7 +334,7 @@ module DSL
297
334
  #
298
335
  def ng_repeater_elements(repeater, index, binding, opt = {})
299
336
  opt[:root_selector] ||= ng_root_selector
300
- ng.get_nodes :findRepeaterElement, [repeater, index, binding], opt
337
+ ng.get_nodes_2 :findRepeaterElementIds, [repeater, index, binding], opt
301
338
  end
302
339
  end
303
340
  end
@@ -32,6 +32,37 @@ module Angular
32
32
  make_call(method, params, opt)
33
33
  end
34
34
 
35
+ #
36
+ # @param opt
37
+ # - :using
38
+ # - :root_selector
39
+ # - :wait
40
+ #
41
+ def get_nodes_2(method, params, opt = {})
42
+ opt = {
43
+ nodes: false,
44
+ using: nil,
45
+ root_selector: ::Angular.root_selector,
46
+ }.merge(opt)
47
+ ids = make_call(method, params, opt)
48
+ raise NotFound.new("#{method}: #{params} - #{opt.inspect}") if ids.nil? || ids.empty?
49
+ make_nodes(ids, opt)
50
+ end
51
+
52
+ def make_nodes(ids, opt)
53
+ result = []
54
+ ids.each do |id|
55
+ id = id.tr('"', '')
56
+ selector = "//*[@capybara-ng-match='#{id}']"
57
+ nodes = page.driver.find_xpath(selector)
58
+
59
+ raise NotFound.new("Failed to match found id to node") if nodes.empty?
60
+ result.concat(nodes)
61
+ end
62
+ page.evaluate_script("clearCapybaraNgMatches('#{opt[:root_selector]}')");
63
+ result
64
+ end
65
+
35
66
  #
36
67
  # @param opt
37
68
  # - :nodes
@@ -60,7 +91,6 @@ module Angular
60
91
 
61
92
  js = "#{method}(#{js_params.join(', ')});"
62
93
  logger.debug js
63
-
64
94
  js_result = page.evaluate_script(js);
65
95
  # logger.debug js_result
66
96
 
@@ -1,3 +1,3 @@
1
1
  module Angular
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -33,8 +33,42 @@ module Angular
33
33
 
34
34
  def setup_waiter
35
35
  script = <<-JS
36
- window.ngReady = false;
37
36
  (function() {
37
+ "use strict";
38
+
39
+ window.ngReady = false;
40
+
41
+ window.nextCapybaraId = function() {
42
+ window.capybaraId = window.capybaraId || 1;
43
+ return window.capybaraId++;
44
+ };
45
+
46
+ window.createCapybaraNgMatches = function(nodes) {
47
+ if (!nodes) {
48
+ return nodes;
49
+ }
50
+
51
+ var matches = [];
52
+ angular.forEach(nodes, function(node) {
53
+ if (node) {
54
+ var match = "cb_" + window.nextCapybaraId();
55
+ node.setAttribute('capybara-ng-match', match);
56
+ matches.push(match);
57
+ }
58
+ });
59
+ return matches;
60
+ };
61
+
62
+ window.clearCapybaraNgMatches = function(rootSelector) {
63
+ rootSelector = rootSelector || 'body';
64
+ var root = document.querySelector(rootSelector);
65
+
66
+ var nodes = root.querySelectorAll('[capybara-ng-match]');
67
+ angular.forEach(nodes, function(node) {
68
+ node.removeAttribute('capybara-ng-match');
69
+ });
70
+ };
71
+
38
72
  var app = angular.element(document.querySelector('[ng-app], [data-ng-app]'));
39
73
  var injector = app.injector();
40
74
  var callback = function() {
@@ -1,13 +1,23 @@
1
1
  cd spec/dummy
2
2
  export BUNDLE_GEMFILE=$PWD/Gemfile
3
3
 
4
- xvfb-run -a bundle exec cucumber
4
+ echo "cucumber - poltergeist"
5
+ xvfb-run -a export CAPYBARA_DRIVER=poltergeist && bundle exec cucumber
5
6
  EXIT_1=$?
6
7
 
7
- xvfb-run -a bundle exec rspec
8
+ echo "cucumber - webkit"
9
+ xvfb-run -a export CAPYBARA_DRIVER=webkit && bundle exec cucumber
8
10
  EXIT_2=$?
9
11
 
10
- if [[ $EXIT_1 != 0 || $EXIT_2 != 0 ]]; then
12
+ echo "rspec - poltergeist"
13
+ xvfb-run -a export CAPYBARA_DRIVER=poltergeist && bundle exec rspec
14
+ EXIT_3=$?
15
+
16
+ echo "rspec - webkit"
17
+ xvfb-run -a export CAPYBARA_DRIVER=webkit && bundle exec rspec
18
+ EXIT_4=$?
19
+
20
+ if [[ $EXIT_1 != 0 || $EXIT_2 != 0 || $EXIT_3 != 0 || $EXIT_4 != 0 ]]; then
11
21
  echo "Failed"
12
22
  exit 1
13
23
  fi
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-ng
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kari
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-18 00:00:00.000000000 Z
11
+ date: 2015-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler