├── .all-contributorsrc ├── .clang-format ├── .gitattributes ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── DEVELOPER.md ├── LICENSE ├── README.md ├── bin └── cliptor ├── circle.yml ├── images ├── IE.jpg ├── chrome.png ├── cliptor.gif ├── cliptor.png ├── coffeeScript.png ├── cucumberjs.png ├── firefox.jpg ├── jasmine.png ├── mocha.svg ├── protractor-cli.png └── typescript.png ├── lib ├── cli.ts ├── commands │ ├── config.ts │ └── install.ts ├── helpers │ ├── fileHelper.ts │ ├── moduleHelper.ts │ └── questions.ts └── utils │ └── npmUtil.ts ├── package-lock.json ├── package.json ├── templates ├── .eslintrc.json ├── protractor.conf.ejs ├── tsconfig.e2e.json └── tslint.json ├── test ├── moduleHelper.spec.ts └── questions.spec.ts ├── tsconfig.json ├── tslint.json └── yarn.lock /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "protractor-cli", 3 | "projectOwner": "igniteram", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "contributors": [ 12 | { 13 | "login": "igniteram", 14 | "name": "Ram Pasala", 15 | "avatar_url": "https://avatars1.githubusercontent.com/u/15998104?v=4", 16 | "profile": "https://in.linkedin.com/in/rpasala", 17 | "contributions": [ 18 | "code", 19 | "doc", 20 | "test", 21 | "bug" 22 | ] 23 | }, 24 | { 25 | "login": "cnishina", 26 | "name": "Craig Nishina", 27 | "avatar_url": "https://avatars3.githubusercontent.com/u/1559007?v=4", 28 | "profile": "https://github.com/cnishina", 29 | "contributions": [ 30 | "code", 31 | "plugin" 32 | ] 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | Language: JavaScript 2 | BasedOnStyle: Google 3 | ColumnLimit: 100 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.ejs linguist-language=JavaScript 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | built 2 | node_modules 3 | .vs_code 4 | npm-debug.log -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .vs_code 2 | package-lock.json 3 | 4 | # dev folders 5 | 6 | built/**/*.map 7 | lib/ 8 | images/ 9 | test/ 10 | 11 | # dev files 12 | 13 | .gitignore 14 | .gitattributes 15 | .npmignore 16 | tsconfig.json 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Release 1.1.0 2 | 3 | ## Breaking Changes 4 | 5 | * removed cross-spawn dependency 6 | 7 | ### Features 8 | 9 | - ([fc25d5e](https://github.com/igniteram/protractor-cli/commit/fc25d5edc09d775f35e356796c19e0425fc936d2)) 10 | feat(install modules): added npm progress & async installation 11 | 12 | ## Release 1.0.1 13 | 14 | ### Features 15 | - ([7441967](https://github.com/igniteram/protractor-cli/commit/7441967b1ec32e4718a656956c4573fd6245aa7a)) 16 | build(commitizen): Added commitizen to the project 17 | ### Fixes 18 | - ([bb5c6b8](https://github.com/igniteram/protractor-cli/commit/bb5c6b8c837f146c2934d2dc726a5e72f8980c4b)) 19 | chore(release):updated package version to 1.0.1 (#23) 20 | 21 | ## Release 1.0.0 22 | 23 | ## Breaking Changes 24 | 25 | - ([30e1a43](https://github.com/igniteram/protractor-cli/commit/30e1a4336e7a5ec0d55a3458d7452476d5d4683c)) 26 | chore(docs):update readme (#19) 27 | 28 | 29 | * Changed the project name to **protractor-cli** 30 | * Updated readme with protracto-cli info 31 | * Moved the spec files to test folder 32 | 33 | - ([a49828e](https://github.com/igniteram/protractor-cli/commit/a49828e065355041aa945e206d43162afcd77f3a)) 34 | chore(release):updated package name to protractor-cli (#22) 35 | 36 | * chore(release):updated package name to protractor-cli 37 | 38 | * chore(release):removed tslint from npmignore 39 | 40 | ### Features 41 | 42 | - ([722f9ba](https://github.com/igniteram/protractor-cli/commit/722f9baa1a3e3f40ec1dd51d1557914357edfac5)) 43 | chore(modules): added yarn for better package management (#15) 44 | 45 | 46 | - ([0c97bb5](https://github.com/igniteram/protractor-cli/commit/0c97bb5666664d0a56c73c789c3bf673b47b8776)) 47 | chore(modules): add linters option to cli (#13) 48 | 49 | * Added eslint-plugin-protractor & tslint options to cli 50 | * Updated all dependencies 51 | 52 | - ([84859ba](https://github.com/igniteram/protractor-cli/commit/84859ba90e34cb11e3767f0ed744870c65d278ae)) 53 | chore(modules):update deprecated coffee-script module (#18) 54 | 55 | * chore(modules):update deprecated coffee-script module 56 | * updated coffee-script to new coffeescript module 57 | 58 | * chore(tests):fix unit tests for coffeescript 59 | 60 | - ([c761e6c](https://github.com/igniteram/protractor-cli/commit/c761e6c7540effb5d7994b1d4780e75cdacb413d)) 61 | chore(loglevel):replace previous loglevel to config interface (#17) 62 | 63 | * protractor's new changes support loglevel in config file 64 | * added loglevel option in config ejs file 65 | 66 | ### Fixes 67 | 68 | - ([90d98e3](https://github.com/igniteram/protractor-cli/commit/90d98e3037f8a8a6707ea6a3b6e730c51e6e6738)) 69 | chore(release):updated package.json to 1.0 version (#21) 70 | 71 | * chore(docs):updated badge links in readme 72 | 73 | * chore(release):updated package.json to 1.0 version 74 | 75 | - ([d5509ff](https://github.com/igniteram/protractor-cli/commit/d5509ff3f594e15ec63a09b0f431b5942c6aa3ee)) 76 | chore(docs):updated badge links in readme (#20) 77 | 78 | - ([da30e17](https://github.com/igniteram/protractor-cli/commit/da30e17ffdee0cae998776978aa9f25b8376c93f)) 79 | bug(template):fixed cucumber custom framework config (#16) 80 | 81 | * Added the custom framework option for cucumber 82 | * Upgraded the cross-spawn to 6.x 83 | 84 | - ([722f9ba](https://github.com/igniteram/protractor-cli/commit/722f9baa1a3e3f40ec1dd51d1557914357edfac5)) 85 | chore(modules): added yarn for better package management (#15) 86 | 87 | - ([63b64a0](https://github.com/igniteram/protractor-cli/commit/63b64a00cc1b5f6de66ed58ff6e48058805cc7f8)) 88 | Chore(cleanup): Updated license & moduleHelper spec file (#12) 89 | 90 | * chore(license): updated license year & version 91 | 92 | * chore(cleanup_specs): Added removeDevModules function in moduleHelper spec 93 | 94 | - ([05e0874](https://github.com/igniteram/protractor-cli/commit/05e0874343d85cbc8d31f4a69174f6a76efbf260)) 95 | chore(cleanup modules):move all modules to dev dependencies (#10) 96 | 97 | * chore(cleanup modules):move all modules to dev dependencies 98 | 99 | ## Release 0.2.1 100 | 101 | ### Fixes 102 | 103 | - ([05e0874](https://github.com/igniteram/protractor-cli/commit/05e0874343d85cbc8d31f4a69174f6a76efbf260)) 104 | chore(cleanup modules):move all modules to dev dependencies (#10) 105 | 106 | * chore(cleanup modules):move all modules to dev dependencies 107 | 108 | * Removed save dependency installation. 109 | * Added unit test for module helper 110 | * Bumped to version to 0.2.0 111 | 112 | * updated circle.yml 113 | 114 | -------------------------------------------------------------------------------- /DEVELOPER.md: -------------------------------------------------------------------------------- 1 | ## Building and Testing Protractor-CLI 2 | 3 | This document describes building, testing, releasing Protractor-CLI and provides an overview of 4 | the repository layout. 5 | 6 | ### Prerequisite software 7 | 8 | The prerequisite software - Node.js, npm, git, jdk 9 | 10 | ### Getting the source code 11 | 12 | Fork Protractor-CLI from github, then clone your fork with: 13 | 14 | ```shell 15 | git clone git@github.com:/protractor-cli.git 16 | 17 | # Go to the Protractor-CLI directory: 18 | cd protractor-cli/ 19 | 20 | # Add the main protractor-cli repository as an upstream remote to your repository: 21 | git remote add upstream https://github.com/igniteram/protractor-cli.git 22 | ``` 23 | 24 | ## Installing and Building 25 | 26 | All Protractor-CLI dependencies come from npm. Install with: 27 | 28 | ```shell 29 | npm install 30 | ``` 31 | One could also make use of yarn package manager as this repository is integrated with yarn.lock file. 32 | 33 | This will also trigger our build step. The build step runs the TypeScript compiler 34 | and copies necessary files into the output `built` directory. To run the build step 35 | independently, run: 36 | 37 | ```shell 38 | npm run prepublish 39 | ``` 40 | 41 | ### Installing Cliptor binary globally 42 | 43 | `npm link` is very similar to `npm install -g` except that instead of downloading the package from the repo, the just cloned protractor-cli folder becomes the global package. 44 | 45 | `cliptor` binary will be available to you globally and any changes you make in this folder could be verified by running binary from anywhere. 46 | 47 | You can see the other available npm scripts in `package.json`. 48 | 49 | ## Formatting 50 | 51 | Protractor-CLI uses clang-format to format the source code. If the source code is not properly formatted, 52 | the CI will fail and the PR can not be merged. 53 | 54 | You can automatically format your code by running: 55 | 56 | ```shell 57 | npm run format 58 | ``` 59 | 60 | You can check that you will pass lint tests with: 61 | 62 | ```shell 63 | npm run lint 64 | 65 | ``` 66 | 67 | ## Code layout 68 | 69 | `bin/` contains cliptor binary. 70 | `images/` contains the repo images. 71 | `lib/` contains the actual Protractor-CLI typescript code. 72 | `templates/` contains the templates used for generating config , tslint & json files. 73 | `test/` contains unit tests and configuration files for tests. 74 | 75 | Most of the code is written in TypeScript, with the exception of a few js files. 76 | 77 | `lib/commands` consist of cliptor commands i.e. install & config. 78 | `lib/helpers` consist helper files for file generation, module installation & command line questions. 79 | `utils` contains npm utility file - wrapper around npm installation for protractor-cli. 80 | `cli.ts` invokes the commander module and integrates the commands. 81 | 82 | 83 | ## Testing 84 | 85 | Run `npm test` to run the full test suite. This project uses [Jest](https://github.com/facebook/jest) 86 | 87 | ## Important dependencies 88 | 89 | [TypeScript](https://github.com/Microsoft/TypeScript): This project is entirely written using typescript inline with protractor & angular projects. 90 | 91 | [Inquirer](https://github.com/SBoudrias/Inquirer.js): This is used to generate the protractor-cli's interactive cli. 92 | 93 | [Commander](https://github.com/tj/commander.js): This is used to integrate all protractor-cli commands in a nead command line interface. 94 | 95 | [EJS](https://github.com/mde/ejs): This is used to generated the protractor.config.js file from the template protractor.config.ejs. 96 | 97 | [Chalk](https://github.com/chalk/chalk): Helps console logging in a colorful way. 98 | 99 | [Jest](https://github.com/facebook/jest): The popular unit testing framework by facebook, protractor-cli's unit tests are being written using jest. 100 | 101 | [JS-beautify](https://github.com/beautify-web/js-beautify): It beautifies your javascript, protractor-cli uses this to beautify config and json files programatically. 102 | 103 | ## Commit by Commitizen 104 | 105 | This project has been integrated by commitizen, one can invoke the commitizen cli by running `npm run commit` before any commit , it would run a clean build and lint all files. 106 | 107 | ## Continuous Integration 108 | 109 | PRs or changes submitted to master will automatically trigger continuous integration Circle CI. 110 | 111 | Circle CI runs a slightly modified version of `npm test` in a single VM. It installs 112 | the modules it needs locally. 113 | 114 | ## Changelog 115 | 116 | See [CHANGELOG.md](https://github.com/angular/protractor/blob/master/CHANGELOG.md) for detailed changelog. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Ram Pasala 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | protractor-cli.png 3 |

4 | 5 |

6 | An Interactive command line interface & config helper for ProtractorJS 7 |

8 | 9 |

10 | circleCI Status 11 | commitizen 12 | dependencies status 13 | npm version 14 | JEST 15 | contributors 16 | MIT License 17 |

18 | 19 | --- 20 | 21 | ###

[About](#about) **|** [To Get Started](#to-get-started) **|** [Installation](#installation) **|** [Commands](#commands)

22 | 23 | ## About 24 | 25 | Protractor-CLI(formerly Cliptor.js) is an interactive command line interface which helps in setting up hassle free protractor projects. It takes user's inputs for generating protractor config files and also downloads the dependencies needed for writing e2e tests. 26 | 27 |

28 | cliptor.gif 29 |

30 | 31 | ### What protractor-cli is trying to solve? 32 | 33 | Since protractor supports multiple frameworks and has many functionalities associated with them , users face it quite challenging to know the config options and experience a hard time to choose the right library to use in their e2e projects. 34 | 35 | This project focuses primarily to solve these issues by generating config files based on user's input and downloads the respective dependencies automatically. 36 | 37 | ## To Get Started 38 | 39 | #### Pre-requisites 40 | 1.NodeJS installed globally in the system. 41 | https://nodejs.org/en/download/ 42 | 43 | ## Installation 44 | 45 | Let's start by installing protractor-cli globally with [npm](https://www.npmjs.com/). 46 | 47 | ```sh 48 | $ npm install --global protractor-cli 49 | ``` 50 | ## Commands 51 | 52 | A global binary **cliptor** will be installed, currently it supports two primary commands - **config** & **install** with no arguments. 53 | `cliptor --help` will show these list commands. `cliptor --version` will show the current version of cliptor. 54 | 55 | ### config 56 | 57 | ```sh 58 | $ cliptor config 59 | ``` 60 | Starts protractor's interactive cli, generates config files & downloads protractor related dependencies! 61 | 62 | ### install 63 | 64 | ```sh 65 | $ cliptor install 66 | ``` 67 | This installs protractor & webdriver-manager globally, it also updates webdriver-manager which downloads **chrome**, **firefox** & **internet explorer** drivers. One can skip this step and use the `cliptor config` command if they want to run selenium server in other ways! 68 | 69 | ## Library Support 70 | 71 | Protractor-CLI supports all the major libraries and frameworks that **Protractor** currently supports, let us have a look- 72 | 73 | ### Test Frameworks 74 | 75 | 76 | 77 | 78 | 79 | Jasmine being the default framework. Mocha & Cucumber have good support as well! 80 | 81 | ### Transpilers 82 | 83 |
84 | 85 | 86 |
87 | 88 | 89 | Since this project has been entirely written using [TypeScript](https://www.typescriptlang.org/). You would find extensive support for it. Protractor also has recently migrated to typescript. 90 | 91 | You could use the typescript features by simply selecting your specific framework & transpiler option provided by protractor-cli. 92 | 93 | Jasmine being the default framework , protractor-cli asks whether you would want to use typescript as a transpiler which then installs **typescript**, **jasmine types** and also generates **tsconfig.json** automatically! 94 | 95 | [Coffee-Script](http://coffeescript.org/) support has also been provided with **mocha** & **cucumber** frameworks. You could write your scripts using coffee-script and the above frameworks will auto-compile them. The best part is you don't have to do it manaully as protractor-cli does it for you! 96 | 97 | ### Browser Configuration 98 | 99 | Protractor-CLI supports all three major browser configuration - 100 | 101 |
102 | 103 | 104 | 105 |
106 | 107 | ### Test Environments 108 | 109 | * **Local Machine** - It is your local test development environment 110 | * **Cloud Service** - If you want to develop and maintain your test scripts in cloud services like - **Sauce Labs** & **BrowserStack**. 111 | * **Remote Machine** - If you know the address of a remote machine where selenium server resides you could use this environment configuration. 112 | 113 | ### Logging 114 | 115 | Protractor has 4 types of logging mechanism - 116 | 117 | * **info** (default) 118 | * **warn** 119 | * **debug** 120 | * **error** 121 | 122 | One could refer this [StackOverFlow link](https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels) to understand what they are and when to use them. Normally you would have to configure these in your config file manually but now protractor-cli does it for you. 123 | 124 | ### Reports 125 | 126 | Protractor-CLI installs & configures popular & well maintained report modules which could be integrated with protractor. 127 | 128 | Framework | Report Types | Report Module 129 | --- | --- | --- 130 | | `Jasmine` |
`dot`

`spec`

`json`

`html`
|
Protractor jasmine's default dot console reporter

[jasmine-spec-reporter](https://github.com/bcaudan/jasmine-spec-reporter) for flashy console spec reporter

Protractor's `resultJsonOutputFile` config option generates json reports

[protractor-jasmine2-screenshot-reporter](protractor-jasmine2-screenshot-reporter) for html reports.
131 | | `Mocha` |
`dot`

`spec`

`json`

`html`
|
Mocha's default dot console reporter in mochaOpts

Built in spec console reporter

Built in mocha's json reporter

[Mochawesome](https://github.com/adamgruber/mochawesome) for html reports. 132 | | `cucumber` |
`progress`

`summary`

`json`

`html`
|
Cucumber's default progress console reporter

Summary console reporter

Json reporter which generates cucumber json reports

[cucumber-html-reporter](https://github.com/gkushang/cucumber-html-reporter) for html reports. 133 | 134 | ### Contributions 135 | 136 | For contributors who want to improve this repo by contributing some code, reporting bugs, issues or improving documentation - PR's are highly welcome, please maintain the coding style , folder structure , detailed description of documentation and bugs/issues with examples if possible. 137 | 138 | #### Development Hints 139 | 140 | Please see [DEVELOPER.md](https://github.com/igniteram/protractor-cli/blob/master/DEVELOPER.md) 141 | 142 | ### Attributions 143 | 144 | Protractor-CLI was mainly inspired by [WebdriverIO’s](https://github.com/webdriverio/webdriverio) cli. I would also like to give credit to the Angular’s Protractor community for creating such a wonderful project which inspired this project development. 145 | ## Contributors 146 | 147 | 148 | 149 | | [
Ram Pasala](https://in.linkedin.com/in/rpasala)
[💻](https://github.com/igniteram/protractor-cli/commits?author=igniteram "Code") [📖](https://github.com/igniteram/protractor-cli/commits?author=igniteram "Documentation") [⚠️](https://github.com/igniteram/protractor-cli/commits?author=igniteram "Tests") [🐛](https://github.com/igniteram/protractor-cli/issues?q=author%3Aigniteram "Bug reports") | [
Craig Nishina](https://github.com/cnishina)
[💻](https://github.com/igniteram/protractor-cli/commits?author=cnishina "Code") [🔌](#plugin-cnishina "Plugin/utility libraries") | 150 | | :---: | :---: | 151 | 152 | Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)): 153 | 154 | 155 | 156 | 157 | 158 | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! -------------------------------------------------------------------------------- /bin/cliptor: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | process.env.NODE_ENV = process.env.NODE_ENV || 'test'; 4 | 5 | require('../built/cli.js'); -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 8 4 | 5 | test: 6 | override: 7 | - npm test -------------------------------------------------------------------------------- /images/IE.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniteram/protractor-cli/80c466a50a06f8023a527452f3b58e83a77f0a22/images/IE.jpg -------------------------------------------------------------------------------- /images/chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniteram/protractor-cli/80c466a50a06f8023a527452f3b58e83a77f0a22/images/chrome.png -------------------------------------------------------------------------------- /images/cliptor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniteram/protractor-cli/80c466a50a06f8023a527452f3b58e83a77f0a22/images/cliptor.gif -------------------------------------------------------------------------------- /images/cliptor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniteram/protractor-cli/80c466a50a06f8023a527452f3b58e83a77f0a22/images/cliptor.png -------------------------------------------------------------------------------- /images/coffeeScript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniteram/protractor-cli/80c466a50a06f8023a527452f3b58e83a77f0a22/images/coffeeScript.png -------------------------------------------------------------------------------- /images/cucumberjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniteram/protractor-cli/80c466a50a06f8023a527452f3b58e83a77f0a22/images/cucumberjs.png -------------------------------------------------------------------------------- /images/firefox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniteram/protractor-cli/80c466a50a06f8023a527452f3b58e83a77f0a22/images/firefox.jpg -------------------------------------------------------------------------------- /images/jasmine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniteram/protractor-cli/80c466a50a06f8023a527452f3b58e83a77f0a22/images/jasmine.png -------------------------------------------------------------------------------- /images/mocha.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha Logoimage/svg+xmlMocha Logo08-21-2015Dick DeLeon <ddeleon@decipherinc.com>CC BY-SA 4.0mochamochajsChristopher Hiller <boneskull@boneskull.com> -------------------------------------------------------------------------------- /images/protractor-cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniteram/protractor-cli/80c466a50a06f8023a527452f3b58e83a77f0a22/images/protractor-cli.png -------------------------------------------------------------------------------- /images/typescript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniteram/protractor-cli/80c466a50a06f8023a527452f3b58e83a77f0a22/images/typescript.png -------------------------------------------------------------------------------- /lib/cli.ts: -------------------------------------------------------------------------------- 1 | import * as program from 'commander'; 2 | import {config} from './commands/config'; 3 | import {install} from './commands/install'; 4 | const pkg = require('../package.json'); 5 | 6 | program.version(pkg.version) 7 | .description('Protractor\'s Interactive CLI') 8 | .command('*', '', {noHelp: true, isDefault: true}) 9 | .action(() => { 10 | program.help(); 11 | }); 12 | 13 | const cliArgs = Object.assign(program, config, install); 14 | cliArgs.parse(process.argv); 15 | 16 | if (!cliArgs.args.length) { 17 | cliArgs.help(); 18 | } 19 | 20 | /** 21 | * Public Interface 22 | */ 23 | export {program}; 24 | -------------------------------------------------------------------------------- /lib/commands/config.ts: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | import * as inquirer from 'inquirer'; 3 | import {program} from '../cli'; 4 | import {createConfigFile} from '../helpers/fileHelper'; 5 | import {installModules} from '../helpers/moduleHelper'; 6 | import {questions} from '../helpers/questions'; 7 | 8 | program.command('config') 9 | .alias('c') 10 | .description('Starts protractor\'s interactive cli') 11 | .action(async () => { 12 | if (!process.argv.slice(3).length) { 13 | console.log(` 14 | ============================ 15 | ${chalk.red.bold('PROTRACTOR\'s INTERACTIVE CLI')} 16 | ============================ 17 | 18 | `); 19 | const answers = await inquirer.prompt(questions); 20 | try { 21 | await installModules(answers); 22 | } catch (err) { 23 | throw new Error(err); 24 | } 25 | await createConfigFile(answers); 26 | 27 | } else { 28 | console.error(chalk.red(` 29 | ${'Config command doesn\'t have any arguments! Try running the command only!'}`)); 30 | process.exit(0); 31 | } 32 | }); 33 | 34 | /** 35 | * Public Interface 36 | */ 37 | export const config = {program}; 38 | -------------------------------------------------------------------------------- /lib/commands/install.ts: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | 3 | import {program} from '../cli'; 4 | import {checkPackageJson, installPkgs, updateWebdriver} from '../utils/npmUtil'; 5 | const pkgs = ['protractor', 'webdriver-manager']; 6 | 7 | program.command('install') 8 | .alias('i') 9 | .description('Installs protractor and webdriver dependencies globally!') 10 | .action(async () => { 11 | if (!process.argv.slice(3).length) { 12 | try { 13 | await checkPackageJson(); 14 | await installPkgs( 15 | 'Installing Protractor & Webdriver-Manager Pkgs Globally!...', pkgs, {global: true}); 16 | const updateWd: any = await updateWebdriver(); 17 | console.log(updateWd); 18 | } catch (err) { 19 | throw new Error(err); 20 | } 21 | } else { 22 | console.error(chalk.red(` 23 | ${'Install command doesn\'t have any arguments! Try running the command only!'}`)); 24 | process.exit(0); 25 | } 26 | }); 27 | 28 | /** 29 | * Public Interface 30 | */ 31 | export const install = {program}; 32 | -------------------------------------------------------------------------------- /lib/helpers/fileHelper.ts: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | import * as ejs from 'ejs'; 3 | import * as fs from 'fs'; 4 | import * as jsBeautify from 'js-beautify'; 5 | import * as mkdirp from 'mkdirp'; 6 | import * as path from 'path'; 7 | const tsconfig = require('../../templates/tsconfig.e2e.json'); 8 | import {promisify} from 'util'; 9 | 10 | const mkdirpAsync = promisify(mkdirp); 11 | const readFileAsync = promisify(fs.readFile.bind(fs)); 12 | const writeFileAsync = promisify(fs.writeFile.bind(fs)); 13 | 14 | const cukeJsonFormatter: string = `json:./reports/cucumber_report.json`; 15 | let beforeLaunchExpression: string; 16 | let formatExpression: string; 17 | let jasmineReportExpression: string; 18 | let logExpression: string; 19 | let mochaReportExpression: string; 20 | let onCompleteExpression: string; 21 | let onPrepareExpression: string; 22 | let seleniumAddressExpression: string; 23 | let seleniumServerJarExpression: string; 24 | let transpilerExpression: string; 25 | const tsconfigTypes: string[] = []; 26 | 27 | function existsAsync(filePath: string) { 28 | let fulfill: any = null; 29 | const promise = new Promise((x) => { 30 | fulfill = x; 31 | }); 32 | fs.access(filePath, (err) => { 33 | fulfill(!err); 34 | }); 35 | return promise; 36 | } 37 | 38 | async function createDirectory(filepath: string) { 39 | if (filepath.indexOf('*') > -1) { 40 | filepath = filepath.substring(0, filepath.indexOf('*')); 41 | } 42 | const dirname = path.join(process.cwd(), filepath); 43 | try { 44 | if (!(await existsAsync(dirname))) { 45 | mkdirpAsync(dirname); 46 | } 47 | } catch (err) { 48 | throw new Error(err.toString()); 49 | } 50 | } 51 | 52 | async function createTSconfigfile(options: string[]) { 53 | tsconfig.compilerOptions.types = tsconfig.compilerOptions.types.concat(options); 54 | try { 55 | await writeFileAsync( 56 | path.join(process.cwd(), './tsconfig.e2e.json'), JSON.stringify(tsconfig, null, 4)); 57 | } catch (err) { 58 | throw new Error(err.toString()); 59 | } 60 | } 61 | 62 | async function createTSLintFile() { 63 | try { 64 | await writeFileAsync( 65 | path.join(process.cwd(), './tslint.json'), JSON.stringify(tsconfig, null, 4)); 66 | } catch (err) { 67 | throw new Error(err.toString()); 68 | } 69 | } 70 | 71 | async function createESLintRCFile() { 72 | try { 73 | await writeFileAsync( 74 | path.join(process.cwd(), './.eslintrc.json'), JSON.stringify(tsconfig, null, 4)); 75 | } catch (err) { 76 | throw new Error(err.toString()); 77 | } 78 | } 79 | 80 | async function createConfigFile(answers: any) { 81 | if (answers.backend.indexOf('local machine') > -1) { 82 | if (!answers.drivers && !answers.webdriver) { 83 | seleniumServerJarExpression = `seleniumServerjar: '${answers.seleniumJar}',`; 84 | seleniumAddressExpression = `seleniumAddress: '${answers.seleniumAddress}',`; 85 | } 86 | if (answers.webdriver) { 87 | seleniumAddressExpression = `seleniumAddress: '${answers.seleniumAddress}',`; 88 | } 89 | } else if (answers.backend.indexOf('remote selenium server') > -1) { 90 | seleniumAddressExpression = `seleniumAddress: '${answers.host}',`; 91 | } 92 | if (answers.framework === 'jasmine') { 93 | if (answers.transpilerType === 'typescript') { 94 | tsconfigTypes.push('jasmine', 'jasminewd2'); 95 | beforeLaunchExpression = `require('ts-node').register({ 96 | project: './tsconfig.e2e.json' 97 | });`; 98 | } 99 | if (answers.reportType === 'spec') { 100 | jasmineReportExpression = `const {SpecReporter} = require('jasmine-spec-reporter');`; 101 | onPrepareExpression = `jasmine.getEnv().addReporter(new SpecReporter({ 102 | spec: { 103 | displayStacktrace: true 104 | } 105 | })); 106 | `; 107 | } else if (answers.reportType === 'html') { 108 | jasmineReportExpression = 109 | `const HtmlScreenshotReporter = require('protractor-jasmine2-screenshot-reporter');`; 110 | onPrepareExpression = `jasmine.getEnv().addReporter(new HtmlScreenshotReporter({ 111 | dest: 'target/screenshots', 112 | filename: 'protractor_jasmine_report.html' 113 | })); 114 | `; 115 | } 116 | } 117 | if (answers.framework === 'mocha') { 118 | if (answers.transpilerType === 'typescript') { 119 | tsconfigTypes.push('mocha'); 120 | transpilerExpression = `'ts:ts-node/register'`; 121 | } else if (answers.transpilerType === 'coffeescript') { 122 | transpilerExpression = `'coffee:coffeescript/register'`; 123 | } 124 | if (answers.reportType === 'html') { 125 | mochaReportExpression = `'mochawesome', 126 | reporterOptions : { 127 | reportDir: './reports', 128 | reportFileName: 'protractor_mocha_report', 129 | enableCharts: true 130 | }`; 131 | } else { 132 | mochaReportExpression = answers.reportType; 133 | } 134 | } 135 | if (answers.framework === 'cucumber') { 136 | if (answers.transpilerType === 'typescript') { 137 | tsconfigTypes.push('cucumber'); 138 | transpilerExpression = `'ts:ts-node/register'`; 139 | } else if (answers.transpilerType === 'coffeescript') { 140 | transpilerExpression = `'coffee:coffeescript/register'`; 141 | } 142 | formatExpression = answers.cucumberReportType; 143 | if (answers.cucumberReportType === 'json') { 144 | formatExpression = cukeJsonFormatter; 145 | } 146 | if (answers.cucumberReportType === 'html') { 147 | formatExpression = cukeJsonFormatter; 148 | onCompleteExpression = `const cucumberReporterOptions = { 149 | theme: 'bootstrap', 150 | jsonFile: './reports/cucumber_report.json', 151 | output: process.cwd() + './reports/cucumber_reporter.html', 152 | reportSuiteAsScenarios: true 153 | }; 154 | reporter.generate(cucumberReporterOptions); 155 | `; 156 | } 157 | } 158 | try { 159 | if (answers.specPath) { 160 | await createDirectory(answers.specs); 161 | } 162 | if (answers.featurePath) { 163 | await createDirectory(answers.specs); 164 | await createDirectory(answers.stepDefinitions); 165 | } 166 | if (answers.transpilerType === 'typescript') { 167 | await createTSconfigfile(tsconfigTypes); 168 | } 169 | if (answers.linter === 'tslint') { 170 | await createTSLintFile(); 171 | } 172 | if (answers.linter === 'eslint-plugin-protractor') { 173 | await createESLintRCFile(); 174 | } 175 | } catch (err) { 176 | throw new Error(err); 177 | } 178 | 179 | if (answers.logging === 'error') { 180 | logExpression = answers.logging.toUpperCase(); 181 | } else if (answers.logging === 'warn') { 182 | logExpression = answers.logging.toUpperCase(); 183 | } else if (answers.logging === 'debug') { 184 | logExpression = answers.logging.toUpperCase(); 185 | } else { 186 | logExpression = 'INFO'; 187 | } 188 | if (answers.createReportPath) { 189 | await createDirectory(answers.reportPath); 190 | } 191 | 192 | try { 193 | const templateData = 194 | await readFileAsync(path.join(__dirname, '../../templates/protractor.conf.ejs'), 'utf8'); 195 | const renderedFile = ejs.render(templateData, { 196 | answers, 197 | beforeLaunchExpression, 198 | formatExpression, 199 | jasmineReportExpression, 200 | logExpression, 201 | mochaReportExpression, 202 | onCompleteExpression, 203 | onPrepareExpression, 204 | seleniumAddressExpression, 205 | seleniumServerJarExpression, 206 | transpilerExpression, 207 | }); 208 | await writeFileAsync( 209 | path.join(process.cwd(), './protractor.conf.js'), jsBeautify(renderedFile)); 210 | console.log(` 211 | ${chalk.green('Configuration file was created successfully!')} 212 | ${chalk.green('To run your tests, execute:')} 213 | ${chalk.green('$ protractor protractor.conf.js')} 214 | `); 215 | } catch (err) { 216 | throw new Error(err.toString()); 217 | } 218 | } 219 | 220 | export {existsAsync, createConfigFile}; 221 | -------------------------------------------------------------------------------- /lib/helpers/moduleHelper.ts: -------------------------------------------------------------------------------- 1 | import {checkPackageJson, installPkgs} from '../utils/npmUtil'; 2 | 3 | // install protractor by default as dev dependency 4 | const devModules: string[] = ['protractor']; 5 | 6 | async function installModules(answers: any) { 7 | if (answers.framework === 'jasmine') { 8 | if (answers.transpilerType === 'typescript') { 9 | devModules.push('typescript', '@types/node', '@types/jasmine', 'ts-node'); 10 | } else if (answers.transpilerType === 'coffeescript') { 11 | devModules.push('coffeescript'); 12 | } 13 | if (answers.reportType === 'spec') { 14 | devModules.push('jasmine-spec-reporter'); 15 | } 16 | if (answers.reportType === 'html') { 17 | devModules.push('protractor-jasmine2-screenshot-reporter'); 18 | } 19 | } 20 | if (answers.framework === 'mocha') { 21 | if (answers.transpiler) { 22 | if (answers.transpilerType === 'typescript') { 23 | devModules.push('typescript', '@types/node', '@types/mocha', 'ts-node'); 24 | } else if (answers.transpilerType === 'coffeescript') { 25 | devModules.push('coffeescript'); 26 | } 27 | } 28 | if (answers.reportType === 'html') { 29 | devModules.push('mochawesome'); 30 | } 31 | } 32 | if (answers.framework === 'cucumber') { 33 | devModules.push('cucumber', 'protractor-cucumber-framework'); 34 | if (answers.transpiler) { 35 | if (answers.transpilerType === 'typescript') { 36 | devModules.push('typescript', '@types/node', '@types/cucumber', 'ts-node'); 37 | } else if (answers.transpilerType === 'coffeescript') { 38 | devModules.push('coffeescript'); 39 | } 40 | } 41 | if (answers.cucumberReportType === 'html') { 42 | devModules.push('cucumber-html-reporter'); 43 | } 44 | } 45 | if (answers.linter) { 46 | if (answers.linter === 'tslint') { 47 | devModules.push('tslint', 'tslint-eslint-rules'); 48 | } else { 49 | devModules.push('eslint', 'eslint-plugin-protractor'); 50 | } 51 | } 52 | 53 | if (devModules.length > 0) { 54 | try { 55 | await checkPackageJson(); 56 | await installPkgs('Installing dev dependencies...', devModules, { 57 | saveDev: true, 58 | }); 59 | } catch (err) { 60 | console.log(err); 61 | } 62 | } 63 | } 64 | 65 | /** 66 | * Public Interface 67 | */ 68 | export {installModules, devModules}; 69 | -------------------------------------------------------------------------------- /lib/helpers/questions.ts: -------------------------------------------------------------------------------- 1 | const browsers = ['chrome', 'firefox', 'internet explorer']; 2 | const cloudServices = ['sauce labs', 'browserstack']; 3 | const frameworks = ['jasmine', 'mocha', 'cucumber']; 4 | const linters = ['eslint-plugin-protractor', 'tslint']; 5 | const logType = ['info', 'error', 'warn', 'debug']; 6 | const reportTypes = ['dot', 'spec', 'json', 'html']; 7 | const cucumberReportTypes = ['progress', 'summary', 'json', 'html']; 8 | const transpilers = ['typescript', 'coffeescript']; 9 | 10 | const questions: any[] = [ 11 | { 12 | default: 'http://localhost', 13 | message: 'What is the base url of your application?', 14 | name: 'baseURL', 15 | type: 'input', 16 | }, 17 | { 18 | choices: [ 19 | 'My local machine', 20 | 'In cloud services like Sauce Labs or Browserstack', 21 | 'I know a remote selenium server', 22 | ], 23 | default: 'My local machine', 24 | message: 'What is your test environment?', 25 | name: 'backend', 26 | type: 'list', 27 | }, 28 | { 29 | default: 'http://127.0.0.1:4444/wd/hub', 30 | message: 'What is the host address of that remote server?', 31 | name: 'host', 32 | type: 'input', 33 | when: (answers: any) => answers.backend.indexOf('remote selenium') > -1, 34 | }, 35 | { 36 | choices: cloudServices, 37 | default: 'sauce labs', 38 | message: 'Please select the could service: ', 39 | name: 'services', 40 | type: 'list', 41 | when: (answers: any) => answers.backend.indexOf('In cloud services ') > -1, 42 | }, 43 | { 44 | default: 'SAUCE_USERNAME', 45 | message: 'Environment variable for sauce labs username', 46 | name: 'sauceUser', 47 | type: 'input', 48 | when: (answers: any) => answers.services === 'sauce labs', 49 | }, 50 | { 51 | default: 'SAUCE_ACCESS_KEY', 52 | message: 'Environment variable for sauce labs access key', 53 | name: 'sauceKey', 54 | type: 'input', 55 | when: (answers: any) => answers.services === 'sauce labs', 56 | }, 57 | { 58 | default: 'BROWSER_STACK_USERNAME', 59 | message: 'Environment variable for Browserstack username', 60 | name: 'browserstackUser', 61 | type: 'input', 62 | when: (answers: any) => answers.services === 'browserstack', 63 | }, 64 | { 65 | default: 'BROWSER_STACK_ACCESS_KEY', 66 | message: 'Environment variable for Browserstack access key', 67 | name: 'browserstackKey', 68 | type: 'input', 69 | when: (answers: any) => answers.services === 'browserstack', 70 | }, 71 | { 72 | default: true, 73 | message: 'Do you want to use webdriver-manager\'s drivers?', 74 | name: 'webdriver', 75 | type: 'confirm', 76 | when: (answers: any) => answers.backend.indexOf('local machine') > -1, 77 | }, 78 | { 79 | default: false, 80 | message: 'Do you want to use built in browser drivers?', 81 | name: 'drivers', 82 | type: 'confirm', 83 | when: (answers: any) => !answers.webdriver && answers.backend.indexOf('local machine') > -1, 84 | }, 85 | { 86 | default: './selenium/*.jar', 87 | message: 'Please enter the selenium jar file location:', 88 | name: 'seleniumJar', 89 | type: 'input', 90 | when: (answers: any) => 91 | !answers.drivers && !answers.webdriver && answers.backend.indexOf('local machine') > -1, 92 | }, 93 | { 94 | default: 'http://localhost:4444/wd/hub', 95 | message: 'Please enter the local selenium server address:', 96 | name: 'seleniumAddress', 97 | type: 'input', 98 | when: (answers: any) => !answers.drivers && answers.backend.indexOf('local machine') > -1, 99 | }, 100 | { 101 | choices: browsers, 102 | default: 'chrome', 103 | message: 'Select the choice of your browser:', 104 | name: 'browser', 105 | type: 'list', 106 | }, 107 | { 108 | choices: frameworks, 109 | default: 'jasmine', 110 | message: 'Which framework do you want to use?', 111 | name: 'framework', 112 | type: 'list', 113 | }, 114 | { 115 | default: true, 116 | message: 'Do you want to use a transpiler?', 117 | name: 'transpiler', 118 | type: 'confirm', 119 | }, 120 | { 121 | choices: transpilers, 122 | default: 'typescript', 123 | message: 'Please select the transpiler:', 124 | name: 'transpilerType', 125 | type: 'list', 126 | when: (answers: any) => answers.transpiler, 127 | }, 128 | { 129 | default: (answers: any) => { 130 | if (answers.transpilerType === 'typescript') { 131 | return './test/specs/**/*.ts'; 132 | } else if (answers.transpilerType === 'coffeescript') { 133 | return './test/specs/**/*.coffee'; 134 | } else { 135 | return './test/specs/**/*.js'; 136 | } 137 | }, 138 | message: 'Where are your test specs located?', 139 | name: 'specs', 140 | type: 'input', 141 | when: (answers: any) => answers.framework.match(/(jasmine|mocha)/), 142 | }, 143 | { 144 | default: true, 145 | message: (answers: any) => { 146 | let folderPath: string; 147 | if (answers.specs.indexOf('*') > -1) { 148 | folderPath = answers.specs.substring(0, answers.specs.indexOf('*')); 149 | } 150 | return `Do you want to create ${folderPath} folder?`; 151 | }, 152 | name: 'specPath', 153 | type: 'confirm', 154 | when: (answers: any) => answers.framework.match(/(jasmine|mocha)/), 155 | 156 | }, 157 | { 158 | default: './features/**/*.feature', 159 | message: 'Where are your feature files located?', 160 | name: 'specs', 161 | type: 'input', 162 | when: (answers: any) => answers.framework === 'cucumber', 163 | }, 164 | { 165 | default: (answers: any) => { 166 | if (answers.transpilerType === 'typescript') { 167 | return './features/stepDefinitions/**/*.ts'; 168 | } else if (answers.transpilerType === 'coffeescript') { 169 | return './features/stepDefinitions/**/*.coffee'; 170 | } else { 171 | return './features/stepDefinitions/**/*.js'; 172 | } 173 | }, 174 | message: 'Where are your step definitions located?', 175 | name: 'stepDefinitions', 176 | type: 'input', 177 | when: (answers: any) => answers.framework === 'cucumber', 178 | }, 179 | { 180 | default: true, 181 | message: 'Do you want to create the above folders?', 182 | name: 'featurePath', 183 | type: 'confirm', 184 | when: (answers: any) => answers.framework === 'cucumber', 185 | 186 | }, 187 | { 188 | choices: logType, 189 | default: 'info', 190 | message: 'Level of logging verbosity:', 191 | name: 'logging', 192 | type: 'list', 193 | }, 194 | { 195 | choices: linters, 196 | default: true, 197 | message: 'Please select the following linters to install:', 198 | name: 'linter', 199 | type: 'list', 200 | when: (answers: any) => answers.transpilerType !== 'coffeescript', 201 | }, 202 | { 203 | default: true, 204 | message: 'Do you want to generate reports of your tests?', 205 | name: 'reports', 206 | type: 'confirm', 207 | }, 208 | { 209 | choices: reportTypes, 210 | default: 'dot', 211 | message: 'Please select the type of report:', 212 | name: 'reportType', 213 | type: 'list', 214 | when: (answers: any) => answers.reports && answers.framework.match(/(jasmine|mocha)/), 215 | }, 216 | { 217 | choices: cucumberReportTypes, 218 | default: 'progress', 219 | message: 'Please select the type of report:', 220 | name: 'cucumberReportType', 221 | type: 'list', 222 | when: (answers: any) => answers.reports && answers.framework === 'cucumber', 223 | }, 224 | { 225 | default: './reports', 226 | message: 'Where do you want to store your reports?', 227 | name: 'reportPath', 228 | type: 'input', 229 | when: (answers: any) => answers.reports, 230 | }, 231 | { 232 | default: true, 233 | message: (answers: any) => { 234 | return `Do you want to create ${answers.reportPath} folder?`; 235 | }, 236 | name: 'createReportPath', 237 | type: 'confirm', 238 | when: (answers: any) => answers.reports, 239 | }, 240 | ]; 241 | 242 | /** 243 | * Public Inteface 244 | */ 245 | export {questions}; 246 | -------------------------------------------------------------------------------- /lib/utils/npmUtil.ts: -------------------------------------------------------------------------------- 1 | import {existsAsync} from '../helpers/fileHelper'; 2 | const {spawn} = require('child_process'); 3 | const chalk = require('chalk'); 4 | 5 | import * as path from 'path'; 6 | 7 | async function checkPackageJson() { 8 | const dir = path.resolve(process.cwd()); 9 | const pkgJson = path.join(dir, 'package.json'); 10 | if (!await (existsAsync(pkgJson))) { 11 | console.log( 12 | chalk.red('\nCould not find a package.json file! ') + 13 | chalk.green('Creating package.json...')); 14 | 15 | const initPkg = spawn('npm', ['init', '--yes'], {stdio: 'pipe'}); 16 | 17 | let stderr = ''; 18 | 19 | initPkg.stderr.on('data', (data: any) => { 20 | stderr += data; 21 | }); 22 | 23 | initPkg.on('close', (code: number) => { 24 | if (code !== 0) { 25 | console.log(chalk.red( 26 | '\nUnable to create package.json! ' + 27 | `${stderr}`)); 28 | } 29 | }); 30 | } 31 | } 32 | 33 | async function installPkgs(des: string, packages: string[], opts: any) { 34 | return new Promise((resolve, reject) => { 35 | const args: string[] = ['--loglevel=error']; 36 | if (opts.save) { 37 | args.push('-S'); 38 | } 39 | if (opts.saveDev) { 40 | args.push('-D'); 41 | } 42 | if (opts.global) { 43 | args.push('-g'); 44 | } 45 | const cliArgs: string[] = ['i'].concat(args, packages); 46 | 47 | process.stdout.write('\n' + chalk.yellow(des) + '\n'); 48 | 49 | const install = spawn('npm', cliArgs, {stdio: 'inherit'}); 50 | 51 | install.on('error', (err: Error) => { 52 | if (err) { 53 | reject(err); 54 | } 55 | }); 56 | 57 | install.on('exit', (code: any) => { 58 | if (code === 0) { 59 | resolve('successfully installed packages!'); 60 | } 61 | }); 62 | }); 63 | } 64 | 65 | async function unInstallPkgs(des: string, packages: string[], opts: any) { 66 | return new Promise((resolve, reject) => { 67 | const args: string[] = ['--loglevel=error']; 68 | if (opts.save) { 69 | args.push('-S'); 70 | } 71 | if (opts.saveDev) { 72 | args.push('-D'); 73 | } 74 | if (opts.global) { 75 | args.push('-g'); 76 | } 77 | const cliArgs: string[] = ['uninstall'].concat(args, packages); 78 | 79 | process.stdout.write('\n' + chalk.yellow(des) + '\n'); 80 | 81 | const install = spawn('npm', cliArgs, {stdio: 'inherit'}); 82 | 83 | install.on('error', (err: Error) => { 84 | if (err) { 85 | reject(err); 86 | } 87 | }); 88 | 89 | install.on('exit', (code: any) => { 90 | if (code === 0) { 91 | resolve('successfully unInstalled packages!'); 92 | } 93 | }); 94 | }); 95 | } 96 | 97 | async function updateWebdriver() { 98 | return new Promise((resolve, reject) => { 99 | process.stdout.write( 100 | chalk.yellow('\nDownloading chrome, firefox & internet explorer drivers...\n')); 101 | const install = spawn('webdriver-manager', ['update', '--ie'], {stdio: 'inherit'}); 102 | 103 | install.on('error', (err: Error) => { 104 | if (err) { 105 | reject(err); 106 | } 107 | }); 108 | 109 | install.on('exit', (code: any) => { 110 | if (code === 0) { 111 | resolve(` 112 | ${chalk.green('Protractor & Webdriver-Manager dependencies installed successfully!')} 113 | ${chalk.green('To start the selenium server, execute:')} 114 | ${chalk.green('$ webdriver-manager start')} 115 | `); 116 | } 117 | }); 118 | }); 119 | } 120 | 121 | export {checkPackageJson, installPkgs, unInstallPkgs, updateWebdriver}; 122 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "protractor-cli", 3 | "version": "1.1.1", 4 | "description": "Protractor's Interactive CLI", 5 | "main": "built/cli.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/igniteram/protractor-cli.git" 9 | }, 10 | "bin": { 11 | "cliptor": "bin/cliptor" 12 | }, 13 | "scripts": { 14 | "prebuild": "npm run format", 15 | "build": "tsc", 16 | "clean": "rimraf built/", 17 | "clean-build": "npm run clean && npm run build", 18 | "precommit": "npm run clean-build && npm run lint", 19 | "commit": "git-cz", 20 | "format": "clang-format -i --glob='+(lib|test)/**/*.ts'", 21 | "lint": "tslint -c tslint.json 'lib/**/*.ts'", 22 | "prepublish": "npm run clean-build", 23 | "pretest": "npm run lint", 24 | "test": "jest", 25 | "compile": "tsc -w" 26 | }, 27 | "keywords": [ 28 | "angular", 29 | "protractor", 30 | "command line interface", 31 | "typescript", 32 | "cli", 33 | "angular-cli", 34 | "webdriver", 35 | "jasmine", 36 | "mocha", 37 | "cucumber", 38 | "protractor-cucumber", 39 | "selenium", 40 | "testing" 41 | ], 42 | "author": "Ram Pasala ", 43 | "license": "MIT", 44 | "dependencies": { 45 | "chalk": "^2.4.1", 46 | "commander": "^2.15.1", 47 | "ejs": "^2.6.1", 48 | "inquirer": "^6.2.0", 49 | "js-beautify": "^1.7.5", 50 | "mkdirp": "^0.5.1" 51 | }, 52 | "devDependencies": { 53 | "@types/commander": "^2.12.2", 54 | "@types/ejs": "^2.5.1", 55 | "@types/inquirer": "0.0.43", 56 | "@types/jest": "^23.3.9", 57 | "@types/js-beautify": "1.8.0", 58 | "@types/mkdirp": "^0.5.2", 59 | "@types/node": "^10.12.3", 60 | "clang-format": "^1.0.55", 61 | "commitizen": "^3.0.4", 62 | "cz-conventional-changelog": "^2.1.0", 63 | "jest": "^23.6.0", 64 | "ts-jest": "^23.10.4", 65 | "tslint": "^5.10.0", 66 | "tslint-eslint-rules": "^5.3.1", 67 | "typescript": "^3.1.6" 68 | }, 69 | "typings": "built/index", 70 | "engines": { 71 | "node": ">=6.9.x" 72 | }, 73 | "jest": { 74 | "verbose": true, 75 | "roots": [ 76 | "test/" 77 | ], 78 | "transform": { 79 | "^.+\\.ts?$": "/node_modules/ts-jest/preprocessor.js" 80 | }, 81 | "moduleFileExtensions": [ 82 | "ts", 83 | "js", 84 | "json" 85 | ], 86 | "testRegex": "/test/.*\\.(ts|js)$", 87 | "testPathIgnorePatterns": [ 88 | "/built/lib", 89 | "/node_modules/", 90 | "/test/moduleHelper.spec.ts" 91 | ] 92 | }, 93 | "config": { 94 | "commitizen": { 95 | "path": "./node_modules/cz-conventional-changelog" 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /templates/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | }, 5 | "plugins": [ 6 | "protractor" 7 | ], 8 | "extends": "plugin:protractor/recommended", 9 | "rules": { 10 | "indent": [ 11 | "error", 12 | 2, 13 | { 14 | "SwitchCase": 1 15 | } 16 | ], 17 | "linebreak-style": [ 18 | "error", 19 | "unix" 20 | ], 21 | "quotes": [ 22 | "error", 23 | "single" 24 | ], 25 | "semi": [ 26 | "error", 27 | "never" 28 | ], 29 | "complexity": [ 30 | "error", 31 | { 32 | "max": 9 33 | } 34 | ] 35 | } 36 | } -------------------------------------------------------------------------------- /templates/protractor.conf.ejs: -------------------------------------------------------------------------------- 1 | <%- jasmineReportExpression _%> 2 | <% if(answers.framework === "cucumber" && answers.cucumberReportType === "html") { _%> 3 | const reporter = require("cucumber-html-reporter"); 4 | <% } %> 5 | exports.config = { 6 | 7 | allScriptsTimeout: 120000, 8 | <% if(seleniumServerJarExpression) { %> 9 | <%- seleniumServerJarExpression _%> 10 | <% } _%> 11 | <% if(seleniumAddressExpression) { %> 12 | <%- seleniumAddressExpression _%> 13 | <% } _%> 14 | <% if(answers.drivers) { %> 15 | directConnect: true, 16 | <% } _%> 17 | <% if(answers.backend.indexOf("cloud services") > -1) { %> 18 | <% if(answers.sauceUser && answers.sauceKey) { %> 19 | sauceUser: '<%=answers.sauceUser_%>', 20 | sauceKey: '<%=answers.sauceKey_%>', 21 | <% } else if(answers.browserstackUser && answers.browserstackKey) { %> 22 | browserstackUser: '<%=answers.browserstackUser_%>', 23 | browserstackKey: '<%=answers.browserstackKey_%>', 24 | <% } _%> 25 | <% } %> 26 | baseUrl: '<%= answers.baseURL _%>', 27 | capabilities: { 28 | browserName: '<%= answers.browser%>' 29 | }, 30 | <% if(answers.framework === 'cucumber') { %> 31 | framework: 'custom', 32 | frameworkPath: require.resolve("protractor-cucumber-framework"), 33 | <% } else { _%> 34 | framework: '<%= answers.framework%>', 35 | <% } _%> 36 | specs: [ 37 | '<%= answers.specs %>' 38 | ], 39 | logLevel: '<%- logExpression _%>', 40 | <%_ if(answers.framework.match(/(jasmine|mocha)/) && answers.reportType === "json") { _%> 41 | resultJsonOutputFile: "<%= `${answers.reportPath}/`+'protractor_report.json' %>", 42 | <%_ } _%> 43 | <%_ if(beforeLaunchExpression) { _%> 44 | beforeLaunch: () => { 45 | <%- beforeLaunchExpression _%> 46 | }, 47 | <%_ } _%> 48 | <%_ if(answers.framework === "jasmine") { _%> 49 | jasmineNodeOpts: { 50 | defaultTimeoutInterval: 120000, 51 | <% if(answers.reportType === "spec") { _%> 52 | print: () => {}, 53 | <% } _%> 54 | showColors: true, 55 | random: false, 56 | }, 57 | <%_ } _%> 58 | <%_ if(answers.framework === "mocha") { _%> 59 | mochaOpts: { 60 | bail: true, 61 | colors: true, 62 | compilers:<%- transpilerExpression %>, 63 | reporter:<%- mochaReportExpression %>, 64 | timeout: 30000, 65 | ui: "bdd", 66 | }, 67 | <%_ } _%> 68 | <%_ if(onPrepareExpression) { %> 69 | onPrepare: () => { 70 | <%- onPrepareExpression %> 71 | }, 72 | <%_ } %> 73 | <%_ if(answers.framework === "cucumber"){ %> 74 | cucumberOpts: { 75 | "compiler":<%- transpilerExpression %>, 76 | "dry-run": false, 77 | "fail-fast": false, 78 | "format":["<%- formatExpression _%>"], 79 | "require":["<%= answers.stepDefinitions _%>"], 80 | "tags":"", 81 | 82 | }, 83 | <% } _%> 84 | <% if(onCompleteExpression) { _%> 85 | onComplete: () => { 86 | <%- onCompleteExpression _%> 87 | } 88 | <% } _%> 89 | }; 90 | /* 91 | ==================================================================== 92 | For full list of Protractor config options, 93 | see- https://github.com/angular/protractor/blob/master/lib/config.ts 94 | ==================================================================== 95 | **/ -------------------------------------------------------------------------------- /templates/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "moduleResolution": "node", 6 | "sourceMap": false, 7 | "declaration": false, 8 | "removeComments": false, 9 | "noImplicitAny": true, 10 | "outDir": "./built-tsc", 11 | "typeRoots": [ "node_modules/@types" ], 12 | "types": [ 13 | "node" 14 | ] 15 | }, 16 | "exclude": [ 17 | "node_modules", 18 | "built-tsc" 19 | ] 20 | } -------------------------------------------------------------------------------- /templates/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint-eslint-rules" 4 | ], 5 | "rules": { 6 | "no-duplicate-imports": true, 7 | "no-duplicate-variable": true, 8 | "no-jasmine-focus": true, 9 | "no-var-keyword": true, 10 | "semicolon": [true], 11 | "variable-name": [true, "ban-keywords"], 12 | "no-inner-declarations": [true, "function"] 13 | } 14 | } -------------------------------------------------------------------------------- /test/moduleHelper.spec.ts: -------------------------------------------------------------------------------- 1 | import {devModules, installModules} from '../lib/helpers/moduleHelper'; 2 | import {unInstallPkgs} from '../lib/utils/npmUtil'; 3 | 4 | const removeDevModule = (element: string) => { 5 | const devIndex = devModules.indexOf(element); 6 | if (devModules.indexOf(element) > -1) { 7 | devModules.splice(devIndex, 1); 8 | } 9 | }; 10 | 11 | const removeDevModules = (elements: any) => { 12 | if (Array.isArray(elements)) { 13 | elements.forEach((element) => { 14 | removeDevModule(element); 15 | }); 16 | } 17 | }; 18 | 19 | describe('To test the install module function and verify its installation process', async () => { 20 | it('Verify module installation if framework is jasmine with typescript', async () => { 21 | const answers = { 22 | framework: 'jasmine', 23 | transpilerType: 'typescript', 24 | }; 25 | const mockFn = jest.fn(installModules); 26 | mockFn(answers); 27 | expect(devModules).toEqual([ 28 | 'protractor', 29 | 'typescript', 30 | '@types/node', 31 | '@types/jasmine', 32 | 'ts-node', 33 | ]); 34 | await unInstallPkgs('', ['protractor', '@types/jasmine', 'ts-node'], {saveDev: true}); 35 | removeDevModules(['@types/jasmine', 'typescript', '@types/node', 'ts-node']); 36 | }); 37 | 38 | it('Verify module installation if framework is jasmine with coffeescript', async () => { 39 | const answers = { 40 | framework: 'jasmine', 41 | transpilerType: 'coffeescript', 42 | }; 43 | const mockFn = jest.fn(installModules); 44 | mockFn(answers); 45 | expect(devModules).toEqual([ 46 | 'protractor', 47 | 'coffeescript', 48 | ]); 49 | await unInstallPkgs('', ['protractor', 'coffeescript'], {saveDev: true}); 50 | removeDevModules(['coffeescript']); 51 | }); 52 | 53 | it('Verify module installation if framework is jasmine with spec reporter', async () => { 54 | const answers = { 55 | framework: 'jasmine', 56 | reportType: 'spec', 57 | }; 58 | const mockFn = jest.fn(installModules); 59 | mockFn(answers); 60 | expect(devModules).not.toContain('typescript'); 61 | expect(devModules).toContain('jasmine-spec-reporter'); 62 | await unInstallPkgs('', devModules, {saveDev: true}); 63 | removeDevModule('jasmine-spec-reporter'); 64 | }); 65 | 66 | it('Verify module installation if framework is jasmine with html reporter', async () => { 67 | const answers = { 68 | framework: 'jasmine', 69 | reportType: 'html', 70 | }; 71 | const mockFn = jest.fn(installModules); 72 | mockFn(answers); 73 | expect(devModules).not.toContain('typescript'); 74 | expect(devModules).toContain('protractor-jasmine2-screenshot-reporter'); 75 | await unInstallPkgs('', devModules, {saveDev: true}); 76 | removeDevModule('protractor-jasmine2-screenshot-reporter'); 77 | }); 78 | 79 | it('Verify module installation if framework is mocha with typescript', async () => { 80 | const answers = { 81 | framework: 'mocha', 82 | transpiler: true, 83 | transpilerType: 'typescript', 84 | }; 85 | const mockFn = jest.fn(installModules); 86 | mockFn(answers); 87 | expect(devModules).not.toContain('coffeescript'); 88 | expect(devModules).toEqual([ 89 | 'protractor', 90 | 'typescript', 91 | '@types/node', 92 | '@types/mocha', 93 | 'ts-node', 94 | ]); 95 | await unInstallPkgs('', ['protractor', '@types/mocha', 'ts-node'], {saveDev: true}); 96 | removeDevModules(['typescript', '@types/node', '@types/mocha', 'ts-node']); 97 | }); 98 | 99 | it('Verify module installation if framework is mocha with coffeescript', async () => { 100 | const answers = { 101 | framework: 'mocha', 102 | transpiler: true, 103 | transpilerType: 'coffeescript', 104 | }; 105 | const mockFn = jest.fn(installModules); 106 | mockFn(answers); 107 | expect(devModules).not.toContain('typescript'); 108 | expect(devModules).toContain('coffeescript'); 109 | expect(devModules.length).toEqual(2); 110 | await unInstallPkgs('', devModules, {saveDev: true}); 111 | removeDevModule('coffeescript'); 112 | }); 113 | 114 | it('Verify module installation if framework is mocha with html report', async () => { 115 | const answers = { 116 | framework: 'mocha', 117 | reportType: 'html', 118 | }; 119 | const mockFn = jest.fn(installModules); 120 | mockFn(answers); 121 | expect(devModules).not.toContain('typescript'); 122 | expect(devModules).not.toContain('coffeescript'); 123 | expect(devModules).toContain('mochawesome'); 124 | await unInstallPkgs('', devModules, {saveDev: true}); 125 | removeDevModule('mochawesome'); 126 | }); 127 | 128 | it('Verify module installation if framework is cucumber', async () => { 129 | const answers = { 130 | framework: 'cucumber', 131 | }; 132 | const mockFn = jest.fn(installModules); 133 | mockFn(answers); 134 | expect(devModules).not.toContain('typescript'); 135 | expect(devModules).not.toContain('coffeescript'); 136 | expect(devModules).toEqual(['protractor', 'cucumber', 'protractor-cucumber-framework']); 137 | await unInstallPkgs('', devModules, {saveDev: true}); 138 | removeDevModules(['cucumber', 'protractor-cucumber-framework']); 139 | }); 140 | 141 | it('Verify module installation if framework is cucumber with typescript', async () => { 142 | const answers = { 143 | framework: 'cucumber', 144 | transpiler: true, 145 | transpilerType: 'typescript', 146 | }; 147 | const mockFn = jest.fn(installModules); 148 | mockFn(answers); 149 | expect(devModules).not.toContain('coffeescript'); 150 | expect(devModules).toEqual([ 151 | 'protractor', 152 | 'cucumber', 153 | 'protractor-cucumber-framework', 154 | 'typescript', 155 | '@types/node', 156 | '@types/cucumber', 157 | 'ts-node', 158 | ]); 159 | await unInstallPkgs( 160 | '', 161 | ['protractor', 'cucumber', 'protractor-cucumber-framework', '@types/cucumber', 'ts-node'], 162 | {saveDev: true}); 163 | removeDevModules([ 164 | 'typescript', 165 | 'cucumber', 166 | 'protractor-cucumber-framework', 167 | '@types/node', 168 | '@types/cucumber', 169 | 'ts-node', 170 | ]); 171 | }); 172 | 173 | it('Verify module installation if framework is cucumber with coffeescript', async () => { 174 | const answers = { 175 | framework: 'cucumber', 176 | transpiler: true, 177 | transpilerType: 'coffeescript', 178 | }; 179 | const mockFn = jest.fn(installModules); 180 | mockFn(answers); 181 | expect(devModules).not.toContain('typescript'); 182 | expect(devModules).toEqual([ 183 | 'protractor', 184 | 'cucumber', 185 | 'protractor-cucumber-framework', 186 | 'coffeescript', 187 | ]); 188 | await unInstallPkgs('', devModules, {saveDev: true}); 189 | removeDevModules(['cucumber', 'protractor-cucumber-framework', 'coffeescript']); 190 | }); 191 | 192 | it('Verify module installation if framework is cucumber with html report', async () => { 193 | const answers = { 194 | cucumberReportType: 'html', 195 | framework: 'cucumber', 196 | }; 197 | const mockFn = jest.fn(installModules); 198 | mockFn(answers); 199 | expect(devModules).not.toContain('typescript'); 200 | expect(devModules).not.toContain('coffeescript'); 201 | expect(devModules).toContain('cucumber-html-reporter'); 202 | await unInstallPkgs('', devModules, {saveDev: true}); 203 | removeDevModules(['cucumber', 'protractor-cucumber-framework', 'cucumber-html-reporter']); 204 | }); 205 | 206 | it('Verify module installation if linter is eslint-plugin-protractor', async () => { 207 | const answers = { 208 | linter: 'eslint-plugin-protractor', 209 | }; 210 | const mockFn = jest.fn(installModules); 211 | mockFn(answers); 212 | expect(devModules).not.toContain('coffeescript'); 213 | expect(devModules).toEqual(['protractor', 'eslint', 'eslint-plugin-protractor']); 214 | await unInstallPkgs('', devModules, {saveDev: true}); 215 | removeDevModules(['eslint', 'eslint-plugin-protractor']); 216 | }); 217 | 218 | it('Verify module installation if linter is tslint', async () => { 219 | const answers = { 220 | linter: 'tslint', 221 | }; 222 | const mockFn = jest.fn(installModules); 223 | mockFn(answers); 224 | expect(devModules).not.toContain('coffeescript'); 225 | expect(devModules).toEqual(['protractor', 'tslint', 'tslint-eslint-rules']); 226 | await unInstallPkgs('', ['protractor', 'tslint-eslint-rules'], {saveDev: true}); 227 | removeDevModules(['protractor', 'tslint', 'tslint-eslint-rules']); 228 | }); 229 | }); 230 | -------------------------------------------------------------------------------- /test/questions.spec.ts: -------------------------------------------------------------------------------- 1 | import {questions} from '../lib/helpers/questions'; 2 | const totalQuestions: number = questions.length; 3 | 4 | describe('To test the questions object and verify its contents', () => { 5 | it('should verify the length of questions', () => { 6 | expect(questions).toHaveLength(totalQuestions); 7 | }); 8 | 9 | it('should verify the baseUrl object', () => { 10 | expect(questions[0]).toEqual({ 11 | default: 'http://localhost', 12 | message: 'What is the base url of your application?', 13 | name: 'baseURL', 14 | type: 'input', 15 | }); 16 | }); 17 | 18 | it('should verify the backend object', () => { 19 | expect(questions[1]).toEqual({ 20 | choices: [ 21 | 'My local machine', 22 | 'In cloud services like Sauce Labs or Browserstack', 23 | 'I know a remote selenium server', 24 | ], 25 | default: 'My local machine', 26 | message: 'What is your test environment?', 27 | name: 'backend', 28 | type: 'list', 29 | }); 30 | }); 31 | 32 | it('should verify the host object', () => { 33 | expect(questions[2].name).toBe('host'); 34 | expect(questions[2].message).toBe('What is the host address of that remote server?'); 35 | expect(questions[2].default).toBe('http://127.0.0.1:4444/wd/hub'); 36 | expect(questions[2].type).toBe('input'); 37 | const answers = { 38 | backend: 'remote selenium', 39 | }; 40 | expect(questions[2].when(answers)).toBe(true); 41 | }); 42 | 43 | it('should verify the services object', () => { 44 | expect(questions[3].choices).toEqual(['sauce labs', 'browserstack']); 45 | expect(questions[3].name).toBe('services'); 46 | expect(questions[3].message).toBe('Please select the could service: '); 47 | expect(questions[3].default).toBe('sauce labs'); 48 | expect(questions[3].type).toBe('list'); 49 | const answers = { 50 | backend: 'In cloud services ', 51 | }; 52 | expect(questions[3].when(answers)).toBe(true); 53 | }); 54 | 55 | it('should verify sauceUser object', () => { 56 | expect(questions[4].name).toBe('sauceUser'); 57 | expect(questions[4].message).toBe('Environment variable for sauce labs username'); 58 | expect(questions[4].default).toBe('SAUCE_USERNAME'); 59 | expect(questions[4].type).toBe('input'); 60 | const answers = { 61 | services: 'sauce labs', 62 | }; 63 | expect(questions[4].when(answers)).toBe(true); 64 | }); 65 | 66 | it('should verify sauceKey object', () => { 67 | expect(questions[5].name).toBe('sauceKey'); 68 | expect(questions[5].message).toBe('Environment variable for sauce labs access key'); 69 | expect(questions[5].default).toBe('SAUCE_ACCESS_KEY'); 70 | expect(questions[5].type).toBe('input'); 71 | const answers = { 72 | services: 'sauce labs', 73 | }; 74 | expect(questions[5].when(answers)).toBe(true); 75 | }); 76 | 77 | it('should verify the browserstackUser object', () => { 78 | expect(questions[6].name).toBe('browserstackUser'); 79 | expect(questions[6].message).toBe('Environment variable for Browserstack username'); 80 | expect(questions[6].default).toBe('BROWSER_STACK_USERNAME'); 81 | expect(questions[6].type).toBe('input'); 82 | const answers = { 83 | services: 'browserstack', 84 | }; 85 | expect(questions[6].when(answers)).toBe(true); 86 | }); 87 | 88 | it('should verify the browserstackKey object', () => { 89 | expect(questions[7].name).toBe('browserstackKey'); 90 | expect(questions[7].message).toBe('Environment variable for Browserstack access key'); 91 | expect(questions[7].default).toBe('BROWSER_STACK_ACCESS_KEY'); 92 | expect(questions[7].type).toBe('input'); 93 | const answers = { 94 | services: 'browserstack', 95 | }; 96 | expect(questions[7].when(answers)).toBe(true); 97 | }); 98 | 99 | it('should verify webdriver object', () => { 100 | expect(questions[8].name).toBe('webdriver'); 101 | expect(questions[8].message).toBe('Do you want to use webdriver-manager\'s drivers?'); 102 | expect(questions[8].default).toBe(true); 103 | expect(questions[8].type).toBe('confirm'); 104 | const answers = { 105 | backend: 'local machine', 106 | }; 107 | expect(questions[8].when(answers)).toBe(true); 108 | }); 109 | 110 | it('should verify drivers object', () => { 111 | expect(questions[9].name).toBe('drivers'); 112 | expect(questions[9].message).toBe('Do you want to use built in browser drivers?'); 113 | expect(questions[9].default).toBe(false); 114 | expect(questions[9].type).toBe('confirm'); 115 | const answers = { 116 | backend: 'local machine', 117 | webdriver: false, 118 | }; 119 | expect(questions[9].when(answers)).toBe(true); 120 | }); 121 | 122 | it('should verify seleniumJar object', () => { 123 | expect(questions[10].name).toBe('seleniumJar'); 124 | expect(questions[10].message).toBe('Please enter the selenium jar file location:'); 125 | expect(questions[10].default).toBe('./selenium/*.jar'); 126 | expect(questions[10].type).toBe('input'); 127 | const answers = { 128 | backend: 'local machine', 129 | drivers: false, 130 | webdriver: false, 131 | }; 132 | expect(questions[10].when(answers)).toBe(true); 133 | }); 134 | 135 | it('should verify seleniumAddress object', () => { 136 | expect(questions[11].name).toBe('seleniumAddress'); 137 | expect(questions[11].message).toBe('Please enter the local selenium server address:'); 138 | expect(questions[11].default).toBe('http://localhost:4444/wd/hub'); 139 | expect(questions[11].type).toBe('input'); 140 | const answers = { 141 | backend: 'local machine', 142 | drivers: false, 143 | }; 144 | expect(questions[11].when(answers)).toBe(true); 145 | }); 146 | 147 | it('should verify browser object', () => { 148 | expect(questions[12].choices).toEqual(['chrome', 'firefox', 'internet explorer']); 149 | expect(questions[12].name).toBe('browser'); 150 | expect(questions[12].message).toBe('Select the choice of your browser:'); 151 | expect(questions[12].default).toBe('chrome'); 152 | expect(questions[12].type).toBe('list'); 153 | }); 154 | 155 | it('should verify framework object', () => { 156 | expect(questions[13].choices).toEqual(['jasmine', 'mocha', 'cucumber']); 157 | expect(questions[13].name).toBe('framework'); 158 | expect(questions[13].message).toBe('Which framework do you want to use?'); 159 | expect(questions[13].default).toBe('jasmine'); 160 | expect(questions[13].type).toBe('list'); 161 | }); 162 | it('should verify transpiler object', () => { 163 | expect(questions[14].name).toBe('transpiler'); 164 | expect(questions[14].message).toBe('Do you want to use a transpiler?'); 165 | expect(questions[14].default).toBe(true); 166 | expect(questions[14].type).toBe('confirm'); 167 | }); 168 | 169 | it('should verify transpilerType object', () => { 170 | expect(questions[15].choices).toEqual(['typescript', 'coffeescript']); 171 | expect(questions[15].name).toBe('transpilerType'); 172 | expect(questions[15].message).toBe('Please select the transpiler:'); 173 | expect(questions[15].default).toBe('typescript'); 174 | expect(questions[15].type).toBe('list'); 175 | const answers = { 176 | transpiler: true, 177 | }; 178 | expect(questions[15].when(answers)).toBe(true); 179 | }); 180 | 181 | it('should verify specs object', () => { 182 | expect(questions[16].name).toBe('specs'); 183 | expect(questions[16].message).toBe('Where are your test specs located?'); 184 | expect(questions[16].type).toBe('input'); 185 | const answers = { 186 | framework: 'jasmine', 187 | transpilerType: 'typescript', 188 | }; 189 | expect(questions[16].default(answers)).toBe('./test/specs/**/*.ts'); 190 | answers.transpilerType = 'coffeescript'; 191 | expect(questions[16].default(answers)).toBe('./test/specs/**/*.coffee'); 192 | delete answers.transpilerType; 193 | expect(questions[16].default(answers)).toBe('./test/specs/**/*.js'); 194 | expect(questions[16].when(answers)).toContain('jasmine'); 195 | answers.framework = 'mocha'; 196 | expect(questions[16].when(answers)).toContain('mocha'); 197 | }); 198 | 199 | it('should verify specPath object', () => { 200 | expect(questions[17].name).toBe('specPath'); 201 | expect(questions[17].default).toBe(true); 202 | expect(questions[17].type).toBe('confirm'); 203 | const answers = { 204 | framework: 'jasmine', 205 | specs: './tests/**/*.js', 206 | }; 207 | expect(questions[17].message(answers)).toBe('Do you want to create ./tests/ folder?'); 208 | expect(questions[17].when(answers)).toContain('jasmine'); 209 | answers.framework = 'mocha'; 210 | expect(questions[17].when(answers)).toContain('mocha'); 211 | }); 212 | 213 | it('should verify feature files object', () => { 214 | expect(questions[18].name).toBe('specs'); 215 | expect(questions[18].default).toBe('./features/**/*.feature'); 216 | expect(questions[18].type).toBe('input'); 217 | expect(questions[18].message).toBe('Where are your feature files located?'); 218 | const answers = { 219 | framework: 'cucumber', 220 | }; 221 | expect(questions[18].when(answers)).toBe(true); 222 | }); 223 | 224 | it('should verify stepDefinitions object', () => { 225 | expect(questions[19].name).toBe('stepDefinitions'); 226 | const answers = { 227 | framework: 'cucumber', 228 | transpilerType: 'typescript', 229 | }; 230 | expect(questions[19].default(answers)).toBe('./features/stepDefinitions/**/*.ts'); 231 | answers.transpilerType = 'coffeescript'; 232 | expect(questions[19].default(answers)).toBe('./features/stepDefinitions/**/*.coffee'); 233 | delete answers.transpilerType; 234 | expect(questions[19].default(answers)).toBe('./features/stepDefinitions/**/*.js'); 235 | expect(questions[19].type).toBe('input'); 236 | expect(questions[19].message).toBe('Where are your step definitions located?'); 237 | expect(questions[19].when(answers)).toBe(true); 238 | }); 239 | 240 | it('should verify featurePath object', () => { 241 | expect(questions[20].name).toBe('featurePath'); 242 | expect(questions[20].default).toBe(true); 243 | expect(questions[20].type).toBe('confirm'); 244 | expect(questions[20].message).toBe('Do you want to create the above folders?'); 245 | const answers = { 246 | framework: 'cucumber', 247 | }; 248 | expect(questions[20].when(answers)).toBe(true); 249 | }); 250 | 251 | it('should verify logging object', () => { 252 | expect(questions[21].choices).toEqual(['info', 'error', 'warn', 'debug']); 253 | expect(questions[21].name).toBe('logging'); 254 | expect(questions[21].default).toBe('info'); 255 | expect(questions[21].type).toBe('list'); 256 | expect(questions[21].message).toBe('Level of logging verbosity:'); 257 | }); 258 | 259 | it('should verify linters objects', () => { 260 | expect(questions[22].name).toBe('linter'); 261 | expect(questions[22].default).toBe(true); 262 | expect(questions[22].type).toBe('list'); 263 | expect(questions[22].message).toBe('Please select the following linters to install:'); 264 | const answers = { 265 | transpilerType: 'typescript', 266 | }; 267 | expect(questions[22].when(answers)).not.toBe('coffeescript'); 268 | }); 269 | 270 | it('should verify reports objects', () => { 271 | expect(questions[23].name).toBe('reports'); 272 | expect(questions[23].default).toBe(true); 273 | expect(questions[23].type).toBe('confirm'); 274 | expect(questions[23].message).toBe('Do you want to generate reports of your tests?'); 275 | }); 276 | 277 | it('should verify reportType object', () => { 278 | expect(questions[24].choices).toEqual(['dot', 'spec', 'json', 'html']); 279 | expect(questions[24].name).toBe('reportType'); 280 | expect(questions[24].default).toBe('dot'); 281 | expect(questions[24].type).toBe('list'); 282 | expect(questions[24].message).toBe('Please select the type of report:'); 283 | const answers = { 284 | framework: 'jasmine', 285 | reports: true, 286 | }; 287 | expect(questions[24].when(answers)).toContain('jasmine'); 288 | answers.framework = 'mocha'; 289 | expect(questions[24].when(answers)).toContain('mocha'); 290 | }); 291 | 292 | it('should verify cucumberReportType object', () => { 293 | expect(questions[25].choices).toEqual(['progress', 'summary', 'json', 'html']); 294 | expect(questions[25].name).toBe('cucumberReportType'); 295 | expect(questions[25].default).toBe('progress'); 296 | expect(questions[25].type).toBe('list'); 297 | expect(questions[25].message).toBe('Please select the type of report:'); 298 | const answers = { 299 | framework: 'cucumber', 300 | reports: true, 301 | }; 302 | expect(questions[25].when(answers)).toBe(true); 303 | }); 304 | 305 | it('should verify reportPath object', () => { 306 | expect(questions[26].name).toBe('reportPath'); 307 | expect(questions[26].default).toBe('./reports'); 308 | expect(questions[26].type).toBe('input'); 309 | expect(questions[26].message).toBe('Where do you want to store your reports?'); 310 | const answers = { 311 | reports: true, 312 | }; 313 | expect(questions[26].when(answers)).toBe(true); 314 | }); 315 | 316 | it('should verify createReportPath object', () => { 317 | expect(questions[27].name).toBe('createReportPath'); 318 | expect(questions[27].default).toBe(true); 319 | expect(questions[27].type).toBe('confirm'); 320 | const answers = { 321 | reportPath: './reports', 322 | reports: true, 323 | }; 324 | expect(questions[27].message(answers)).toBe('Do you want to create ./reports folder?'); 325 | expect(questions[27].when(answers)).toBe(true); 326 | }); 327 | }); 328 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "declaration": true, 8 | "removeComments": false, 9 | "noImplicitAny": true, 10 | "outDir": "built/", 11 | "typeRoots": [ "./node_modules/@types","./built" ], 12 | "types": [ 13 | "node", 14 | "inquirer", 15 | "commander", 16 | "ejs", 17 | "mkdirp", 18 | "jest" 19 | ] 20 | }, 21 | "exclude": [ 22 | "built", 23 | "node_modules", 24 | "test" 25 | ] 26 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint:recommended"], 4 | "jsRules": {}, 5 | "rules": { 6 | "no-duplicate-imports": true, 7 | "no-duplicate-variable": true, 8 | "no-var-keyword": true, 9 | "no-var-requires": false, 10 | "no-string-literal":false, 11 | "quotemark": [true, "single", "avoid-escape"], 12 | "semicolon": [true], 13 | "variable-name": [true, "ban-keywords"], 14 | "no-console": [false], 15 | "max-line-length": [true, 200], 16 | "triple-equals": [true, "allow-null-check"], 17 | "trailing-comma": [ 18 | true, 19 | { 20 | "multiline": { 21 | "objects": "always", 22 | "arrays": "always", 23 | "functions": "never", 24 | "typeLiterals": "ignore" 25 | } 26 | } 27 | ] 28 | } 29 | } 30 | --------------------------------------------------------------------------------