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
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require ::File.expand_path("../cornucopia", File.dirname(__FILE__))
|
|
2
|
+
require ::File.expand_path("../cornucopia/factory_girl/dynamic_association", File.dirname(__FILE__))
|
|
3
|
+
|
|
4
|
+
load ::File.expand_path("capybara/install_finder_extensions.rb", File.dirname(__FILE__))
|
|
5
|
+
load ::File.expand_path("capybara/install_matcher_extensions.rb", File.dirname(__FILE__))
|
|
6
|
+
load ::File.expand_path("site_prism/install_element_extensions.rb", File.dirname(__FILE__))
|
|
7
|
+
|
|
8
|
+
Around do |scenario, block|
|
|
9
|
+
seed_value = Cornucopia::Util::Configuration.seed ||
|
|
10
|
+
100000000000000000000000000000000000000 + rand(899999999999999999999999999999999999999)
|
|
11
|
+
|
|
12
|
+
scenario.instance_variable_set :@seed_value, seed_value
|
|
13
|
+
|
|
14
|
+
block.call
|
|
15
|
+
|
|
16
|
+
if scenario.failed?
|
|
17
|
+
seed_value = scenario.instance_variable_get(:@seed_value)
|
|
18
|
+
puts ("random seed for testing was: #{seed_value}")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
After do |scenario|
|
|
23
|
+
if scenario.failed?
|
|
24
|
+
Cornucopia::Util::ReportBuilder.current_report.
|
|
25
|
+
within_section("Test Error: #{scenario.feature.title}:#{scenario.title}") do |report|
|
|
26
|
+
configured_report = Cornucopia::Util::Configuration.report_configuration :cucumber
|
|
27
|
+
|
|
28
|
+
configured_report.add_report_objects scenario: scenario, cucumber: self
|
|
29
|
+
configured_report.generate_report(report)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
at_exit do
|
|
35
|
+
Cornucopia::Util::ReportBuilder.current_report.close
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Cornucopia::Util::ReportBuilder.new_report("cucumber_report")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Cornucopia
|
|
2
|
+
module FactoryGirl
|
|
3
|
+
class DynamicAssociations
|
|
4
|
+
##
|
|
5
|
+
# association creates an association which allows arguments or will call a block to create the
|
|
6
|
+
# associated object.
|
|
7
|
+
#
|
|
8
|
+
#
|
|
9
|
+
def association(name, options, &block)
|
|
10
|
+
options
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require ::File.expand_path("../cornucopia", File.dirname(__FILE__))
|
|
2
|
+
load ::File.expand_path("capybara/install_finder_extensions.rb", File.dirname(__FILE__))
|
|
3
|
+
load ::File.expand_path("capybara/install_matcher_extensions.rb", File.dirname(__FILE__))
|
|
4
|
+
load ::File.expand_path("site_prism/install_element_extensions.rb", File.dirname(__FILE__))
|
|
5
|
+
|
|
6
|
+
RSpec.configure do |config|
|
|
7
|
+
config.before(:suite) do |*args|
|
|
8
|
+
Cornucopia::Util::ReportBuilder.new_report("rspec_report")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
config.after(:suite) do
|
|
12
|
+
Cornucopia::Util::ReportBuilder.current_report.close
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
config.around(:each) do |example|
|
|
16
|
+
@seed_value = Cornucopia::Util::Configuration.seed ||
|
|
17
|
+
100000000000000000000000000000000000000 + rand(899999999999999999999999999999999999999)
|
|
18
|
+
|
|
19
|
+
srand(@seed_value)
|
|
20
|
+
|
|
21
|
+
example.run
|
|
22
|
+
|
|
23
|
+
test_example = example.example if example.respond_to?(:example)
|
|
24
|
+
test_example ||= self.example if self.respond_to?(:example)
|
|
25
|
+
if (test_example.exception)
|
|
26
|
+
puts ("random seed for testing was: #{@seed_value}")
|
|
27
|
+
|
|
28
|
+
Cornucopia::Util::ReportBuilder.current_report.
|
|
29
|
+
within_section("Test Error: #{test_example.full_description}") do |report|
|
|
30
|
+
configured_report = Cornucopia::Util::Configuration.report_configuration :rspec
|
|
31
|
+
|
|
32
|
+
configured_report.add_report_objects example: test_example
|
|
33
|
+
configured_report.generate_report(report)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
|
|
3
|
+
module Cornucopia
|
|
4
|
+
module SitePrism
|
|
5
|
+
module ElementExtensions
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
# patterned_elements defines a set of elements where the find pattern is based on the
|
|
10
|
+
# name that will be used for the element.
|
|
11
|
+
#
|
|
12
|
+
# element will be called once for each element with the find pattern where the string
|
|
13
|
+
# `%{element_name}` will be replace with the name for the element.
|
|
14
|
+
# The pattern must include `%{element_name}`.
|
|
15
|
+
#
|
|
16
|
+
# Parameters:
|
|
17
|
+
# pattern - String - This is the pattern that will be used to create the find option
|
|
18
|
+
# for the element. The pattern must include `%{element_name}`.
|
|
19
|
+
# elements - An array of symbols for the elements which will be defined.
|
|
20
|
+
# options - A set of options
|
|
21
|
+
# find_type: The type of the finder which will be used. The default is :css
|
|
22
|
+
# element_array: If not false or nil, this will cause the function to call `elements` instead
|
|
23
|
+
# of `element`
|
|
24
|
+
# additional_options: A hash of additional options which will be sent to element call.
|
|
25
|
+
#
|
|
26
|
+
# Examples:
|
|
27
|
+
# patterned_elements "\#%{element_name}",
|
|
28
|
+
# :user_first_name,
|
|
29
|
+
# :user_last_name,
|
|
30
|
+
# :user_middle_name,
|
|
31
|
+
# :user_sex
|
|
32
|
+
#
|
|
33
|
+
# Will call:
|
|
34
|
+
# element :user_first_name, "\#user_first_name"
|
|
35
|
+
# element :user_last_name, "\#user_last_name"
|
|
36
|
+
# element :user_middle_name, "\#user_middle_name"
|
|
37
|
+
# element :user_sex, "\#user_sex"
|
|
38
|
+
#
|
|
39
|
+
# patterned_elements "//option[contains(text(), \"${element_name}\")]",
|
|
40
|
+
# :Cincinati,
|
|
41
|
+
# :Chicago,
|
|
42
|
+
# :Denver,
|
|
43
|
+
# find_type: :xpath,
|
|
44
|
+
# additional_options: { visible: false }
|
|
45
|
+
#
|
|
46
|
+
# Will call:
|
|
47
|
+
# element :Cincinati, :xpath, "//option[contains(text(), \"Cincinati\")]", visible: false
|
|
48
|
+
# element :Chicago, :xpath, "//option[contains(text(), \"Chicago\")]", visible: false
|
|
49
|
+
# element :Denver, :xpath, "//option[contains(text(), \"Denver\")]", visible: false
|
|
50
|
+
def patterned_elements(pattern, *elements)
|
|
51
|
+
options = elements.extract_options!
|
|
52
|
+
|
|
53
|
+
unless pattern =~ /\%\{element_name\}/
|
|
54
|
+
raise Exception.new("Invalid pattern \"#{pattern}\". Pattern must contain \"%{element_name}\".")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
element_function = :element
|
|
58
|
+
element_function = :elements if options[:element_array]
|
|
59
|
+
|
|
60
|
+
element_name_index = 0
|
|
61
|
+
options_array = []
|
|
62
|
+
if options[:find_type]
|
|
63
|
+
options_array << options[:find_type]
|
|
64
|
+
element_name_index += 1
|
|
65
|
+
end
|
|
66
|
+
options_array << :__blank__
|
|
67
|
+
options_array << pattern
|
|
68
|
+
options_array << options[:additional_options] if options[:additional_options]
|
|
69
|
+
|
|
70
|
+
elements.each do |element_name|
|
|
71
|
+
options_array[element_name_index] = element_name.to_s.gsub(/[-]/, "_").to_sym
|
|
72
|
+
options_array[element_name_index + 1] = pattern % { element_name: element_name }
|
|
73
|
+
send element_function, *options_array
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# form_elements defines an ID finder for most form elements. Given a <model_name> and an
|
|
78
|
+
# array of <field_name>s, this function will call `element` once for each <field_name>
|
|
79
|
+
# defining an id based element assuming it was definied within a form for <model_name>.
|
|
80
|
+
#
|
|
81
|
+
# This is based off the fact that the IDs for most form elements follows a basic pattern
|
|
82
|
+
# of: "<model_name>_<field_name>".
|
|
83
|
+
#
|
|
84
|
+
# Parameters:
|
|
85
|
+
# model_name
|
|
86
|
+
# field_names
|
|
87
|
+
# options - A set of options
|
|
88
|
+
# element_array: If not false or nil, this will cause the function to call `elements` instead
|
|
89
|
+
# of `element`
|
|
90
|
+
#
|
|
91
|
+
# Example:
|
|
92
|
+
# form_elements :user,
|
|
93
|
+
# :first_name,
|
|
94
|
+
# :last_name,
|
|
95
|
+
# :middle_name,
|
|
96
|
+
# :sex
|
|
97
|
+
#
|
|
98
|
+
# Will call:
|
|
99
|
+
# element :first_name, "\#user_first_name"
|
|
100
|
+
# element :last_name, "\#user_last_name"
|
|
101
|
+
# element :middle_name, "\#user_middle_name"
|
|
102
|
+
# element :sex, "\#user_sex"
|
|
103
|
+
def form_elements(model_name, *field_names)
|
|
104
|
+
options = field_names.extract_options!
|
|
105
|
+
|
|
106
|
+
patterned_elements "\##{model_name}_%{element_name}", *field_names, options.slice(:element_array)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# id_elements defines an ID finder where the id of the element is the name for the element.
|
|
110
|
+
#
|
|
111
|
+
# Parameters:
|
|
112
|
+
# element_names - An array of elements to define where the id of the element is the same as the element name
|
|
113
|
+
# options - A set of options
|
|
114
|
+
# element_array: If not false or nil, this will cause the function to call `elements` instead
|
|
115
|
+
# of `element`
|
|
116
|
+
#
|
|
117
|
+
# Example:
|
|
118
|
+
# id_elements :some_object,
|
|
119
|
+
# :another_object
|
|
120
|
+
#
|
|
121
|
+
# Will call:
|
|
122
|
+
# element :some_object, "\#some_object"
|
|
123
|
+
# element :another_object, "\#another_object"
|
|
124
|
+
def id_elements(*element_names)
|
|
125
|
+
options = element_names.extract_options!
|
|
126
|
+
|
|
127
|
+
patterned_elements "\#%{element_name}", *element_names, options.slice(:element_array)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# class_elements defines an ID finder where the class of the element is the name for the element.
|
|
131
|
+
#
|
|
132
|
+
# Parameters:
|
|
133
|
+
# element_names - An array of elements to define where the id of the element is the same as the element name
|
|
134
|
+
# options - A set of options
|
|
135
|
+
# element_array: If not false or nil, this will cause the function to call `elements` instead
|
|
136
|
+
# of `element`
|
|
137
|
+
#
|
|
138
|
+
# Example:
|
|
139
|
+
# id_elements :some_object,
|
|
140
|
+
# :another_object
|
|
141
|
+
#
|
|
142
|
+
# Will call:
|
|
143
|
+
# element :some_object, ".some_object"
|
|
144
|
+
# element :another_object, ".another_object"
|
|
145
|
+
def class_elements(*element_names)
|
|
146
|
+
options = element_names.extract_options!
|
|
147
|
+
|
|
148
|
+
patterned_elements ".%{element_name}", *element_names, options.slice(:element_array)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# indexed_elements defines a set of elements where the finder pattern can be based off of
|
|
152
|
+
# an index value.
|
|
153
|
+
#
|
|
154
|
+
# This can be useful for table columns for example.
|
|
155
|
+
#
|
|
156
|
+
# Parameters:
|
|
157
|
+
# index_pattern - String - This is the pattern that will be used to create the find option
|
|
158
|
+
# for the element. The pattern must include `%{element_index}`.
|
|
159
|
+
# element_names - An array of symbols for the elements which will be defined.
|
|
160
|
+
# The name :__skip__ will be ignored. Ignored elements will always increment by one and
|
|
161
|
+
# will ignore the increment value.
|
|
162
|
+
# options - A set of options
|
|
163
|
+
# find_type: The type of the finder which will be used. The default is :css
|
|
164
|
+
# element_array: If not false or nil, this will cause the function to call `elements` instead
|
|
165
|
+
# of `element`
|
|
166
|
+
# additional_options: A hash of additional options which will be sent to element call.
|
|
167
|
+
# start_index: The start value for the first index element.
|
|
168
|
+
# increment: The amount the index will be incremented by each time.
|
|
169
|
+
#
|
|
170
|
+
# Examples:
|
|
171
|
+
# indexed_elements "\#my_table tr td:nth-child(%{element_index})",
|
|
172
|
+
# :first_name,
|
|
173
|
+
# :last_name,
|
|
174
|
+
# :middle_name,
|
|
175
|
+
# :sex
|
|
176
|
+
#
|
|
177
|
+
# Will call:
|
|
178
|
+
# element :first_name, "\#my_table tr td:nth-child(1)"
|
|
179
|
+
# element :last_name, "\#my_table tr td:nth-child(2)"
|
|
180
|
+
# element :middle_name, "\#my_table tr td:nth-child(3)"
|
|
181
|
+
# element :sex, "\#my_table tr td:nth-child(4)"
|
|
182
|
+
#
|
|
183
|
+
# indexed_elements "\#my_table tr td:nth-child(%{element_index})",
|
|
184
|
+
# :first_name,
|
|
185
|
+
# :last_name,
|
|
186
|
+
# :middle_name,
|
|
187
|
+
# :__skip__
|
|
188
|
+
# :sex
|
|
189
|
+
#
|
|
190
|
+
# Will call:
|
|
191
|
+
# element :first_name, "\#my_table tr td:nth-child(1)"
|
|
192
|
+
# element :last_name, "\#my_table tr td:nth-child(2)"
|
|
193
|
+
# element :middle_name, "\#my_table tr td:nth-child(3)"
|
|
194
|
+
# element :sex, "\#my_table tr td:nth-child(5)"
|
|
195
|
+
#
|
|
196
|
+
# indexed_elements "\#my_table tr td:nth-child(%{element_index})",
|
|
197
|
+
# :first_name,
|
|
198
|
+
# :last_name,
|
|
199
|
+
# :middle_name,
|
|
200
|
+
# :__skip__
|
|
201
|
+
# :sex,
|
|
202
|
+
# start_index: 4
|
|
203
|
+
# increment: 3
|
|
204
|
+
#
|
|
205
|
+
# Will call:
|
|
206
|
+
# element :first_name, "\#my_table tr td:nth-child(4)"
|
|
207
|
+
# element :last_name, "\#my_table tr td:nth-child(7)"
|
|
208
|
+
# element :middle_name, "\#my_table tr td:nth-child(10)"
|
|
209
|
+
# element :sex, "\#my_table tr td:nth-child(12)"
|
|
210
|
+
def indexed_elements(index_pattern, *element_names)
|
|
211
|
+
options = element_names.extract_options!
|
|
212
|
+
|
|
213
|
+
element_function = :element
|
|
214
|
+
element_function = :elements if options[:element_array]
|
|
215
|
+
|
|
216
|
+
element_index = options[:start_index] || 1
|
|
217
|
+
index_increment = options[:increment] || 1
|
|
218
|
+
|
|
219
|
+
unless index_pattern =~ /\%\{element_index\}/
|
|
220
|
+
raise Exception.new("Invalid index_pattern \"#{index_pattern}\". Pattern must contain \"%{element_index}\".")
|
|
221
|
+
end
|
|
222
|
+
raise Exception.new("Increment value may not be 0") if index_increment == 0
|
|
223
|
+
|
|
224
|
+
options_array = []
|
|
225
|
+
element_name_index = 0
|
|
226
|
+
if options[:find_type]
|
|
227
|
+
options_array << options[:find_type]
|
|
228
|
+
element_name_index += 1
|
|
229
|
+
end
|
|
230
|
+
options_array << :__blank__
|
|
231
|
+
options_array << index_pattern
|
|
232
|
+
options_array << options[:additional_options] if options[:additional_options]
|
|
233
|
+
|
|
234
|
+
element_names.each do |element_name|
|
|
235
|
+
if [:__blank__, :__skip__].include?(element_name)
|
|
236
|
+
element_index += 1
|
|
237
|
+
next
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
options_array[element_name_index] = element_name
|
|
241
|
+
options_array[element_name_index + 1] = index_pattern % { element_index: element_index }
|
|
242
|
+
send element_function, *options_array
|
|
243
|
+
element_index += index_increment
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# I don't need this right now.
|
|
248
|
+
# I am thinking that I should try using x-path next time I need this.
|
|
249
|
+
#
|
|
250
|
+
# # immediate_child_element element_name, find_string == element element_name, "> #{find_string}"
|
|
251
|
+
# def immediate_child_element(element_name, *find_args)
|
|
252
|
+
# self.class_eval do
|
|
253
|
+
# elements "__cornucopia_element_#{element_name}", *find_args
|
|
254
|
+
# end
|
|
255
|
+
#
|
|
256
|
+
# define_method element_name.to_s do
|
|
257
|
+
# the_element = send("__cornucopia_element_#{element_name}").reduce([]) do |array, element|
|
|
258
|
+
# array << element if element.parent == self.root_element
|
|
259
|
+
# array
|
|
260
|
+
# end
|
|
261
|
+
#
|
|
262
|
+
# raise ::Capybara::ElementNotFound unless the_element.length > 0
|
|
263
|
+
# raise ::Capybara::Ambiguous unless the_element.length == 1
|
|
264
|
+
#
|
|
265
|
+
# the_element[0]
|
|
266
|
+
# end
|
|
267
|
+
# end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
load ::File.expand_path("install_element_extensions.rb", File.dirname(__FILE__))
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
$cornucopia_element_extension_installed = false unless defined? $cornucopia_element_extension_installed
|
|
2
|
+
|
|
3
|
+
if Object.const_defined?("SitePrism") &&
|
|
4
|
+
::SitePrism.const_defined?("Page") &&
|
|
5
|
+
!$cornucopia_element_extension_installed
|
|
6
|
+
module ::SitePrism
|
|
7
|
+
class Page
|
|
8
|
+
include Cornucopia::SitePrism::ElementExtensions
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
if Object.const_defined?("SitePrism") &&
|
|
14
|
+
::SitePrism.const_defined?("Section") &&
|
|
15
|
+
!$cornucopia_element_extension_installed
|
|
16
|
+
$cornucopia_element_extension_installed = true
|
|
17
|
+
|
|
18
|
+
module ::SitePrism
|
|
19
|
+
class Section
|
|
20
|
+
include Cornucopia::SitePrism::ElementExtensions
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
module Cornucopia
|
|
2
|
+
module SitePrism
|
|
3
|
+
# PageApplication is a class used to fetch page objects and memoize them
|
|
4
|
+
# without really having to know anything about them.
|
|
5
|
+
#
|
|
6
|
+
# This class is intended to be the base class for a page application object.
|
|
7
|
+
#
|
|
8
|
+
# An example of how it is designed to work is:
|
|
9
|
+
#
|
|
10
|
+
# class MyApplication < Cornucopia::SitePrism::PageApplication
|
|
11
|
+
# def pages_module
|
|
12
|
+
# MyPagesModule
|
|
13
|
+
# end
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# module MyPagesModule
|
|
17
|
+
# class MyPage < SitePrism::Page
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# page = MyApplication.my_page
|
|
22
|
+
#
|
|
23
|
+
#
|
|
24
|
+
# The system works as follows:
|
|
25
|
+
# * Pages are defined as: BaseModule::SubModule::NamePage
|
|
26
|
+
# BaseModule:: is optional
|
|
27
|
+
# SubModule:: is optional and you can have as many levels as you want
|
|
28
|
+
# Name is the name of the page
|
|
29
|
+
# Page is recommended to distinguish pages from sections
|
|
30
|
+
#
|
|
31
|
+
# * A singleton instance of your application class is memoized. That instance
|
|
32
|
+
# is used to instantiate and memoize all of the page objects. Additional
|
|
33
|
+
# functions and properties which you may need may be added to this class.
|
|
34
|
+
# Remember, this singleton instance is instantiated once per test run and
|
|
35
|
+
# will be reused in multiple tests.
|
|
36
|
+
#
|
|
37
|
+
# * To get a page object, simply use your class object and call the underscored name
|
|
38
|
+
# of the page and its modules as a class method. The class method name will be
|
|
39
|
+
# deconstructed and constantized into a page object. The page object will be created
|
|
40
|
+
# once and then cached for future use. Use 2 underscores (__) between modules.
|
|
41
|
+
# To get the sample page it would be: MyApplication.sub_module__name_page
|
|
42
|
+
#
|
|
43
|
+
# All you have to do is define the page objects under a single module namespace and the
|
|
44
|
+
# application class will recognize the pages and return them.
|
|
45
|
+
|
|
46
|
+
class PageApplication
|
|
47
|
+
@@current_instances = {}
|
|
48
|
+
|
|
49
|
+
def pages_module
|
|
50
|
+
Object
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class << self
|
|
54
|
+
def current_instance
|
|
55
|
+
@@current_instances[self.name] ||= self.new
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Redirect any non-class methods to the instance if the instance supports them.
|
|
59
|
+
def method_missing(method_sym, *arguments, &block)
|
|
60
|
+
if self.current_instance.respond_to?(method_sym, true)
|
|
61
|
+
self.current_instance.send(method_sym, *arguments)
|
|
62
|
+
else
|
|
63
|
+
super
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def respond_to?(method_sym, include_private = false)
|
|
68
|
+
if self.current_instance.respond_to?(method_sym, include_private)
|
|
69
|
+
true
|
|
70
|
+
else
|
|
71
|
+
super
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def is_page_name?(method_name)
|
|
77
|
+
is_page_name = false
|
|
78
|
+
if method_name =~ /^[@a-z0-9_]+$/i
|
|
79
|
+
base_class = pages_module
|
|
80
|
+
|
|
81
|
+
is_page_name = true
|
|
82
|
+
method_name.split("__").each do |module_name|
|
|
83
|
+
if module_name.blank?
|
|
84
|
+
is_page_name = false
|
|
85
|
+
break;
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
unless base_class.const_defined?(module_name.camelize)
|
|
89
|
+
is_page_name = false
|
|
90
|
+
break
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
base_class = "#{base_class}::#{module_name.camelize}".constantize
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
is_page_name
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def method_missing(method_sym, *arguments, &block)
|
|
101
|
+
method_name = method_sym.to_s
|
|
102
|
+
if is_page_name?(method_name)
|
|
103
|
+
return_page = instance_variable_get("@#{method_name}")
|
|
104
|
+
unless return_page
|
|
105
|
+
return_page = "#{pages_module.to_s}::#{method_name.split("__").map(&:camelize).join("::")}".constantize.new
|
|
106
|
+
instance_variable_set("@#{method_name}", return_page)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
return_page
|
|
110
|
+
else
|
|
111
|
+
super
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def respond_to?(method_sym, include_private = false)
|
|
116
|
+
method_name = method_sym.to_s
|
|
117
|
+
|
|
118
|
+
if is_page_name?(method_name)
|
|
119
|
+
true
|
|
120
|
+
else
|
|
121
|
+
super
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|