Cellophane is a thin wrapper around 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.
gem install cellophane
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
step_path: cuke/steps
step_path:
nested_in: step_definition
Notes
Use the first method if your step defitions follow the structure of your features. For example:
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
Use the second method if each feature directory has its own step definitions directory:
my_project - app - config - features - admin - step_definitions - user - step_definitions - visitor - step_definitions - support - db - lib - etc, etc
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:
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
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
my_project - app - config - features - admin - step_definitions - user - step_definitions - visitor - step_definitions - support - db - lib - etc, etc
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]
requires: - cuke/support - cuke/steps/shared
Notes
requires
are passed to Cucumber as defined, so absolute paths are respected.
Cellophane has the following command line options:
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.
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.
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:
my_project - app - config - cuke - features - steps - support - db - lib - etc, etc
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:
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
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
cucumber -r cuke/support -r cuke/steps/admin/reports cuke/features/admin/reports
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:
cellophane admin/*
As time went on, more patterns began to emerge from my workflow, and with them, Cellophane gained abilities.
Using the example project above:
# 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
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.
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
cellophane -t one,two cucumber -t @one,@two
AND
cellophane -t one,+two cucumber -t @one -t @two
NOT
cellophane -t one,~two cucumber -t @one -t ~@two
Mixed tags in a logical order
cellophane -t one,two,~three,+four cucumber -t @one,@two -t @four -t ~@three
Mixed tags not in a logical order
cellophane -t +four,one,~three,two cucumber -t @one,@two -t @four -t ~@three
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
cellophane -t 1-3 cucumber -t @1,@2,@3
Numeric NOT ranges
cellophane -t ~1-3 cucumber -t ~@1 -t ~@2 -t ~@3
Numeric OR range with a NOT
cellophane -t 1-3,~2 cucumber -t @1,@3