cornucopia 0.1.55 → 0.2.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.
Files changed (37) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +0 -2
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -1
  5. data/Gemfile.lock +297 -0
  6. data/cornucopia.gemspec +13 -12
  7. data/lib/cornucopia/capybara/finder_diagnostics/find_action/found_element.rb +155 -0
  8. data/lib/cornucopia/capybara/finder_diagnostics/find_action.rb +417 -0
  9. data/lib/cornucopia/capybara/finder_diagnostics.rb +9 -551
  10. data/lib/cornucopia/capybara/finder_extensions.rb +34 -26
  11. data/lib/cornucopia/capybara/install_extensions.rb +6 -6
  12. data/lib/cornucopia/capybara/matcher_extensions.rb +110 -47
  13. data/lib/cornucopia/capybara/page_diagnostics/window_iterator.rb +42 -0
  14. data/lib/cornucopia/capybara/page_diagnostics.rb +1 -30
  15. data/lib/cornucopia/capybara/synchronizable.rb +1 -1
  16. data/lib/cornucopia/site_prism/class_extensions.rb +13 -0
  17. data/lib/cornucopia/site_prism/element_extensions.rb +7 -4
  18. data/lib/cornucopia/site_prism/install_extensions.rb +1 -1
  19. data/lib/cornucopia/site_prism/page_application.rb +3 -3
  20. data/lib/cornucopia/site_prism/section_extensions.rb +3 -11
  21. data/lib/cornucopia/util/report_builder.rb +1 -1
  22. data/lib/cornucopia/version.rb +1 -1
  23. data/spec/dummy/app/assets/config/manifest.js +2 -0
  24. data/spec/dummy/config/application.rb +1 -1
  25. data/spec/lib/capybara/finder_diagnostics_spec.rb +11 -13
  26. data/spec/lib/capybara/finder_extensions_spec.rb +19 -11
  27. data/spec/lib/capybara/matcher_extensions_spec.rb +13 -15
  28. data/spec/lib/capybara/page_diagnostics_spec.rb +1 -1
  29. data/spec/lib/site_prism/element_extensions_spec.rb +3 -3
  30. data/spec/lib/util/configured_report_spec.rb +4 -4
  31. data/spec/lib/util/log_capture_spec.rb +5 -5
  32. data/spec/lib/util/report_builder_spec.rb +3 -3
  33. data/spec/lib/util/report_table_spec.rb +5 -5
  34. data/spec/pages/cornucopia_report_pages/cornucopia_report_test_contents_page.rb +1 -1
  35. data/spec/sample_report.rb +6 -6
  36. data/spec/spec_helper.rb +5 -1
  37. metadata +37 -10
@@ -2,6 +2,8 @@
2
2
 
3
3
  require ::File.expand_path("../util/configuration", File.dirname(__FILE__))
4
4
  require ::File.expand_path("../util/report_builder", File.dirname(__FILE__))
5
+ require ::File.expand_path("finder_diagnostics/find_action", File.dirname(__FILE__))
6
+ require ::File.expand_path("finder_diagnostics/find_action/found_element", File.dirname(__FILE__))
5
7
 
6
8
  module Cornucopia
7
9
  module Capybara
@@ -24,12 +26,13 @@ module Cornucopia
24
26
  # select
25
27
  # etc.
26
28
  # args - the arguments that you would pass into the function normally.
29
+ # options - the options that you would pass into the function normally.
27
30
  #
28
31
  # Usage:
29
- # Instead of calling: <test_object>.<function> <args>
30
- # you would call: test_finder <test_object>, :<function>, <args>
31
- def self.test_finder(test_object, function_name, *args, &block)
32
- Cornucopia::Capybara::FinderDiagnostics::FindAction.new(test_object, {}, {}, function_name, *args, &block).run
32
+ # Instead of calling: <test_object>.<function> <args>, <options>
33
+ # you would call: test_finder <test_object>, :<function>, <args>, <options>
34
+ def self.test_finder(test_object, function_name, *args, **options, &block)
35
+ Cornucopia::Capybara::FinderDiagnostics::FindAction.new(test_object, {}, {}, function_name, *args, **options, &block).run
33
36
  end
34
37
 
35
38
  # This takes the same arguments as the #test_finder function, but
@@ -38,8 +41,8 @@ module Cornucopia
38
41
  # This is for the times when the finder finds something, but you
39
42
  # think that it may be wrong, or for whatever reason, you want
40
43
  # more information about it to be output.
41
- def self.diagnose_finder(test_object, function_name, *args, &block)
42
- find_action = Cornucopia::Capybara::FinderDiagnostics::FindAction.new(test_object, {}, {}, function_name, *args, &block)
44
+ def self.diagnose_finder(test_object, function_name, *args, **options, &block)
45
+ find_action = Cornucopia::Capybara::FinderDiagnostics::FindAction.new(test_object, {}, {}, function_name, *args, **options, &block)
43
46
 
44
47
  results = find_action.run
45
48
  results = results.to_a if function_name == :all
@@ -47,551 +50,6 @@ module Cornucopia
47
50
 
48
51
  results
49
52
  end
50
-
51
- # At the end of the day, almost everything in Capybara calls all to find the element that needs
52
- # to be worked on. The main difference is if it is synchronized or not.
53
- #
54
- # The FindAction class also uses all, but it is never synchronized, and its primary purpose
55
- # is really to output a bunch of diagnostic information to try to help you do a postmortem on
56
- # just what is happening.
57
- #
58
- # A lot of things could be happening, so a lot of information is output, not all of which is
59
- # relevant or even useful in every situation.
60
- #
61
- # The first thing output is the error (the problem)
62
- # Then what action was being tried is output (context)
63
- #
64
- # In case the problem was with finding the desired element, a list of all elements which
65
- # could be found using the passed in parameters is output.
66
- #
67
- # In case the problem was with context (inside a within block on purpose or accidentally)
68
- # a list of all other elements which could be found on the page using the passed in
69
- # parameters is output.
70
- #
71
- # In case the problem is something else, we output a screenshot and the page HTML.
72
- #
73
- # In case the problem has now solved itself, we try the action again. (This has a very low
74
- # probability of working as this basically devolves to just duplicating what Capybara is already doing,
75
- # but it seems like it is worth a shot at least...)
76
- #
77
- # In case the problem is a driver bug (specifically Selenium which has some known issues) and
78
- # is in fact why I even bother trying to do this, try performing the action via javascript.
79
- # NOTE: As noted in many blogs this type of workaround is not generally a good idea as it can
80
- # result in false-positives. However since Selenium is buggy, this is the
81
- # best solution I have other than going to capybara-webkit or poltergeist
82
- class FindAction
83
- @@diagnosed_finders = {}
84
-
85
- Cornucopia::Util::ReportBuilder.on_close do
86
- Cornucopia::Capybara::FinderDiagnostics::FindAction.clear_diagnosed_finders
87
- end
88
-
89
- # Clears the class variable @@diagnosed_finders between tests if called.
90
- # This is done so that finder analysis is called at least once per test.
91
- def self.clear_diagnosed_finders
92
- @@diagnosed_finders = {}
93
- end
94
-
95
- attr_accessor :return_value
96
- attr_accessor :support_options
97
-
98
- def initialize(test_object, report_options, support_options, function_name, *args, &block)
99
- @test_object = test_object
100
- @function_name = function_name
101
- @args = args
102
- @block = block
103
- @support_options = support_options
104
- @report_options = report_options || {}
105
-
106
- @report_options[:report] ||= Cornucopia::Util::ReportBuilder.current_report
107
- end
108
-
109
- def run
110
- begin
111
- simple_run
112
- rescue
113
- error = $!
114
- if perform_analysis(support_options[:__cornucopia_retry_with_found])
115
- # Cornucopia::Util::Configuration.alternate_retry)
116
- @return_value
117
- else
118
- raise error
119
- end
120
- end
121
- end
122
-
123
- def simple_run(cornucopia_args = {})
124
- simple_run_args = @args.clone
125
- simple_run_options = {}
126
-
127
- if simple_run_args.last.is_a? Hash
128
- simple_run_options = simple_run_args.pop
129
- end
130
-
131
- @test_object.send(@function_name, *simple_run_args, simple_run_options.merge(cornucopia_args))
132
- end
133
-
134
- # def can_dump_details?(attempt_retry, attempt_alternate_retry)
135
- def can_dump_details?(attempt_retry)
136
- can_dump = false
137
-
138
- if (Object.const_defined?("Capybara"))
139
- can_dump = !@@diagnosed_finders.keys.include?(dump_detail_args(attempt_retry))
140
- end
141
-
142
- can_dump
143
- end
144
-
145
- def capybara_session
146
- if Object.const_defined?("::Capybara") &&
147
- ::Capybara.send(:session_pool).present?
148
- my_page = ::Capybara.current_session
149
-
150
- my_page if (my_page && my_page.current_url.present? && my_page.current_url != "about:blank")
151
- end
152
- rescue StandardError
153
- nil
154
- end
155
-
156
- # def dump_detail_args(attempt_retry, attempt_alternate_retry)
157
- def dump_detail_args(attempt_retry)
158
- check_args = search_args.clone
159
- my_page = capybara_session
160
-
161
- check_args << options.clone
162
- check_args << !!attempt_retry
163
- # check_args << !!attempt_alternate_retry
164
-
165
- if (my_page && my_page.current_url.present? && my_page.current_url != "about:blank")
166
- check_args << Digest::SHA2.hexdigest(my_page.html)
167
- end
168
-
169
- check_args
170
- end
171
-
172
- # def perform_retry(attempt_retry, attempt_alternate_retry, report, report_table)
173
- def perform_retry(attempt_retry, report, report_table)
174
- retry_successful = false
175
-
176
- if attempt_retry && retry_action_with_found_element(report, report_table)
177
- retry_successful = true
178
- # else
179
- # if attempt_alternate_retry && alternate_action_with_found_element(report, report_table)
180
- # retry_successful = true
181
- # end
182
- end
183
-
184
- retry_successful
185
- end
186
-
187
- # def perform_analysis(attempt_retry, attempt_alternate_retry)
188
- def perform_analysis(attempt_retry)
189
- retry_successful = false
190
-
191
- time = Benchmark.measure do
192
- puts " Cornucopia::FinderDiagnostics::perform_analysis" if Cornucopia::Util::Configuration.benchmark
193
-
194
- if can_dump_details?(attempt_retry)
195
- generate_report "An error occurred while processing \"#{@function_name.to_s}\":",
196
- $! do |report, report_table|
197
- retry_successful = perform_retry(attempt_retry, report, report_table)
198
- end
199
-
200
- dump_args = dump_detail_args(attempt_retry)
201
- @@diagnosed_finders[dump_args] = { tried: true }
202
- else
203
- retry_successful = perform_retry(attempt_retry, nil, nil)
204
- end
205
- end
206
-
207
- puts " Cornucopia::FinderDiagnostics::perform_analysis time: #{time}" if Cornucopia::Util::Configuration.benchmark
208
-
209
- retry_successful
210
- end
211
-
212
- def generate_report(message, error = nil, &block)
213
- if @report_options[:report] && @report_options[:table]
214
- generate_report_in_table @report_options[:table], error, &block
215
- else
216
- @report_options[:report] ||= Cornucopia::Util::ReportBuilder.current_report
217
- @report_options[:table] = nil
218
-
219
- @report_options[:report].within_section(message) do |report|
220
- generate_report_in_table @report_options[:table], error, &block
221
- end
222
- end
223
- end
224
-
225
- def generate_report_in_table(table, error = nil, &block)
226
- @report_options[:table] = table
227
-
228
- init_search_args
229
- all_elements
230
- all_other_elements
231
- guessed_types
232
-
233
- configured_report = Cornucopia::Util::Configuration.report_configuration(:capybara_finder_diagnostics)
234
-
235
- configured_report.add_report_objects(finder: self, exception: error)
236
- configured_report.generate_report(@report_options[:report], report_table: @report_options[:table], &block)
237
- end
238
-
239
- def retry_action_with_found_element report, report_table
240
- return_result = false
241
- result = "Failed"
242
-
243
- case @function_name.to_s
244
- when "assert_selector"
245
- if found_element
246
- @return_value = true
247
- return_result = true
248
- result = "Found"
249
- end
250
-
251
- when "assert_no_selector"
252
- unless found_element
253
- @return_value = true
254
- return_result = true
255
- result = "Not Found"
256
- end
257
-
258
- when "find", "all"
259
- if found_element
260
- result = "Success"
261
-
262
- @return_value = found_element
263
-
264
- return_result = true
265
- end
266
- end
267
-
268
- report_table.write_stats "Retrying action:", result if report_table && return_result
269
-
270
- return_result
271
- end
272
-
273
- # def alternate_action_with_found_element report, report_table
274
- # return_result = false
275
- #
276
- # result = "Could not attempt to try the action through an alternate method."
277
- # if found_element &&
278
- # ::Capybara.current_session.respond_to?(:evaluate_script)
279
- # begin
280
- # native_id = get_attribute found_element, "id"
281
- # if (native_id)
282
- # case @function_name.to_s
283
- # when "click_link_or_button", "click_link", "click_button"
284
- # @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].click()")
285
- # when "fill_in"
286
- # @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].val(\"#{options[:with]}\")")
287
- # when "choose", "check"
288
- # @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].val(\"checked\", true)")
289
- # when "uncheck"
290
- # @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].val(\"checked\", false)")
291
- # when "select"
292
- # @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].val(\"selected\", true)")
293
- # when "unselect"
294
- # @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].val(\"selected\", false)")
295
- # else
296
- # result = "Could not decide what to do with #{@function_name}"
297
- # raise new Exception("unknown action")
298
- # end
299
- #
300
- # return_result = true
301
- # end
302
- # rescue
303
- # result ||= "Still couldn't do the action - #{$!.to_s}."
304
- # end
305
- # end
306
- #
307
- # report_table.write_stats "Trying alternate action:", result if report_table
308
- # return_result
309
- # end
310
-
311
- def found_element
312
- if @function_name.to_sym == :all
313
- all_elements.map(&:found_element)
314
- else
315
- if all_elements && all_elements.length == 1
316
- all_elements[0].try(:found_element)
317
- else
318
- nil
319
- end
320
- end
321
- end
322
-
323
- def all_elements
324
- unless @all_elements
325
- if options && options.has_key?(:from)
326
- from_within = nil
327
-
328
- @report_options[:report].within_table(report_table: @report_options[:table]) do |report_table|
329
- Cornucopia::Util::ReportTable.new(nested_table: report_table,
330
- nested_table_label: "Within block:") do |sub_report|
331
- sub_report_options = @report_options.clone
332
- sub_report_options[:table] = sub_report
333
- from_within = Cornucopia::Capybara::FinderDiagnostics::FindAction.
334
- new(@test_object,
335
- sub_report_options,
336
- {},
337
- :find,
338
- :select,
339
- options[:from])
340
-
341
- from_within.generate_report_in_table(sub_report, nil)
342
- end
343
- end
344
-
345
- from_element = from_within.found_element
346
- if search_args[0].is_a?(Symbol)
347
- search_args[0] = :option
348
- end
349
- options.delete(:from)
350
-
351
- unless from_element
352
- @all_elements = []
353
- return @all_elements
354
- end
355
- else
356
- from_element = @test_object
357
- end
358
-
359
- begin
360
- @all_elements = from_element.all(*search_args, visible: false, __cornucopia_no_analysis: true).to_a
361
- rescue
362
- @all_elements = []
363
- end
364
-
365
- if @all_elements
366
- @all_elements = @all_elements.map do |element|
367
- FoundElement.new(element)
368
- end.compact
369
- end
370
- end
371
-
372
- @all_elements
373
- end
374
-
375
- def all_other_elements
376
- unless @all_other_elements
377
- from_element = capybara_session
378
-
379
- return unless from_element
380
-
381
- begin
382
- @all_other_elements = from_element.all(*search_args, visible: false, __cornucopia_no_analysis: true).to_a
383
- rescue
384
- @all_other_elements = []
385
- end
386
-
387
- if @all_other_elements
388
- @all_other_elements = @all_other_elements.map do |element|
389
- FoundElement.new(element) unless all_elements.include?(element)
390
- end
391
-
392
- @all_other_elements = @all_other_elements - @all_elements
393
- @all_other_elements.compact!
394
- end
395
- end
396
-
397
- @all_other_elements
398
- end
399
-
400
- def search_args
401
- init_search_args
402
- @search_args
403
- end
404
-
405
- def options
406
- init_search_args
407
- @options
408
- end
409
-
410
- def init_search_args
411
- unless @search_args
412
- @search_args = @args.clone
413
- @options = {}
414
-
415
- if @search_args.last.is_a? Hash
416
- @options = @search_args.pop
417
- end
418
- if guessed_types.length > 0 && @search_args[0] != guessed_types[0]
419
- @search_args.insert(0, guessed_types[0])
420
- end
421
- if guessed_types.length <= 0 && @search_args[0] != ::Capybara.default_selector
422
- @search_args.insert(0, ::Capybara.default_selector)
423
- end
424
- end
425
- end
426
-
427
- # a list of guesses as to what kind of object is being searched for
428
- def guessed_types
429
- unless @guessed_types
430
- if search_args.length > 0
431
- if search_args[0].is_a?(Symbol)
432
- @guessed_types = [search_args[0]]
433
- else
434
- @guessed_types = [:id, :css, :xpath, :link_or_button, :fillable_field, :radio_button, :checkbox, :select, :option,
435
- :file_field, :table, :field, :fieldset, :content].select do |test_type|
436
- begin
437
- @test_object.all(test_type, *search_args, visible: false, __cornucopia_no_analysis: true).length > 0
438
- rescue
439
- # Normally bad form, but for this function, we just don't want this to throw errors.
440
- # We are only concerned with whatever actually succeeds.
441
- false
442
- end
443
- end
444
- end
445
- end
446
- end
447
-
448
- @guessed_types
449
- end
450
-
451
- private
452
-
453
- class FoundElement
454
- ELEMENT_ATTRIBUTES = [
455
- "text",
456
- "value",
457
- "visible?",
458
- "checked?",
459
- "selected?",
460
- "tag_name",
461
- "location",
462
- "id",
463
- "src",
464
- "name",
465
- "href",
466
- "style",
467
- "path",
468
- "outerHTML"
469
- ]
470
-
471
- NATIVE_ATTRIBUTES = [
472
- "size",
473
- "type"
474
- ]
475
-
476
- PREDEFINED_ATTRIBUTES = NATIVE_ATTRIBUTES + ELEMENT_ATTRIBUTES
477
-
478
- attr_reader :found_element
479
-
480
- def capybara_session
481
- if Object.const_defined?("::Capybara") &&
482
- ::Capybara.send(:session_pool).present?
483
- my_page = ::Capybara.current_session
484
-
485
- my_page if (my_page && my_page.current_url.present? && my_page.current_url != "about:blank")
486
- end
487
- rescue StandardError
488
- nil
489
- end
490
-
491
- def ==(comparison_object)
492
- comparison_object.equal?(self) ||
493
- (comparison_object.instance_of?(self.class) &&
494
- (comparison_object.found_element == found_element
495
- # ||
496
- # (comparison_object.instance_variable_get(:@elem_text) == @elem_text &&
497
- # comparison_object.instance_variable_get(:@elem_value) == @elem_value &&
498
- # comparison_object.instance_variable_get(:@elem_visible) == @elem_visible &&
499
- # comparison_object.instance_variable_get(:@elem_checked) == @elem_checked &&
500
- # comparison_object.instance_variable_get(:@elem_selected) == @elem_selected &&
501
- # comparison_object.instance_variable_get(:@elem_tag_name) == @elem_tag_name &&
502
- # comparison_object.instance_variable_get(:@elem_location) == @elem_location &&
503
- # comparison_object.instance_variable_get(:@elem_size) == @elem_size &&
504
- # comparison_object.instance_variable_get(:@elem_id) == @elem_id &&
505
- # comparison_object.instance_variable_get(:@elem_name) == @elem_name &&
506
- # comparison_object.instance_variable_get(:@elem_href) == @elem_href &&
507
- # comparison_object.instance_variable_get(:@elem_style) == @elem_style &&
508
- # comparison_object.instance_variable_get(:@elem_path) == @elem_path &&
509
- # comparison_object.instance_variable_get(:@elem_outerHTML) == @elem_outerHTML &&
510
- # comparison_object.instance_variable_get(:@native_class) == @native_class &&
511
- # comparison_object.instance_variable_get(:@native_value) == @native_value &&
512
- # comparison_object.instance_variable_get(:@native_type) == @native_type
513
- # )
514
- )
515
- ) ||
516
- comparison_object == found_element
517
- end
518
-
519
- def initialize(found_element)
520
- @found_element = found_element
521
- ELEMENT_ATTRIBUTES.each do |attrib|
522
- variable_name = attrib.to_s.gsub("?", "")
523
- instance_variable_set("@elem_#{variable_name.gsub(/[\-]/, "_")}", get_attribute(attrib))
524
- end
525
-
526
- NATIVE_ATTRIBUTES.each do |attrib|
527
- instance_variable_set("@native_#{attrib.gsub(/[\-]/, "_")}", get_native_attribute(attrib))
528
- end
529
-
530
- instance_variable_set("@native_class", @found_element[:class])
531
-
532
- session = capybara_session
533
- if session.driver.respond_to?(:browser) &&
534
- session.driver.browser.respond_to?(:execute_script) &&
535
- session.driver.browser.method(:execute_script).arity != 1
536
- begin
537
- # This is a "trick" that works with Selenium, but which might not work with other drivers...
538
- script = "var attrib_list = [];
539
- var attrs = arguments[0].attributes;
540
- for (var nIndex = 0; nIndex < attrs.length; nIndex += 1)
541
- {
542
- var a = attrs[nIndex];
543
- attrib_list.push(a.name);
544
- };
545
- return attrib_list;"
546
-
547
- attributes = session.driver.browser.execute_script(script, @found_element.native)
548
- attributes.each do |attritue|
549
- unless PREDEFINED_ATTRIBUTES.include?(attritue)
550
- instance_variable_set("@native_#{attritue.gsub(/[\-]/, "_")}", @found_element[attritue])
551
- end
552
- end
553
-
554
- @elem_outerHTML ||= session.driver.browser.execute_script("return arguments[0].outerHTML", @found_element.native)
555
- rescue ::Capybara::NotSupportedByDriverError
556
- end
557
- end
558
-
559
- # information from Selenium that may not be available depending on the form, the full outerHTML of the element
560
- if (session.respond_to?(:evaluate_script))
561
- unless (@elem_id.blank?)
562
- begin
563
- @elem_outerHTML ||= session.evaluate_script("document.getElementById('#{@elem_id}').outerHTML")
564
- rescue ::Capybara::NotSupportedByDriverError
565
- end
566
- end
567
- end
568
- end
569
-
570
- def get_attribute(attribute)
571
- if @found_element.respond_to?(attribute)
572
- begin
573
- @found_element.send(attribute)
574
- rescue ::Capybara::NotSupportedByDriverError
575
- rescue ArgumentError
576
- end
577
- elsif @found_element.respond_to?(:[]) && @found_element[attribute]
578
- @found_element[attribute]
579
- else
580
- get_native_attribute(attribute)
581
- end
582
- end
583
-
584
- def get_native_attribute(attribute)
585
- if @found_element.native.respond_to?(attribute)
586
- @found_element.native.send(attribute)
587
- elsif @found_element.native.respond_to?(:[])
588
- @found_element.native[attribute]
589
- else
590
- nil
591
- end
592
- end
593
- end
594
- end
595
53
  end
596
54
  end
597
55
  end
@@ -10,34 +10,41 @@ module Cornucopia
10
10
  module FinderExtensions
11
11
  extend ActiveSupport::Concern
12
12
 
13
- included do
14
- alias_method :__cornucopia_capybara_orig_find, :find
15
- alias_method :__cornucopia_capybara_orig_all, :all
13
+ def find(*args, **options, &block)
14
+ retry_count = 0
15
+ result = nil
16
16
 
17
- define_method :find do |*args, &block|
18
- __cornucopia_finder_function(:find, *args, &block)
19
- end
17
+ support_options, normal_options = __cornucopia__extract_support_options(**options)
18
+
19
+ begin
20
+ retry_count += 1
21
+ result = super(*args, **normal_options, &block) if __cornucopia__call_super?(:find, *args, **normal_options, &block)
22
+ rescue Selenium::WebDriver::Error::StaleElementReferenceError
23
+ retry if __cornucopia__retry_finder?(retry_count, support_options)
20
24
 
21
- define_method :all do |*args, &block|
22
- __cornucopia_finder_function(:all, *args, &block)
25
+ result = __cornucopia__analyze_finder(:find, support_options, *args, **normal_options, &block)
26
+ rescue StandardError
27
+ result = __cornucopia__analyze_finder(:find, support_options, *args, **normal_options, &block)
23
28
  end
29
+
30
+ result
24
31
  end
25
32
 
26
- def __cornucopia_finder_function(finder_function, *args, &block)
33
+ def all(*args, **options, &block)
27
34
  retry_count = 0
28
35
  result = nil
29
36
 
30
- support_options = __cornucopia__extract_support_options(*args, &block)
37
+ support_options, normal_options = __cornucopia__extract_support_options(**options)
31
38
 
32
39
  begin
33
40
  retry_count += 1
34
- result = send("__cornucopia_capybara_orig_#{finder_function}", *args, &block)
41
+ result = super(*args, **normal_options, &block) if __cornucopia__call_super?(:all, *args, **normal_options, &block)
35
42
  rescue Selenium::WebDriver::Error::StaleElementReferenceError
36
- retry if __cornucopia__retry_finder(retry_count, support_options)
43
+ retry if __cornucopia__retry_finder?(retry_count, support_options)
37
44
 
38
- result = __cornucopia__analyze_finder(finder_function, support_options, *args, &block)
45
+ result = __cornucopia__analyze_finder(:all, support_options, *args, **normal_options, &block)
39
46
  rescue StandardError
40
- result = __cornucopia__analyze_finder(finder_function, support_options, *args, &block)
47
+ result = __cornucopia__analyze_finder(:all, support_options, *args, **normal_options, &block)
41
48
  end
42
49
 
43
50
  result
@@ -45,19 +52,14 @@ module Cornucopia
45
52
 
46
53
  private
47
54
 
48
- def __cornucopia__extract_support_options(*args, &block)
49
- support_options = {}
55
+ def __cornucopia__extract_support_options(**options)
56
+ support_options = options.slice(:__cornucopia_no_analysis, :__cornucopia_retry_with_found)
57
+ normal_options = options.slice(*(options.keys - %i[__cornucopia_no_analysis __cornucopia_retry_with_found]))
50
58
 
51
- if args[-1].is_a?(Hash)
52
- support_options[:__cornucopia_no_analysis] = args[-1].delete(:__cornucopia_no_analysis)
53
- support_options[:__cornucopia_retry_with_found] = args[-1].delete(:__cornucopia_retry_with_found)
54
- # support_options[:__cornucopia_alternate_retry] = args[-1].delete(:__cornucopia_alternate_retry)
55
- end
56
-
57
- support_options
59
+ [support_options, normal_options]
58
60
  end
59
61
 
60
- def __cornucopia__analyze_finder(function_name, support_options, *args, &block)
62
+ def __cornucopia__analyze_finder(function_name, support_options, *args, **options, &block)
61
63
  return_value = nil
62
64
  error = $!
63
65
 
@@ -71,7 +73,9 @@ module Cornucopia
71
73
  {},
72
74
  support_options,
73
75
  function_name,
74
- *args, &block)
76
+ *args,
77
+ **options,
78
+ &block)
75
79
 
76
80
  if find_action.perform_analysis(Cornucopia::Util::Configuration.retry_with_found ||
77
81
  support_options[:__cornucopia_retry_with_found])
@@ -89,10 +93,14 @@ module Cornucopia
89
93
  return_value
90
94
  end
91
95
 
92
- def __cornucopia__retry_finder(retry_count, support_options)
96
+ def __cornucopia__retry_finder?(retry_count, support_options)
93
97
  retry_count <= Cornucopia::Util::Configuration.selenium_cache_retry_count &&
94
98
  !support_options[:__cornucopia_no_analysis]
95
99
  end
100
+
101
+ def __cornucopia__call_super?(_function_name, *_args, **_normal_options, &_block)
102
+ true
103
+ end
96
104
  end
97
105
  end
98
106
  end