cucumber_factory 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  doc
2
2
  pkg
3
3
  *.gem
4
+ .idea
5
+
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
@@ -8,7 +8,7 @@ task :default => :spec
8
8
 
9
9
  desc "Run all specs"
10
10
  Spec::Rake::SpecTask.new() do |t|
11
- t.spec_opts = ['--options', "\"spec/spec.opts\""]
11
+ t.spec_opts = ['--options', "\"spec/support/spec.opts\""]
12
12
  t.spec_files = FileList['spec/**/*_spec.rb']
13
13
  end
14
14
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.0
1
+ 1.5.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{cucumber_factory}
8
- s.version = "1.4.0"
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-01-28}
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/rcov.opts",
52
- "spec/spec.opts",
53
- "spec/spec_helper.rb"
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.5}
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/models/opera.rb",
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/app/controllers/application_controller.rb",
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/boot.rb",
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/factory_spec.rb",
82
- "spec/spec_helper.rb"
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
+
@@ -1,2 +1,2 @@
1
- # Include hook code here
2
- require 'cucumber_factory/factory'
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
- ## This file is copied to ~/spec when you run 'ruby script/generate rspec'
28
- ## from the project root directory.
29
- #ENV["RAILS_ENV"] ||= 'test'
30
- #require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
31
- #require 'spec/autorun'
32
- #require 'spec/rails'
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
@@ -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
- version: 1.4.0
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-01-28 00:00:00 +01:00
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.5
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/models/opera.rb
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/app/controllers/application_controller.rb
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/boot.rb
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