= pickle

Pickle gives you cucumber steps that create your models easily from factory-girl or
machinist factories/blueprints.  You can also just use ActiveRecord but it's not as cool.

References to the models are stored in the current world, not necessarily for the purpose of checking the db
(although you could use it for that), but for enabling easy reference to urls, and for
building complex givens which require a bunch of models collaborating

== Resources

<b>Github</b> for code: http://github.com/ianwhite/pickle

<b>Gemcutter</b> for the gem: http://gemcutter.org/gems/pickle

<b>API</b> docs: {Pickle rdoc on github}[http://ianwhite.github.com/pickle/doc/]

<b>Google group</b> for questions: http://groups.google.com/group/pickle-cucumber

<b>Lighthouse</b> for bugs: http://ianwhite.lighthouseapp.com/projects/25941-pickle

<b>Railscast</b> presentation: http://railscasts.com/episodes/186-pickle-with-cucumber

<b>Blog articles</b>: {dynamic50: Integration testing with cucumber and pickle}[http://blog.dynamic50.com/index.php/2009/04/integration-testing-with-cucumber-and-pickle/], {rubyflare: pickle my cucumber}[http://rubyflare.com/2009/10/28/pickle-my-cucumber/]

== Install

Install pickle either as a rails plugin, or a gem

  # gem from gemcutter
  sudo gem install pickle

  # gem dependency (in config/environments/cucumber.rb)
  config.gem 'pickle'

  # plugin
  script/plugin install git://github.com/ianwhite/pickle.git
  
  # or, plugin as submodule
  git submodule add git://github.com/ianwhite/pickle.git vendor/plugins/pickle

== CI

It's tested against all stable branches of 2.x rails, and edge, with the latest versions of rspec, cucumber, factory_girl, machinist.

== Run the tests

To run the specs do:

  rake spec
  
To run the features (rails 2.3 only ATM):

  rake cucumber

== Contributors

The following people have made Pickle better:

* {Nick Rutherford}[http://github.com/nruth]
* {Tobi Knaup}[http://github.com/guenter]
* {Michael MacDonald}[http://github.com/schlick]
* {Michael Moen}[http://github.com/UnderpantsGnome]
* {Myron Marston}[http://github.com/myronmarston]
* {Stephan Hagemann}[http://github.com/xing]
* {Chris Flipse}[http://github.com/cflipse]

== Get Started

(you'd better install cucumber)

  script/generate pickle [paths] [email]

Now have a look at <tt>features/step_definitions/pickle_steps.rb</tt>

If you want path steps and email steps then just add 'paths' and/or 'email'.  The code/steps will be
written to <tt>features/env/paths.rb</tt> and
<tt>features/step_definitions/email_steps.rb</tt> respectively.

=== Using with plain ole Active Record

If you have an AR called 'Post', with required fields 'title', and 'body', then you can now write 
steps like this

  Given a post exists with title: "My Post", body: "My body"

=== Using with factory-girl or machinist

But you're using Machinist or FactoryGirl right?!  To leverage all of the factories/blueprints
you've written, you can just do stuff like

  Given a user exists
  And another user exists with role: "admin"

  # later
  Then a user should exist with name: "Fred"
  And that user should be activated # this uses rspec predicate matchers

==== Machinst: require your blueprints and reset Shams

(The latest version of pickle supports {multiple blueprints}[http://github.com/notahat/machinist/commit/d6492e6927a8aa1819926e48b22377171fd20496], for 
earlier versions of machinist use pickle <= 0.1.10)

In your <tt>features/support/env.rb</tt> add the following lines at the bottom

  require "#{Rails.root}/spec/blueprints" # or wherever they live
  Before { Sham.reset } # reset Shams in between scenarios

==== FactoryGirl: make sure factories are loaded

In your config/environments/cucumber.rb file, make sure the factory-girl gem is included (unless it's installed as a plugin).

If that doesn't solve loading issues then require your factories.rb file directly in a file called 'features/support/factory_girl.rb'

  # example features/support/factory_girl.rb
  require File.dirname(__FILE__) + '/../../spec/factories'

=== Configuring Pickle

You can tell pickle to use another factory adapter (see Pickle::Adapter), or
create mappings from english expressions to pickle model names.  You can also
override many of the options on the Pickle::Config object if you so choose.

In: <tt>features/support/pickle.rb</tt>

  require 'pickle/world'

  Pickle.configure do |config|
    config.adapters = [:machinist, YourOwnAdapterClass]
    config.map 'me', 'myself', 'my', 'I', :to => 'user: "me"'
  end
  
Out of the box pickle looks for machinist, then factory-girl, then finally active-record 'factories'.
If you find that your steps aren't working with your factories, it's probably the case that your factory
setup is not being included in your cucumber environment (see comments above regarding machinist and factory-girl).

== API

=== Steps

When you run <tt>script/generate pickle</tt> you get the following steps

==== Given steps

"Given <b>a model</b> exists",  e.g.

  Given a user exists
  Given a user: "fred" exists
  Given the user exists
  
"Given <b>a model</b> exists with <b>fields</b>",  e.g.

  Given a user exists with name: "Fred"
  Given a user exists with name: "Fred", activated: false
  
You can refer to other models in the fields

  Given a user exists
  And a post exists with author: the user
  
  Given a person: "fred" exists
  And a person: "ethel" exists
  And a fatherhood exists with parent: user "fred", child: user "ethel"
  
"Given <b>n models</b> exist", e.g.
  
  Given 10 users exist
  
"Given <b>n models</b> exist with <b>fields</b>", examples:

  Given 10 users exist with activated: false
  
"Given the following <b>models</b> exist:", examples:

  Given the following users exist
    | name  | activated |
    | Fred  | false     |
    | Ethel | true      |

==== Then steps

===== Asserting existence of models

"Then <b>a model</b> should exist",  e.g.

  Then a user should exist

"Then <b>a model</b> should exist with <b>fields</b>", e.g.

  Then a user: "fred" should exist with name: "Fred" # we can label the found user for later use
  
You can use other models, booleans, numerics, and strings as fields

  Then a person should exist with child: person "ethel"
  Then a user should exist with activated: false
  Then a user should exist with activated: true, email: "fred@gmail.com"
  
"Then <b>n models</b> should exist", e.g.

  Then 10 events should exist
  
"Then <b>n models</b> should exist with <b>fields</b>", e.g.

  Then 2 people should exist with father: person "fred"
  
"Then the following <b>models</b> exist". This allows the creation of multiple models
using a table syntax. Using a column with the singularized name of the model creates a referenceable model. E.g.

  Then the following users exist:
    | name   | activated |
    | Freddy | false     |

  Then the following users exist:
    | user | name   | activated |
    | Fred | Freddy | false     |
  
===== Asserting associations

One-to-one assocs: "Then <b>a model</b> should be <b>other model</b>'s <b>association</b>", e.g.

  Then the person: "fred" should be person: "ethel"'s father
  
Many-to-one assocs: "Then <b>a model</b> should be [in|one of] <b>other model</b>'s <b>association</b>", e.g.

  Then the person: "ethel" should be one of person: "fred"'s children
  Then the comment should be in the post's comments
  
===== Asserting predicate methods

"Then <b>a model</b> should [be|have] [a|an] <b>predicate</b>", e.g.
  
  Then the user should have a status # => user.status.should be_present
  Then the user should have a stale password # => user.should have_stale_password
  Then the car: "batmobile" should be fast # => car.should be_fast
  
"Then <b>a model</b> should not [be|have] [a|an] <b>predicate</b>", e.g.

  Then person: "fred" should not be childless # => fred.should_not be_childless
  
=== Regexps for use in your own steps

By default you get some regexps available in the main namespace for use
in creating your own steps: `capture_model`, `capture_fields`, and others (see lib/pickle.rb)

(You can use any of the regexps that Pickle uses by using the Pickle.parser namespace, see
Pickle::Parser::Matchers for the methods available)

*capture_model*

  Given /^#{capture_model} exists$/ do |model_name|
    model(model_name).should_not == nil
  end

  Then /^I should be at the (.*?) page$/ |page|
    if page =~ /#{capture_model}'s/
      url_for(model($1))
    else
      # ...
    end
  end

  Then /^#{capture_model} should be one of #{capture_model}'s posts$/ do |post, forum|
    post = model!(post)
    forum = model!(forum)
    forum.posts.should include(post)
  end 

*capture_fields*

This is useful for setting attributes, and knows about pickle model names so that you
can build up composite objects with ease

  Given /^#{capture_model} exists with #{capture_fields}$/ do |model_name, fields|
    create_model(model_name, fields)
  end

  # example of use
  Given a user exists
  And a post exists with author: the user # this step will assign the above user as :author on the post