cornucopia 0.1.55 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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