cucumber_factory 1.4.0 → 1.5.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/.gitignore +2 -0
- data/README.rdoc +12 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/cucumber_factory.gemspec +22 -17
- data/lib/cucumber/factory.rb +109 -0
- data/lib/cucumber/step_mother_ext.rb +36 -0
- data/lib/cucumber_factory.rb +2 -2
- data/spec/factory_spec.rb +0 -111
- data/spec/spec_helper.rb +7 -56
- data/spec/step_mother_ext_spec.rb +29 -0
- data/spec/steps_spec.rb +115 -0
- data/spec/{rcov.opts → support/rcov.opts} +0 -0
- data/spec/{spec.opts → support/spec.opts} +0 -0
- metadata +29 -17
- data/lib/cucumber_factory/factory.rb +0 -108
data/README.rdoc
CHANGED
@@ -43,6 +43,18 @@ You can use named Machinist blueprint such as <tt>Movie.blueprint(:comedy)</tt>
|
|
43
43
|
|
44
44
|
Inherited factory_girl factories are not supported yet.
|
45
45
|
|
46
|
+
== Overriding factory steps
|
47
|
+
|
48
|
+
If you want to override a factory step with your own version, just do so:
|
49
|
+
|
50
|
+
Given /^there is a movie with good actors$/ do
|
51
|
+
movie = Movie.make
|
52
|
+
movie.actors << Actor.make(:name => 'Clive Owen')
|
53
|
+
movie.actors << Actor.make(:name => 'Denzel Washington')
|
54
|
+
end
|
55
|
+
|
56
|
+
Custom steps will always be preferred over factory steps. Also Cucumber will not raise a warning about ambiguous steps if the only other matching step is a factory step.
|
57
|
+
|
46
58
|
=== Credits
|
47
59
|
|
48
60
|
Henning Koch
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.5.0
|
data/cucumber_factory.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{cucumber_factory}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Henning Koch"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-06-20}
|
13
13
|
s.description = %q{Cucumber Factory allows you to create ActiveRecord models from your Cucumber features without writing step definitions for each model.}
|
14
14
|
s.email = %q{github@makandra.de}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -22,8 +22,9 @@ Gem::Specification.new do |s|
|
|
22
22
|
"Rakefile",
|
23
23
|
"VERSION",
|
24
24
|
"cucumber_factory.gemspec",
|
25
|
+
"lib/cucumber/factory.rb",
|
26
|
+
"lib/cucumber/step_mother_ext.rb",
|
25
27
|
"lib/cucumber_factory.rb",
|
26
|
-
"lib/cucumber_factory/factory.rb",
|
27
28
|
"spec/app_root/app/controllers/application_controller.rb",
|
28
29
|
"spec/app_root/app/models/job_offer.rb",
|
29
30
|
"spec/app_root/app/models/machinist_model.rb",
|
@@ -48,38 +49,42 @@ Gem::Specification.new do |s|
|
|
48
49
|
"spec/app_root/log/.gitignore",
|
49
50
|
"spec/app_root/script/console",
|
50
51
|
"spec/factory_spec.rb",
|
51
|
-
"spec/
|
52
|
-
"spec/
|
53
|
-
"spec/
|
52
|
+
"spec/spec_helper.rb",
|
53
|
+
"spec/step_mother_ext_spec.rb",
|
54
|
+
"spec/steps_spec.rb",
|
55
|
+
"spec/support/rcov.opts",
|
56
|
+
"spec/support/spec.opts"
|
54
57
|
]
|
55
58
|
s.homepage = %q{http://github.com/makandra/cucumber_factory}
|
56
59
|
s.rdoc_options = ["--charset=UTF-8"]
|
57
60
|
s.require_paths = ["lib"]
|
58
|
-
s.rubygems_version = %q{1.3.
|
61
|
+
s.rubygems_version = %q{1.3.6}
|
59
62
|
s.summary = %q{Create records from Cucumber features without writing step definitions.}
|
60
63
|
s.test_files = [
|
61
|
-
"spec/app_root/app/
|
62
|
-
"spec/app_root/app/models/movie.rb",
|
64
|
+
"spec/app_root/app/controllers/application_controller.rb",
|
63
65
|
"spec/app_root/app/models/job_offer.rb",
|
64
|
-
"spec/app_root/app/models/payment.rb",
|
65
66
|
"spec/app_root/app/models/machinist_model.rb",
|
67
|
+
"spec/app_root/app/models/movie.rb",
|
68
|
+
"spec/app_root/app/models/opera.rb",
|
69
|
+
"spec/app_root/app/models/payment.rb",
|
66
70
|
"spec/app_root/app/models/plain_ruby_class.rb",
|
67
71
|
"spec/app_root/app/models/user.rb",
|
68
|
-
"spec/app_root/
|
72
|
+
"spec/app_root/config/boot.rb",
|
69
73
|
"spec/app_root/config/environment.rb",
|
74
|
+
"spec/app_root/config/environments/in_memory.rb",
|
70
75
|
"spec/app_root/config/environments/mysql.rb",
|
71
76
|
"spec/app_root/config/environments/postgresql.rb",
|
72
|
-
"spec/app_root/config/environments/sqlite3.rb",
|
73
|
-
"spec/app_root/config/environments/in_memory.rb",
|
74
77
|
"spec/app_root/config/environments/sqlite.rb",
|
75
|
-
"spec/app_root/config/
|
78
|
+
"spec/app_root/config/environments/sqlite3.rb",
|
76
79
|
"spec/app_root/config/routes.rb",
|
77
|
-
"spec/app_root/db/migrate/002_create_users.rb",
|
78
80
|
"spec/app_root/db/migrate/001_create_movies.rb",
|
81
|
+
"spec/app_root/db/migrate/002_create_users.rb",
|
79
82
|
"spec/app_root/db/migrate/003_create_payments.rb",
|
80
83
|
"spec/app_root/lib/console_with_fixtures.rb",
|
81
|
-
"spec/
|
82
|
-
"spec/
|
84
|
+
"spec/spec_helper.rb",
|
85
|
+
"spec/step_mother_ext_spec.rb",
|
86
|
+
"spec/steps_spec.rb",
|
87
|
+
"spec/factory_spec.rb"
|
83
88
|
]
|
84
89
|
|
85
90
|
if s.respond_to? :specification_version then
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Factory
|
3
|
+
class << self
|
4
|
+
|
5
|
+
# List of Cucumber step definitions created by #add_steps
|
6
|
+
attr_reader :step_definitions
|
7
|
+
|
8
|
+
def add_steps(dsl)
|
9
|
+
@step_definitions = []
|
10
|
+
steps.each do |step|
|
11
|
+
@step_definitions << (dsl.instance_eval do
|
12
|
+
Given(step[:pattern], &step[:action])
|
13
|
+
end)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def steps
|
18
|
+
[ { :pattern => /^"([^\"]*)" is an? (.+?)( \(.+?\))?( with the .+?)?$/,
|
19
|
+
:action => lambda { |name, raw_model, raw_variant, raw_attributes| Cucumber::Factory.parse_named_creation(self, name, raw_model, raw_variant, raw_attributes) } },
|
20
|
+
{ :pattern => /^there is an? (.+?)( \(.+?\))?( with the .+?)?$/,
|
21
|
+
:action => lambda { |raw_model, raw_variant, raw_attributes| Cucumber::Factory.parse_creation(self, raw_model, raw_variant, raw_attributes) } } ]
|
22
|
+
end
|
23
|
+
|
24
|
+
# # Emulate Cucumber step matching for specs
|
25
|
+
# def parse(world, command)
|
26
|
+
# command = command.sub(/^When |Given |Then /, "")
|
27
|
+
# steps.each do |step|
|
28
|
+
# match = step[:pattern].match(command)
|
29
|
+
# if match
|
30
|
+
# step[:action].bind(world).call(*match.captures)
|
31
|
+
# return
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
# raise "No step definition for: #{command}"
|
35
|
+
# end
|
36
|
+
|
37
|
+
def parse_named_creation(world, name, raw_model, raw_variant, raw_attributes)
|
38
|
+
record = parse_creation(world, raw_model, raw_variant, raw_attributes)
|
39
|
+
variable = variable_name_from_prose(name)
|
40
|
+
world.instance_variable_set variable, record
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_creation(world, raw_model, raw_variant, raw_attributes)
|
44
|
+
model_class = model_class_from_prose(raw_model)
|
45
|
+
attributes = {}
|
46
|
+
if raw_attributes.present? && raw_attributes.strip.present?
|
47
|
+
raw_attributes.scan(/(the|and|with| )+(.*?) ("([^\"]*)"|above)/).each do |fragment|
|
48
|
+
value = nil
|
49
|
+
attribute = fragment[1].downcase.gsub(" ", "_").to_sym
|
50
|
+
value_type = fragment[2] # 'above' or a quoted string
|
51
|
+
value = fragment[3]
|
52
|
+
association = model_class.reflect_on_association(attribute) if model_class.respond_to?(:reflect_on_association)
|
53
|
+
if association.present?
|
54
|
+
if value_type == "above"
|
55
|
+
# Don't use class.last, in sqlite that is not always the last inserted element
|
56
|
+
value = association.klass.find(:last, :order => "id") or raise "There is no last #{attribute}"
|
57
|
+
else
|
58
|
+
value = world.instance_variable_get(variable_name_from_prose(value))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
attributes[attribute] = value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
variant = raw_variant.present? && /\((.*?)\)/.match(raw_variant)[1].downcase.gsub(" ", "_")
|
65
|
+
create_record(model_class, variant, attributes)
|
66
|
+
end
|
67
|
+
|
68
|
+
def model_class_from_prose(prose)
|
69
|
+
# don't use \w which depends on the system locale
|
70
|
+
prose.gsub(/[^A-Za-z0-9_]+/, "_").camelize.constantize
|
71
|
+
end
|
72
|
+
|
73
|
+
def variable_name_from_prose(prose)
|
74
|
+
# don't use \w which depends on the system locale
|
75
|
+
name = prose.downcase.gsub(/[^A-Za-z0-9_]+/, '_')
|
76
|
+
name = name.gsub(/^_+/, '').gsub(/_+$/, '')
|
77
|
+
name = "_#{name}" unless name.length >= 0 && name =~ /^[a-z]/
|
78
|
+
:"@#{name}"
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def factory_girl_factory_name(model_class)
|
84
|
+
model_class.to_s.underscore.to_sym
|
85
|
+
end
|
86
|
+
|
87
|
+
def create_record(model_class, variant, attributes)
|
88
|
+
factory_name = factory_girl_factory_name(model_class)
|
89
|
+
if defined?(::Factory) && factory = ::Factory.factories[factory_name]
|
90
|
+
::Factory.create(factory_name, attributes)
|
91
|
+
elsif model_class.respond_to?(:make) # Machinist blueprint
|
92
|
+
if variant.present?
|
93
|
+
model_class.make(variant.to_sym, attributes)
|
94
|
+
else
|
95
|
+
model_class.make(attributes)
|
96
|
+
end
|
97
|
+
elsif model_class.respond_to?(:create!) # Plain ActiveRecord
|
98
|
+
model = model_class.new
|
99
|
+
model.send(:attributes=, attributes, false) # ignore attr_accessible
|
100
|
+
model.save!
|
101
|
+
model
|
102
|
+
else
|
103
|
+
model_class.new(attributes)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'cucumber/step_mother'
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
|
5
|
+
class Ambiguous
|
6
|
+
|
7
|
+
attr_reader :matches
|
8
|
+
|
9
|
+
def initialize_with_remembering_matches(step_name, matches, *args)
|
10
|
+
@matches = matches
|
11
|
+
initialize_without_remembering_matches(step_name, matches, *args)
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method_chain :initialize, :remembering_matches
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
class StepMother
|
19
|
+
|
20
|
+
def step_match_with_factory_priority(*args)
|
21
|
+
step_match_without_factory_priority(*args)
|
22
|
+
rescue Ambiguous => e
|
23
|
+
matched_definitions = e.matches.collect(&:step_definition)
|
24
|
+
if matched_definitions.size == 2 && (Cucumber::Factory.step_definitions & matched_definitions).any?
|
25
|
+
(matched_definitions - Cucumber::Factory.step_definitions).first
|
26
|
+
else
|
27
|
+
raise
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method_chain :step_match, :factory_priority
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
data/lib/cucumber_factory.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
|
2
|
-
require '
|
1
|
+
require 'cucumber/factory'
|
2
|
+
require 'cucumber/step_mother_ext'
|
data/spec/factory_spec.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
|
-
class Factory # for factory_girl compatibility spec
|
4
|
-
def self.factories
|
5
|
-
{}
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
3
|
describe Cucumber::Factory do
|
10
4
|
|
11
5
|
describe 'add_steps' do
|
@@ -40,110 +34,5 @@ describe Cucumber::Factory do
|
|
40
34
|
end
|
41
35
|
|
42
36
|
end
|
43
|
-
|
44
|
-
describe 'parse' do
|
45
|
-
|
46
|
-
before(:each) do
|
47
|
-
@world = Object.new
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should create ActiveRecord models by calling #new and #save!" do
|
51
|
-
movie = Movie.new
|
52
|
-
Movie.should_receive(:new).with().and_return(movie)
|
53
|
-
movie.should_receive(:save!)
|
54
|
-
Cucumber::Factory.parse(@world, "Given there is a movie")
|
55
|
-
end
|
56
|
-
|
57
|
-
it "should create models that have a machinist blueprint by calling #make" do
|
58
|
-
MachinistModel.should_receive(:make).with({ :attribute => "foo"})
|
59
|
-
Cucumber::Factory.parse(@world, 'Given there is a machinist model with the attribute "foo"')
|
60
|
-
end
|
61
|
-
|
62
|
-
it "should be able to invoke machinist blueprint variants" do
|
63
|
-
MachinistModel.should_receive(:make).with(:variant, { :attribute => "foo"})
|
64
|
-
Cucumber::Factory.parse(@world, 'Given there is a machinist model (variant) with the attribute "foo"')
|
65
|
-
end
|
66
|
-
|
67
|
-
it "should be able to invoke machinist blueprint variants containing spaces or uppercase characters in prose" do
|
68
|
-
MachinistModel.should_receive(:make).with(:variant_mark_two, { :attribute => "foo"})
|
69
|
-
Cucumber::Factory.parse(@world, 'Given there is a machinist model (Variant Mark Two) with the attribute "foo"')
|
70
|
-
end
|
71
|
-
|
72
|
-
it "should create models that have a factory_girl factory by calling #Factory.make(:model_name)" do
|
73
|
-
Factory.should_receive(:factories).with().and_return({ :job_offer => :job_offer_factory }) # Fake factory look up in factory_girl
|
74
|
-
Factory.should_receive(:create).with(:job_offer, { :title => "Awesome job" })
|
75
|
-
Cucumber::Factory.parse(@world, 'Given there is a job offer with the title "Awesome job"')
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should instantiate plain ruby classes by calling #new" do
|
79
|
-
PlainRubyClass.should_receive(:new).with({})
|
80
|
-
Cucumber::Factory.parse(@world, "Given there is a plain ruby class")
|
81
|
-
end
|
82
|
-
|
83
|
-
it "should instantiate classes with multiple words in their name" do
|
84
|
-
JobOffer.should_receive(:new).with({})
|
85
|
-
Cucumber::Factory.parse(@world, "Given there is a job offer")
|
86
|
-
end
|
87
|
-
|
88
|
-
it "should instantiate classes with uppercase characters in their name" do
|
89
|
-
user = User.new
|
90
|
-
User.should_receive(:new).and_return(user)
|
91
|
-
Cucumber::Factory.parse(@world, "Given there is a User")
|
92
|
-
end
|
93
|
-
|
94
|
-
it "should allow either 'a' or 'an' for the article" do
|
95
|
-
Opera.should_receive(:new).with({})
|
96
|
-
Cucumber::Factory.parse(@world, "Given there is an opera")
|
97
|
-
end
|
98
|
-
|
99
|
-
it "should create records with attributes" do
|
100
|
-
movie = Movie.new
|
101
|
-
Movie.stub(:new => movie)
|
102
|
-
movie.should_receive(:"attributes=").with({ :title => "Sunshine", :year => "2007" }, false)
|
103
|
-
Cucumber::Factory.parse(@world, 'Given there is a movie with the title "Sunshine" and the year "2007"')
|
104
|
-
end
|
105
|
-
|
106
|
-
it "should create records with attributes containing spaces" do
|
107
|
-
movie = Movie.new
|
108
|
-
Movie.stub(:new => movie)
|
109
|
-
movie.should_receive(:"attributes=").with({ :box_office_result => "99999999" }, false)
|
110
|
-
Cucumber::Factory.parse(@world, 'Given there is a movie with the box office result "99999999"')
|
111
|
-
end
|
112
|
-
|
113
|
-
it "should create records with attributes containing uppercase characters" do
|
114
|
-
user = User.new
|
115
|
-
User.stub(:new => user)
|
116
|
-
user.should_receive(:"attributes=").with({ :name => "Susanne" }, false)
|
117
|
-
Cucumber::Factory.parse(@world, 'Given there is a User with the Name "Susanne"')
|
118
|
-
end
|
119
|
-
|
120
|
-
it "should override attr_accessible protection" do
|
121
|
-
Cucumber::Factory.parse(@world, 'Given there is a payment with the amount "120" and the comment "Thanks for lending"')
|
122
|
-
payment = Payment.last
|
123
|
-
payment.amount.should == 120
|
124
|
-
payment.comment.should == 'Thanks for lending'
|
125
|
-
end
|
126
|
-
|
127
|
-
it "should set instance variables in the world" do
|
128
|
-
Cucumber::Factory.parse(@world, 'Given "Sunshine" is a movie with the title "Sunshine" and the year "2007"')
|
129
|
-
@world.instance_variable_get(:'@sunshine').title.should == "Sunshine"
|
130
|
-
end
|
131
|
-
|
132
|
-
it "should understand pointers to instance variables" do
|
133
|
-
Cucumber::Factory.parse(@world, 'Given "Before Sunrise" is a movie with the title "Before Sunrise"')
|
134
|
-
Cucumber::Factory.parse(@world, 'Given "Before Sunset" is a movie with the title "Before Sunset" and the prequel "Before Sunrise"')
|
135
|
-
@world.instance_variable_get(:'@before_sunset').prequel.title.should == "Before Sunrise"
|
136
|
-
end
|
137
|
-
|
138
|
-
it "should allow to point to a previously created record through 'above'" do
|
139
|
-
Cucumber::Factory.parse(@world, 'Given there is a user with the name "Jane"')
|
140
|
-
Cucumber::Factory.parse(@world, 'Given there is a movie with the title "Before Sunrise"')
|
141
|
-
Cucumber::Factory.parse(@world, 'Given there is a movie with the title "Before Sunset" and the reviewer above and the prequel above')
|
142
|
-
@before_sunset = Movie.find_by_title!("Before Sunset")
|
143
|
-
@before_sunset.prequel.title.should == "Before Sunrise"
|
144
|
-
@before_sunset.reviewer.name.should == "Jane"
|
145
|
-
end
|
146
|
-
|
147
|
-
end
|
148
37
|
|
149
38
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
1
|
$: << File.join(File.dirname(__FILE__), "/../lib" )
|
2
|
-
#require 'lib/cucumber_factory'
|
3
|
-
# Dir["spec/fixtures/**/*.rb"].each {|f| require f}
|
4
|
-
|
5
|
-
|
6
2
|
|
7
3
|
# Set the default environment to sqlite3's in_memory database
|
8
4
|
ENV['RAILS_ENV'] ||= 'in_memory'
|
@@ -23,55 +19,10 @@ Spec::Runner.configure do |config|
|
|
23
19
|
config.use_instantiated_fixtures = false
|
24
20
|
end
|
25
21
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
#
|
34
|
-
## Requires supporting files with custom matchers and macros, etc,
|
35
|
-
## in ./support/ and its subdirectories.
|
36
|
-
#Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
37
|
-
#
|
38
|
-
#Spec::Runner.configure do |config|
|
39
|
-
# # If you're not using ActiveRecord you should remove these
|
40
|
-
# # lines, delete config/database.yml and disable :active_record
|
41
|
-
# # in your config/boot.rb
|
42
|
-
# config.use_transactional_fixtures = true
|
43
|
-
# config.use_instantiated_fixtures = false
|
44
|
-
# config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
|
45
|
-
#
|
46
|
-
# # == Fixtures
|
47
|
-
# #
|
48
|
-
# # You can declare fixtures for each example_group like this:
|
49
|
-
# # describe "...." do
|
50
|
-
# # fixtures :table_a, :table_b
|
51
|
-
# #
|
52
|
-
# # Alternatively, if you prefer to declare them only once, you can
|
53
|
-
# # do so right here. Just uncomment the next line and replace the fixture
|
54
|
-
# # names with your fixtures.
|
55
|
-
# #
|
56
|
-
# # config.global_fixtures = :table_a, :table_b
|
57
|
-
# #
|
58
|
-
# # If you declare global fixtures, be aware that they will be declared
|
59
|
-
# # for all of your examples, even those that don't use them.
|
60
|
-
# #
|
61
|
-
# # You can also declare which fixtures to use (for example fixtures for test/fixtures):
|
62
|
-
# #
|
63
|
-
# # config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
|
64
|
-
# #
|
65
|
-
# # == Mock Framework
|
66
|
-
# #
|
67
|
-
# # RSpec uses it's own mocking framework by default. If you prefer to
|
68
|
-
# # use mocha, flexmock or RR, uncomment the appropriate line:
|
69
|
-
# #
|
70
|
-
# # config.mock_with :mocha
|
71
|
-
# # config.mock_with :flexmock
|
72
|
-
# # config.mock_with :rr
|
73
|
-
# #
|
74
|
-
# # == Notes
|
75
|
-
# #
|
76
|
-
# # For more information take a look at Spec::Runner::Configuration and Spec::Runner
|
77
|
-
#end
|
22
|
+
def prepare_cucumber_example
|
23
|
+
@step_mother = Cucumber::StepMother.new
|
24
|
+
@language = @step_mother.load_programming_language('rb')
|
25
|
+
@dsl = Object.new
|
26
|
+
@dsl.extend(Cucumber::RbSupport::RbDsl)
|
27
|
+
Cucumber::Factory.add_steps(@dsl)
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
require 'cucumber'
|
4
|
+
require 'cucumber/rb_support/rb_language'
|
5
|
+
|
6
|
+
describe Cucumber::StepMother, 'extended with cucumber_factory' do
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
prepare_cucumber_example
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'step_match' do
|
13
|
+
|
14
|
+
it "should not raise an ambiguous step error and return the user step if the only other matching step is a factory step" do
|
15
|
+
user_step = @dsl.Given(/^there is a movie with a funny tone/){}
|
16
|
+
@step_mother.step_match('there is a movie with a funny tone').should == user_step
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should still raise an ambiguous step error if more than two non-factory steps match" do
|
20
|
+
@dsl.Given(/^there is a movie with (.*?) tone/){}
|
21
|
+
@dsl.Given(/^there is a movie with a funny tone/){}
|
22
|
+
expect do
|
23
|
+
@step_mother.step_match('there is a movie with a funny tone')
|
24
|
+
end.to raise_error(Cucumber::Ambiguous)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/spec/steps_spec.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
require 'cucumber'
|
4
|
+
require 'cucumber/rb_support/rb_language'
|
5
|
+
|
6
|
+
class Factory # for factory_girl compatibility spec
|
7
|
+
def self.factories
|
8
|
+
{}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'steps provided by cucumber_factory' do
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
prepare_cucumber_example
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should create ActiveRecord models by calling #new and #save!" do
|
19
|
+
movie = Movie.new
|
20
|
+
Movie.should_receive(:new).with().and_return(movie)
|
21
|
+
movie.should_receive(:save!)
|
22
|
+
@step_mother.invoke("there is a movie")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should create models that have a machinist blueprint by calling #make" do
|
26
|
+
MachinistModel.should_receive(:make).with({ :attribute => "foo"})
|
27
|
+
@step_mother.invoke('there is a machinist model with the attribute "foo"')
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should be able to invoke machinist blueprint variants" do
|
31
|
+
MachinistModel.should_receive(:make).with(:variant, { :attribute => "foo"})
|
32
|
+
@step_mother.invoke('there is a machinist model (variant) with the attribute "foo"')
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should be able to invoke machinist blueprint variants containing spaces or uppercase characters in prose" do
|
36
|
+
MachinistModel.should_receive(:make).with(:variant_mark_two, { :attribute => "foo"})
|
37
|
+
@step_mother.invoke('there is a machinist model (Variant Mark Two) with the attribute "foo"')
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should create models that have a factory_girl factory by calling #Factory.make(:model_name)" do
|
41
|
+
Factory.should_receive(:factories).with().and_return({ :job_offer => :job_offer_factory }) # Fake factory look up in factory_girl
|
42
|
+
Factory.should_receive(:create).with(:job_offer, { :title => "Awesome job" })
|
43
|
+
@step_mother.invoke('there is a job offer with the title "Awesome job"')
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should instantiate plain ruby classes by calling #new" do
|
47
|
+
PlainRubyClass.should_receive(:new).with({})
|
48
|
+
@step_mother.invoke("there is a plain ruby class")
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should instantiate classes with multiple words in their name" do
|
52
|
+
JobOffer.should_receive(:new).with({})
|
53
|
+
@step_mother.invoke("there is a job offer")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should instantiate classes with uppercase characters in their name" do
|
57
|
+
user = User.new
|
58
|
+
User.should_receive(:new).and_return(user)
|
59
|
+
@step_mother.invoke("there is a User")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should allow either 'a' or 'an' for the article" do
|
63
|
+
Opera.should_receive(:new).with({})
|
64
|
+
@step_mother.invoke("there is an opera")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should create records with attributes" do
|
68
|
+
movie = Movie.new
|
69
|
+
Movie.stub(:new => movie)
|
70
|
+
movie.should_receive(:"attributes=").with({ :title => "Sunshine", :year => "2007" }, false)
|
71
|
+
@step_mother.invoke('there is a movie with the title "Sunshine" and the year "2007"')
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should create records with attributes containing spaces" do
|
75
|
+
movie = Movie.new
|
76
|
+
Movie.stub(:new => movie)
|
77
|
+
movie.should_receive(:"attributes=").with({ :box_office_result => "99999999" }, false)
|
78
|
+
@step_mother.invoke('there is a movie with the box office result "99999999"')
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should create records with attributes containing uppercase characters" do
|
82
|
+
user = User.new
|
83
|
+
User.stub(:new => user)
|
84
|
+
user.should_receive(:"attributes=").with({ :name => "Susanne" }, false)
|
85
|
+
@step_mother.invoke('there is a User with the Name "Susanne"')
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should override attr_accessible protection" do
|
89
|
+
@step_mother.invoke('there is a payment with the amount "120" and the comment "Thanks for lending"')
|
90
|
+
payment = Payment.last
|
91
|
+
payment.amount.should == 120
|
92
|
+
payment.comment.should == 'Thanks for lending'
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should set instance variables in the world" do
|
96
|
+
@step_mother.invoke('"Sunshine" is a movie with the title "Sunshine" and the year "2007"')
|
97
|
+
@language.current_world.instance_variable_get(:'@sunshine').title.should == "Sunshine"
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should understand pointers to instance variables" do
|
101
|
+
@step_mother.invoke('"Before Sunrise" is a movie with the title "Before Sunrise"')
|
102
|
+
@step_mother.invoke('"Before Sunset" is a movie with the title "Before Sunset" and the prequel "Before Sunrise"')
|
103
|
+
@language.current_world.instance_variable_get(:'@before_sunset').prequel.title.should == "Before Sunrise"
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should allow to point to a previously created record through 'above'" do
|
107
|
+
@step_mother.invoke('there is a user with the name "Jane"')
|
108
|
+
@step_mother.invoke('there is a movie with the title "Before Sunrise"')
|
109
|
+
@step_mother.invoke('there is a movie with the title "Before Sunset" and the reviewer above and the prequel above')
|
110
|
+
@before_sunset = Movie.find_by_title!("Before Sunset")
|
111
|
+
@before_sunset.prequel.title.should == "Before Sunrise"
|
112
|
+
@before_sunset.reviewer.name.should == "Jane"
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
File without changes
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cucumber_factory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 5
|
8
|
+
- 0
|
9
|
+
version: 1.5.0
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Henning Koch
|
@@ -9,7 +14,7 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-
|
17
|
+
date: 2010-06-20 00:00:00 +02:00
|
13
18
|
default_executable:
|
14
19
|
dependencies: []
|
15
20
|
|
@@ -28,8 +33,9 @@ files:
|
|
28
33
|
- Rakefile
|
29
34
|
- VERSION
|
30
35
|
- cucumber_factory.gemspec
|
36
|
+
- lib/cucumber/factory.rb
|
37
|
+
- lib/cucumber/step_mother_ext.rb
|
31
38
|
- lib/cucumber_factory.rb
|
32
|
-
- lib/cucumber_factory/factory.rb
|
33
39
|
- spec/app_root/app/controllers/application_controller.rb
|
34
40
|
- spec/app_root/app/models/job_offer.rb
|
35
41
|
- spec/app_root/app/models/machinist_model.rb
|
@@ -54,9 +60,11 @@ files:
|
|
54
60
|
- spec/app_root/log/.gitignore
|
55
61
|
- spec/app_root/script/console
|
56
62
|
- spec/factory_spec.rb
|
57
|
-
- spec/rcov.opts
|
58
|
-
- spec/spec.opts
|
59
63
|
- spec/spec_helper.rb
|
64
|
+
- spec/step_mother_ext_spec.rb
|
65
|
+
- spec/steps_spec.rb
|
66
|
+
- spec/support/rcov.opts
|
67
|
+
- spec/support/spec.opts
|
60
68
|
has_rdoc: true
|
61
69
|
homepage: http://github.com/makandra/cucumber_factory
|
62
70
|
licenses: []
|
@@ -70,41 +78,45 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
70
78
|
requirements:
|
71
79
|
- - ">="
|
72
80
|
- !ruby/object:Gem::Version
|
81
|
+
segments:
|
82
|
+
- 0
|
73
83
|
version: "0"
|
74
|
-
version:
|
75
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
85
|
requirements:
|
77
86
|
- - ">="
|
78
87
|
- !ruby/object:Gem::Version
|
88
|
+
segments:
|
89
|
+
- 0
|
79
90
|
version: "0"
|
80
|
-
version:
|
81
91
|
requirements: []
|
82
92
|
|
83
93
|
rubyforge_project:
|
84
|
-
rubygems_version: 1.3.
|
94
|
+
rubygems_version: 1.3.6
|
85
95
|
signing_key:
|
86
96
|
specification_version: 3
|
87
97
|
summary: Create records from Cucumber features without writing step definitions.
|
88
98
|
test_files:
|
89
|
-
- spec/app_root/app/
|
90
|
-
- spec/app_root/app/models/movie.rb
|
99
|
+
- spec/app_root/app/controllers/application_controller.rb
|
91
100
|
- spec/app_root/app/models/job_offer.rb
|
92
|
-
- spec/app_root/app/models/payment.rb
|
93
101
|
- spec/app_root/app/models/machinist_model.rb
|
102
|
+
- spec/app_root/app/models/movie.rb
|
103
|
+
- spec/app_root/app/models/opera.rb
|
104
|
+
- spec/app_root/app/models/payment.rb
|
94
105
|
- spec/app_root/app/models/plain_ruby_class.rb
|
95
106
|
- spec/app_root/app/models/user.rb
|
96
|
-
- spec/app_root/
|
107
|
+
- spec/app_root/config/boot.rb
|
97
108
|
- spec/app_root/config/environment.rb
|
109
|
+
- spec/app_root/config/environments/in_memory.rb
|
98
110
|
- spec/app_root/config/environments/mysql.rb
|
99
111
|
- spec/app_root/config/environments/postgresql.rb
|
100
|
-
- spec/app_root/config/environments/sqlite3.rb
|
101
|
-
- spec/app_root/config/environments/in_memory.rb
|
102
112
|
- spec/app_root/config/environments/sqlite.rb
|
103
|
-
- spec/app_root/config/
|
113
|
+
- spec/app_root/config/environments/sqlite3.rb
|
104
114
|
- spec/app_root/config/routes.rb
|
105
|
-
- spec/app_root/db/migrate/002_create_users.rb
|
106
115
|
- spec/app_root/db/migrate/001_create_movies.rb
|
116
|
+
- spec/app_root/db/migrate/002_create_users.rb
|
107
117
|
- spec/app_root/db/migrate/003_create_payments.rb
|
108
118
|
- spec/app_root/lib/console_with_fixtures.rb
|
109
|
-
- spec/factory_spec.rb
|
110
119
|
- spec/spec_helper.rb
|
120
|
+
- spec/step_mother_ext_spec.rb
|
121
|
+
- spec/steps_spec.rb
|
122
|
+
- spec/factory_spec.rb
|
@@ -1,108 +0,0 @@
|
|
1
|
-
module Cucumber
|
2
|
-
module Factory
|
3
|
-
|
4
|
-
def self.add_steps(world)
|
5
|
-
steps.each do |step|
|
6
|
-
world.instance_eval do
|
7
|
-
Given(step[0], &step[1].bind(world))
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.steps
|
13
|
-
[
|
14
|
-
[
|
15
|
-
/^"([^\"]*)" is an? (.+?)( \(.+?\))?( with the .+?)?$/,
|
16
|
-
lambda { |name, raw_model, raw_variant, raw_attributes| Cucumber::Factory.parse_named_creation(self, name, raw_model, raw_variant, raw_attributes) }
|
17
|
-
],
|
18
|
-
[
|
19
|
-
/^there is an? (.+?)( \(.+?\))?( with the .+?)?$/,
|
20
|
-
lambda { |raw_model, raw_variant, raw_attributes| Cucumber::Factory.parse_creation(self, raw_model, raw_variant, raw_attributes) }
|
21
|
-
]
|
22
|
-
]
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.parse(world, command)
|
26
|
-
command = command.sub(/^When |Given |Then /, "")
|
27
|
-
steps.each do |step|
|
28
|
-
match = step[0].match(command)
|
29
|
-
if match
|
30
|
-
step[1].bind(world).call(*match.captures)
|
31
|
-
return
|
32
|
-
end
|
33
|
-
end
|
34
|
-
raise "No step definition for: #{command}"
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.parse_named_creation(world, name, raw_model, raw_variant, raw_attributes)
|
38
|
-
record = parse_creation(world, raw_model, raw_variant, raw_attributes)
|
39
|
-
variable = variable_name_from_prose(name)
|
40
|
-
world.instance_variable_set variable, record
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.parse_creation(world, raw_model, raw_variant, raw_attributes)
|
44
|
-
model_class = model_class_from_prose(raw_model)
|
45
|
-
attributes = {}
|
46
|
-
if raw_attributes.present? && raw_attributes.strip.present?
|
47
|
-
raw_attributes.scan(/(the|and|with| )+(.*?) ("([^\"]*)"|above)/).each do |fragment|
|
48
|
-
value = nil
|
49
|
-
attribute = fragment[1].downcase.gsub(" ", "_").to_sym
|
50
|
-
value_type = fragment[2] # 'above' or a quoted string
|
51
|
-
value = fragment[3]
|
52
|
-
association = model_class.reflect_on_association(attribute) if model_class.respond_to?(:reflect_on_association)
|
53
|
-
if association.present?
|
54
|
-
if value_type == "above"
|
55
|
-
# Don't use class.last, in sqlite that is not always the last inserted element
|
56
|
-
value = association.klass.find(:last, :order => "id") or raise "There is no last #{attribute}"
|
57
|
-
else
|
58
|
-
value = world.instance_variable_get(variable_name_from_prose(value))
|
59
|
-
end
|
60
|
-
end
|
61
|
-
attributes[attribute] = value
|
62
|
-
end
|
63
|
-
end
|
64
|
-
variant = raw_variant.present? && /\((.*?)\)/.match(raw_variant)[1].downcase.gsub(" ", "_")
|
65
|
-
create_record(model_class, variant, attributes)
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.model_class_from_prose(prose)
|
69
|
-
# don't use \w which depends on the system locale
|
70
|
-
prose.gsub(/[^A-Za-z0-9_]+/, "_").camelize.constantize
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.variable_name_from_prose(prose)
|
74
|
-
# don't use \w which depends on the system locale
|
75
|
-
name = prose.downcase.gsub(/[^A-Za-z0-9_]+/, '_')
|
76
|
-
name = name.gsub(/^_+/, '').gsub(/_+$/, '')
|
77
|
-
name = "_#{name}" unless name.length >= 0 && name =~ /^[a-z]/
|
78
|
-
:"@#{name}"
|
79
|
-
end
|
80
|
-
|
81
|
-
private
|
82
|
-
|
83
|
-
def self.factory_girl_factory_name(model_class)
|
84
|
-
model_class.to_s.underscore.to_sym
|
85
|
-
end
|
86
|
-
|
87
|
-
def self.create_record(model_class, variant, attributes)
|
88
|
-
factory_name = factory_girl_factory_name(model_class)
|
89
|
-
if defined?(::Factory) && factory = ::Factory.factories[factory_name]
|
90
|
-
::Factory.create(factory_name, attributes)
|
91
|
-
elsif model_class.respond_to?(:make) # Machinist blueprint
|
92
|
-
if variant.present?
|
93
|
-
model_class.make(variant.to_sym, attributes)
|
94
|
-
else
|
95
|
-
model_class.make(attributes)
|
96
|
-
end
|
97
|
-
elsif model_class.respond_to?(:create!) # Plain ActiveRecord
|
98
|
-
model = model_class.new
|
99
|
-
model.send(:attributes=, attributes, false) # ignore attr_accessible
|
100
|
-
model.save!
|
101
|
-
model
|
102
|
-
else
|
103
|
-
model_class.new(attributes)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
end
|
108
|
-
end
|