h1. Cellophane
Cellophane
is a thin wrapper around “Cucumber”:github.com/aslakhellesoy/cucumber that is intended to make it easier to structure projects in ways that make sense to the people working on them. It has been tested with Cucumber 0.10.0 on Ruby 1.8.7-p302 and Ruby 1.9.2-p0.
h3. Installation
@gem install cellophane@
h3. Configuration
h4. Project-specific File
Cellophane
can be configured project by project through the use of a @.cellophane.yaml@ file that lives in the root of your project. Configurable options are:
Directive @cuke_command@
Explanation Tells Cellophane
how to call Cucumber. Defaults to @cucumber@.
Examples @cuke_command: bundle exec cucumber@ @cuke_command: script/cucumber@ @cuke_command: cuke@ (as in a shell alias)
Directive @cucumber@
Explanation Options you want to pass to Cucumber by default.
Example @cucumber: –format progress –no-profile@
Notes Anything defined by @cucumber@ in the configuration file will be overwritten by the @-c/–cucumber@ command line switch (see below).
Directive @feature_path@
Explanation Root location of your feature files. Defaults @features@.
Example @feature_path: cuke/features@
Notes The path is relative to your project's root.
Directive @step_path@
Explanation Location of your step definitions. Defaults to @features/step_definitions@. It can be defined in two ways:
# a path relative to the project root # nested in each feature directory
Examples <pre><code> step_path: cuke/steps step_path:
nested_in: step_definition
</code></pre>
Notes Use the first method if your step defitions follow the structure of your features. For example:
<pre> my_project
- app - config - cuke - features - admin - reports - user_maintenance - user - communication - profile - steps - admin - reports - user_maintenance - user - communication - profile - support - db - lib - etc, etc
</pre>
Use the second method if each feature directory has its own step definitions directory:
<pre> my_project
- app - config - features - admin - step_definitions - user - step_definitions - visitor - step_definitions - support - db - lib - etc, etc
</pre>
Directive @shared@
Explanation Automatically load steps named shared_steps.rb in all directories that comprise the step path for the current feature file. Defaults to true. This option allows you to share steps among features while keeping them organized according to scope.
Examples @shared: global@ # instead of looking for shared_steps.rb, look for global_steps.rb @shared: false@ # don't automatically require shared steps
Notes Consider the following project structure:
<pre> my_project
- app - config - cuke - features - admin - reports - user_maintenance - user - communication - profile - steps - admin - reports - user_maintenance - user - communication - profile - support - db - lib - etc, etc
</pre>
When you run a feature in @features/admin/reports/weekly.feature@, Cellophane
will automatically require shared steps found in the following locations:
@steps/admin/reports/shared_steps.rb@ # steps specific to admin reports @steps/admin/shared_steps.rb@ # steps specific to admin @steps/shared_steps.rb@ # steps used by the whole application
If your steps are nested, Cellophane
will look for shared steps only in the nested step location. For example, if your project looks like
<pre> my_project
- app - config - features - admin - step_definitions - user - step_definitions - visitor - step_definitions - support - db - lib - etc, etc
</pre>
and you run a feature in @features/admin/email.feature@, Cellophane
will look for @features/admin/step_definitions/shared_steps.rb@.
Directive @requires@
Explanation Other directories or files that Cucumber needs to require. It is an array.
Examples @requires: [cuke/support, cuke/steps/shared]@
<pre> requires:
- cuke/support - cuke/steps/shared
</pre>
Notes @requires@ are passed to Cucumber as defined, so absolute paths are respected.
h4. Command Line
Cellophane
has the following command line options:
<pre> Usage: cellophane [options] PATTERN
-r, --regexp PATTERN is a regular expression. Default is false. -t, --tags TAGS Tags to include/exclude. -c, --cucumber OPTIONS Options to pass to cucumber. -p, --print Echo the command instead of calling cucumber. -d, --debug Require ruby-debug. -v, --version Display the version. -h, --help Display this screen.
</pre>
PATTERN is the pattern of feature files that you are interested in. By default PATTERN is a glob, but by using the @-r/–regexp@ switch, you can pass a Ruby regular expression instead (no slashes necessary). When using a glob, you can specify that files matching the pattern are to be excluded by preceeding the pattern with a tilde (~). You can also combine include and exclude patterns in the same call. See below for examples.
If you need to pass something through to Cucumber, such as a formatter, use the @-c/–cucumber@ switch. Depending on what it is you are passing through, you might need to enclose it in quotes. Do keep in mind that @-c/–cucumber@ on the command line overrides that defined in the YAML file.
@-d/–debug@ is only useful for Cellophane
development and will have no effect on Cucumber.
h3. History
By default, Cucumber expects features to live in @features@ and step definitions to live in @features/step_definitions@. When running a feature, all step definitions are loaded unless you explicitly require just the ones you want. If you structure your project differently, you have to require files explicitly, which gets old real fast.
After some experimenting with different directory structures, I settled on the following for my own projects:
<pre> my_project
- app - config - cuke - features - steps - support - db - lib - etc, etc
</pre>
It's based on the structure of the @spec@ directory and I find that it fits my brain pretty well. There are three organizational strategies that I found myself following:
# separation of features in subdirectories # keeping feature specific steps in files that are named according to the feature # keeping all shared steps in files that are named in a more generalized fashion
For example, a project my look like this:
<pre> my_project
- app - config - cuke - features - admin - reports - user_maintenance - user - communication - profile - steps - admin - reports - user_maintenance - user - communication - profile - support - db - lib - etc, etc
</pre>
If the features in @cuke/features/admin/reports@ had any steps that were specific to them, they would live @cuke/steps/admin/reports@. Any steps that are shared between two or more features would go in files in @cuke/support@.
To use this structure in Cucumber requires explicitly requiring the files/directories with every run. To run all of the features in @cuke/features/admin/reports@, I would enter the command
<pre> cucumber -r cuke/support -r cuke/steps/admin/reports cuke/features/admin/reports </pre>
I got weary of doing that all the time, so I experimented with aliases and profiles, neither of which really met my needs. So I created Cellophane
. With it, the same features could be as easy as:
<pre> cellophane admin/* </pre>
As time went on, more patterns began to emerge from my workflow, and with them, Cellophane
gained abilities.
h3. Examples and Notes
h4. Features
Using the example project above:
<pre> # run all features cellophane
# run everything in admin cellophane admin/*
# run everything in admin, except the reports cellophane admin/*,~admin/reports/*
# run everything, except the admin reports cellophane ~admin/reports/*
# run all user_maintenance features regardless of where they are cellophane /user_maintenance/
# run all features in files with email in the name cellophane **/email
# or use a regular expression cellophane -r email </pre>
h4. Step Definitions
Cellophane
does assume that your steps are defined in files that follow the naming of your features. For each feature file that is found, Cellophane
will look for a step file with the same name and automatically require it. To require shared step definitions, put them in a folder and include that folder in the @requires@ section of @.cellophane.yaml@. Also look into the @shared@ directive of the configuration file, which allows more fine-grained control of shared steps.
For example, if you have a feature defined in @<feature path>/admin/user/account_maintenance.feature@, Cellophane
will automatically require a step definition file located in @<step path>/admin/user/account_maintenance_steps.rb@. Unless you are using nested step definitions in @.cellophane.yaml@ (@step_path: {nested_in: steps }@, in which case Cellophane
will automatically require @<feature path>/admin/user/steps/account_maintenance_steps.rb@ if it exists.
h4. Tags
You don't need to use @. You can if you want, but it's not necessary.
Cellophane
supports OR, AND, and NOT tags. Examples will probably illustrate better than words.
OR
<pre> cellophane -t one,two cucumber -t @one,@two </pre>
AND
<pre> cellophane -t one,+two cucumber -t @one -t @two </pre>
NOT
<pre> cellophane -t one,~two cucumber -t @one -t ~@two </pre>
Mixed tags in a logical order
<pre> cellophane -t one,two,~three,+four cucumber -t @one,@two -t @four -t ~@three </pre>
Mixed tags not in a logical order
<pre> cellophane -t +four,one,~three,two cucumber -t @one,@two -t @four -t ~@three </pre>
I like to tag my scenarios with numeric values so I can easily run a specific scenario at any give time. It may sound a bit unusual, but I find it very handy.
Numeric OR ranges
<pre> cellophane -t 1-3 cucumber -t @1,@2,@3 </pre>
Numeric NOT ranges
<pre> cellophane -t ~1-3 cucumber -t ~@1 -t ~@2 -t ~@3 </pre>
Numeric OR range with a NOT
<pre> cellophane -t 1-3,~2 cucumber -t @1,@3 </pre>