├── .codeclimate.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── .nvmrc ├── .travis.yml ├── LICENSE ├── README.md ├── babel.config.js ├── gulp ├── eslint.js └── test.js ├── gulpfile.babel.js ├── package-lock.json ├── package.json ├── src └── index.js └── test ├── specs └── webdriver.spec.js └── wdio.conf.js /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | rubocop: 4 | enabled: false 5 | coffeelint: 6 | enabled: false 7 | eslint: 8 | enabled: true 9 | csslint: 10 | enabled: false 11 | ratings: 12 | paths: 13 | - "src/*.js" 14 | exclude_paths: 15 | - node_modules/**/* 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 4 11 | 12 | end_of_line = lf 13 | charset = utf-8 14 | trim_trailing_whitespace = true 15 | insert_final_newline = false 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | coverage/ 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard", 3 | "parser": "babel-eslint", 4 | "rules": { 5 | "indent": [2, 4] 6 | }, 7 | "globals": { 8 | "expect": true, 9 | "describe": true, 10 | "before": true, 11 | "beforeEach": true, 12 | "after": true, 13 | "afterEach": true, 14 | "it": true, 15 | "should": true, 16 | "browser": true, 17 | "browserA": true, 18 | "mock": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | coverage 5 | .idea 6 | lib 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 12 5 | 6 | services: 7 | - xvfb 8 | 9 | branches: 10 | only: 11 | - main 12 | 13 | before_script: 14 | - "export DISPLAY=:99.0" 15 | 16 | script: "npm test" 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 WebdriverIO 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gulp-webdriver [![Build Status](https://travis-ci.org/webdriverio/gulp-webdriver.svg?branch=master)](https://travis-ci.org/webdriverio/gulp-webdriver) [![Join the chat at https://gitter.im/webdriverio/gulp-webdriver](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/webdriverio/gulp-webdriver?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | ============== 3 | 4 | > gulp-webdriver is a gulp plugin to run e2e tests with the [WebdriverIO](http://webdriver.io) testrunner 5 | 6 | ## Install 7 | 8 | ```shell 9 | npm install gulp-webdriver --save-dev 10 | ``` 11 | 12 | ## Usage 13 | 14 | You can run WebdriverIO locally by running this simple task: 15 | 16 | ```js 17 | import webdriver from 'gulp-webdriver'; 18 | 19 | gulp.task('test:e2e', function() { 20 | return gulp.src('wdio.conf.js').pipe(webdriver()); 21 | }); 22 | ``` 23 | 24 | gulp-webdriver makes the wdio testrunner easily accessible and allows you to run multiple config files 25 | sequentially. If desired, you can pass additional arguments to the wdio command to specify your test. 26 | You can find all available options [here](http://webdriver.io/guide/testrunner/gettingstarted.html) 27 | or by executing `$ wdio --help` (if you have WebdriverIO installed globally). 28 | 29 | ```js 30 | import webdriver from 'gulp-webdriver'; 31 | 32 | gulp.task('test:e2e', function() { 33 | return gulp.src('wdio.conf.js').pipe(webdriver({ 34 | logLevel: 'info', 35 | waitforTimeout: 10000, 36 | reporter: 'spec' 37 | })); 38 | }); 39 | ``` 40 | 41 | The wdio testrunner currently supports Mocha, Jasmine (v2.0) and Cucumber, and you may reference webdriver instances inside your spec files or step definition by using a global variable called "browser". For more information, please see the official WebdriverIO test framework documentation [here](http://webdriver.io/guide/testrunner/frameworks.html). 42 | 43 | ## Contributing 44 | Please fork, add specs, and send pull requests! In lieu of a formal styleguide, take care to 45 | maintain the existing coding style. 46 | 47 | ## Release History 48 | * 2015-06-22   v0.1.0    first release 49 | * 2015-06-22   v0.1.1    fixed package.json 50 | * 2015-09-03   v1.0.0    let gulp-webdriver be a simple tool to run tests with the wdio test runner 51 | * 2015-09-09   v1.0.1    better Windows support, allow gulp-webdriver without options 52 | * 2015-12-01   v1.0.2    bumped WebdriverIO version to 3.3.0 53 | * 2015-12-01   v1.0.3    fixed wdio path on windows 54 | * 2016-03-16   v2.0.0    updated codebase to ES6 and WebdriverIO to v4.0 55 | * 2016-03-30   v2.0.1    improved error handling 56 | * 2016-07-06   v2.0.2    fixed bug where gulp end event was not fired 57 | * 2019-12-17   v3.0.0    Support for WebdriverIO v5 58 | * 2020-04-20   v4.0.0    Support for WebdriverIO v6 59 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', { 4 | targets: { 5 | node: 10 6 | } 7 | }] 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /gulp/eslint.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp' 2 | import eslint from 'gulp-eslint' 3 | 4 | function eslinter (cb) { 5 | gulp.src(['**/*.js', '!node_modules/**', '!build/**']) 6 | .pipe(eslint()) 7 | .pipe(eslint.format()) 8 | .pipe(eslint.failAfterError()) 9 | cb() 10 | } 11 | 12 | module.exports = options => { 13 | return { default: eslinter, eslint: eslinter } 14 | } 15 | -------------------------------------------------------------------------------- /gulp/test.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp' 2 | import selenium from 'selenium-standalone' 3 | import webdriver from '../lib/index' 4 | 5 | module.exports = options => { 6 | const errorLog = options.errorHandler('Selenium start') 7 | 8 | function seleniumStart (done) { 9 | selenium.install({ 10 | logger (message) { 11 | process.stdout.write(`${message} \n`) 12 | }, 13 | progressCb: (totalLength, progressLength) => { 14 | process.stdout.write(`Downloading drivers ${Math.round(progressLength / totalLength * 100)}% \r`) 15 | } 16 | }, err => { 17 | if (err) return done(err) 18 | 19 | selenium.start({ 20 | spawnOptions: { 21 | stdio: 'ignore' 22 | } 23 | }, (err, child) => { 24 | selenium.child = child 25 | errorLog(err) 26 | done() 27 | }) 28 | }) 29 | } 30 | 31 | function seleniumWebdriver (done) { 32 | return gulp.src(`${options.test}/wdio.*`) 33 | .pipe(webdriver({ 34 | logLevel: 'info', 35 | waitforTimeout: 12345, 36 | framework: 'mocha', 37 | // only for testing purposes 38 | cucumberOpts: { 39 | require: 'nothing' 40 | } 41 | })).once('end', () => { 42 | selenium.child.kill() 43 | }) 44 | } 45 | 46 | const { series } = require('gulp') 47 | return { 48 | test: series(seleniumStart, seleniumWebdriver), 49 | default: module.test 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | const colors = require('ansi-colors') 2 | const { series } = require('gulp') 3 | 4 | const logger = require('@wdio/logger').default 5 | const log = logger('gulp-webdriver') 6 | 7 | const options = { 8 | src: 'src', 9 | dist: 'lib', 10 | test: 'test', 11 | errorHandler: (title) => { 12 | return (err) => { 13 | if (err) { 14 | log.error(`${colors.red([title]) + err.toString()}`) 15 | } else { 16 | log.info(`${colors.redBright([title])}`) 17 | } 18 | } 19 | } 20 | } 21 | 22 | const { eslint } = require('./gulp/eslint')(options) 23 | const { test } = require('./gulp/test')(options) 24 | 25 | exports.eslint = eslint 26 | exports.test = test 27 | exports.default = series(eslint, test) 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-webdriver", 3 | "version": "4.0.0", 4 | "description": "gulp-webdriver is a gulp plugin to run e2e tests with the WebdriverIO testrunner", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/webdriverio/gulp-webdriver.git" 8 | }, 9 | "main": "lib/index.js", 10 | "scripts": { 11 | "prepublish": "npm run compile", 12 | "compile": "babel --presets @babel/env -d lib/ src/", 13 | "eslint": "eslint gulp/ src/ test/ *.js", 14 | "test": "gulp test", 15 | "pretest": "npm run eslint && npm run compile" 16 | }, 17 | "engines": { 18 | "node": ">=12" 19 | }, 20 | "keywords": [ 21 | "webdriverio", 22 | "gulp", 23 | "selenium", 24 | "webdriver", 25 | "mocha", 26 | "test", 27 | "testing", 28 | "bdd", 29 | "tdd", 30 | "saucelabs", 31 | "runner", 32 | "gulpplugin" 33 | ], 34 | "author": "Christian Bromann ", 35 | "license": "MIT", 36 | "bugs": { 37 | "url": "https://github.com/webdriverio/gulp-webdriver/issues" 38 | }, 39 | "homepage": "https://github.com/webdriverio/gulp-webdriver", 40 | "dependencies": { 41 | "plugin-error": "^1.0.1", 42 | "resolve": "^1.16.1", 43 | "through2": "^3.0.1" 44 | }, 45 | "peerDependencies": { 46 | "@wdio/cli": "^6.1.0" 47 | }, 48 | "devDependencies": { 49 | "@babel/cli": "^7.8.4", 50 | "@babel/core": "^7.9.0", 51 | "@babel/preset-env": "^7.9.5", 52 | "@babel/register": "^7.9.0", 53 | "@wdio/cli": "^6.1.0", 54 | "@wdio/dot-reporter": "^6.0.16", 55 | "@wdio/local-runner": "^6.1.0", 56 | "@wdio/logger": "^6.0.16", 57 | "@wdio/mocha-framework": "^6.1.0", 58 | "@wdio/sync": "^6.1.0", 59 | "ansi-colors": "^4.1.1", 60 | "babel-eslint": "^10.1.0", 61 | "codeclimate-test-reporter": "^0.5.1", 62 | "del": "^5.1.0", 63 | "eslint": "^6.8.0", 64 | "eslint-config-standard": "^14.1.1", 65 | "eslint-plugin-import": "^2.20.2", 66 | "eslint-plugin-node": "^11.1.0", 67 | "eslint-plugin-promise": "^4.2.1", 68 | "eslint-plugin-standard": "^4.0.1", 69 | "gulp": "^4.0.2", 70 | "gulp-babel": "^8.0.0", 71 | "gulp-eslint": "^6.0.0", 72 | "mocha": "^7.1.1", 73 | "run-sequence": "^2.2.1", 74 | "selenium-standalone": "^6.17.0" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import through from 'through2' 2 | import resolve from 'resolve' 3 | import path from 'path' 4 | import PluginError from 'plugin-error' 5 | 6 | module.exports = (options) => { 7 | return through.obj(function (file, encoding, callback) { 8 | const stream = this 9 | const Launcher = require(path.join(path.dirname(resolve.sync('@wdio/cli')), 'launcher')).default 10 | const wdio = new Launcher(file.path, options) 11 | 12 | wdio.run().then(code => { 13 | process.stdin.pause() 14 | 15 | if (code !== 0) { 16 | process.nextTick( 17 | () => stream.emit( 18 | 'error', 19 | new PluginError( 20 | 'gulp-webdriver', 21 | `wdio exited with code ${code}`, 22 | { showStack: false } 23 | ) 24 | ) 25 | ) 26 | } 27 | 28 | callback() 29 | process.nextTick( 30 | () => stream.emit('end')) 31 | }, e => { 32 | process.stdin.pause() 33 | process.nextTick( 34 | () => stream.emit( 35 | 'error', 36 | new PluginError( 37 | 'gulp-webdriver', 38 | e, 39 | { showStack: true } 40 | ) 41 | ) 42 | ) 43 | }) 44 | 45 | return stream 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /test/specs/webdriver.spec.js: -------------------------------------------------------------------------------- 1 | describe('gulp-webdriverjs test', () => { 2 | it('should have right options', () => { 3 | expect(browser.config.waitforTimeout).toBe(12345) 4 | expect(browser.config.logLevel).toBe('info') 5 | }) 6 | 7 | it('checks if title contains the search query', () => { 8 | browser.url('/') 9 | expect(browser).toHaveTitle('WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /test/wdio.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | 3 | // 4 | // ================== 5 | // Specify Test Files 6 | // ================== 7 | // Define which test specs should run. The pattern is relative to the directory 8 | // from which `wdio` was called. Notice that, if you are calling `wdio` from an 9 | // NPM script (see https://docs.npmjs.com/cli/run-script) then the current working 10 | // directory is where your package.json resides, so `wdio` will be called from there. 11 | // 12 | path: '/wd/hub', 13 | specs: [ 14 | './test/specs/**/*.js' 15 | ], 16 | // Patterns to exclude. 17 | exclude: [ 18 | // 'path/to/excluded/files' 19 | ], 20 | // 21 | // ============ 22 | // Capabilities 23 | // ============ 24 | // Define your capabilities here. WebdriverIO can run multiple capabilities at the same 25 | // time. Depending on the number of capabilities, WebdriverIO launches several test 26 | // sessions. Within your capabilities you can overwrite the spec and exclude options in 27 | // order to group specific specs to a specific capability. 28 | // 29 | // First, you can define how many instances should be started at the same time. Let's 30 | // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have 31 | // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec 32 | // files and you set maxInstances to 10, all spec files will get tested at the same time 33 | // and 30 processes will get spawned. The property handles how many capabilities 34 | // from the same test should run tests. 35 | // 36 | capabilities: [{ 37 | browserName: 'firefox' 38 | }], 39 | // 40 | // =================== 41 | // Test Configurations 42 | // =================== 43 | // Define all options that are relevant for the WebdriverIO instance here 44 | // 45 | // Level of logging verbosity: silent | verbose | command | data | result | error 46 | logLevel: 'info', 47 | // 48 | // Set a base URL in order to shorten url command calls. If your url parameter starts 49 | // with "/", then the base url gets prepended. 50 | baseUrl: 'http://webdriver.io', 51 | // 52 | // Default timeout for all waitFor* commands. 53 | waitforTimeout: 10000, 54 | // 55 | // Default timeout in milliseconds for request 56 | // if Selenium Grid doesn't send response 57 | connectionRetryTimeout: 90000, 58 | // 59 | // Default request retries count 60 | connectionRetryCount: 3, 61 | // 62 | // Initialize the browser instance with a WebdriverIO plugin. The object should have the 63 | // plugin name as key and the desired plugin options as properties. Make sure you have 64 | // the plugin installed before running any tests. The following plugins are currently 65 | // available: 66 | // WebdriverCSS: https://github.com/webdriverio/webdrivercss 67 | // WebdriverRTC: https://github.com/webdriverio/webdriverrtc 68 | // Browserevent: https://github.com/webdriverio/browserevent 69 | // plugins: { 70 | // webdrivercss: { 71 | // screenshotRoot: 'my-shots', 72 | // failedComparisonsRoot: 'diffs', 73 | // misMatchTolerance: 0.05, 74 | // screenWidth: [320,480,640,1024] 75 | // }, 76 | // webdriverrtc: {}, 77 | // browserevent: {} 78 | // }, 79 | // 80 | // Test runner services 81 | // Services take over a specific job you don't want to take care of. They enhance 82 | // your test setup with almost no effort. Unlike plugins, they don't add new 83 | // commands. Instead, they hook themselves up into the test process. 84 | // services: [],// 85 | // Framework you want to run your specs with. 86 | // The following are supported: Mocha, Jasmine, and Cucumber 87 | // see also: http://webdriver.io/guide/testrunner/frameworks.html 88 | // 89 | // Make sure you have the wdio adapter package for the specific framework installed 90 | // before running any tests. 91 | framework: 'mocha', 92 | // 93 | // Test reporter for stdout. 94 | // The following are supported: dot (default), spec, and xunit 95 | // see also: http://webdriver.io/guide/testrunner/reporters.html 96 | reporters: ['dot'], 97 | 98 | // 99 | // Options to be passed to Mocha. 100 | // See the full list at http://mochajs.org/ 101 | mochaOpts: { 102 | require: ['@babel/register'], 103 | ui: 'bdd', 104 | timeout: 60 * 1000 105 | } 106 | // 107 | // ===== 108 | // Hooks 109 | // ===== 110 | // WedriverIO provides several hooks you can use to interfere with the test process in order to enhance 111 | // it and to build services around it. You can either apply a single function or an array of 112 | // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got 113 | // resolved to continue. 114 | // 115 | // Gets executed once before all workers get launched. 116 | // onPrepare: function (config, capabilities) { 117 | // }, 118 | // 119 | // Gets executed before test execution begins. At this point you can access all global 120 | // variables, such as `browser`. It is the perfect place to define custom commands. 121 | // before: function (capabilities, specs) { 122 | // }, 123 | // 124 | // Hook that gets executed before the suite starts 125 | // beforeSuite: function (suite) { 126 | // }, 127 | // 128 | // Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling 129 | // beforeEach in Mocha) 130 | // beforeHook: function () { 131 | // }, 132 | // 133 | // Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling 134 | // afterEach in Mocha) 135 | // afterHook: function () { 136 | // }, 137 | // 138 | // Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts. 139 | // beforeTest: function (test) { 140 | // }, 141 | // 142 | // Runs before a WebdriverIO command gets executed. 143 | // beforeCommand: function (commandName, args) { 144 | // }, 145 | // 146 | // Runs after a WebdriverIO command gets executed 147 | // afterCommand: function (commandName, args, result, error) { 148 | // }, 149 | // 150 | // Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) starts. 151 | // afterTest: function (test) { 152 | // }, 153 | // 154 | // Hook that gets executed after the suite has ended 155 | // afterSuite: function (suite) { 156 | // }, 157 | // 158 | // Gets executed after all tests are done. You still have access to all global variables from 159 | // the test. 160 | // after: function (capabilities, specs) { 161 | // }, 162 | // 163 | // Gets executed after all workers got shut down and the process is about to exit. It is not 164 | // possible to defer the end of the process using a promise. 165 | // onComplete: function(exitCode) { 166 | // } 167 | } 168 | --------------------------------------------------------------------------------