A debuggable JS BDD framework that uses the official selenium-webdriver for Node and cucumber-js.
npm install selenium-cucumber-js --save-dev
node ./node_modules/selenium-cucumber-js/index.js -s ./step-definitions
-h, --help output usage information
-V, --version output the version number
-s, --steps <path> path to step definitions. defaults to ./step-definitions
-p, --pageObjects <path> path to page objects. defaults to ./page-objects
-b, --browser <path> name of browser to use. defaults to chrome
-t, --tags <tagName> name of tag to run
A feature file is a Business Readable, Domain Specific Language file that lets you describe software’s behaviour without detailing how that behaviour is implemented. Feature files are written using the Gherkin syntax and must live in a folder named features within the root of your project.
# ./features/google-search.feature
Feature: Searching for vote cards app
As an internet user
In order to find out more about the itunes vote cards app
I want to be able to search for information about the itunes vote cards app
Scenario: Google search for vote cards app
When I search Google for "itunes vote cards app"
Then I should see some results
Step definitions are the glue between features files and the actual system under test. Step definitions are written in JavaScript and should be stored in either ./features/step-definitions
or ./step-definitions
folder. If you use a different location you must provide the path via the -s
command line switch.
// ./step-definitions/google-search.js
module.exports = function () {
this.When(/^I search Google for "([^"]*)"$/, function (searchQuery) {
driver.get('http://www.google.com');
var input = driver.findElement(by.name('q'));
input.sendKeys(searchQuery);
input.sendKeys(selenium.Key.ENTER);
});
this.Then(/^I should see some results$/, function () {
driver.wait(until.elementsLocated(by.css('div.g')), 10000);
return driver.findElements(by.css('div.g')).then(function (elements) {
expect(elements.length).to.not.equal(0);
});
});
};
The following variables are available within the Given()
, When()
and Then()
functions:
Variable | Description |
---|---|
driver |
an instance of selenium web driver (the browser) |
selenium |
the raw selenium-webdriver module, providing access to static properties/methods |
page |
page objects |
by |
the selenium By class used to locate elements on the page |
until |
the selenium until class used to wait for elements/events |
expect |
instance of chai expect to expect('something').to.equal('something') |
assert |
instance of chai assert to assert.isOk('everything', 'everything is ok') |
trace |
handy trace method to log console output with increased visibility |
Page objects are accessible via the global page
variable and are automatically loaded from ./page-objects
or the path specified using the -p
switch. Page objects are exposed using the camel case version of their filename, for example ./page-objects/google-search.js
becomes page.googleSearch
. Page objects also have access to the same runtime variables described in step definitions section above.
An example page object:
// ./page-objects/gogole-search.js
module.exports = {
elements: {
searchInput: by.name('q')
},
preformSearch: function (keywords) {
// notice the element path below use the full page qualifier
var input = driver.findElement(page.googleSearch.elements.searchInput);
input.sendKeys(keywords);
input.sendKeys(selenium.Key.ENTER);
}
};
And its usage within a step definition:
module.exports = function () {
this.When(/^I search Google for "([^"]*)"$/, function (searchQuery) {
page.googleSearch.preformSearch(searchQuery);
});
};
You can register event handlers for the following events within the cucumber lifecycle.
Event | Example |
---|---|
BeforeFeature | this.BeforeFeatures(function(feature, callback) {}) |
BeforeScenario | this.BeforeScenario(function(scenario, callback) {}); |
AfterScenario | this.AfterScenario(function(scenario, callback) {}); |
AfterFeature | this.AfterFeature(function(feature, callback) {}); |
Selenium methods return a JavaScript Promise that will be resolved when the method completes. This means you can assign a .then
function and use it to trigger your debugger by inserting a debugger
statement, for example:
module.exports = function () {
this.When(/^I search Google for "([^"]*)"$/, function (searchQuery) {
driver.findElement(by.name('q')).then(function(input) {
expect(input).to.exist;
debugger; // <<- your IDE should step in at this point, with the browser open
return input;
})
.then(function(input){
input.sendKeys(searchQuery);
input.sendKeys(selenium.Key.ENTER);
});
});
};
This project includes an example feature file and step definition to help you get started. You can run the example using the following command:
node ./node_modules/selenium-cucumber-js/index.js