{"id":13583297,"url":"https://github.com/john-doherty/selenium-cucumber-js","last_synced_at":"2025-04-05T03:12:04.999Z","repository":{"id":55398173,"uuid":"67008147","full_name":"john-doherty/selenium-cucumber-js","owner":"john-doherty","description":"Browser automation framework written in pure JavaScript using official selenium-webdriver and cucumber-js","archived":false,"fork":false,"pushed_at":"2024-07-23T07:50:06.000Z","size":255,"stargazers_count":121,"open_issues_count":40,"forks_count":89,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-03T17:54:13.536Z","etag":null,"topics":["bdd","browser-automation","cucumber-js","javascript","nodejs","selenium-webdriver","test-automation","testautomation"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/john-doherty.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-08-31T06:02:05.000Z","updated_at":"2025-01-14T23:52:58.000Z","dependencies_parsed_at":"2025-01-18T23:26:54.821Z","dependency_job_id":"ab807b65-67dd-48f8-ba0b-03b373c8a758","html_url":"https://github.com/john-doherty/selenium-cucumber-js","commit_stats":{"total_commits":199,"total_committers":21,"mean_commits":9.476190476190476,"dds":"0.29648241206030146","last_synced_commit":"89d52b2aa787d6c8a61ba066a2325a045095436e"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/john-doherty%2Fselenium-cucumber-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/john-doherty%2Fselenium-cucumber-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/john-doherty%2Fselenium-cucumber-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/john-doherty%2Fselenium-cucumber-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/john-doherty","download_url":"https://codeload.github.com/john-doherty/selenium-cucumber-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247280272,"owners_count":20912967,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bdd","browser-automation","cucumber-js","javascript","nodejs","selenium-webdriver","test-automation","testautomation"],"created_at":"2024-08-01T15:03:23.174Z","updated_at":"2025-04-05T03:12:04.981Z","avatar_url":"https://github.com/john-doherty.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# selenium-cucumber-js\n\n[![npm](https://img.shields.io/npm/dt/selenium-cucumber-js.svg)](https://www.npmjs.com/package/selenium-cucumber-js)\n\nJavaScript browser automation framework using official [selenium-webdriver](http://seleniumhq.github.io/selenium/docs/api/javascript/ \"view webdriver js documentation\") and [cucumber-js](https://github.com/cucumber/cucumber-js \"view cucumber js documentation\").\n\nIf you prefer to work with puppeteer check out [puppeteer-cucumber-js](https://github.com/orca-scan/puppeteer-cucumber-js)\n\n**Table of Contents**\n\n* [Installation](#installation)\n* [Usage](#usage)\n  * [Options](#options)\n    * [Configuration file](#configuration-file)\n  * [Feature files](#feature-files)\n  * [Step definitions](#step-definitions)\n  * [Page objects](#page-objects)\n  * [Shared objects](#shared-objects)\n  * [Helpers](#helpers)\n  * [Visual Comparison](#visual-comparison)\n  * [Before/After hooks](#beforeafter-hooks)\n  * [Reports](#reports)\n  * [How to debug](#how-to-debug)\n  * [Directory structure](#directory-structure)\n* [Demo](#demo)\n* [Bugs](#bugs)\n* [Contributing](#contributing)\n* [Troubleshooting](#troubleshooting)\n  * [IntelliJ Cucumber Plugin](#intellij-cucumber-plugin)\n\n## Installation\n\n```bash\nnpm install selenium-cucumber-js --save-dev\n```\n\n## Usage\n\n```bash\nnode ./node_modules/selenium-cucumber-js/index.js -s ./step-definitions\n```\n\n### Options\n\n```bash\n-h, --help                          output usage information\n-V, --version                       output the version number\n-s, --steps \u003cpath\u003e                  path to step definitions. defaults to ./step-definitions\n-p, --pageObjects \u003cpath\u003e            path to page objects. defaults to ./page-objects\n-o, --sharedObjects [paths]         path to shared objects (repeatable). defaults to ./shared-objects\n-b, --browser \u003cpath\u003e                name of browser to use. defaults to chrome\n-k, --browser-teardown \u003coptional\u003e   browser teardown strategy after every scenario (always, clear, none). defaults to \"always\"\n-r, --reports \u003cpath\u003e                output path to save reports. defaults to ./reports\n-d, --disableLaunchReport           disable the auto opening the browser with test report\n-j, --junit \u003cpath\u003e                  output path to save junit-report.xml defaults to ./reports\n-t, --tags \u003ctagName\u003e                name of tag to run\n-f, --featureFile \u003cpath\u003e            a specific feature file to run\n-x, --timeOut \u003cn\u003e                   steps definition timeout in milliseconds. defaults to 10 seconds\n-n, --noScreenshot                  disable auto capturing of screenshots when an error is encountered\n```\n\nBy default tests are run using Google Chrome, to run tests using another browser supply the name of that browser along with the `-b` switch. Available options are:\n\nBrowser    | Example\n---------- | ---------------\nChrome     | `-b chrome`\nFirefox    | `-b firefox`\nPhantom JS | `-b phantomjs`\nElectron   | `-b electron`\nCustom     | `-b customDriver.js`\n\nTo use your own driver, create a customDriver.js file in the root of your project and provide the filename with the `-b` switch.\n\n#### Configuration file\n\nConfiguration options can be set using a `selenium-cucumber-js.json` file at the root of your project. The JSON keys use the \"long name\" from the command line options. For example the following duplicates default configuration:\n\n```json\n{\n    \"steps\": \"./step-definitions\",\n    \"pageObjects\": \"./page-objects\",\n    \"sharedObjects\": \"./shared-objects\",\n    \"reports\": \"./reports\",\n    \"browser\": \"chrome\",\n    \"timeout\": 10000\n}\n```\n\nWhereas the following would set configuration to match the expected directory structure of IntelliJ's Cucumber plugin, and make default timeout one minute. _Note that the default browser has not been overridden and will remain 'chrome'._\n\n```json\n{\n    \"steps\": \"./features/step_definitions\",\n    \"pageObjects\": \"./features/page_objects\",\n    \"sharedObjects\": \"./features/shared_objects\",\n    \"reports\": \"./features/reports\",\n    \"timeout\": 60000\n}\n```\n\n### Feature files\n\nA feature file is a [Business Readable, Domain Specific Language](http://martinfowler.com/bliki/BusinessReadableDSL.html) file that lets you describe software’s behavior without detailing how that behavior is implemented. Feature files are written using the [Gherkin syntax](https://github.com/cucumber/cucumber/wiki/Gherkin) and must live in a folder named **features** within the root of your project.\n\n```gherkin\n# ./features/google-search.feature\n\nFeature: Searching for vote cards app\n  As an internet user\n  In order to find out more about the itunes vote cards app\n  I want to be able to search for information about the itunes vote cards app\n\n  Scenario: Google search for vote cards app\n    When I search Google for \"itunes vote cards app\"\n    Then I should see some results\n```\n\n### Browser teardown strategy\n\nThe browser automatically closes after each scenario to ensure the next scenario uses a fresh browser environment. But\nyou can change this behavior with the \"-k\" or the \"--browser-teardown\" parameter.\n\nValue      |  Description\n---------- | ---------------\n`always`   | the browser automatically closes (default)\n`clear`    | the browser automatically clears cookies, local and session storages\n`none`     | the browser does nothing\n\n### Step definitions\n\nStep definitions act as the glue between features files and the actual system under test.\n\n_To avoid confusion **always** return a JavaScript promise your step definition in order to let cucumber know when your task has completed._\n\n```javascript\n// ./step-definitions/google-search-steps.js\n\nmodule.exports = function () {\n\n    this.Then(/^I should see some results$/, function () {\n\n        // driver wait returns a promise so return that\n        return driver.wait(until.elementsLocated(by.css('div.g')), 10000).then(function(){\n\n            // return the promise of an element to the following then.\n            return driver.findElements(by.css('div.g'));\n        })\n        .then(function (elements) {\n\n            // verify this element has children\n            expect(elements.length).to.not.equal(0);\n        });\n    });\n};\n```\n\nThe following variables are available within the ```Given()```, ```When()``` and ```Then()``` functions:\n\n| Variable    | Description |\n| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n| `driver`    | an instance of [selenium web driver](http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebDriver.html) (_the browser_)\n| `selenium`  | the raw [selenium-webdriver](http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/) module, providing access to static properties/methods\n| `page`      | collection of **page** objects loaded from disk and keyed by filename\n| `shared`    | collection of **shared** objects loaded from disk and keyed by filename\n| `helpers`   | a collection of [helper methods](runtime/helpers.js) _things selenium does not provide but really should!_\n| `by`        | the selenium [By](http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_By.html) class used to locate elements on the page\n| `until`     | the selenium [until](http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/until.html) class used to wait for elements/events\n| `expect`    | instance of [chai expect](http://chaijs.com/api/bdd/) to ```expect('something').to.equal('something')```\n| `assert`    | instance of [chai assert](http://chaijs.com/api/assert/) to ```assert.isOk('everything', 'everything is ok')```\n| `trace`     | handy trace method to log console output with increased visibility\n\n### Page objects\n\nPage objects are accessible via a global ```page``` object and are automatically loaded from ```./page-objects``` _(or the path specified using the ```-p``` switch)_. Page objects are exposed via a camel-cased version of their filename, for example ```./page-objects/google-search.js``` becomes ```page.googleSearch```. You can also use subdirectories, for example ```./page-objects/dir/google-search.js``` becomes ```page.dir.googleSearch```.\n\nPage objects also have access to the same runtime variables available to step definitions.\n\nAn example page object:\n\n```javascript\n// ./page-objects/google-search.js\n\nmodule.exports = {\n\n    url: 'http://www.google.co.uk',\n\n    elements: {\n        searchInput: by.name('q'),\n        searchResultLink: by.css('div.g \u003e h3 \u003e a')\n    },\n\n    /**\n     * enters a search term into Google's search box and presses enter\n     * @param {string} searchQuery\n     * @returns {Promise} a promise to enter the search values\n     */\n    performSearch: function (searchQuery) {\n\n        var selector = page.googleSearch.elements.searchInput;\n\n        // return a promise so the calling function knows the task has completed\n        return driver.findElement(selector).sendKeys(searchQuery, selenium.Key.ENTER);\n    }\n};\n```\n\nAnd its usage within a step definition:\n\n```js\n// ./step-definitions/google-search-steps.js\nthis.When(/^I search Google for \"([^\"]*)\"$/, function (searchQuery) {\n\n    return helpers.loadPage('http://www.google.com').then(function() {\n\n        // use a method on the page object which also returns a promise\n        return page.googleSearch.performSearch(searchQuery);\n    })\n});\n```\n\n### Shared objects\n\nShared objects allow you to share anything from test data to helper methods throughout your project via a global ```shared``` object. Shared objects are automatically loaded from ```./shared-objects``` _(or the path specified using the ```-o``` switch)_ and made available via a camel-cased version of their filename, for example ```./shared-objects/test-data.js``` becomes ```shared.testData```. You can also use subdirectories, for example ```./shared-objects/dir/test-data.js``` becomes ```shared.dir.testData```.\n\n\nShared objects also have access to the same runtime variables available to step definitions.\n\nAn example shared object:\n\n```javascript\n// ./shared-objects/test-data.js\n\nmodule.exports = {\n    username: \"import-test-user\",\n    password: \"import-test-pa**word\"\n}\n```\n\nAnd its usage within a step definition:\n\n```js\nmodule.exports = function () {\n\n    this.Given(/^I am logged in\"$/, function () {\n\n        driver.findElement(by.name('usn')).sendKeys(shared.testData.username);\n        driver.findElement(by.name('pass')).sendKeys(shared.testData.password);\n    });\n};\n```\n\n### Helpers\n\n`selenium-cucumber-js` contains a few helper methods to make working with selenium a bit easier, those methods are:\n\n```js\n// Load a URL, returning only when the \u003cbody\u003e tag is present\nhelpers.loadPage('http://www.google.com');\n\n// get the value of a HTML attribute\nhelpers.getAttributeValue('body', 'class');\n\n// get a list of elements matching a query selector who's inner text matches param.\nhelpers.getElementsContainingText('nav[role=\"navigation\"] ul li a', 'Safety Boots');\n\n// get first elements matching a query selector who's inner text matches textToMatch param\nhelpers.getFirstElementContainingText('nav[role=\"navigation\"] ul li a', 'Safety Boots');\n\n// click element(s) that are not visible (useful in situations where a menu needs a hover before a child link appears)\nhelpers.clickHiddenElement('nav[role=\"navigation\"] ul li a','Safety Boots');\n\n// wait until a HTML attribute equals a particular value\nhelpers.waitUntilAttributeEquals('html', 'data-busy', 'false', 5000);\n\n// wait until a HTML attribute exists\nhelpers.waitUntilAttributeExists('html', 'data-busy', 5000);\n\n// wait until a HTML attribute no longer exists\nhelpers.waitUntilAttributeDoesNotExists('html', 'data-busy', 5000);\n\n// get the content value of a :before pseudo element\nhelpers.getPseudoElementBeforeValue('body header');\n\n// get the content value of a :after pseudo element\nhelpers.getPseudoElementAfterValue('body header');\n\n// clear the cookies\nhelpers.clearCookies();\n\n// clear both local and session storages\nhelpers.clearStorages();\n\n// clear both cookies and storages\nhelpers.clearCookiesAndStorages('body header');\n\n// waits until an element to exist and returns it\nhelpers.waitForCssXpathElement('#login-button', 5000);\n\n// scroll until element is visible\nhelpers.scrollToElement(webElement);\n\n// select a value inside a dropdown list by its text\nhelpers.selectByVisibleText('#country', 'Brazil');\n\n// waits and returns an array of all windows opened\nhelpers.waitForNewWindows();\n```\n\n### Visual Comparison\n\nThe `selenium-cucumber-js` framework uses [Applitools Eyes](https://applitools.com/) to add visual checkpoints to your JavaScript Selenium tests. It takes care of getting screenshots of your application from the underlying WebDriver, sending them to the Applitools Eyes server for validation and failing the test when differences are detected. To perform visual comparisons within your tests, obtain an [Applitools Eyes](https://applitools.com/) API Key and assign it to the `eye_key` property of the `selenium-cucumber-js.json` config file in the root of your project.\n\nFor example the following configuration could be used with an increased timeout which allows enough time for visual checks:\n\n```json\n{\n  \"eye_key\": \"Your_Api_Key\",\n  \"timeout\": 50000\n}\n```\n\nAnd its usage within page Objects:\n\n```js\nmodule.exports = {\n\n    url: 'https://applitools.com/helloworld',\n\n    elements: {\n        clickme: by.tagName('button'),\n        searchResultLink: by.css('div.g \u003e h3 \u003e a')\n    },\n\n    applitools_Eyes_Example: function () {\n\n        // Start the test and set the browser's viewport size to 800x600.\n        eyes.open(driver, 'Hello World!', 'My first Javascript test!',\n            {width: 800, height: 600});\n\n        // Navigate the browser to the \"hello world!\" web-site.\n        driver.get(page.HelloWorld.elements.url);\n\n        // Visual checkpoint #1.\n        eyes.checkWindow('Main Page');\n\n        // Click the \"Click me!\" button.\n        driver.findElement(page.HelloWorld.elements.clickme).click();\n\n        // Visual checkpoint #2.\n        eyes.checkWindow('Click!');\n\n        // End the test.\n        eyes.close();\n    }\n};\n```\n\n### Before/After hooks\n\nYou can register before and after handlers for features and scenarios:\n\n| Event          | Example\n| -------------- | ------------------------------------------------------------\n| BeforeFeature  | ```this.BeforeFeatures(function(feature, callback) {})```\n| AfterFeature   | ```this.AfterFeature(function(feature, callback) {});```\n| BeforeScenario | ```this.BeforeScenario(function(scenario, callback) {});```\n| AfterScenario  | ```this.AfterScenario(function(scenario, callback) {});```\n\n```js\nmodule.exports = function () {\n\n    // add a before feature hook\n    this.BeforeFeature(function(feature, done) {\n        console.log('BeforeFeature: ' + feature.getName());\n        done();\n    });\n\n    // add an after feature hook\n    this.AfterFeature(function(feature, done) {\n        console.log('AfterFeature: ' + feature.getName());\n        done();\n    });\n\n    // add before scenario hook\n    this.BeforeScenario(function(scenario, done) {\n        console.log('BeforeScenario: ' + scenario.getName());\n        done();\n    });\n\n    // add after scenario hook\n    this.AfterScenario(function(scenario, done) {\n        console.log('AfterScenario: ' + scenario.getName());\n        done();\n    });\n};\n```\n\n### Reports\n\nHTML and JSON reports are automatically generated and stored in the default `./reports` folder. This location can be changed by providing a new path using the `-r` command line switch:\n\n![Cucumber HTML report](img/cucumber-html-report.png)\n\n### How to debug\n\nMost selenium methods return a [JavaScript Promise](https://spring.io/understanding/javascript-promises \"view JavaScript promise introduction\") that is resolved when the method completes. The easiest way to step in with a debugger is to add a ```.then``` method to a selenium function and place a ```debugger``` statement within it, for example:\n\n```js\nmodule.exports = function () {\n\n    this.When(/^I search Google for \"([^\"]*)\"$/, function (searchQuery, done) {\n\n        driver.findElement(by.name('q')).then(function(input) {\n            expect(input).to.exist;\n            debugger; // \u003c\u003c- your IDE should step in at this point, with the browser open\n            return input;\n        })\n        .then(function(input){\n            input.sendKeys(searchQuery);\n            input.sendKeys(selenium.Key.ENTER);\n\n            done(); // \u003c\u003c- let cucumber know you're done\n        });\n    });\n};\n```\n\n### Directory structure\n\nYou can use the framework without any command line arguments if your application uses the following folder structure:\n\n```bash\n.\n├── features\n│   └── google-search.feature\n├── step-definitions\n│   └── google-search-steps.js\n├── page-objects\n│   └── google-search.js\n└── shared-objects\n│   ├── test-data.js\n│   └── stuff.json\n└── reports\n    ├── cucumber-report.json\n    └── cucumber-report.html\n```\n\n## Demo\n\nThis project includes an example to help you get started. You can run the example using the following command:\n\n```bash\nnode ./node_modules/selenium-cucumber-js/index.js\n```\n\n## Bugs\n\nPlease raise bugs via the [selenium-cucumber-js issue tracker](https://github.com/john-doherty/selenium-cucumber-js/issues) and, if possible, please provide enough information to allow the bug to be reproduced.\n\n## Contributing\n\nEveryone is very welcome to contribute to this project. You can contribute just by submitting bugs or suggesting improvements by [opening an issue on GitHub](https://github.com/john-doherty/selenium-cucumber-js/issues).\n\n## Troubleshooting\n\n### IntelliJ Cucumber Plugin\n\nIntelliJ based IDE's have a plugin that allows the tester to control click on a `Given`, `When`, `Then` statement within a Cucumber feature file and have the user taken to the associated step definition. This plugin relies on your project having the following folder structure:\n\n```bash\n.\n└── features\n   │   google-search.feature\n   └── step_definitions\n   │   └── google-search-steps.js\n   └── page_objects\n   │   └── google-search.js\n   └── shared_objects\n   │   ├── test-data.js\n   │   └── stuff.json\n   └── reports\n       ├── cucumber-report.json\n       └── cucumber-report.html\n```\n\nThis can be achieved by restructuring your project to match the layout above _(notice the underscores)_, and running your tests with the following switches:\n\n```bash\nnode ./node_modules/selenium-cucumber-js/index.js -s ./features/step_definitions -p ./features/page_objects -o ./features/shared_objects -r ./features/reports\n```\n\n### VSCode Cucumber Plugin\n\nVisual Studio Code has also an extension for Cucumber (Gherkin) Language Support + Format + Steps/PageObjects Autocomplete. You can find how to install and use at [Cucumber (Gherkin) Full Support](https://marketplace.visualstudio.com/items?itemName=alexkrechik.cucumberautocomplete).\n\nFollowing the default structure, the `settings.json` should look like this:\n\n```json\n{\n    \"cucumberautocomplete.steps\": [\n        \"step-definitions/*.js\"\n    ],\n    \"cucumberautocomplete.syncfeatures\": \"features/*.feature\",\n    \"cucumberautocomplete.strictGherkinCompletion\": false,\n    \"cucumberautocomplete.onTypeFormat\": true,\n    \"editor.quickSuggestions\": {\n        \"comments\": false,\n        \"strings\": true,\n        \"other\": true\n    },\n    \"cucumberautocomplete.gherkinDefinitionPart\": \"(Given|When|Then)\\\\(\",\n}\n```\n\n## License\n\nLicensed under [ISC License](LICENSE) \u0026copy; [John Doherty](https://twitter.com/mrjohndoherty)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohn-doherty%2Fselenium-cucumber-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohn-doherty%2Fselenium-cucumber-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohn-doherty%2Fselenium-cucumber-js/lists"}