cornucopia 0.1.12
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 +51 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +16 -0
- data/LICENSE.TXT +22 -0
- data/README.md +341 -0
- data/Rakefile +18 -0
- data/cornucopia.gemspec +39 -0
- data/lib/cornucopia.rb +18 -0
- data/lib/cornucopia/capybara/finder_diagnostics.rb +536 -0
- data/lib/cornucopia/capybara/finder_extensions.rb +89 -0
- data/lib/cornucopia/capybara/install_finder_extensions.rb +105 -0
- data/lib/cornucopia/capybara/install_matcher_extensions.rb +39 -0
- data/lib/cornucopia/capybara/matcher_extensions.rb +83 -0
- data/lib/cornucopia/capybara/page_diagnostics.rb +228 -0
- data/lib/cornucopia/cucumber_hooks.rb +38 -0
- data/lib/cornucopia/factory_girl/dynamic_association.rb +14 -0
- data/lib/cornucopia/rspec_hooks.rb +37 -0
- data/lib/cornucopia/site_prism/element_extensions.rb +273 -0
- data/lib/cornucopia/site_prism/install_element_extensions.rb +23 -0
- data/lib/cornucopia/site_prism/page_application.rb +126 -0
- data/lib/cornucopia/source_files/collapse.gif +0 -0
- data/lib/cornucopia/source_files/cornucopia.css +162 -0
- data/lib/cornucopia/source_files/expand.gif +0 -0
- data/lib/cornucopia/source_files/index_base.html +10 -0
- data/lib/cornucopia/source_files/index_contents.html +2 -0
- data/lib/cornucopia/source_files/more_info.js +87 -0
- data/lib/cornucopia/source_files/report_base.html +10 -0
- data/lib/cornucopia/source_files/report_contents.html +3 -0
- data/lib/cornucopia/spinach_hooks.rb +51 -0
- data/lib/cornucopia/util/configuration.rb +493 -0
- data/lib/cornucopia/util/configured_report.rb +520 -0
- data/lib/cornucopia/util/file_asset.rb +46 -0
- data/lib/cornucopia/util/generic_settings.rb +37 -0
- data/lib/cornucopia/util/log_capture.rb +97 -0
- data/lib/cornucopia/util/pretty_formatter.rb +580 -0
- data/lib/cornucopia/util/report_builder.rb +474 -0
- data/lib/cornucopia/util/report_formatters.rb +11 -0
- data/lib/cornucopia/util/report_table.rb +195 -0
- data/lib/cornucopia/version.rb +3 -0
- data/lib/tasks/cornucopia_tasks.rake +4 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +27 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cucumber.yml +8 -0
- data/spec/dummy/config/database.yml +37 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/db/schema.rb +16 -0
- data/spec/dummy/features/support/env.rb +66 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/lib/tasks/cucumber.rake +65 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/cucumber +10 -0
- data/spec/fixtures/sample_page.html +150 -0
- data/spec/lib/capybara/finder_diagnostics_spec.rb +517 -0
- data/spec/lib/capybara/finder_extensions_spec.rb +328 -0
- data/spec/lib/capybara/page_diagnostics_spec.rb +277 -0
- data/spec/lib/site_prism/element_extensions_spec.rb +290 -0
- data/spec/lib/site_prism/page_application_spec.rb +81 -0
- data/spec/lib/util/configuration_spec.rb +254 -0
- data/spec/lib/util/configured_report_spec.rb +1058 -0
- data/spec/lib/util/file_asset_spec.rb +86 -0
- data/spec/lib/util/generic_settings_spec.rb +48 -0
- data/spec/lib/util/log_capture_spec.rb +151 -0
- data/spec/lib/util/pretty_formatter_spec.rb +694 -0
- data/spec/lib/util/report_builder_spec.rb +983 -0
- data/spec/lib/util/report_formatters_spec.rb +13 -0
- data/spec/lib/util/report_table_exception_spec.rb +21 -0
- data/spec/lib/util/report_table_spec.rb +319 -0
- data/spec/pages/cornucopia_report_app.rb +10 -0
- data/spec/pages/google/email_page.rb +22 -0
- data/spec/pages/google/login_page.rb +25 -0
- data/spec/rails_helper.rb +43 -0
- data/spec/sample_report.rb +45 -0
- data/spec/spec_helper.rb +81 -0
- metadata +410 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
rescue LoadError
|
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require 'rdoc/task'
|
|
9
|
+
|
|
10
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
11
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
12
|
+
rdoc.title = 'Cornucopia'
|
|
13
|
+
rdoc.options << '--line-numbers'
|
|
14
|
+
rdoc.rdoc_files.include('README.rdoc')
|
|
15
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
Bundler::GemHelper.install_tasks
|
data/cornucopia.gemspec
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
|
|
5
|
+
# Maintain your gem's version:
|
|
6
|
+
require "cornucopia/version"
|
|
7
|
+
|
|
8
|
+
# Describe your gem and declare its dependencies:
|
|
9
|
+
Gem::Specification.new do |spec|
|
|
10
|
+
spec.name = "cornucopia"
|
|
11
|
+
spec.version = Cornucopia::VERSION
|
|
12
|
+
spec.authors = ["RealNobody"]
|
|
13
|
+
spec.email = ["RealNobody1@cox.net"]
|
|
14
|
+
spec.summary = "A collection of tools to simplify testing tasks."
|
|
15
|
+
spec.description = "A collection of tools I created to simplify and make it easier to see what is happening."
|
|
16
|
+
spec.homepage = "https://github.com/RealNobody/cornucopia"
|
|
17
|
+
spec.license = "MIT"
|
|
18
|
+
|
|
19
|
+
# spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"]
|
|
20
|
+
spec.files = `git ls-files`.split($/)
|
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
23
|
+
spec.require_paths = ["lib"]
|
|
24
|
+
|
|
25
|
+
spec.add_development_dependency "rails"
|
|
26
|
+
spec.add_development_dependency "mysql2"
|
|
27
|
+
spec.add_development_dependency "bundler"
|
|
28
|
+
spec.add_development_dependency "rake"
|
|
29
|
+
spec.add_development_dependency "rspec-rails"
|
|
30
|
+
spec.add_development_dependency "capybara"
|
|
31
|
+
spec.add_development_dependency "cucumber"
|
|
32
|
+
spec.add_development_dependency "cucumber-rails"
|
|
33
|
+
spec.add_development_dependency "faker"
|
|
34
|
+
spec.add_development_dependency "site_prism"
|
|
35
|
+
spec.add_development_dependency "selenium-webdriver"
|
|
36
|
+
spec.add_development_dependency "simplecov"
|
|
37
|
+
spec.add_development_dependency "launchy"
|
|
38
|
+
spec.add_development_dependency "rack"
|
|
39
|
+
end
|
data/lib/cornucopia.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require "cornucopia/version"
|
|
2
|
+
require "cornucopia/util/configuration"
|
|
3
|
+
require "cornucopia/util/configured_report"
|
|
4
|
+
require "cornucopia/util/generic_settings"
|
|
5
|
+
require "cornucopia/util/file_asset"
|
|
6
|
+
require "cornucopia/util/log_capture"
|
|
7
|
+
require "cornucopia/util/pretty_formatter"
|
|
8
|
+
require "cornucopia/util/report_table"
|
|
9
|
+
require "cornucopia/util/report_builder"
|
|
10
|
+
require "cornucopia/capybara/finder_diagnostics"
|
|
11
|
+
require "cornucopia/capybara/page_diagnostics"
|
|
12
|
+
require "cornucopia/capybara/finder_extensions"
|
|
13
|
+
require "cornucopia/capybara/matcher_extensions"
|
|
14
|
+
require "cornucopia/site_prism/element_extensions"
|
|
15
|
+
require "cornucopia/site_prism/page_application"
|
|
16
|
+
|
|
17
|
+
module Cornucopia
|
|
18
|
+
end
|
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
require ::File.expand_path("../util/configuration", File.dirname(__FILE__))
|
|
2
|
+
require ::File.expand_path("../util/report_builder", File.dirname(__FILE__))
|
|
3
|
+
|
|
4
|
+
module Cornucopia
|
|
5
|
+
module Capybara
|
|
6
|
+
class FinderDiagnostics
|
|
7
|
+
# This function calls a "finder" function with the passed in arguments on the passed in object.
|
|
8
|
+
# If the function succeeds, it doesn't do anything else.
|
|
9
|
+
# If the function fails, it tries to figure out why, and provide diagnostic
|
|
10
|
+
# information for further analysis.
|
|
11
|
+
#
|
|
12
|
+
# Parameters:
|
|
13
|
+
# test_object - the object to call the finder function on. Examples could be:
|
|
14
|
+
# self
|
|
15
|
+
# page
|
|
16
|
+
# test_finder(:find, ...)
|
|
17
|
+
# function_name - this is the "finder" function to be called. Examples could be:
|
|
18
|
+
# all
|
|
19
|
+
# find
|
|
20
|
+
# fill_in
|
|
21
|
+
# click_link
|
|
22
|
+
# select
|
|
23
|
+
# etc.
|
|
24
|
+
# args - the arguments that you would pass into the function normally.
|
|
25
|
+
#
|
|
26
|
+
# Usage:
|
|
27
|
+
# Instead of calling: <test_object>.<function> <args>
|
|
28
|
+
# you would call: test_finder <test_object>, :<function>, <args>
|
|
29
|
+
def self.test_finder(test_object, function_name, *args)
|
|
30
|
+
Cornucopia::Capybara::FinderDiagnostics::FindAction.new(test_object, {}, {}, function_name, *args).run
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# This takes the same arguments as the #test_finder function, but
|
|
34
|
+
# it will always output a diagnostic report.
|
|
35
|
+
#
|
|
36
|
+
# This is for the times when the finder finds something, but you
|
|
37
|
+
# think that it may be wrong, or for whatever reason, you want
|
|
38
|
+
# more information about it to be output.
|
|
39
|
+
def self.diagnose_finder(test_object, function_name, *args)
|
|
40
|
+
find_action = Cornucopia::Capybara::FinderDiagnostics::FindAction.new(test_object, {}, {}, function_name, *args)
|
|
41
|
+
|
|
42
|
+
results = find_action.run
|
|
43
|
+
find_action.generate_report "Diagnostic report on \"#{function_name.to_s}\":", nil
|
|
44
|
+
|
|
45
|
+
results
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# At the end of the day, almost everything in Capybara calls all to find the element that needs
|
|
49
|
+
# to be worked on. The main difference is if it is synchronized or not.
|
|
50
|
+
#
|
|
51
|
+
# The FindAction class also uses all, but it is never synchronized, and its primary purpose
|
|
52
|
+
# is really to output a bunch of diagnostic information to try to help you do a postmortem on
|
|
53
|
+
# just what is happening.
|
|
54
|
+
#
|
|
55
|
+
# A lot of things could be happening, so a lot of information is output, not all of which is
|
|
56
|
+
# relevant or even useful in every situation.
|
|
57
|
+
#
|
|
58
|
+
# The first thing output is the error (the problem)
|
|
59
|
+
# Then what action was being tried is output (context)
|
|
60
|
+
#
|
|
61
|
+
# In case the problem was with finding the desired element, a list of all elements which
|
|
62
|
+
# could be found using the passed in parameters is output.
|
|
63
|
+
#
|
|
64
|
+
# In case the problem was with context (inside a within block on purpose or accidentally)
|
|
65
|
+
# a list of all other elements which could be found on the page using the passed in
|
|
66
|
+
# parameters is output.
|
|
67
|
+
#
|
|
68
|
+
# In case the problem is something else, we output a screenshot and the page HTML.
|
|
69
|
+
#
|
|
70
|
+
# In case the problem has now solved itself, we try the action again. (This has a very low
|
|
71
|
+
# probability of working as this basically devolves to just duplicating what Capybara is already doing,
|
|
72
|
+
# but it seems like it is worth a shot at least...)
|
|
73
|
+
#
|
|
74
|
+
# In case the problem is a driver bug (specifically Selenium which has some known issues) and
|
|
75
|
+
# is in fact why I even bother trying to do this, try performing the action via javascript.
|
|
76
|
+
# NOTE: As noted in many blogs this type of workaround is not generally a good idea as it can
|
|
77
|
+
# result in false-positives. However since Selenium is buggy, this is the
|
|
78
|
+
# best solution I have other than going to capybara-webkit or poltergeist
|
|
79
|
+
class FindAction
|
|
80
|
+
@@diagnosed_finders = {}
|
|
81
|
+
|
|
82
|
+
attr_accessor :return_value
|
|
83
|
+
attr_accessor :support_options
|
|
84
|
+
|
|
85
|
+
def initialize(test_object, report_options, support_options, function_name, *args)
|
|
86
|
+
@test_object = test_object
|
|
87
|
+
@function_name = function_name
|
|
88
|
+
@args = args
|
|
89
|
+
@support_options = support_options
|
|
90
|
+
@report_options = report_options || {}
|
|
91
|
+
|
|
92
|
+
@report_options[:report] ||= Cornucopia::Util::ReportBuilder.current_report
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def run
|
|
96
|
+
begin
|
|
97
|
+
simple_run
|
|
98
|
+
rescue
|
|
99
|
+
error = $!
|
|
100
|
+
if perform_analysis(support_options[:__cornucopia_retry_with_found])
|
|
101
|
+
# Cornucopia::Util::Configuration.alternate_retry)
|
|
102
|
+
@return_value
|
|
103
|
+
else
|
|
104
|
+
raise error
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def simple_run(cornucopia_args = {})
|
|
110
|
+
simple_run_args = @args.clone
|
|
111
|
+
simple_run_options = {}
|
|
112
|
+
|
|
113
|
+
if simple_run_args.last.is_a? Hash
|
|
114
|
+
simple_run_options = simple_run_args.pop
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
@test_object.send(@function_name, *simple_run_args, simple_run_options.merge(cornucopia_args))
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# def can_dump_details?(attempt_retry, attempt_alternate_retry)
|
|
121
|
+
def can_dump_details?(attempt_retry)
|
|
122
|
+
can_dump = false
|
|
123
|
+
|
|
124
|
+
if (Object.const_defined?("Capybara"))
|
|
125
|
+
can_dump = !@@diagnosed_finders.keys.include?(dump_detail_args(attempt_retry))
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
can_dump
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# def dump_detail_args(attempt_retry, attempt_alternate_retry)
|
|
132
|
+
def dump_detail_args(attempt_retry)
|
|
133
|
+
check_args = search_args.clone
|
|
134
|
+
my_page = ::Capybara.current_session
|
|
135
|
+
|
|
136
|
+
check_args << options.clone
|
|
137
|
+
check_args << !!attempt_retry
|
|
138
|
+
# check_args << !!attempt_alternate_retry
|
|
139
|
+
|
|
140
|
+
if (my_page && my_page.current_url.present? && my_page.current_url != "about:blank")
|
|
141
|
+
check_args << Digest::SHA2.hexdigest(my_page.html)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
check_args
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# def perform_retry(attempt_retry, attempt_alternate_retry, report, report_table)
|
|
148
|
+
def perform_retry(attempt_retry, report, report_table)
|
|
149
|
+
retry_successful = false
|
|
150
|
+
|
|
151
|
+
if attempt_retry && retry_action_with_found_element(report, report_table)
|
|
152
|
+
retry_successful = true
|
|
153
|
+
# else
|
|
154
|
+
# if attempt_alternate_retry && alternate_action_with_found_element(report, report_table)
|
|
155
|
+
# retry_successful = true
|
|
156
|
+
# end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
retry_successful
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# def perform_analysis(attempt_retry, attempt_alternate_retry)
|
|
163
|
+
def perform_analysis(attempt_retry)
|
|
164
|
+
retry_successful = false
|
|
165
|
+
|
|
166
|
+
if can_dump_details?(attempt_retry)
|
|
167
|
+
generate_report "An error occurred while processing \"#{@function_name.to_s}\":",
|
|
168
|
+
$! do |report, report_table|
|
|
169
|
+
retry_successful = perform_retry(attempt_retry, report, report_table)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
dump_args = dump_detail_args(attempt_retry)
|
|
173
|
+
@@diagnosed_finders[dump_args] = { tried: true }
|
|
174
|
+
else
|
|
175
|
+
retry_successful = perform_retry(attempt_retry, nil, nil)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
retry_successful
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def generate_report(message, error = nil, &block)
|
|
182
|
+
if @report_options[:report] && @report_options[:table]
|
|
183
|
+
generate_report_in_table @report_options[:table], error, &block
|
|
184
|
+
else
|
|
185
|
+
@report_options[:report] ||= Cornucopia::Util::ReportBuilder.current_report
|
|
186
|
+
@report_options[:table] = nil
|
|
187
|
+
|
|
188
|
+
@report_options[:report].within_section(message) do |report|
|
|
189
|
+
generate_report_in_table @report_options[:table], error, &block
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def generate_report_in_table(table, error = nil, &block)
|
|
195
|
+
@report_options[:table] = table
|
|
196
|
+
|
|
197
|
+
init_search_args
|
|
198
|
+
all_elements
|
|
199
|
+
all_other_elements
|
|
200
|
+
guessed_types
|
|
201
|
+
|
|
202
|
+
configured_report = Cornucopia::Util::Configuration.report_configuration(:capybara_finder_diagnostics)
|
|
203
|
+
|
|
204
|
+
configured_report.add_report_objects(finder: self, exception: error)
|
|
205
|
+
configured_report.generate_report(@report_options[:report], report_table: @report_options[:table], &block)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def retry_action_with_found_element report, report_table
|
|
209
|
+
return_result = false
|
|
210
|
+
result = "Failed"
|
|
211
|
+
|
|
212
|
+
case @function_name.to_s
|
|
213
|
+
when "assert_selector"
|
|
214
|
+
if found_element
|
|
215
|
+
@return_value = true
|
|
216
|
+
return_result = true
|
|
217
|
+
result = "Found"
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
when "assert_no_selector"
|
|
221
|
+
unless found_element
|
|
222
|
+
@return_value = true
|
|
223
|
+
return_result = true
|
|
224
|
+
result = "Not Found"
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
when "find", "all"
|
|
228
|
+
if found_element
|
|
229
|
+
result = "Success"
|
|
230
|
+
|
|
231
|
+
@return_value = found_element
|
|
232
|
+
|
|
233
|
+
return_result = true
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
report_table.write_stats "Retrying action:", result if report_table && return_result
|
|
238
|
+
|
|
239
|
+
return_result
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# def alternate_action_with_found_element report, report_table
|
|
243
|
+
# return_result = false
|
|
244
|
+
#
|
|
245
|
+
# result = "Could not attempt to try the action through an alternate method."
|
|
246
|
+
# if found_element &&
|
|
247
|
+
# ::Capybara.current_session.respond_to?(:evaluate_script)
|
|
248
|
+
# begin
|
|
249
|
+
# native_id = get_attribute found_element, "id"
|
|
250
|
+
# if (native_id)
|
|
251
|
+
# case @function_name.to_s
|
|
252
|
+
# when "click_link_or_button", "click_link", "click_button"
|
|
253
|
+
# @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].click()")
|
|
254
|
+
# when "fill_in"
|
|
255
|
+
# @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].val(\"#{options[:with]}\")")
|
|
256
|
+
# when "choose", "check"
|
|
257
|
+
# @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].val(\"checked\", true)")
|
|
258
|
+
# when "uncheck"
|
|
259
|
+
# @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].val(\"checked\", false)")
|
|
260
|
+
# when "select"
|
|
261
|
+
# @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].val(\"selected\", true)")
|
|
262
|
+
# when "unselect"
|
|
263
|
+
# @return_value = ::Capybara.current_session.evaluate_script("$(\"\##{native_id}\")[0].val(\"selected\", false)")
|
|
264
|
+
# else
|
|
265
|
+
# result = "Could not decide what to do with #{@function_name}"
|
|
266
|
+
# raise new Exception("unknown action")
|
|
267
|
+
# end
|
|
268
|
+
#
|
|
269
|
+
# return_result = true
|
|
270
|
+
# end
|
|
271
|
+
# rescue
|
|
272
|
+
# result ||= "Still couldn't do the action - #{$!.to_s}."
|
|
273
|
+
# end
|
|
274
|
+
# end
|
|
275
|
+
#
|
|
276
|
+
# report_table.write_stats "Trying alternate action:", result if report_table
|
|
277
|
+
# return_result
|
|
278
|
+
# end
|
|
279
|
+
|
|
280
|
+
def found_element
|
|
281
|
+
if @function_name.to_sym == :all
|
|
282
|
+
all_elements.map(&:found_element)
|
|
283
|
+
else
|
|
284
|
+
if all_elements && all_elements.length == 1
|
|
285
|
+
all_elements[0].try(:found_element)
|
|
286
|
+
else
|
|
287
|
+
nil
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def all_elements
|
|
293
|
+
unless @all_elements
|
|
294
|
+
if options && options.has_key?(:from)
|
|
295
|
+
from_within = nil
|
|
296
|
+
|
|
297
|
+
@report_options[:report].within_table(report_table: @report_options[:table]) do |report_table|
|
|
298
|
+
Cornucopia::Util::ReportTable.new(nested_table: report_table,
|
|
299
|
+
nested_table_label: "Within block:") do |sub_report|
|
|
300
|
+
sub_report_options = @report_options.clone
|
|
301
|
+
sub_report_options[:table] = sub_report
|
|
302
|
+
from_within = Cornucopia::Capybara::FinderDiagnostics::FindAction.
|
|
303
|
+
new(@test_object,
|
|
304
|
+
sub_report_options,
|
|
305
|
+
{},
|
|
306
|
+
:find,
|
|
307
|
+
:select,
|
|
308
|
+
options[:from])
|
|
309
|
+
|
|
310
|
+
from_within.generate_report_in_table(sub_report, nil)
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
from_element = from_within.found_element
|
|
315
|
+
if search_args[0].is_a?(Symbol)
|
|
316
|
+
search_args[0] = :option
|
|
317
|
+
end
|
|
318
|
+
options.delete(:from)
|
|
319
|
+
|
|
320
|
+
unless from_element
|
|
321
|
+
@all_elements = []
|
|
322
|
+
return @all_elements
|
|
323
|
+
end
|
|
324
|
+
else
|
|
325
|
+
from_element = @test_object
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
@all_elements = from_element.all(*search_args, visible: false, __cornucopia_no_analysis: true).
|
|
329
|
+
to_a.map do |element|
|
|
330
|
+
FoundElement.new(element)
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
@all_elements
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def all_other_elements
|
|
338
|
+
unless @all_other_elements
|
|
339
|
+
from_element = ::Capybara::current_session
|
|
340
|
+
|
|
341
|
+
@all_other_elements = from_element.all(*search_args, visible: false, __cornucopia_no_analysis: true).
|
|
342
|
+
to_a.map do |element|
|
|
343
|
+
FoundElement.new(element) unless all_elements.include?(element)
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
@all_other_elements = @all_other_elements - @all_elements
|
|
347
|
+
@all_other_elements.compact!
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
@all_other_elements
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def search_args
|
|
354
|
+
init_search_args
|
|
355
|
+
@search_args
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def options
|
|
359
|
+
init_search_args
|
|
360
|
+
@options
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def init_search_args
|
|
364
|
+
unless @search_args
|
|
365
|
+
@search_args = @args.clone
|
|
366
|
+
@options = {}
|
|
367
|
+
|
|
368
|
+
if @search_args.last.is_a? Hash
|
|
369
|
+
@options = @search_args.pop
|
|
370
|
+
end
|
|
371
|
+
if guessed_types.length > 0 && @search_args[0] != guessed_types[0]
|
|
372
|
+
@search_args.insert(0, guessed_types[0])
|
|
373
|
+
end
|
|
374
|
+
if guessed_types.length <= 0 && @search_args[0] != ::Capybara.default_selector
|
|
375
|
+
@search_args.insert(0, ::Capybara.default_selector)
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# a list of guesses as to what kind of object is being searched for
|
|
381
|
+
def guessed_types
|
|
382
|
+
unless @guessed_types
|
|
383
|
+
if search_args.length > 0
|
|
384
|
+
if search_args[0].is_a?(Symbol)
|
|
385
|
+
@guessed_types = [search_args[0]]
|
|
386
|
+
else
|
|
387
|
+
@guessed_types = [:id, :css, :xpath, :link_or_button, :fillable_field, :radio_button, :checkbox, :select, :option,
|
|
388
|
+
:file_field, :table, :field, :fieldset, :content].select do |test_type|
|
|
389
|
+
begin
|
|
390
|
+
@test_object.all(test_type, *search_args, visible: false, __cornucopia_no_analysis: true).length > 0
|
|
391
|
+
rescue
|
|
392
|
+
# Normally bad form, but for this function, we just don't want this to throw errors.
|
|
393
|
+
# We are only concerned with whatever actually succeeds.
|
|
394
|
+
false
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
@guessed_types
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
private
|
|
405
|
+
|
|
406
|
+
class FoundElement
|
|
407
|
+
ELEMENT_ATTRIBUTES = [
|
|
408
|
+
"text",
|
|
409
|
+
"value",
|
|
410
|
+
"visible?",
|
|
411
|
+
"checked?",
|
|
412
|
+
"selected?",
|
|
413
|
+
"tag_name",
|
|
414
|
+
"location",
|
|
415
|
+
"id",
|
|
416
|
+
"src",
|
|
417
|
+
"name",
|
|
418
|
+
"href",
|
|
419
|
+
"style",
|
|
420
|
+
"path",
|
|
421
|
+
"outerHTML"
|
|
422
|
+
]
|
|
423
|
+
|
|
424
|
+
NATIVE_ATTRIBUTES = [
|
|
425
|
+
"size",
|
|
426
|
+
"type"
|
|
427
|
+
]
|
|
428
|
+
|
|
429
|
+
PREDEFINED_ATTRIBUTES = NATIVE_ATTRIBUTES + ELEMENT_ATTRIBUTES
|
|
430
|
+
|
|
431
|
+
attr_reader :found_element
|
|
432
|
+
|
|
433
|
+
def ==(comparison_object)
|
|
434
|
+
comparison_object.equal?(self) ||
|
|
435
|
+
(comparison_object.instance_of?(self.class) &&
|
|
436
|
+
(comparison_object.found_element == found_element
|
|
437
|
+
# ||
|
|
438
|
+
# (comparison_object.instance_variable_get(:@elem_text) == @elem_text &&
|
|
439
|
+
# comparison_object.instance_variable_get(:@elem_value) == @elem_value &&
|
|
440
|
+
# comparison_object.instance_variable_get(:@elem_visible) == @elem_visible &&
|
|
441
|
+
# comparison_object.instance_variable_get(:@elem_checked) == @elem_checked &&
|
|
442
|
+
# comparison_object.instance_variable_get(:@elem_selected) == @elem_selected &&
|
|
443
|
+
# comparison_object.instance_variable_get(:@elem_tag_name) == @elem_tag_name &&
|
|
444
|
+
# comparison_object.instance_variable_get(:@elem_location) == @elem_location &&
|
|
445
|
+
# comparison_object.instance_variable_get(:@elem_size) == @elem_size &&
|
|
446
|
+
# comparison_object.instance_variable_get(:@elem_id) == @elem_id &&
|
|
447
|
+
# comparison_object.instance_variable_get(:@elem_name) == @elem_name &&
|
|
448
|
+
# comparison_object.instance_variable_get(:@elem_href) == @elem_href &&
|
|
449
|
+
# comparison_object.instance_variable_get(:@elem_style) == @elem_style &&
|
|
450
|
+
# comparison_object.instance_variable_get(:@elem_path) == @elem_path &&
|
|
451
|
+
# comparison_object.instance_variable_get(:@elem_outerHTML) == @elem_outerHTML &&
|
|
452
|
+
# comparison_object.instance_variable_get(:@native_class) == @native_class &&
|
|
453
|
+
# comparison_object.instance_variable_get(:@native_value) == @native_value &&
|
|
454
|
+
# comparison_object.instance_variable_get(:@native_type) == @native_type
|
|
455
|
+
# )
|
|
456
|
+
)
|
|
457
|
+
) ||
|
|
458
|
+
comparison_object == found_element
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
def initialize(found_element)
|
|
462
|
+
@found_element = found_element
|
|
463
|
+
ELEMENT_ATTRIBUTES.each do |attrib|
|
|
464
|
+
variable_name = attrib.to_s.gsub("?", "")
|
|
465
|
+
instance_variable_set("@elem_#{variable_name}", get_attribute(attrib))
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
NATIVE_ATTRIBUTES.each do |attrib|
|
|
469
|
+
instance_variable_set("@native_#{attrib}", get_native_attribute(attrib))
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
instance_variable_set("@native_class", @found_element[:class])
|
|
473
|
+
|
|
474
|
+
if ::Capybara.current_session.driver.respond_to?(:browser) &&
|
|
475
|
+
::Capybara.current_session.driver.browser.method(:execute_script).arity != 1
|
|
476
|
+
begin
|
|
477
|
+
# This is a "trick" that works with Selenium, but which might not work with other drivers...
|
|
478
|
+
script = "var attrib_list = [];
|
|
479
|
+
var attrs = arguments[0].attributes;
|
|
480
|
+
for (var nIndex = 0; nIndex < attrs.length; nIndex += 1)
|
|
481
|
+
{
|
|
482
|
+
var a = attrs[nIndex];
|
|
483
|
+
attrib_list.push(a.name);
|
|
484
|
+
};
|
|
485
|
+
return attrib_list;"
|
|
486
|
+
|
|
487
|
+
attributes = ::Capybara.current_session.driver.browser.execute_script(script, @found_element.native)
|
|
488
|
+
attributes.each do |attritue|
|
|
489
|
+
unless PREDEFINED_ATTRIBUTES.include?(attritue)
|
|
490
|
+
instance_variable_set("@native_#{attritue}", @found_element[attritue])
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
@elem_outerHTML ||= ::Capybara.current_session.driver.browser.execute_script("return arguments[0].outerHTML", @found_element.native)
|
|
495
|
+
rescue ::Capybara::NotSupportedByDriverError
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
# information from Selenium that may not be available depending on the form, the full outerHTML of the element
|
|
500
|
+
if (::Capybara.current_session.respond_to?(:evaluate_script))
|
|
501
|
+
unless (@elem_id.blank?)
|
|
502
|
+
begin
|
|
503
|
+
@elem_outerHTML ||= ::Capybara.current_session.evaluate_script("document.getElementById('#{@elem_id}').outerHTML")
|
|
504
|
+
rescue ::Capybara::NotSupportedByDriverError
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
def get_attribute(attribute)
|
|
511
|
+
if @found_element.respond_to?(attribute)
|
|
512
|
+
begin
|
|
513
|
+
@found_element.send(attribute)
|
|
514
|
+
rescue ::Capybara::NotSupportedByDriverError
|
|
515
|
+
end
|
|
516
|
+
elsif @found_element.respond_to?(:[]) && @found_element[attribute]
|
|
517
|
+
@found_element[attribute]
|
|
518
|
+
else
|
|
519
|
+
get_native_attribute(attribute)
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def get_native_attribute(attribute)
|
|
524
|
+
if @found_element.native.respond_to?(attribute)
|
|
525
|
+
@found_element.native.send(attribute)
|
|
526
|
+
elsif @found_element.native.respond_to?(:[])
|
|
527
|
+
@found_element.native[attribute]
|
|
528
|
+
else
|
|
529
|
+
nil
|
|
530
|
+
end
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
end
|