mattscilipoti-model_steps 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.
- data/.document +5 -0
- data/.gitignore +8 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +61 -0
- data/VERSION +1 -0
- data/examples/example_helper.rb +17 -0
- data/examples/mattscilipoti-model_steps_example.rb +7 -0
- data/features/mattscilipoti-model_steps.feature +9 -0
- data/features/step_definitions/mattscilipoti-model_steps_steps.rb +2 -0
- data/features/support/env.rb +6 -0
- data/lib/mattscilipoti-model_steps.rb +3 -0
- data/lib/model_steps/step_definitions.rb +761 -0
- metadata +88 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009-10 Matt Scilipoti
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= mattscilipoti-model_steps
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but
|
13
|
+
bump version in a commit by itself I can ignore when I pull)
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2009-10 Matt Scilipoti. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "mattscilipoti-model_steps"
|
8
|
+
gem.summary = %Q{Model Steps for cucumber}
|
9
|
+
gem.description = %Q{Model Steps for cucumber}
|
10
|
+
gem.email = "matt@scilipoti.name"
|
11
|
+
gem.homepage = "http://github.com/mattscilipoti/mattscilipoti-model_steps"
|
12
|
+
gem.authors = ["Matt Scilipoti"]
|
13
|
+
gem.add_development_dependency "micronaut"
|
14
|
+
gem.add_development_dependency "cucumber"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'micronaut/rake_task'
|
23
|
+
Micronaut::RakeTask.new(:examples) do |examples|
|
24
|
+
examples.pattern = 'examples/**/*_example.rb'
|
25
|
+
examples.ruby_opts << '-Ilib -Iexamples'
|
26
|
+
end
|
27
|
+
|
28
|
+
Micronaut::RakeTask.new(:rcov) do |examples|
|
29
|
+
examples.pattern = 'examples/**/*_example.rb'
|
30
|
+
examples.rcov_opts = '-Ilib -Iexamples'
|
31
|
+
examples.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :examples => :check_dependencies
|
35
|
+
|
36
|
+
begin
|
37
|
+
require 'cucumber/rake/task'
|
38
|
+
Cucumber::Rake::Task.new(:features)
|
39
|
+
|
40
|
+
task :features => :check_dependencies
|
41
|
+
rescue LoadError
|
42
|
+
task :features do
|
43
|
+
abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
task :default => :examples
|
48
|
+
|
49
|
+
require 'rake/rdoctask'
|
50
|
+
Rake::RDocTask.new do |rdoc|
|
51
|
+
if File.exist?('VERSION')
|
52
|
+
version = File.read('VERSION')
|
53
|
+
else
|
54
|
+
version = ""
|
55
|
+
end
|
56
|
+
|
57
|
+
rdoc.rdoc_dir = 'rdoc'
|
58
|
+
rdoc.title = "mattscilipoti-model_steps #{version}"
|
59
|
+
rdoc.rdoc_files.include('README*')
|
60
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
61
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'micronaut'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
+
|
7
|
+
require 'mattscilipoti-model_steps'
|
8
|
+
|
9
|
+
def not_in_editor?
|
10
|
+
!(ENV.has_key?('TM_MODE') || ENV.has_key?('EMACS') || ENV.has_key?('VIM'))
|
11
|
+
end
|
12
|
+
|
13
|
+
Micronaut.configure do |c|
|
14
|
+
c.color_enabled = not_in_editor?
|
15
|
+
c.filter_run :focused => true
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,761 @@
|
|
1
|
+
Cucumber::Ast::Table.class_eval do
|
2
|
+
def is_date_column?(column_name)
|
3
|
+
column_name.columnify =~ /( at|_at|time|date)$/
|
4
|
+
end
|
5
|
+
|
6
|
+
def chronic_parsable_columns
|
7
|
+
chronic_parsable_columns = []
|
8
|
+
headers.each do |col|
|
9
|
+
next unless is_date_column?(col)
|
10
|
+
|
11
|
+
chronic_parsable_columns << col
|
12
|
+
chronic_parsable_columns << col.titleize
|
13
|
+
end
|
14
|
+
return chronic_parsable_columns
|
15
|
+
end
|
16
|
+
|
17
|
+
def map_chronic_columns!
|
18
|
+
self.map_columns!(chronic_parsable_columns) do |cell_value|
|
19
|
+
if cell_value.blank?
|
20
|
+
cell_value
|
21
|
+
else
|
22
|
+
parsed_value = Chronic.parse(cell_value)
|
23
|
+
raise "Chronic can not parse '#{cell_value}' to a date/time." unless parsed_value
|
24
|
+
parsed_value.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def map_columns!(headers_to_map)
|
30
|
+
existing_headers = self.headers & headers_to_map
|
31
|
+
existing_headers.each do |header|
|
32
|
+
self.map_column!(header) { |cell_value| yield cell_value }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
#This file contains steps which work with rails' models, but are not for a specific model
|
40
|
+
Then /^I should see no (\D+)$/ do |requested_model|
|
41
|
+
Then "I should see 0 #{requested_model}"
|
42
|
+
end
|
43
|
+
|
44
|
+
Then /^I should see (\d+) (\D+)$/ do |expected_count, requested_model|
|
45
|
+
expected_count = expected_count.to_i
|
46
|
+
css_class = requested_model.underscore
|
47
|
+
if expected_count > 0
|
48
|
+
response.should have_tag("table.#{css_class}") do
|
49
|
+
with_tag("tbody tr", expected_count)
|
50
|
+
end
|
51
|
+
else
|
52
|
+
#response.should have_tag("div.#{css_class}", translate(:none_found)) #TODO: undefined method `translate' for #<ActionController::Integration::Session:0xb4f3e9e0> (NoMethodError)
|
53
|
+
response.should have_tag("div.#{css_class}", 'None found')
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
Then /^I should see (?:these|the following) (\D+):$/ do |requested_model, table|
|
59
|
+
# table is a Cucumber::Ast::Table
|
60
|
+
table.map_chronic_columns!
|
61
|
+
#WORKAROUND: why does table.diff! expect Trouble to be nil (vs. '')?
|
62
|
+
# table.map_columns!(['Trouble']) {|trouble_message| trouble_message == '\nil' ? nil : trouble_message}
|
63
|
+
|
64
|
+
mapped_table = map_table_headers(table)
|
65
|
+
|
66
|
+
requested_table = (requested_model =~ /^(.+)[(](.+)[)]$/) ? $1 : requested_model
|
67
|
+
|
68
|
+
css_class = requested_table.pluralize.underscore
|
69
|
+
|
70
|
+
html_table = table(tableish("table.#{css_class} tr", 'td,th'))
|
71
|
+
|
72
|
+
mapped_table.diff!(html_table)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
#Given the following Camera Events exist:
|
77
|
+
#Note: use ((?!.*should) to avoid conflicts with
|
78
|
+
# Given the following Camera Events should exist:
|
79
|
+
Given /^(?:these|the following) (?!.*should)(.+) exist:$/ do |requested_model, table|
|
80
|
+
|
81
|
+
# table is a Cucumber::Ast::Table
|
82
|
+
model = requested_model_to_model(requested_model)
|
83
|
+
|
84
|
+
map_table_columns!(table)
|
85
|
+
mapped_table = map_table_headers(table)
|
86
|
+
mapped_table.hashes.each do |table_row|
|
87
|
+
|
88
|
+
requested_params = table_row.dup
|
89
|
+
|
90
|
+
model_params = requested_params_to_model_params(requested_params, model)
|
91
|
+
|
92
|
+
model_under_test = Factory.create(model_to_factory_symbol(model.name), model_params)
|
93
|
+
|
94
|
+
if model_under_test.is_a?(ImportSession)
|
95
|
+
Traffipax.deprecated("special fixture code for 'the following Import Sessions exist'", 'only until ImportSession no longer has ImportSteps') unless ImportSession.new.respond_to?('import_steps')
|
96
|
+
trouble = model_params[:trouble]
|
97
|
+
#ensure last step has proper status
|
98
|
+
#TODO: this is a smell. We are bypassing proper operation. Is this test appropriate?
|
99
|
+
model_under_test.current_step.update_attributes!(:started_at => model_under_test.started_at, :completed_at => model_under_test.completed_at)
|
100
|
+
model_under_test.current_step.trouble = trouble if trouble
|
101
|
+
end
|
102
|
+
|
103
|
+
model_under_test
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
#Given ModelA:unique_ident exists
|
109
|
+
# Create a new ModelA with default_identifier_column = default_identifier
|
110
|
+
Given /^(.+):(.+) exists$/ do |requested_model, default_identifier|
|
111
|
+
model = requested_model_to_model(requested_model)
|
112
|
+
column_name = model.default_identifier_column
|
113
|
+
Factory.create(model_to_factory_symbol(requested_model), column_name => default_identifier)
|
114
|
+
end
|
115
|
+
|
116
|
+
#Given ModelA:DI has 3 ModelBs
|
117
|
+
Given /^(.+):(.+) has (\d+) (?!.*with:)(.+)$/ do |requested_model, default_identifier, association_quantity, requested_association_name|
|
118
|
+
association_quantity = association_quantity.to_i
|
119
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
120
|
+
create_requested_model_associations(model_under_test, association_quantity, requested_association_name.pluralize)
|
121
|
+
end
|
122
|
+
|
123
|
+
#Given ModelA:DI has 3 ModelBs with:
|
124
|
+
# |attribute_name|
|
125
|
+
# |attribute_name|
|
126
|
+
# |value |
|
127
|
+
Given /^(\D+):(.+) has (\d+) (\D+) with:$/ do |requested_model, default_identifier, association_quantity, requested_association_name, table|
|
128
|
+
association_quantity = association_quantity.to_i
|
129
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
130
|
+
# default_params = table ? table.hashes.first : {}
|
131
|
+
default_params = table.hashes.first
|
132
|
+
create_requested_model_associations(model_under_test, association_quantity, requested_association_name.pluralize, [], default_params)
|
133
|
+
end
|
134
|
+
|
135
|
+
#7/09: find_or_create was not creating. Validations? Use Factory?
|
136
|
+
##Given ModelA:DI_A has ModelB:DI_B
|
137
|
+
Given /^(\D+):(.+) has (\D+):(.+)$/ do |requested_model, default_identifier, association_model_name, associated_model_default_identifier|
|
138
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
139
|
+
associated_model = requested_model_to_model(association_model_name)
|
140
|
+
factory_name = model_to_factory_symbol(associated_model)
|
141
|
+
associated_model_under_test = associated_model.find_by_default_identifier(default_identifier) || Factory(factory_name, associated_model.default_identifier_column => default_identifier)
|
142
|
+
|
143
|
+
possible_associations = [association_model_name.underscore, association_model_name.pluralize.underscore]
|
144
|
+
association_name = possible_associations.detect {|association_name| model_under_test.respond_to?(association_name)}
|
145
|
+
|
146
|
+
if association_name
|
147
|
+
if association_name.pluralize == association_name
|
148
|
+
associated_items = model_under_test.send(association_name)
|
149
|
+
associated_items << associated_model_under_test
|
150
|
+
else
|
151
|
+
model_under_test.send(association_name + '=', associated_model_under_test)
|
152
|
+
end
|
153
|
+
model_under_test.save!
|
154
|
+
|
155
|
+
else
|
156
|
+
raise "Neither of these associations exist for #{model_under_test.class.name}: #{possible_associations.inspect}"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
Given /^(.+):(.+) (?:has|had) (?:these|this|the following) attributes:$/ do |requested_model, default_identifier, table|
|
161
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
162
|
+
|
163
|
+
attributes = map_table_headers(table).hashes.first
|
164
|
+
model_under_test.update_attributes!(attributes)
|
165
|
+
end
|
166
|
+
|
167
|
+
#Given ModelA has the following existing ModelB's (see table)
|
168
|
+
# Finds the ModelB's which match the conditions
|
169
|
+
# And assigns themto ModelA.association
|
170
|
+
Given /^(\D+):(.+) has (?:these|the following) existing (\D+):$/ do |requested_model, default_identifier, requested_association_name, table|
|
171
|
+
association_quantity = table.rows.size
|
172
|
+
|
173
|
+
map_table_columns!(table)
|
174
|
+
array_of_requested_params = table.hashes
|
175
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
176
|
+
assign_requested_model_associations(model_under_test, association_quantity, requested_association_name, array_of_requested_params)
|
177
|
+
end
|
178
|
+
|
179
|
+
#Given ModelA has this ModelB (see table)
|
180
|
+
#Given ModelA has these ModelBs (see table)
|
181
|
+
#Given ModelA has the following ModelBs (see table)
|
182
|
+
#Given ModelA has these ModelBs(factory suffix) (see table)
|
183
|
+
Given /^(.+):(.+) (?:has|had) (?:these|this|the following) (?!existing |attributes)(.+)?:$/ do |requested_model, default_identifier, requested_association_name, table|
|
184
|
+
#needs negative look behind (?!existing) for "has these existing ModelBs
|
185
|
+
#needs negative look behind (?!existing|attributes) AND optional (.+)? for "has these attributes"
|
186
|
+
association_quantity = table.rows.size
|
187
|
+
|
188
|
+
map_table_columns!(table)
|
189
|
+
array_of_requested_params = table.hashes
|
190
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
191
|
+
create_requested_model_associations(model_under_test, association_quantity, requested_association_name, array_of_requested_params)
|
192
|
+
end
|
193
|
+
|
194
|
+
Given /^(\D+):(.*) performed (?:a|an) (?!\D+:)(\D+)$/ do |requested_model, default_identifier, requested_activity|
|
195
|
+
model = requested_model_to_model(requested_model)
|
196
|
+
|
197
|
+
perform_activity(model, default_identifier, requested_activity)
|
198
|
+
end
|
199
|
+
|
200
|
+
Given /^(\D+):(.*) performed the following (\D+)(?:s?):$/ do |requested_model, default_identifier, requested_activity, table|
|
201
|
+
model = requested_model_to_model(requested_model)
|
202
|
+
|
203
|
+
activity = perform_activity(model, default_identifier, requested_activity)
|
204
|
+
|
205
|
+
map_table_columns!(table)
|
206
|
+
table.hashes.each do |params|
|
207
|
+
activity_params = params.dup
|
208
|
+
#if successful, completed = started
|
209
|
+
unless params[:completed_at] || params[:trouble]
|
210
|
+
activity_params.merge!(:completed_at => params[:started_at])
|
211
|
+
end
|
212
|
+
activity.update_attributes!(activity_params)
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
#Given no CameraEvents exist
|
218
|
+
#Destroys all CameraEvents
|
219
|
+
Given /^no (?!.*should)(\D+) exist$/ do |requested_models|
|
220
|
+
model_klass = requested_model_to_model(requested_models)
|
221
|
+
model_klass.destroy_all
|
222
|
+
model_klass.count.should == 0
|
223
|
+
end
|
224
|
+
|
225
|
+
#Given x CameraEvents exist
|
226
|
+
#Creates x CameraEvents using FactoryGirl
|
227
|
+
Given /^(\d+) (?!.*should)(\D+) exist$/ do |requested_count, requested_models|
|
228
|
+
requested_count = requested_count.to_i
|
229
|
+
|
230
|
+
model_klass = requested_model_to_model(requested_models)
|
231
|
+
factory_name = model_to_factory_symbol(requested_models)
|
232
|
+
|
233
|
+
requested_count.times do
|
234
|
+
Factory.create(factory_name)
|
235
|
+
end
|
236
|
+
|
237
|
+
model_klass.count.should == requested_count
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
Given /^(\D+):(.+) does not exist$/ do |requested_model, default_identifier|
|
242
|
+
begin
|
243
|
+
model = requested_model_to_model(requested_model)
|
244
|
+
instance = model.find_by_default_identifier(default_identifier)
|
245
|
+
if instance
|
246
|
+
instance.destroy if instance
|
247
|
+
instance.reload.should be_nil
|
248
|
+
end
|
249
|
+
rescue ActiveRecord::RecordNotFound
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
#When I navigate to the page for listing the requested model
|
254
|
+
When /^I list (.+)s$/ do |requested_model|
|
255
|
+
controller_name = requested_model.underscore.pluralize
|
256
|
+
visit send(controller_name + "_path")
|
257
|
+
end
|
258
|
+
|
259
|
+
#When I navigate to the page for showing/editing the requested model
|
260
|
+
When /^I (edit|show) (.+):(.+)$/ do |action, requested_model, default_identifier|
|
261
|
+
parent_requested_model, requested_model = requested_model.split('/') if requested_model.include?('/')
|
262
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
263
|
+
|
264
|
+
action_prefix = case action
|
265
|
+
when 'show'
|
266
|
+
''
|
267
|
+
when 'edit'
|
268
|
+
'edit_'
|
269
|
+
else
|
270
|
+
raise "That action (#{action}) is not currently supported."
|
271
|
+
end
|
272
|
+
|
273
|
+
#TODO: model.controllerize?
|
274
|
+
controller_name = model_under_test.class.base_class.name.underscore
|
275
|
+
|
276
|
+
if parent_requested_model
|
277
|
+
parent_model = model_under_test.send(parent_requested_model.underscore)
|
278
|
+
parent_prefix = "#{parent_requested_model.underscore}_"
|
279
|
+
named_path = action_prefix + parent_prefix + controller_name + "_path"
|
280
|
+
visit send( named_path, parent_model, model_under_test)
|
281
|
+
else
|
282
|
+
named_path = action_prefix + controller_name + "_path"
|
283
|
+
visit send( named_path, model_under_test)
|
284
|
+
end
|
285
|
+
Then "I should not see an error message"
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
When /^I fill in required (.+) fields$/ do |requested_model|
|
290
|
+
fill_in_required_fields requested_model
|
291
|
+
end
|
292
|
+
|
293
|
+
When /^I fill in required (.+) fields except:$/ do |requested_model, table|
|
294
|
+
fill_in_required_fields(requested_model, table.rows.flatten)
|
295
|
+
end
|
296
|
+
|
297
|
+
#Follow from left to right
|
298
|
+
#Finds/Creates/assigns each model consecutively
|
299
|
+
# assigning each previous_model as parent to current
|
300
|
+
# |Jurisdiciton|Location|Batch|
|
301
|
+
# also supports assigning attributes to previous model.
|
302
|
+
# |Jurisdiciton|Location|location_code|
|
303
|
+
When /^we setup the following:$/ do |table|
|
304
|
+
# table is a |US |L1 |L1_B1 |
|
305
|
+
|
306
|
+
table.rows.each do |row|
|
307
|
+
previous_model = nil
|
308
|
+
|
309
|
+
table.headers.each_with_index do |header, column_index|
|
310
|
+
value = row[column_index]
|
311
|
+
|
312
|
+
if previous_model && previous_model.respond_to?("#{header}=")
|
313
|
+
previous_model.update_attributes!(header => value)
|
314
|
+
next
|
315
|
+
end
|
316
|
+
|
317
|
+
factory_name = model_to_factory_symbol(header)
|
318
|
+
model_klass = header.classify.constantize
|
319
|
+
new_model = model_klass.find_by_default_identifier(value)
|
320
|
+
|
321
|
+
new_model_params = {}
|
322
|
+
if previous_model
|
323
|
+
parent = previous_model
|
324
|
+
parent_association = previous_model.class.name.underscore
|
325
|
+
|
326
|
+
case model_klass.name
|
327
|
+
when IncidentBatch.name #compare class to class did NOT work??
|
328
|
+
parent = previous_model.location_camera
|
329
|
+
parent_association = 'location_camera'
|
330
|
+
end
|
331
|
+
new_model_params.merge!({ parent_association => parent })
|
332
|
+
end
|
333
|
+
|
334
|
+
if new_model
|
335
|
+
new_model.update_attributes! new_model_params
|
336
|
+
else
|
337
|
+
new_model_params.merge!({ model_klass.default_identifier_column => value })
|
338
|
+
new_model = Factory.create(factory_name, new_model_params)
|
339
|
+
end
|
340
|
+
|
341
|
+
previous_model = new_model
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
#When method on ModelA:ID
|
347
|
+
When /^I "([^"]+)" for (.+):(.+)$/ do |requested_method_name, requested_model, default_identifier|
|
348
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
349
|
+
model_under_test.send(requested_method_name.underscore)
|
350
|
+
end
|
351
|
+
|
352
|
+
#Then Model:default_identifier should exist
|
353
|
+
Then /^(.+):(.+) should exist$/ do |requested_model, default_identifier|
|
354
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
355
|
+
model_under_test.should_not be_nil
|
356
|
+
end
|
357
|
+
|
358
|
+
Given /^no (\D+) should exist$/ do |requested_models|
|
359
|
+
model_klass = requested_model_to_model(requested_models)
|
360
|
+
model_klass.count.should == 0
|
361
|
+
end
|
362
|
+
|
363
|
+
#Then the following ModelAs should exist
|
364
|
+
#Works against actual models (instead of view)
|
365
|
+
#Verifies model count and each method in each row.
|
366
|
+
#Assumes:
|
367
|
+
# * Header = method name
|
368
|
+
# * the first column in each row is the default identifier for that row.
|
369
|
+
Then /^(?:these|the following) (.+) should exist:$/ do |requested_model, table|
|
370
|
+
# table is a Cucumber::Ast::Table
|
371
|
+
model_klass = requested_model_to_model(requested_model)
|
372
|
+
|
373
|
+
models_to_verify = requested_models(requested_model)
|
374
|
+
assert_models(table, models_to_verify)
|
375
|
+
end
|
376
|
+
|
377
|
+
Then /^there should be (\d*) (.*)$/ do |cnt, requested_model|
|
378
|
+
requested_model_to_model(requested_model).count.should == cnt.to_i
|
379
|
+
end
|
380
|
+
|
381
|
+
###Predicates: Location:L1 should [not] be_reachable
|
382
|
+
###Moved these to rspec. Left as example. Feel free to delete.
|
383
|
+
#Then /^(\D+):(.+) (should|should not) (be \D+)$/ do |requested_model, default_identifier, expectation, predicate_matcher|
|
384
|
+
# model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
385
|
+
# model_under_test.send(expectation.underscore, send(predicate_matcher.underscore))
|
386
|
+
#end
|
387
|
+
|
388
|
+
#Then Location:L1 should have the following Pings
|
389
|
+
#Works against actual models (instead of view)
|
390
|
+
#Verifies model count and each method in each row.
|
391
|
+
#Assumes:
|
392
|
+
# * Header = method name
|
393
|
+
# * the first column in each row is the default identifier for that row.
|
394
|
+
Then /^(\w+):(.+) should have (?:these|the following|this) (.+):$/ do |requested_model, default_identifier, association, table|
|
395
|
+
# table is a Cucumber::Ast::Table
|
396
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
397
|
+
|
398
|
+
associated_models = model_under_test.send(association.underscore)
|
399
|
+
assert_models(table, associated_models)
|
400
|
+
end
|
401
|
+
|
402
|
+
#Then ModelA should have 1 ModelB
|
403
|
+
Then /^(\w+):(.+) should have (\d+) (.+)$/ do |requested_model, default_identifier, association_count, association|
|
404
|
+
model_under_test = requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
405
|
+
|
406
|
+
associated_models = model_under_test.send(association.underscore)
|
407
|
+
associated_models.size.should == association_count.to_i
|
408
|
+
end
|
409
|
+
|
410
|
+
|
411
|
+
private
|
412
|
+
|
413
|
+
#Compare table values against the expected_models' methods
|
414
|
+
#Use '*' as a wild card.
|
415
|
+
#
|
416
|
+
#Assumes:
|
417
|
+
# * Header = method name
|
418
|
+
# * the first column in each row is the default identifier for that row.
|
419
|
+
def assert_models(table, *expected_models)
|
420
|
+
expected_models.flatten!
|
421
|
+
model_klass = expected_models.first && expected_models.first.class.base_class rescue expected_models.first.class #support non-AR models
|
422
|
+
|
423
|
+
map_table_columns!(table)
|
424
|
+
rows = map_table_headers(table).hashes
|
425
|
+
expected_models.count.should == rows.size
|
426
|
+
|
427
|
+
first_column_name = table.headers[0]
|
428
|
+
|
429
|
+
rows.each_with_index do |requested_params, row_index|
|
430
|
+
#Assume first column is unique identifier
|
431
|
+
#TODO: just use all columns as conditions.
|
432
|
+
default_identifier = requested_params[first_column_name]
|
433
|
+
|
434
|
+
#find the model for this row
|
435
|
+
model_under_test = expected_models.detect {|model| model.send(first_column_name).to_s == default_identifier }
|
436
|
+
|
437
|
+
#compare model with expectations
|
438
|
+
requested_params.each do |attribute_name, expected_value|
|
439
|
+
actual = model_under_test.send(attribute_name)
|
440
|
+
if actual.is_a?(ActiveRecord::Base)
|
441
|
+
#if AR model, compare against value of default_identifier_column
|
442
|
+
actual = actual.send(actual.class.default_identifier_column)
|
443
|
+
end
|
444
|
+
|
445
|
+
err_msg = "Expected ##{attribute_name} for '#{model_klass.name}:#{default_identifier}'\n\t to be: '#{expected_value}'\n\tbut was: '#{actual}'\n * Expectations: #{requested_params.inspect} \n * #{model_klass.name}:#{default_identifier}: #{model_under_test.inspect}.\n\n"
|
446
|
+
if expected_value =~ /[*]/ #has wild card
|
447
|
+
expected_value = expected_value.gsub('*', '.*')
|
448
|
+
actual.to_s.should match(expected_value), err_msg
|
449
|
+
else
|
450
|
+
actual.to_s.should eql(expected_value.to_s), err_msg
|
451
|
+
end
|
452
|
+
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
def requested_model_with_identifier_to_model_instance(requested_model, default_identifier)
|
458
|
+
model = requested_model_to_model(requested_model)
|
459
|
+
model_under_test = model.find_by_default_identifier!(default_identifier)
|
460
|
+
return model_under_test
|
461
|
+
rescue ActiveRecord::RecordNotFound
|
462
|
+
factory_name = model_to_factory_symbol(requested_model)
|
463
|
+
Factory.create(factory_name, model.default_identifier_column => default_identifier)
|
464
|
+
end
|
465
|
+
|
466
|
+
def assign_requested_model_associations(model_under_test, association_quantity, requested_association_name, array_of_requested_params = [])
|
467
|
+
model = model_under_test.class
|
468
|
+
|
469
|
+
association_model = requested_model_to_model(requested_association_name)
|
470
|
+
association_name = association_model.name.pluralize.underscore
|
471
|
+
|
472
|
+
|
473
|
+
#TODO: utilize associations in find
|
474
|
+
#convert {'location' => 'L1'}
|
475
|
+
# to {:location_id => 1}
|
476
|
+
# aka {:association.foreign_key => requested_model.id}
|
477
|
+
|
478
|
+
existing_objects = array_of_requested_params.collect do |conditions|
|
479
|
+
if conditions.keys.first == 'default_identifier'
|
480
|
+
#for CameraEvent find by (ImportFile).name
|
481
|
+
association_model.find_by_default_identifier(conditions.values.first)
|
482
|
+
else
|
483
|
+
association_model.find(:first, :conditions => conditions)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
#assign to parent
|
488
|
+
model_under_test.send("#{association_name}=", existing_objects)
|
489
|
+
|
490
|
+
assert_equal association_quantity, model_under_test.send(association_name).size, "#{model.name} has incorrect # of #{association_name}"
|
491
|
+
end
|
492
|
+
|
493
|
+
#polymorphic associations are handled during 'assign_to_parent'
|
494
|
+
def create_requested_model_associations(model_under_test, association_quantity, requested_association_name, array_of_requested_params = [], default_params = {})
|
495
|
+
model = model_under_test.class
|
496
|
+
|
497
|
+
association_model = requested_model_to_model(requested_association_name)
|
498
|
+
association_name = model_to_association_method(requested_association_name)
|
499
|
+
association_factory_name = model_to_factory_symbol(requested_association_name)
|
500
|
+
|
501
|
+
parent_association = {}
|
502
|
+
parent = model.name.underscore
|
503
|
+
|
504
|
+
parent_association = {}
|
505
|
+
if association_model.instance_methods.include?(parent)
|
506
|
+
parent_association = {parent => model_under_test}
|
507
|
+
elsif association_model.instance_methods.include?(parent.pluralize)
|
508
|
+
parent_association = {parent.pluralize => [model_under_test]}
|
509
|
+
end
|
510
|
+
|
511
|
+
objects_to_associate = association_quantity.times.collect do |idx|
|
512
|
+
|
513
|
+
#parse requested params
|
514
|
+
converted_params = {}
|
515
|
+
unless array_of_requested_params.blank?
|
516
|
+
requested_params = array_of_requested_params[idx].dup
|
517
|
+
converted_params = requested_params_to_model_params(requested_params, association_model)
|
518
|
+
end
|
519
|
+
|
520
|
+
association_model_params = {}
|
521
|
+
association_model_params.merge!(parent_association)
|
522
|
+
association_model_params.merge!(default_params.merge(converted_params))
|
523
|
+
cleaned_params = {}
|
524
|
+
association_model_params.each {|key, value| cleaned_params[key] = (value.blank? ? nil : value) }
|
525
|
+
Factory.create(association_factory_name, cleaned_params)
|
526
|
+
end
|
527
|
+
|
528
|
+
#assign to parent
|
529
|
+
if association_name == association_name.singularize
|
530
|
+
model_under_test.send("#{association_name}=", objects_to_associate.first)
|
531
|
+
|
532
|
+
#TODO: why odes it perform the assignment (verified in db), but still return nil?
|
533
|
+
assert_not_nil model_under_test.send(association_name)
|
534
|
+
else
|
535
|
+
#append objects, do not assign array of objects.
|
536
|
+
objects_to_associate.each do |associated_object|
|
537
|
+
association = model_under_test.send("#{association_name}")
|
538
|
+
association.send('<<', associated_object) unless association.include?(associated_object)
|
539
|
+
end
|
540
|
+
# model_under_test.send("#{association_name}=", objects_to_associate)
|
541
|
+
scoped_association_name = model_to_association_method(requested_association_name, true)
|
542
|
+
association, scope = scoped_association_name.split('.')
|
543
|
+
associated_models = model_under_test.send(association)
|
544
|
+
if scope
|
545
|
+
associated_models = associated_models.send(scope)
|
546
|
+
end
|
547
|
+
assert_equal association_quantity, associated_models.size, "#{model.name} has incorrect # of #{scoped_association_name}"
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
def fill_in_required_fields(requested_model, rejected_fields = [])
|
552
|
+
model = requested_model_to_model(requested_model)
|
553
|
+
model_under_test = model.new(Factory.attributes_for(requested_model.underscore.to_sym))
|
554
|
+
testable_attributes = model_under_test.attributes.reject {|attribute_name, value| rejected_fields.include?(attribute_name) }
|
555
|
+
|
556
|
+
testable_attributes.each do |attribute_name, value|
|
557
|
+
if model_under_test.attribute_required?(attribute_name)
|
558
|
+
When "I fill in \"#{attribute_name.to_s.titleize}\" with \"#{value}\""
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
def map_table_columns!(table)
|
564
|
+
table.map_chronic_columns!
|
565
|
+
table.map_columns!(['size']) { |cell_value| eval(cell_value) if cell_value }
|
566
|
+
table.map_columns!(['trouble']) {|trouble_message| Factory.create(:trouble, :message => trouble_message)}
|
567
|
+
end
|
568
|
+
|
569
|
+
def map_table_header(header)
|
570
|
+
#TODO: associations should be underscore'd
|
571
|
+
# mapped_header = header.columnify
|
572
|
+
mapped_header = header
|
573
|
+
mapped_header.sub!('#', 'Number')
|
574
|
+
case header
|
575
|
+
when 'printer'
|
576
|
+
mapped_header = 'printer_prefix'
|
577
|
+
end
|
578
|
+
mapped_header
|
579
|
+
end
|
580
|
+
|
581
|
+
def map_table_headers(table)
|
582
|
+
|
583
|
+
returning(mappings = {}) do
|
584
|
+
table.headers.each do |header|
|
585
|
+
mappings[header] = map_table_header(header)
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
table.map_headers(mappings)
|
590
|
+
end
|
591
|
+
|
592
|
+
#converts model or model name to symbol for factory
|
593
|
+
#Examples:
|
594
|
+
# image --> :image
|
595
|
+
# Image --> :image
|
596
|
+
# Images --> :image
|
597
|
+
# Images(for scene A) --> :image_for_scene_a
|
598
|
+
#
|
599
|
+
def model_to_factory_symbol(model_or_name)
|
600
|
+
model_name =
|
601
|
+
case model_or_name
|
602
|
+
when /^(.+)[(](.+)[)]$/ #handle model(with associations), model(for scene A)
|
603
|
+
model_name = $1.singularize
|
604
|
+
factory_suffix = $2
|
605
|
+
"#{model_name}_#{factory_suffix}"
|
606
|
+
when String
|
607
|
+
model_or_name
|
608
|
+
else
|
609
|
+
model_or_name.name
|
610
|
+
end
|
611
|
+
model_name.singularize.underscore.to_sym
|
612
|
+
end
|
613
|
+
|
614
|
+
#converts model or model name to association method
|
615
|
+
#Examples:
|
616
|
+
# image --> .image
|
617
|
+
# Image --> .image
|
618
|
+
# Images --> .images
|
619
|
+
# Images(for scene A) --> .images.for_scene_a
|
620
|
+
#
|
621
|
+
def model_to_association_method(model_or_name, include_scope = false)
|
622
|
+
requested_association =
|
623
|
+
case model_or_name
|
624
|
+
when /^(.+)[(](.+)[)]$/ #handle model(with associations), i.e. Image(for scene A)
|
625
|
+
association = $1
|
626
|
+
scope = $2
|
627
|
+
include_scope ? "#{association}.#{scope}" : association
|
628
|
+
when String
|
629
|
+
model_or_name
|
630
|
+
else
|
631
|
+
model_or_name.name
|
632
|
+
end
|
633
|
+
requested_association.underscore
|
634
|
+
end
|
635
|
+
|
636
|
+
#Retrieves requested models
|
637
|
+
#
|
638
|
+
#examples:
|
639
|
+
# image --> Image.all
|
640
|
+
# Image --> Image.all
|
641
|
+
# Images --> Image.all
|
642
|
+
# Images(for scene A) --> Image.for_scene_a
|
643
|
+
# Images(active, for scene A) --> Image.active.for_scene_a
|
644
|
+
def requested_models(requested_model)
|
645
|
+
case requested_model
|
646
|
+
when /^(.+)[(](.+)[)]$/ #handle model(with associations), i.e. Image(for scene A)
|
647
|
+
base_model = $1.classify.constantize
|
648
|
+
scopes = $2.split(',')
|
649
|
+
models = base_model
|
650
|
+
|
651
|
+
scopes.each do |scope|
|
652
|
+
models = models.send(scope.strip)
|
653
|
+
end
|
654
|
+
|
655
|
+
models.all
|
656
|
+
|
657
|
+
when String #is name
|
658
|
+
requested_model.singularize.constantize.all
|
659
|
+
else
|
660
|
+
requested_model.all
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
664
|
+
|
665
|
+
def perform_activity(model, default_identifier, requested_activity)
|
666
|
+
model_under_test = model.find_by_default_identifier(default_identifier)
|
667
|
+
activity = model_under_test.send("do#{requested_activity.singularize}".underscore)
|
668
|
+
end
|
669
|
+
|
670
|
+
#TODO: extract concept for these
|
671
|
+
def requested_model_to_model(requested_model)
|
672
|
+
#move "cases" to mpr_model_steps.
|
673
|
+
case requested_model
|
674
|
+
when /^Site[s]?$/i, /^PhosphorylationSite[s]?$/i
|
675
|
+
return StySiteAbstractGene
|
676
|
+
when /^(.+)[(](.+)[)]$/ #handle model(with associations), model(for scene a)
|
677
|
+
return requested_model_to_model($1)
|
678
|
+
else
|
679
|
+
possible_model_name = requested_model.singularize.underscore.classify
|
680
|
+
#Note Ping class exists, so check for PingActivity first.
|
681
|
+
return "#{possible_model_name}Activity".constantize rescue nil
|
682
|
+
return possible_model_name.constantize rescue nil
|
683
|
+
end
|
684
|
+
|
685
|
+
raise "Requested Model (#{requested_model}, as #{possible_model_name}) is not supported."
|
686
|
+
end
|
687
|
+
|
688
|
+
|
689
|
+
def requested_params_to_model_params(requested_params, model)
|
690
|
+
converted_params = {}
|
691
|
+
#pull put associations
|
692
|
+
association_names = model.reflect_on_all_associations.collect &:name
|
693
|
+
|
694
|
+
mapped_params = {}
|
695
|
+
requested_params.each {|header, value| mapped_params[header.columnify] = value}
|
696
|
+
|
697
|
+
association_params = mapped_params.reject { |param_name, value| !association_names.include?(ModelSteps::Inflector.param_to_association_name(param_name)) }
|
698
|
+
association_params.each do |param_name, value|
|
699
|
+
next unless value
|
700
|
+
|
701
|
+
association_name = ModelSteps::Inflector.param_to_association_name(param_name).to_s
|
702
|
+
|
703
|
+
if value.include?(':') #is a model:unique_id
|
704
|
+
associated_model_class_name, default_identifier = value.split(':')
|
705
|
+
else
|
706
|
+
association = model.reflect_on_all_associations.detect {|each_association| each_association.name == ModelSteps::Inflector.param_to_association_name(param_name)}
|
707
|
+
associated_model_class_name = association.options[:class_name] || association_name.classify
|
708
|
+
default_identifier = value
|
709
|
+
end
|
710
|
+
|
711
|
+
associated_model = associated_model_class_name.constantize.find_by_default_identifier(default_identifier)
|
712
|
+
|
713
|
+
# TODO handle multiple associations
|
714
|
+
if /s$/ =~ association_name
|
715
|
+
converted_params[association_name] = [associated_model]
|
716
|
+
else
|
717
|
+
converted_params[association_name] = associated_model
|
718
|
+
end
|
719
|
+
end
|
720
|
+
|
721
|
+
model_ar_attr_params = mapped_params.reject {|param_name, value| !model.column_names.include?(param_name)}
|
722
|
+
model_attr_setter_params = mapped_params.reject {|param_name, value| !model.instance_methods.include?(param_name + '=') || association_params.keys.include?(param_name + '=')}
|
723
|
+
|
724
|
+
|
725
|
+
model_setter_params = mapped_params.reject {|param_name, value| !model_ar_attr_params.keys.include?(param_name) && !model_attr_setter_params.keys.include?(param_name) }
|
726
|
+
|
727
|
+
#TODO: pass date_column_names from class, instead of class?
|
728
|
+
model_params = model_setter_params#.parse_dates(model)
|
729
|
+
|
730
|
+
non_model_params = mapped_params.reject do |param_name, value|
|
731
|
+
model_setter_params.keys.include?(param_name) || association_params.keys.include?(param_name)
|
732
|
+
end
|
733
|
+
|
734
|
+
non_model_params.each do |param_name, value|
|
735
|
+
case param_name
|
736
|
+
when 'location_code'
|
737
|
+
location_association = model.new.is_a?(Activity) ? :toiler : :location
|
738
|
+
converted_params[location_association] = Location.find_by_location_code(value)
|
739
|
+
when 'success?'
|
740
|
+
success = non_model_params['success?'].to_bool
|
741
|
+
unless success
|
742
|
+
converted_params[:command_trouble] = CommandTrouble.new(:message => 'TESTING TROUBLE')
|
743
|
+
end
|
744
|
+
when 'trouble'
|
745
|
+
message = non_model_params['trouble']
|
746
|
+
converted_params[:trouble] = Trouble.new(:message => message) if message
|
747
|
+
else
|
748
|
+
#TODO:
|
749
|
+
raise "Header (#{param_name}) is not supported for #{model.name}."
|
750
|
+
end
|
751
|
+
end
|
752
|
+
model_params.merge(converted_params)
|
753
|
+
end
|
754
|
+
|
755
|
+
module ModelSteps
|
756
|
+
class Inflector
|
757
|
+
def self.param_to_association_name(param_name)
|
758
|
+
param_name.underscore.to_sym
|
759
|
+
end
|
760
|
+
end
|
761
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mattscilipoti-model_steps
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matt Scilipoti
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-24 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: micronaut
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: cucumber
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description: Model Steps for cucumber
|
36
|
+
email: matt@scilipoti.name
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- examples/example_helper.rb
|
52
|
+
- examples/mattscilipoti-model_steps_example.rb
|
53
|
+
- features/mattscilipoti-model_steps.feature
|
54
|
+
- features/step_definitions/mattscilipoti-model_steps_steps.rb
|
55
|
+
- features/support/env.rb
|
56
|
+
- lib/mattscilipoti-model_steps.rb
|
57
|
+
- lib/model_steps/step_definitions.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://github.com/mattscilipoti/mattscilipoti-model_steps
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options:
|
64
|
+
- --charset=UTF-8
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.3.5
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: Model Steps for cucumber
|
86
|
+
test_files:
|
87
|
+
- examples/example_helper.rb
|
88
|
+
- examples/mattscilipoti-model_steps_example.rb
|