Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Cucumber is a tool for running automated tests written in plain language. It allows you to write tests that anyone can understand, regardless of their technical knowledge. Cucumber supports Behavior Driven Development (BDD) and is used to bridge the communication gap between stakeholders and developers.
Writing Features in Gherkin
Cucumber uses Gherkin syntax to define test scenarios in plain language. This makes it easy for non-technical stakeholders to understand and contribute to the test cases.
Feature: User login
Scenario: Successful login
Given the user is on the login page
When the user enters valid credentials
Then the user should be redirected to the dashboard
Step Definitions
Step definitions are the actual code implementations of the steps defined in Gherkin. They link the plain language steps to executable code.
const { Given, When, Then } = require('@cucumber/cucumber');
Given('the user is on the login page', function () {
// code to navigate to login page
});
When('the user enters valid credentials', function () {
// code to enter credentials
});
Then('the user should be redirected to the dashboard', function () {
// code to check redirection
});
Hooks
Hooks allow you to run code before and after each scenario. This is useful for setting up and tearing down test environments.
const { Before, After } = require('@cucumber/cucumber');
Before(function () {
// code to run before each scenario
});
After(function () {
// code to run after each scenario
});
Data Tables
Data tables allow you to run the same scenario with multiple sets of data. This is useful for testing different input combinations.
Feature: User login
Scenario Outline: Successful login with multiple users
Given the user is on the login page
When the user enters <username> and <password>
Then the user should be redirected to the dashboard
Examples:
| username | password |
| user1 | pass1 |
| user2 | pass2 |
jest-cucumber is a library that allows you to use Cucumber's Gherkin syntax with Jest. It provides a way to write BDD-style tests using Jest as the test runner. Compared to Cucumber, jest-cucumber is more tightly integrated with Jest and may be easier to set up for projects already using Jest.
cypress-cucumber-preprocessor is a plugin for Cypress that allows you to write your tests in Gherkin syntax. It combines the power of Cypress for end-to-end testing with the readability of Cucumber. This package is ideal for teams that prefer using Cypress for their testing needs but want to leverage BDD.
CodeceptJS is an end-to-end testing framework that supports BDD-style tests. It allows you to write tests in plain language and supports multiple test runners and helpers. Compared to Cucumber, CodeceptJS offers more flexibility in terms of test runners and integrations.
Cucumber, the popular Behaviour-Driven Development tool, brought to your JavaScript stack.
It runs on both Node.js and modern web browsers.
Cucumber.js is tested on:
To see an example of cucumber-js
in a browser:
$ npm install
$ node example/server.js
http://localhost:9797
Cucumber.js is available as an npm module.
Install globally with:
$ npm install -g cucumber
Install as a development dependency of your application with:
$ npm install --save-dev cucumber
Features are written with the Gherkin syntax
# features/my_feature.feature
Feature: Example feature
As a user of Cucumber.js
I want to have documentation on Cucumber
So that I can concentrate on building awesome applications
Scenario: Reading documentation
Given I am on the Cucumber.js GitHub repository
When I go to the README file
Then I should see "Usage" as the page title
Support files let you setup the environment in which steps will be run, and define step definitions.
World is a constructor function with utility properties, destined to be used in step definitions:
// features/support/world.js
var zombie = require('zombie');
function World() {
this.browser = new zombie(); // this.browser will be available in step definitions
this.visit = function (url, callback) {
this.browser.visit(url, callback);
};
}
module.exports = function() {
this.World = World;
};
If you need to perform operations before/after every scenario, use hooks.
Step definitions are the glue between features written in Gherkin and the actual system under test. They are written in JavaScript.
All step definitions will run with this
set to what is known as the World in Cucumber. It's an object exposing useful methods, helpers and variables to your step definitions. A new instance of World
is created before each scenario.
Step definitions are contained within one or more wrapper functions.
Those wrappers are run before executing the feature suite. this
is an object holding important properties like the Given()
, When()
and Then()
functions. Another notable property is World
; it contains a default World
constructor that can be either extended or replaced.
Step definitions are run when steps match their name. this
is an instance of World
.
// features/step_definitions/my_step_definitions.js
module.exports = function () {
this.Given(/^I am on the Cucumber.js GitHub repository$/, function (callback) {
// Express the regexp above with the code you wish you had.
// `this` is set to a World instance.
// i.e. you may use this.browser to execute the step:
this.visit('https://github.com/cucumber/cucumber-js', callback);
// The callback is passed to visit() so that when the job's finished, the next step can
// be executed by Cucumber.
});
this.When(/^I go to the README file$/, function (callback) {
// Express the regexp above with the code you wish you had. Call callback() at the end
// of the step, or callback.pending() if the step is not yet implemented:
callback.pending();
});
this.Then(/^I should see "(.*)" as the page title$/, function (title, callback) {
// matching groups are passed as parameters to the step definition
var pageTitle = this.browser.text('title');
if (title === pageTitle) {
callback();
} else {
callback(new Error("Expected to be on page with title " + title));
}
});
};
Instead of Node.js-style callbacks, promises can be returned by step definitions:
this.Given(/^I am on the Cucumber.js GitHub repository$/, function () {
// Notice how `callback` is omitted from the parameters
return this.visit('https://github.com/cucumber/cucumber-js');
// A promise, returned by zombie.js's `visit` method is returned to Cucumber.
});
Simply omit the last callback
parameter and return the promise.
Often, asynchronous behaviour is not needed in step definitions. Simply omit the callback parameter, do not return anything and Cucumber will treat the step definition function as synchronous:
this.Given(/^I add one cucumber$/, function () {
// Notice how `callback` is omitted from the parameters
this.cucumberCount += 1;
});
It is also possible to use simple strings instead of regexps as step definition patterns:
this.Then('I should see "$title" as the page title', function (title, callback) {
// the above string is converted to the following Regexp by Cucumber:
// /^I should see "([^"]*)" as the page title$/
var pageTitle = this.browser.text('title');
if (title === pageTitle) {
callback();
} else {
callback(new Error("Expected to be on page with title " + title));
}
});
'I have $count "$string"'
would translate to /^I have (.*) "([^"]*)"$/
.
When steps have a data table, they are passed an object with methods that can be used to access the data.
hashes
: returns an array of objects where each row is converted to an object (column header is the key)rows
: returns the table as a 2-D array, without the first rowraw
: returns the table as a 2-D arrayrowsHash
: returns an object where each row corresponds to an entry (first column is the key, second column is the value)See this feature for examples
By default, asynchronous hooks and steps timeout after 5000 milliseconds. This can be modified globally with:
// features/support/env.js
var configure = function () {
this.setDefaultTimeout(60 * 1000);
};
module.exports = configure;
A specific step's timeout can be set with:
// features/step_definitions/my_steps.js
var mySteps = function () {
this.Given(/^a slow step$/, {timeout: 60 * 1000}, function(callback) {
// Does some slow browser/filesystem/network actions
});
};
module.exports = mySteps;
Hooks can be used to prepare and clean the environment before and after each scenario is executed. Hooks can use callbacks, return promises, or be synchronous. The first argument to hooks is always the current scenario. See Cucumber.Api.Scenario for more information.
To run something before every scenario, use before hooks:
// features/support/hooks.js (this path is just a suggestion)
var myHooks = function () {
this.Before(function (scenario) {
// Just like inside step definitions, "this" is set to a World instance.
// It's actually the same instance the current scenario step definitions
// will receive.
// Let's say we have a bunch of "maintenance" methods available on our World
// instance, we can fire some to prepare the application for the next
// scenario:
this.bootFullTextSearchServer();
this.createSomeUsers();
});
};
module.exports = myHooks;
If you need to run asynchronous code, simply accept a callback in your hook function and run it when you're done:
this.Before(function (scenario, callback) {
this.createUsers(callback);
});
Or return a promise:
this.Before(function (scenario) {
// assuming this.createUsers returns a promise:
return this.createUsers();
});
The before hook counterpart is the after hook. It's similar in shape but is executed, well, after every scenario:
// features/support/after_hooks.js
var myAfterHooks = function () {
this.After(function (scenario) {
// Again, "this" is set to the World instance the scenario just finished
// playing with.
// We can then do some cleansing:
this.emptyDatabase();
this.shutdownFullTextSearchServer();
});
};
module.exports = myAfterHooks;
It's also possible to combine both before and after hooks in one single definition with the help of around hooks:
// features/support/advanced_hooks.js
myAroundHooks = function () {
this.Around(function (scenario, runScenario) {
// "this" is - as always - an instance of World promised to the scenario.
// First do the "before scenario" tasks:
this.bootFullTextSearchServer();
this.createSomeUsers();
// When the "before" duty is finished, tell Cucumber to execute the scenario
// and pass a function to be called when the scenario is finished:
// The first argument to runScenario is the error, if any, of the before tasks
// The second argument is a function which performs the after tasks
// it can use callbacks, return a promise or be synchronous
runScenario(null, function () {
// Now, we can do our "after scenario" stuff:
this.emptyDatabase();
this.shutdownFullTextSearchServer();
});
});
};
module.exports = myAroundHooks;
As with Before
and After
hooks, Around
hooks functions (both pre- and post-scenario functions) can accept a callback or return a promise if you need asynchronous operations.
Hooks can be conditionally elected for execution based on the tags of the scenario.
// features/support/hooks.js (this path is just a suggestion)
var myHooks = function () {
this.Before("@foo", "@bar,@baz", function (scenario) {
// This hook will be executed before scenarios tagged with @foo and either
// @bar or @baz.
// ...
});
};
module.exports = myHooks;
You can attach text, images and files to the Cucumber report using the scenario object:
this.After(function (scenario) {
scenario.attach('Some text');
});
By default, text is saved with a MIME type of text/plain
. You can also specify
a different MIME type:
this.After(function (scenario) {
scenario.attach('{"name": "some JSON"}', 'application/json');
});
Images and other binary data can be attached using a stream.Readable. In that case, passing a callback to attach()
becomes mandatory:
this.After(function (scenario, callback) {
if (scenario.isFailed()) {
var stream = getScreenshotOfError();
scenario.attach(stream, 'image/png', function(err) {
callback(err);
});
}
else {
callback();
}
});
Images and binary data can also be attached using a Buffer:
this.After(function (scenario) {
if (scenario.isFailed()) {
var buffer = getScreenshotOfError();
scenario.attach(buffer, 'image/png');
}
});
Here is an example of saving a screenshot using WebDriver when a scenario fails:
this.After(function (scenario, callback) {
if (scenario.isFailed()) {
webDriver.takeScreenshot().then(stream) {
scenario.attach(stream, 'image/png', callback);
}, function(err) {
callback(err);
});
}
else {
callback();
}
});
The after features event is emitted once all features have been executed, just before the process exits. It can be used for tasks such as closing your browser after running automated browser tests with selenium or phantomjs.
note: There are "Before" and "After" events for each of the following: "Features", "Feature", "Scenario", "Step" as well as the standalone events "Background" and "StepResult". e.g. "BeforeScenario".
// features/support/after_hooks.js
var myAfterHooks = function () {
this.registerHandler('AfterFeatures', function (event, callback) {
// clean up!
// Be careful, there is no World instance available on `this` here
// because all scenarios are done and World instances are long gone.
callback();
});
}
module.exports = myAfterHooks;
Cucumber.js includes a executable file to run the features.
If you installed Cucumber.js globally, you may run it with:
$ cucumber.js
If you installed Cucumber locally, you may need to specify the path to the executable:
$ ./node_modules/.bin/cucumber.js
Note to Windows users: invoke Cucumber.js with cucumber-js
instead of cucumber.js
. The latter is causing the operating system to invoke JScript instead of Node.js, because of the file extension.
$ cucumber.js features/my_feature.feature
$ cucumber.js features/my_feature.feature:3
$ cucumber.js --name "topic 1"
Use --require <FILE|DIR>
to require files before executing the features.
If not used, all "*.js" files (and other extensions specifed by --compiler
) that are siblings
or below the features will be loaded automatically. Automatic
loading is disabled when this option is specified, and all loading becomes explicit.
Files under directories named "support" are always loaded first
Use --format <TYPE[:PATH]>
to specify the format of the output.
If PATH is not supplied, the formatter prints to stdout.
If PATH is supplied, it prints to the given file.
If multiple formats are specified with the same output, only the last is used.
Built-in formatters
.gitignore
Use --tags <EXPRESSION>
to run specific features or scenarios.
--tags @dev
: tagged with @dev--tags ~@dev
: NOT tagged with @dev
--tags @foo,@bar
: tagged with @foo
OR bar
--tags @foo --tags @bar
: tagged with @foo
AND bar
Step definitions and support files can be written in other languages that transpile to javascript.
To do this use the CLI option --compiler <file_extension>:<module_name>
.
Running require("<module_name>")
, should make it possible to require files with the given extension.
As an example, load CoffeeScript support files with --compiler coffee:coffee-script/register
.
Undefined steps snippets are printed in javascript by default.
Custom snippet syntaxes can be used with --snippet-syntax <FILE>
.
See here for an example.
In order to store and reuse commonly used CLI options, you can add a cucumber.js
file to your project root directory. The file should export an object where the key is the profile name and the value is a string of CLI options. The profile can be applied with -p <NAME>
or --profile <NAME>
. This will prepend the profile's CLI options to the ones provided by the command line. Multiple profiles can be specified at a time. If no profile is specified and a profile named default
exists, it will be applied.
cucumber
and snippets
to your package,
so it can easily be found by searching npm.A few example apps are available for you to browse:
See CONTRIBUTING.
[0.9.5] - 2016-02-16
FAQs
The official JavaScript implementation of Cucumber.
The npm package cucumber receives a total of 180,371 weekly downloads. As such, cucumber popularity was classified as popular.
We found that cucumber demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 6 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.