├── types └── wdio.d.ts ├── .prettierrc.json ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── src ├── pages │ ├── Page.ts │ └── Homepage.ts ├── features │ └── homepage-search.feature └── stepDefinitions │ └── homepage-search.steps.ts ├── tsconfig.json ├── README.md ├── LICENSE ├── .gitignore ├── package.json └── wdio.conf.js /types/wdio.d.ts: -------------------------------------------------------------------------------- 1 | declare module WebdriverIO { 2 | // adding command to `browser` 3 | interface Browser { 4 | browserCustomCommand: (arg) => void 5 | } 6 | } -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "printWidth": 80, 4 | "tabWidth": 4, 5 | "singleQuote": true, 6 | "trailingComma": "es5" 7 | } -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "alexkrechik.cucumberautocomplete", 4 | "dbaeumer.vscode-eslint", 5 | "esbenp.prettier-vscode" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/Page.ts: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | const jsdom = require("jsdom"); 3 | const { JSDOM } = jsdom; 4 | 5 | export default abstract class Page { 6 | private _path: string; 7 | 8 | public open(path: string): void { 9 | this._path = path; 10 | browser.url(path); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "*": ["./*"], 6 | "src/*": ["./src/*"] 7 | }, 8 | "typeRoots": ["./types"], 9 | "types": [ 10 | "node", 11 | "@wdio/sync", 12 | "chai", 13 | "@wdio/cucumber-framework", 14 | "reflect-metadata" 15 | ], 16 | "target": "es5", 17 | "lib": ["es2018", "dom"], 18 | "experimentalDecorators": true 19 | }, 20 | "include": ["./src/**/*.ts"] 21 | } 22 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "run all", 9 | "type": "node", 10 | "request": "launch", 11 | // "args": ["wdio.conf.js", "--spec", "${file}"], 12 | "args": ["wdio.conf.js"], 13 | "cwd": "${workspaceFolder}", 14 | "autoAttachChildProcesses": true, 15 | "program": "${workspaceRoot}/node_modules/@wdio/cli/bin/wdio.js", 16 | "console": "integratedTerminal" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebdriverIO CucumberJS Typescript 2 | 3 | ## Usage 4 | 5 | npm install 6 | npm run test 7 | npm run test:debug 8 | npm run allure-report 9 | 10 | ## Boilerplate project with CucumberJS configured with typescript 11 | 12 | - Allure Reporter 13 | - Typescript PageObjects 14 | - Typescirpt Cucumber step decorators 15 | - Chai For assertions 16 | - Selenium Standalone with chrome and firefox capabilties in headless mode 17 | - Vscode launch configuration to debug tests 18 | 19 | ## Debugging Tests 20 | 21 | - `browser.debug()` statement in code and then: `npm run test:debug` this will enalbe debug repl in console window 22 | - Add breakpoints in vscode or debugger statement and run launch configuration in vscode. 23 | 24 | ### Dependencies 25 | 26 | Java must be installed to run allure reports 27 | -------------------------------------------------------------------------------- /src/features/homepage-search.feature: -------------------------------------------------------------------------------- 1 | Feature: Performing a Google Search 2 | 3 | As a user on the Google search page 4 | I want to search for Selenium-Webdriver 5 | Because I want to learn more about it 6 | 7 | Background: 8 | 9 | Given I am on the search page 10 | 11 | Scenario: Performing a search operation 12 | When I enter "Selenium Webdriver" into the search box 13 | And I click the search button 14 | Then I should see a list of search results 15 | 16 | Scenario Outline: Performing a search operation with passing test data as data table 17 | When I enter into the search box 18 | And I click the search button 19 | Then I should see a list of search results 20 | 21 | Examples: 22 | |searchItem| 23 | |"Selenium Webdriver"| -------------------------------------------------------------------------------- /src/stepDefinitions/homepage-search.steps.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import { binding, given, when, then } from 'cucumber-tsflow'; 3 | import homepage from '../pages/Homepage'; 4 | 5 | @binding() 6 | export class HomepageSearchSteps { 7 | @given(/^I am on the search page$/) 8 | public async givenOnHomepage() { 9 | homepage.open(); 10 | const title = browser.getTitle(); 11 | 12 | assert.equal(title, 'Google'); 13 | } 14 | 15 | @when(/^I enter "([^"]*)" into the search box$/) 16 | public whenIEnterSearchText(arg1) { 17 | homepage.enterText(arg1); 18 | } 19 | 20 | @when(/^I click the search button$/) 21 | public whenSearchClicked() { 22 | homepage.search(); 23 | } 24 | 25 | @then(/^I should see a list of search results$/) 26 | public resultsShouldShow() { 27 | assert.isTrue(homepage.isSearched()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/pages/Homepage.ts: -------------------------------------------------------------------------------- 1 | import Page from './Page'; 2 | 3 | class Homepage extends Page { 4 | /** 5 | * define elements 6 | */ 7 | //get usernameInput() { return $('//*[@name="username"]'); } 8 | 9 | get searchInput() { return $('input.gLFyf'); } 10 | get searchButton() { return $('input.gNO89b'); } 11 | get resultsList() { return $('#resultStats'); } 12 | 13 | /** 14 | * define or overwrite page methods 15 | */ 16 | 17 | open () { 18 | super.open('https://google.com') //provide your additional URL if any. this will append to the baseUrl to form complete URL 19 | browser.pause(1000); 20 | } 21 | 22 | enterText (item) { 23 | this.searchInput.clearValue(); 24 | this.searchInput.setValue(item); 25 | browser.pause(1000); 26 | } 27 | 28 | search () { 29 | this.searchButton.click(); 30 | } 31 | isSearched () { 32 | this.resultsList.waitForDisplayed(1000); 33 | return this.resultsList.isDisplayed(); 34 | } 35 | } 36 | 37 | export default new Homepage(); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 sat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # allure 64 | allure-report 65 | allure-results 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e2e", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "wdio", 8 | "test:debug": "DEBUG=true wdio", 9 | "allure-report": "allure generate ./allure-results --clean && allure open" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/chai": "^4.2.3", 15 | "@types/cucumber": "^4.0.7", 16 | "@types/jsdom": "^12.2.4", 17 | "@types/reflect-metadata": "^0.1.0", 18 | "@types/webdriverio": "^5.0.0", 19 | "@wdio/allure-reporter": "^5.15.2", 20 | "@wdio/cli": "^5.15.2", 21 | "@wdio/cucumber-framework": "^5.15.1", 22 | "@wdio/local-runner": "^5.15.2", 23 | "@wdio/selenium-standalone-service": "^5.15.0", 24 | "@wdio/spec-reporter": "^5.15.2", 25 | "@wdio/sync": "^5.15.1", 26 | "allure-commandline": "^2.13.0", 27 | "chai": "^4.2.0", 28 | "cucumber-tsflow": "^3.2.0", 29 | "prettier": "^1.18.2", 30 | "ts-node": "^8.4.1", 31 | "tsconfig-paths": "^3.9.0", 32 | "typescript": "^3.6.4", 33 | "webdriverio": "^5.15.2" 34 | }, 35 | "dependencies": { 36 | "jsdom": "^15.2.0", 37 | "node-fetch": "^2.6.0", 38 | "reflect-metadata": "^0.1.13" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.validate": [ 3 | "javascript", 4 | "javascriptreact", 5 | "typescript", 6 | "typescriptreact" 7 | ], 8 | 9 | "debug.node.autoAttach": "off", 10 | "diffEditor.ignoreTrimWhitespace": true, 11 | "diffEditor.renderSideBySide": true, 12 | "cucumberautocomplete.steps": ["src/stepDefinitions/**/*.ts"], 13 | "cucumberautocomplete.syncfeatures": "src/features/**/*feature", 14 | "cucumberautocomplete.strictGherkinCompletion": true, 15 | "cucumberautocomplete.strictGherkinValidation": true, 16 | "cucumberautocomplete.smartSnippets": true, 17 | "cucumberautocomplete.stepsInvariants": true, 18 | "cucumberautocomplete.customParameters": [ 19 | { 20 | "parameter": "{ab}", 21 | "value": "(a|b)" 22 | } 23 | ], 24 | "cucumberautocomplete.skipDocStringsFormat": true, 25 | "cucumberautocomplete.formatConfOverride": { 26 | "And": 3, 27 | "But": "relative" 28 | }, 29 | "cucumberautocomplete.onTypeFormat": true, 30 | "editor.quickSuggestions": { 31 | "comments": false, 32 | "strings": true, 33 | "other": true 34 | }, 35 | "cucumberautocomplete.gherkinDefinitionPart": "(Given|When|Then)\\(", 36 | "[typescript]": { 37 | "editor.defaultFormatter": "esbenp.prettier-vscode" 38 | }, 39 | "editor.formatOnSave": true, 40 | "workbench.colorCustomizations": { 41 | "activityBar.background": "#be8067", 42 | "activityBar.foreground": "#15202b", 43 | "activityBar.inactiveForeground": "#15202b99", 44 | "activityBarBadge.background": "#a6d9b4", 45 | "activityBarBadge.foreground": "#15202b", 46 | "titleBar.activeBackground": "#aa6448", 47 | "titleBar.inactiveBackground": "#aa644899", 48 | "titleBar.activeForeground": "#e7e7e7", 49 | "titleBar.inactiveForeground": "#e7e7e799", 50 | "statusBar.background": "#aa6448", 51 | "statusBarItem.hoverBackground": "#be8067", 52 | "statusBar.foreground": "#e7e7e7" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /wdio.conf.js: -------------------------------------------------------------------------------- 1 | const { addArgument } = require('@wdio/allure-reporter').default; 2 | const debug = !!process.env.DEBUG; 3 | const execArgv = debug ? ['--inspect'] : []; 4 | const stepTimout = debug ? 24 * 60 * 60 * 1000 : 6000; 5 | const capabilities = debug 6 | ? [{ browserName: 'chrome', maxInstances: 1 }] 7 | : [ 8 | { 9 | // maxInstances can get overwritten per capability. So if you have an in-house Selenium 10 | // grid with only 5 firefox instances available you can make sure that not more than 11 | // 5 instances get started at a time. 12 | maxInstances: 5, 13 | // 14 | browserName: 'chrome', 15 | // If outputDir is provided WebdriverIO can capture driver session logs 16 | // it is possible to configure which logTypes to include/exclude. 17 | // excludeDriverLogs: ['*'], // pass '*' to exclude all driver session logs 18 | // excludeDriverLogs: ['bugreport', 'server'], 19 | 'goog:chromeOptions': { 20 | // to run chrome headless the following flags are required 21 | // (see https://developers.google.com/web/updates/2017/04/headless-chrome) 22 | args: [ 23 | '--headless', 24 | '--disable-gpu', 25 | '--disable-software-rasterizer', 26 | ], 27 | }, 28 | }, 29 | { 30 | maxInstances: 5, 31 | browserName: 'firefox', 32 | 'moz:firefoxOptions': { 33 | // flag to activate Firefox headless mode (see https://github.com/mozilla/geckodriver/blob/master/README.md#firefox-capabilities for more details about moz:firefoxOptions) 34 | args: ['-headless'], 35 | }, 36 | }, 37 | ]; 38 | 39 | const maxInstances = debug ? 1 : 10; 40 | let scenarioCounter = 0; 41 | 42 | exports.config = { 43 | // 44 | // ==================== 45 | // Runner Configuration 46 | // ==================== 47 | // 48 | // WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or 49 | // on a remote machine). 50 | runner: 'local', 51 | // 52 | // Override default path ('/wd/hub') for chromedriver service. 53 | path: '/wd/hub', 54 | port: 4444, 55 | // 56 | // ================== 57 | // Specify Test Files 58 | // ================== 59 | // Define which test specs should run. The pattern is relative to the directory 60 | // from which `wdio` was called. Notice that, if you are calling `wdio` from an 61 | // NPM script (see https://docs.npmjs.com/cli/run-script) then the current working 62 | // directory is where your package.json resides, so `wdio` will be called from there. 63 | // 64 | specs: ['./src/features/**/*.feature'], 65 | // Patterns to exclude. 66 | exclude: [ 67 | // 'path/to/excluded/files' 68 | ], 69 | // 70 | // ============ 71 | // Capabilities 72 | // ============ 73 | // Define your capabilities here. WebdriverIO can run multiple capabilities at the same 74 | // time. Depending on the number of capabilities, WebdriverIO launches several test 75 | // sessions. Within your capabilities you can overwrite the spec and exclude options in 76 | // order to group specific specs to a specific capability. 77 | // 78 | // First, you can define how many instances should be started at the same time. Let's 79 | // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have 80 | // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec 81 | // files and you set maxInstances to 10, all spec files will get tested at the same time 82 | // and 30 processes will get spawned. The property handles how many capabilities 83 | // from the same test should run tests. 84 | // 85 | maxInstances: maxInstances, 86 | // 87 | // If you have trouble getting all important capabilities together, check out the 88 | // Sauce Labs platform configurator - a great tool to configure your capabilities: 89 | // https://docs.saucelabs.com/reference/platforms-configurator 90 | // 91 | capabilities: capabilities, 92 | // 93 | // =================== 94 | // Test Configurations 95 | // =================== 96 | // Define all options that are relevant for the WebdriverIO instance here 97 | // 98 | // Level of logging verbosity: trace | debug | info | warn | error | silent 99 | logLevel: 'silent', 100 | 101 | // in debug mode passes --inspect 102 | execArgv: execArgv, 103 | // 104 | // Set specific log levels per logger 105 | // loggers: 106 | // - webdriver, webdriverio 107 | // - @wdio/applitools-service, @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service 108 | // - @wdio/mocha-framework, @wdio/jasmine-framework 109 | // - @wdio/local-runner, @wdio/lambda-runner 110 | // - @wdio/sumologic-reporter 111 | // - @wdio/cli, @wdio/config, @wdio/sync, @wdio/utils 112 | // Level of logging verbosity: trace | debug | info | warn | error | silent 113 | // logLevels: { 114 | // webdriver: 'info', 115 | // '@wdio/applitools-service': 'info' 116 | // }, 117 | // 118 | // If you only want to run your tests until a specific amount of tests have failed use 119 | // bail (default is 0 - don't bail, run all tests). 120 | bail: 0, 121 | // 122 | // Set a base URL in order to shorten url command calls. If your `url` parameter starts 123 | // with `/`, the base url gets prepended, not including the path portion of your baseUrl. 124 | // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url 125 | // gets prepended directly. 126 | baseUrl: 'http://localhost:3112', 127 | // 128 | // Default timeout for all waitFor* commands. 129 | waitforTimeout: 10000, 130 | // 131 | // Default timeout in milliseconds for request 132 | // if Selenium Grid doesn't send response 133 | connectionRetryTimeout: 90000, 134 | // 135 | // Default request retries count 136 | connectionRetryCount: 3, 137 | // 138 | // Test runner services 139 | // Services take over a specific job you don't want to take care of. They enhance 140 | // your test setup with almost no effort. Unlike plugins, they don't add new 141 | // commands. Instead, they hook themselves up into the test process. 142 | services: ['selenium-standalone'], 143 | 144 | // Framework you want to run your specs with. 145 | // The following are supported: Mocha, Jasmine, and Cucumber 146 | // see also: https://webdriver.io/docs/frameworks.html 147 | // 148 | // Make sure you have the wdio adapter package for the specific framework installed 149 | // before running any tests. 150 | framework: 'cucumber', 151 | // 152 | // The number of times to retry the entire specfile when it fails as a whole 153 | // specFileRetries: 1, 154 | // 155 | // Test reporter for stdout. 156 | // The only one supported by default is 'dot' 157 | // see also: https://webdriver.io/docs/dot-reporter.html 158 | reporters: [ 159 | 'spec', 160 | [ 161 | 'allure', 162 | { 163 | outputDir: 'allure-results', 164 | disableWebdriverStepsReporting: true, 165 | disableWebdriverScreenshotsReporting: false, 166 | useCucumberStepReporter: true, 167 | }, 168 | ], 169 | ], 170 | 171 | // If you are using Cucumber you need to specify the location of your step definitions. 172 | cucumberOpts: { 173 | backtrace: false, // show full backtrace for errors 174 | dryRun: false, // invoke formatters without executing steps 175 | failFast: false, // abort the run on first failure 176 | format: ['pretty'], // (type[:path]) specify the output format, optionally supply PATH to redirect formatter output (repeatable) 177 | colors: true, // disable colors in formatter output 178 | snippets: true, // hide step definition snippets for pending steps 179 | source: true, // hide source uris 180 | profile: [], // (name) specify the profile to use 181 | strict: false, // fail if there are any undefined or pending steps 182 | tagExpression: '', // (expression) only execute the features or scenarios with tags matching the expression 183 | timeout: stepTimout, // timeout for step definitions 184 | ignoreUndefinedDefinitions: false, // Enable this config to treat undefined definitions as warnings 185 | requireModule: [ 186 | // ("extension:module") require files with the given EXTENSION after requiring MODULE (repeatable) 187 | 'tsconfig-paths/register', 188 | () => { 189 | require('ts-node').register({ files: true }); 190 | }, 191 | ], 192 | require: ['./src/stepDefinitions/*.steps.ts'], // (file/dir) require files before executing features 193 | }, 194 | 195 | // 196 | // ===== 197 | // Hooks 198 | // ===== 199 | // WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance 200 | // it and to build services around it. You can either apply a single function or an array of 201 | // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got 202 | // resolved to continue. 203 | /** 204 | * Gets executed once before all workers get launched. 205 | * @param {Object} config wdio configuration object 206 | * @param {Array.} capabilities list of capabilities details 207 | */ 208 | // onPrepare: function (config, capabilities) { 209 | // }, 210 | /** 211 | * Gets executed just before initialising the webdriver session and test framework. It allows you 212 | * to manipulate configurations depending on the capability or spec. 213 | * @param {Object} config wdio configuration object 214 | * @param {Array.} capabilities list of capabilities details 215 | * @param {Array.} specs List of spec file paths that are to be run 216 | */ 217 | // beforeSession: function (config, capabilities, specs) { 218 | // }, 219 | /** 220 | * Gets executed before test execution begins. At this point you can access to all global 221 | * variables like `browser`. It is the perfect place to define custom commands. 222 | * @param {Array.} capabilities list of capabilities details 223 | * @param {Array.} specs List of spec file paths that are to be run 224 | */ 225 | // before: function (capabilities, specs) { 226 | // }, 227 | before: function(capabilities, specs) { 228 | // require('ts-node/register'); 229 | require('ts-node').register({ files: true }); 230 | }, 231 | /** 232 | * Runs before a WebdriverIO command gets executed. 233 | * @param {String} commandName hook command name 234 | * @param {Array} args arguments that command would receive 235 | */ 236 | // beforeCommand: function (commandName, args) { 237 | // }, 238 | /** 239 | * Runs before a Cucumber feature 240 | */ 241 | beforeFeature: function(uri, feature, scenarios) { 242 | scenarioCounter = 0; 243 | }, 244 | /** 245 | * Runs before a Cucumber scenario 246 | */ 247 | // beforeScenario: function (uri, feature, scenario, sourceLocation) { 248 | // }, 249 | /** 250 | * Runs before a Cucumber step 251 | */ 252 | // beforeStep: function (uri, feature, stepData, context) { 253 | // }, 254 | /** 255 | * Runs after a Cucumber step 256 | */ 257 | // afterStep: function (uri, feature, { error, result, duration, passed }, stepData, context) { 258 | // }, 259 | afterStep: function(uri, feature, { error }) { 260 | if (error !== undefined) { 261 | browser.takeScreenshot(); 262 | } 263 | }, 264 | /** 265 | * Runs after a Cucumber scenario 266 | */ 267 | afterScenario: function(uri, feature, scenario, result, sourceLocation) { 268 | scenarioCounter += 1; 269 | addArgument('Scenario #', scenarioCounter); 270 | }, 271 | /** 272 | * Runs after a Cucumber feature 273 | */ 274 | // afterFeature: function (uri, feature, scenarios) { 275 | // }, 276 | // afterTest: function(test) { 277 | // if (test.error !== undefined) { 278 | // browser.takeScreenshot(); 279 | // } 280 | // } 281 | /** 282 | * Runs after a WebdriverIO command gets executed 283 | * @param {String} commandName hook command name 284 | * @param {Array} args arguments that command would receive 285 | * @param {Number} result 0 - command success, 1 - command error 286 | * @param {Object} error error object if any 287 | */ 288 | // afterCommand: function (commandName, args, result, error) { 289 | // }, 290 | /** 291 | * Gets executed after all tests are done. You still have access to all global variables from 292 | * the test. 293 | * @param {Number} result 0 - test pass, 1 - test fail 294 | * @param {Array.} capabilities list of capabilities details 295 | * @param {Array.} specs List of spec file paths that ran 296 | */ 297 | // after: function (result, capabilities, specs) { 298 | // }, 299 | /** 300 | * Gets executed right after terminating the webdriver session. 301 | * @param {Object} config wdio configuration object 302 | * @param {Array.} capabilities list of capabilities details 303 | * @param {Array.} specs List of spec file paths that ran 304 | */ 305 | // afterSession: function (config, capabilities, specs) { 306 | // }, 307 | /** 308 | * Gets executed after all workers got shut down and the process is about to exit. An error 309 | * thrown in the onComplete hook will result in the test run failing. 310 | * @param {Object} exitCode 0 - success, 1 - fail 311 | * @param {Object} config wdio configuration object 312 | * @param {Array.} capabilities list of capabilities details 313 | * @param {} results object containing test results 314 | */ 315 | // onComplete: function(exitCode, config, capabilities, results) { 316 | // }, 317 | /** 318 | * Gets executed when a refresh happens. 319 | * @param {String} oldSessionId session ID of the old session 320 | * @param {String} newSessionId session ID of the new session 321 | */ 322 | //onReload: function(oldSessionId, newSessionId) { 323 | //} 324 | }; 325 | --------------------------------------------------------------------------------