From 768e82a5a7e8ed38760a5e6d0b95cbef26dc8c92 Mon Sep 17 00:00:00 2001 From: redaktice Date: Wed, 30 Sep 2020 18:53:01 -0600 Subject: [PATCH 1/3] Converting to ES2015, inspired by georgie105 More cleanup updating linters and more fixes Updating travis ci and removing lint errors Updating CI test runner and eslint for console logs Working on mocha tests, because context is a thing More mild approach Updating version and more ES2015 conversion --- .eslintrc.yml | 5 +- .travis.yml | 43 +- appveyor.yml | 37 +- bin/express-cli.js | 555 ++++++------ package.json | 4 +- templates/js/app.js.ejs | 16 +- templates/js/www.ejs | 18 +- test/cmd.js | 1656 ++++++++++++++++++++---------------- test/support/app-runner.js | 131 +-- test/support/utils.js | 68 +- 10 files changed, 1367 insertions(+), 1166 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index 5b09f907..38242dcd 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,5 +1,8 @@ root: true -extends: standard +extends: + - 'eslint:recommended' + - 'plugin:node/recommended' rules: no-param-reassign: error no-shadow: error + no-console: off diff --git a/.travis.yml b/.travis.yml index 13edaf41..8e9607f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,10 @@ language: node_js node_js: - - "0.10" - - "0.12" - - "1.8" - - "2.5" - - "3.3" - - "4.9" - - "5.12" - - "6.16" - - "7.10" - - "8.15" - - "9.11" + - '8.15' + - '9.11' + - 10 + - 11 + - 12 matrix: fast_finish: true sudo: false @@ -22,33 +16,6 @@ before_install: - | # Skip updating shrinkwrap / lock npm config set shrinkwrap false - # Setup Node.js version-specific dependencies - - | - # eslint for linting - # - remove on Node.js < 6 - if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 6 ]]; then - node -pe 'Object.keys(require("./package").devDependencies).join("\n")' | \ - grep -E '^eslint(-|$)' | \ - xargs npm rm --save-dev - fi - - | - # mocha for testing - # - use 3.x for Node.js < 4 - # - use 5.x for Node.js < 6 - if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 4 ]]; then - npm install --save-dev mocha@3.5.3 - elif [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 6 ]]; then - npm install --save-dev mocha@5.2.0 - fi - - | - # supertest for http calls - # - use 2.0.0 for Node.js < 4 - # - use 3.4.2 for Node.js < 6 - if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 4 ]]; then - npm install --save-dev supertest@2.0.0 - elif [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 6 ]]; then - npm install --save-dev supertest@3.4.2 - fi # Update Node.js modules - | # Prune and rebuild node_modules diff --git a/appveyor.yml b/appveyor.yml index 6e5603a1..ebdc8d2e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,16 +1,10 @@ environment: matrix: - - nodejs_version: "0.10" - - nodejs_version: "0.12" - - nodejs_version: "1.8" - - nodejs_version: "2.5" - - nodejs_version: "3.3" - - nodejs_version: "4.9" - - nodejs_version: "5.12" - - nodejs_version: "6.16" - - nodejs_version: "7.10" - - nodejs_version: "8.15" - - nodejs_version: "9.11" + - nodejs_version: '8.15' + - nodejs_version: '9.11' + - nodejs_version: '10' + - nodejs_version: '11' + - nodejs_version: '12' cache: - node_modules install: @@ -28,25 +22,6 @@ install: cmd.exe /c "node -pe `"Object.keys(require('./package').devDependencies).join('\n')`"" | ` sls "^eslint(-|$)" | ` %{ npm rm --silent --save-dev $_ } - # Setup Node.js version-specific dependencies - - ps: | - # mocha for testing - # - use 3.x for Node.js < 4 - # - use 5.x for Node.js < 6 - if ([int]$env:nodejs_version.split(".")[0] -lt 4) { - npm install --silent --save-dev mocha@3.5.3 - } elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) { - npm install --silent --save-dev mocha@5.2.0 - } - - ps: | - # supertest for http calls - # - use 2.0.0 for Node.js < 4 - # - use 3.4.2 for Node.js < 6 - if ([int]$env:nodejs_version.split(".")[0] -lt 4) { - npm install --silent --save-dev supertest@2.0.0 - } elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) { - npm install --silent --save-dev supertest@3.4.2 - } # Update Node.js modules - ps: | # Prune & rebuild node_modules @@ -64,4 +39,4 @@ test_script: npm --version # Run test script - npm run test-ci -version: "{build}" +version: '{build}' diff --git a/bin/express-cli.js b/bin/express-cli.js index d0c80b7f..bede3529 100755 --- a/bin/express-cli.js +++ b/bin/express-cli.js @@ -1,129 +1,153 @@ #!/usr/bin/env node -var ejs = require('ejs') -var fs = require('fs') -var minimatch = require('minimatch') -var mkdirp = require('mkdirp') -var path = require('path') -var program = require('commander') -var readline = require('readline') -var sortedObject = require('sorted-object') -var util = require('util') - -var MODE_0666 = parseInt('0666', 8) -var MODE_0755 = parseInt('0755', 8) -var TEMPLATE_DIR = path.join(__dirname, '..', 'templates') -var VERSION = require('../package').version - -var _exit = process.exit +const ejs = require('ejs'); +const fs = require('fs'); +const minimatch = require('minimatch'); +const mkdirp = require('mkdirp'); +const path = require('path'); +const program = require('commander'); +const readline = require('readline'); +const sortedObject = require('sorted-object'); +const util = require('util'); + +const MODE_0666 = parseInt('0666', 8); +const MODE_0755 = parseInt('0755', 8); +const TEMPLATE_DIR = path.join(__dirname, '..', 'templates'); +const VERSION = require('../package').version; + +const _exit = process.exit; // Re-assign process.exit because of commander // TODO: Switch to a different command framework -process.exit = exit +process.exit = exit; // CLI around(program, 'optionMissingArgument', function (fn, args) { - program.outputHelp() - fn.apply(this, args) - return { args: [], unknown: [] } -}) + program.outputHelp(); + fn.apply(this, args); + return { args: [], unknown: [] }; +}); before(program, 'outputHelp', function () { // track if help was shown for unknown option - this._helpShown = true -}) + this._helpShown = true; +}); before(program, 'unknownOption', function () { // allow unknown options if help was shown, to prevent trailing error - this._allowUnknownOption = this._helpShown + this._allowUnknownOption = this._helpShown; // show help if not yet shown if (!this._helpShown) { - program.outputHelp() + program.outputHelp(); } -}) +}); program .name('express') .version(VERSION, ' --version') .usage('[options] [dir]') - .option('-e, --ejs', 'add ejs engine support', renamedOption('--ejs', '--view=ejs')) - .option(' --pug', 'add pug engine support', renamedOption('--pug', '--view=pug')) - .option(' --hbs', 'add handlebars engine support', renamedOption('--hbs', '--view=hbs')) - .option('-H, --hogan', 'add hogan.js engine support', renamedOption('--hogan', '--view=hogan')) - .option('-v, --view ', 'add view support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)') + .option( + '-e, --ejs', + 'add ejs engine support', + renamedOption('--ejs', '--view=ejs'), + ) + .option( + ' --pug', + 'add pug engine support', + renamedOption('--pug', '--view=pug'), + ) + .option( + ' --hbs', + 'add handlebars engine support', + renamedOption('--hbs', '--view=hbs'), + ) + .option( + '-H, --hogan', + 'add hogan.js engine support', + renamedOption('--hogan', '--view=hogan'), + ) + .option( + '-v, --view ', + 'add view support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)', + ) .option(' --no-view', 'use static html instead of view engine') - .option('-c, --css ', 'add stylesheet support (less|stylus|compass|sass) (defaults to plain css)') + .option( + '-c, --css ', + 'add stylesheet support (less|stylus|compass|sass) (defaults to plain css)', + ) .option(' --git', 'add .gitignore') .option('-f, --force', 'force on non-empty directory') - .parse(process.argv) + .parse(process.argv); if (!exit.exited) { - main() + main(); } /** * Install an around function; AOP. */ -function around (obj, method, fn) { - var old = obj[method] +function around(obj, method, fn) { + const old = obj[method]; obj[method] = function () { - var args = new Array(arguments.length) - for (var i = 0; i < args.length; i++) args[i] = arguments[i] - return fn.call(this, old, args) - } + const args = new Array(arguments.length); + for (let i = 0; i < args.length; i++) { + args[i] = arguments[i]; + } + return fn.call(this, old, args); + }; } /** * Install a before function; AOP. */ -function before (obj, method, fn) { - var old = obj[method] +function before(obj, method, fn) { + const old = obj[method]; obj[method] = function () { - fn.call(this) - old.apply(this, arguments) - } + fn.call(this); + old.apply(this, arguments); + }; } /** * Prompt for confirmation on STDOUT/STDIN */ -function confirm (msg, callback) { - var rl = readline.createInterface({ +function confirm(msg, callback) { + const rl = readline.createInterface({ input: process.stdin, - output: process.stdout - }) + output: process.stdout, + }); - rl.question(msg, function (input) { - rl.close() - callback(/^y|yes|ok|true$/i.test(input)) - }) + rl.question(msg, (input) => { + rl.close(); + callback(/^y|yes|ok|true$/i.test(input)); + }); } /** * Copy file from template directory. */ -function copyTemplate (from, to) { - write(to, fs.readFileSync(path.join(TEMPLATE_DIR, from), 'utf-8')) +function copyTemplate(original, to) { + write(to, fs.readFileSync(path.join(TEMPLATE_DIR, original), 'utf-8')); } /** * Copy multiple files from template directory. */ -function copyTemplateMulti (fromDir, toDir, nameGlob) { +function copyTemplateMulti(fromDir, toDir, nameGlob) { fs.readdirSync(path.join(TEMPLATE_DIR, fromDir)) .filter(minimatch.filter(nameGlob, { matchBase: true })) - .forEach(function (name) { - copyTemplate(path.join(fromDir, name), path.join(toDir, name)) - }) + .forEach((name) => { + copyTemplate(path.join(fromDir, name), path.join(toDir, name)); + }); } /** @@ -133,229 +157,232 @@ function copyTemplateMulti (fromDir, toDir, nameGlob) { * @param {string} dir */ -function createApplication (name, dir) { - console.log() +function createApplication(name, dir) { + console.log(); // Package - var pkg = { - name: name, + const pkg = { + name, version: '0.0.0', private: true, scripts: { - start: 'node ./bin/www' + start: 'node ./bin/www', }, dependencies: { - 'debug': '~2.6.9', - 'express': '~4.16.1' - } - } + debug: '~2.6.9', + express: '~4.16.1', + }, + }; // JavaScript - var app = loadTemplate('js/app.js') - var www = loadTemplate('js/www') + const app = loadTemplate('js/app.js'); + const www = loadTemplate('js/www'); // App name - www.locals.name = name + www.locals.name = name; // App modules - app.locals.localModules = Object.create(null) - app.locals.modules = Object.create(null) - app.locals.mounts = [] - app.locals.uses = [] + app.locals.localModules = Object.create(null); + app.locals.modules = Object.create(null); + app.locals.mounts = []; + app.locals.uses = []; // Request logger - app.locals.modules.logger = 'morgan' - app.locals.uses.push("logger('dev')") - pkg.dependencies.morgan = '~1.9.1' + app.locals.modules.logger = 'morgan'; + app.locals.uses.push("logger('dev')"); + pkg.dependencies.morgan = '~1.9.1'; // Body parsers - app.locals.uses.push('express.json()') - app.locals.uses.push('express.urlencoded({ extended: false })') + app.locals.uses.push('express.json()'); + app.locals.uses.push('express.urlencoded({ extended: false })'); // Cookie parser - app.locals.modules.cookieParser = 'cookie-parser' - app.locals.uses.push('cookieParser()') - pkg.dependencies['cookie-parser'] = '~1.4.4' + app.locals.modules.cookieParser = 'cookie-parser'; + app.locals.uses.push('cookieParser()'); + pkg.dependencies['cookie-parser'] = '~1.4.4'; if (dir !== '.') { - mkdir(dir, '.') + mkdir(dir, '.'); } - mkdir(dir, 'public') - mkdir(dir, 'public/javascripts') - mkdir(dir, 'public/images') - mkdir(dir, 'public/stylesheets') + mkdir(dir, 'public'); + mkdir(dir, 'public/javascripts'); + mkdir(dir, 'public/images'); + mkdir(dir, 'public/stylesheets'); // copy css templates switch (program.css) { case 'less': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.less') - break + copyTemplateMulti('css', dir + '/public/stylesheets', '*.less'); + break; case 'stylus': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.styl') - break + copyTemplateMulti('css', dir + '/public/stylesheets', '*.styl'); + break; case 'compass': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.scss') - break + copyTemplateMulti('css', dir + '/public/stylesheets', '*.scss'); + break; case 'sass': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.sass') - break + copyTemplateMulti('css', dir + '/public/stylesheets', '*.sass'); + break; default: - copyTemplateMulti('css', dir + '/public/stylesheets', '*.css') - break + copyTemplateMulti('css', dir + '/public/stylesheets', '*.css'); + break; } // copy route templates - mkdir(dir, 'routes') - copyTemplateMulti('js/routes', dir + '/routes', '*.js') + mkdir(dir, 'routes'); + copyTemplateMulti('js/routes', dir + '/routes', '*.js'); if (program.view) { // Copy view templates - mkdir(dir, 'views') - pkg.dependencies['http-errors'] = '~1.6.3' + mkdir(dir, 'views'); + pkg.dependencies['http-errors'] = '~1.6.3'; switch (program.view) { case 'dust': - copyTemplateMulti('views', dir + '/views', '*.dust') - break + copyTemplateMulti('views', dir + '/views', '*.dust'); + break; case 'ejs': - copyTemplateMulti('views', dir + '/views', '*.ejs') - break + copyTemplateMulti('views', dir + '/views', '*.ejs'); + break; case 'hbs': - copyTemplateMulti('views', dir + '/views', '*.hbs') - break + copyTemplateMulti('views', dir + '/views', '*.hbs'); + break; case 'hjs': - copyTemplateMulti('views', dir + '/views', '*.hjs') - break + copyTemplateMulti('views', dir + '/views', '*.hjs'); + break; case 'jade': - copyTemplateMulti('views', dir + '/views', '*.jade') - break + copyTemplateMulti('views', dir + '/views', '*.jade'); + break; case 'pug': - copyTemplateMulti('views', dir + '/views', '*.pug') - break + copyTemplateMulti('views', dir + '/views', '*.pug'); + break; case 'twig': - copyTemplateMulti('views', dir + '/views', '*.twig') - break + copyTemplateMulti('views', dir + '/views', '*.twig'); + break; case 'vash': - copyTemplateMulti('views', dir + '/views', '*.vash') - break + copyTemplateMulti('views', dir + '/views', '*.vash'); + break; } } else { // Copy extra public files - copyTemplate('js/index.html', path.join(dir, 'public/index.html')) + copyTemplate('js/index.html', path.join(dir, 'public/index.html')); } // CSS Engine support switch (program.css) { case 'compass': - app.locals.modules.compass = 'node-compass' - app.locals.uses.push("compass({ mode: 'expanded' })") - pkg.dependencies['node-compass'] = '0.2.3' - break + app.locals.modules.compass = 'node-compass'; + app.locals.uses.push("compass({ mode: 'expanded' })"); + pkg.dependencies['node-compass'] = '0.2.3'; + break; case 'less': - app.locals.modules.lessMiddleware = 'less-middleware' - app.locals.uses.push("lessMiddleware(path.join(__dirname, 'public'))") - pkg.dependencies['less-middleware'] = '~2.2.1' - break + app.locals.modules.lessMiddleware = 'less-middleware'; + app.locals.uses.push("lessMiddleware(path.join(__dirname, 'public'))"); + pkg.dependencies['less-middleware'] = '~2.2.1'; + break; case 'sass': - app.locals.modules.sassMiddleware = 'node-sass-middleware' - app.locals.uses.push("sassMiddleware({\n src: path.join(__dirname, 'public'),\n dest: path.join(__dirname, 'public'),\n indentedSyntax: true, // true = .sass and false = .scss\n sourceMap: true\n})") - pkg.dependencies['node-sass-middleware'] = '0.11.0' - break + app.locals.modules.sassMiddleware = 'node-sass-middleware'; + app.locals.uses.push( + "sassMiddleware({\n src: path.join(__dirname, 'public'),\n dest: path.join(__dirname, 'public'),\n indentedSyntax: true, // true = .sass and false = .scss\n sourceMap: true\n})", + ); + pkg.dependencies['node-sass-middleware'] = '0.11.0'; + break; case 'stylus': - app.locals.modules.stylus = 'stylus' - app.locals.uses.push("stylus.middleware(path.join(__dirname, 'public'))") - pkg.dependencies['stylus'] = '0.54.5' - break + app.locals.modules.stylus = 'stylus'; + app.locals.uses.push("stylus.middleware(path.join(__dirname, 'public'))"); + pkg.dependencies['stylus'] = '0.54.5'; + break; } // Index router mount - app.locals.localModules.indexRouter = './routes/index' - app.locals.mounts.push({ path: '/', code: 'indexRouter' }) + app.locals.localModules.indexRouter = './routes/index'; + app.locals.mounts.push({ path: '/', code: 'indexRouter' }); // User router mount - app.locals.localModules.usersRouter = './routes/users' - app.locals.mounts.push({ path: '/users', code: 'usersRouter' }) + app.locals.localModules.usersRouter = './routes/users'; + app.locals.mounts.push({ path: '/users', code: 'usersRouter' }); // Template support switch (program.view) { case 'dust': - app.locals.modules.adaro = 'adaro' + app.locals.modules.adaro = 'adaro'; app.locals.view = { engine: 'dust', - render: 'adaro.dust()' - } - pkg.dependencies.adaro = '~1.0.4' - break + render: 'adaro.dust()', + }; + pkg.dependencies.adaro = '~1.0.4'; + break; case 'ejs': - app.locals.view = { engine: 'ejs' } - pkg.dependencies.ejs = '~2.6.1' - break + app.locals.view = { engine: 'ejs' }; + pkg.dependencies.ejs = '~2.6.1'; + break; case 'hbs': - app.locals.view = { engine: 'hbs' } - pkg.dependencies.hbs = '~4.0.4' - break + app.locals.view = { engine: 'hbs' }; + pkg.dependencies.hbs = '~4.0.4'; + break; case 'hjs': - app.locals.view = { engine: 'hjs' } - pkg.dependencies.hjs = '~0.0.6' - break + app.locals.view = { engine: 'hjs' }; + pkg.dependencies.hjs = '~0.0.6'; + break; case 'jade': - app.locals.view = { engine: 'jade' } - pkg.dependencies.jade = '~1.11.0' - break + app.locals.view = { engine: 'jade' }; + pkg.dependencies.jade = '~1.11.0'; + break; case 'pug': - app.locals.view = { engine: 'pug' } - pkg.dependencies.pug = '2.0.0-beta11' - break + app.locals.view = { engine: 'pug' }; + pkg.dependencies.pug = '2.0.0-beta11'; + break; case 'twig': - app.locals.view = { engine: 'twig' } - pkg.dependencies.twig = '~0.10.3' - break + app.locals.view = { engine: 'twig' }; + pkg.dependencies.twig = '~0.10.3'; + break; case 'vash': - app.locals.view = { engine: 'vash' } - pkg.dependencies.vash = '~0.12.6' - break + app.locals.view = { engine: 'vash' }; + pkg.dependencies.vash = '~0.12.6'; + break; default: - app.locals.view = false - break + app.locals.view = false; + break; } // Static files - app.locals.uses.push("express.static(path.join(__dirname, 'public'))") + app.locals.uses.push("express.static(path.join(__dirname, 'public'))"); if (program.git) { - copyTemplate('js/gitignore', path.join(dir, '.gitignore')) + copyTemplate('js/gitignore', path.join(dir, '.gitignore')); } // sort dependencies like npm(1) - pkg.dependencies = sortedObject(pkg.dependencies) + pkg.dependencies = sortedObject(pkg.dependencies); // write files - write(path.join(dir, 'app.js'), app.render()) - write(path.join(dir, 'package.json'), JSON.stringify(pkg, null, 2) + '\n') - mkdir(dir, 'bin') - write(path.join(dir, 'bin/www'), www.render(), MODE_0755) + write(path.join(dir, 'app.js'), app.render()); + write(path.join(dir, 'package.json'), JSON.stringify(pkg, null, 2) + '\n'); + mkdir(dir, 'bin'); + write(path.join(dir, 'bin/www'), www.render(), MODE_0755); - var prompt = launchedFromCmd() ? '>' : '$' + const prompt = launchedFromCmd() ? '>' : '$'; if (dir !== '.') { - console.log() - console.log(' change directory:') - console.log(' %s cd %s', prompt, dir) + console.log(); + console.log(` + change directory: + ${prompt} cd ${dir}`); } - console.log() - console.log(' install dependencies:') - console.log(' %s npm install', prompt) - console.log() - console.log(' run the app:') + console.log(` + install dependencies: + ${prompt} npm install + + run the app:`); if (launchedFromCmd()) { - console.log(' %s SET DEBUG=%s:* & npm start', prompt, name) + console.log(` ${prompt} SET DEBUG=${name}:* & npm start'`); } else { - console.log(' %s DEBUG=%s:* npm start', prompt, name) + console.log(` ${prompt} DEBUG=${name}:* npm start`); } - console.log() + console.log(); } /** @@ -364,11 +391,12 @@ function createApplication (name, dir) { * @param {String} pathName */ -function createAppName (pathName) { - return path.basename(pathName) +function createAppName(pathName) { + return path + .basename(pathName) .replace(/[^A-Za-z0-9.-]+/g, '-') .replace(/^[-_.]+|-+$/g, '') - .toLowerCase() + .toLowerCase(); } /** @@ -378,110 +406,123 @@ function createAppName (pathName) { * @param {Function} fn */ -function emptyDirectory (dir, fn) { - fs.readdir(dir, function (err, files) { - if (err && err.code !== 'ENOENT') throw err - fn(!files || !files.length) - }) +function emptyDirectory(dir, fn) { + fs.readdir(dir, (err, files) => { + if (err && err.code !== 'ENOENT') { + throw err; + } + fn(!files || !files.length); + }); } /** * Graceful exit for async STDIO */ -function exit (code) { +function exit(code) { // flush output for Node.js Windows pipe bug // https://github.com/joyent/node/issues/6247 is just one bug example // https://github.com/visionmedia/mocha/issues/333 has a good discussion - function done () { - if (!(draining--)) _exit(code) + function done() { + if (!draining--) { + _exit(code); + } } - var draining = 0 - var streams = [process.stdout, process.stderr] + let draining = 0; + const streams = [process.stdout, process.stderr]; - exit.exited = true + exit.exited = true; - streams.forEach(function (stream) { + streams.forEach((stream) => { // submit empty write request and wait for completion - draining += 1 - stream.write('', done) - }) + draining += 1; + stream.write('', done); + }); - done() + done(); } /** * Determine if launched from cmd.exe */ -function launchedFromCmd () { - return process.platform === 'win32' && - process.env._ === undefined +function launchedFromCmd() { + return process.platform === 'win32' && process.env._ === undefined; } /** * Load template file. */ -function loadTemplate (name) { - var contents = fs.readFileSync(path.join(__dirname, '..', 'templates', (name + '.ejs')), 'utf-8') - var locals = Object.create(null) +function loadTemplate(name) { + const contents = fs.readFileSync( + path.join(__dirname, '..', 'templates', name + '.ejs'), + 'utf-8', + ); + const locals = Object.create(null); - function render () { + function render() { return ejs.render(contents, locals, { - escape: util.inspect - }) + escape: util.inspect, + }); } return { - locals: locals, - render: render - } + locals, + render, + }; } /** * Main program. */ -function main () { +function main() { // Path - var destinationPath = program.args.shift() || '.' + const destinationPath = program.args.shift() || '.'; // App name - var appName = createAppName(path.resolve(destinationPath)) || 'hello-world' + const appName = createAppName(path.resolve(destinationPath)) || 'hello-world'; // View engine if (program.view === true) { - if (program.ejs) program.view = 'ejs' - if (program.hbs) program.view = 'hbs' - if (program.hogan) program.view = 'hjs' - if (program.pug) program.view = 'pug' + if (program.ejs) { + program.view = 'ejs'; + } else if (program.hbs) { + program.view = 'hbs'; + } else if (program.hogan) { + program.view = 'hjs'; + } else if (program.pug) { + program.view = 'pug'; + } } // Default view engine if (program.view === true) { - warning('the default view engine will not be jade in future releases\n' + - "use `--view=jade' or `--help' for additional options") - program.view = 'jade' + warning( + 'the default view engine will not be jade in future releases\n' + + "use `--view=jade' or `--help' for additional options", + ); + program.view = 'jade'; } // Generate application - emptyDirectory(destinationPath, function (empty) { + emptyDirectory(destinationPath, (empty) => { if (empty || program.force) { - createApplication(appName, destinationPath) + createApplication(appName, destinationPath); } else { - confirm('destination is not empty, continue? [y/N] ', function (ok) { + confirm('destination is not empty, continue? [y/N] ', (ok) => { if (ok) { - process.stdin.destroy() - createApplication(appName, destinationPath) + process.stdin.destroy(); + createApplication(appName, destinationPath); } else { - console.error('aborting') - exit(1) + console.error('aborting'); + exit(1); } - }) + }); } - }) + }); } /** @@ -491,11 +532,11 @@ function main () { * @param {string} dir */ -function mkdir (base, dir) { - var loc = path.join(base, dir) +function mkdir(base, dir) { + const loc = path.join(base, dir); - console.log(' \x1b[36mcreate\x1b[0m : ' + loc + path.sep) - mkdirp.sync(loc, MODE_0755) + console.log(` \x1b[36mcreate\x1b[0m : ${loc}${path.sep}`); + mkdirp.sync(loc, MODE_0755); } /** @@ -505,11 +546,17 @@ function mkdir (base, dir) { * @param {String} newName */ -function renamedOption (originalName, newName) { - return function (val) { - warning(util.format("option `%s' has been renamed to `%s'", originalName, newName)) - return val - } +function renamedOption(originalName, newName) { + return (val) => { + warning( + util.format( + "option `%s' has been renamed to `%s'", + originalName, + newName, + ), + ); + return val; + }; } /** @@ -518,12 +565,12 @@ function renamedOption (originalName, newName) { * @param {String} message */ -function warning (message) { - console.error() - message.split('\n').forEach(function (line) { - console.error(' warning: %s', line) - }) - console.error() +function warning(message) { + console.error(); + message.split('\n').forEach((line) => { + console.error(` warning: ${line}`); + }); + console.error(); } /** @@ -533,7 +580,7 @@ function warning (message) { * @param {String} str */ -function write (file, str, mode) { - fs.writeFileSync(file, str, { mode: mode || MODE_0666 }) - console.log(' \x1b[36mcreate\x1b[0m : ' + file) +function write(file, str, mode) { + fs.writeFileSync(file, str, { mode: mode || MODE_0666 }); + console.log(` \x1b[36mcreate\x1b[0m : ${file}`); } diff --git a/package.json b/package.json index f9bfe584..b3b0ed13 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "express-generator", "description": "Express' application generator", - "version": "4.16.1", + "version": "5.0.0", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", @@ -51,7 +51,7 @@ "validate-npm-package-name": "3.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 8.0.0" }, "files": [ "LICENSE", diff --git a/templates/js/app.js.ejs b/templates/js/app.js.ejs index 2ef75aec..0b9ea581 100644 --- a/templates/js/app.js.ejs +++ b/templates/js/app.js.ejs @@ -1,17 +1,17 @@ <% if (view) { -%> -var createError = require('http-errors'); +const createError = require('http-errors'); <% } -%> -var express = require('express'); -var path = require('path'); +const express = require('express'); +const path = require('path'); <% Object.keys(modules).sort().forEach(function (variable) { -%> -var <%- variable %> = require('<%- modules[variable] %>'); +const <%- variable %> = require('<%- modules[variable] %>'); <% }); -%> <% Object.keys(localModules).sort().forEach(function (variable) { -%> -var <%- variable %> = require('<%- localModules[variable] %>'); +const <%- variable %> = require('<%- localModules[variable] %>'); <% }); -%> -var app = express(); +const app = express(); <% if (view) { -%> // view engine setup @@ -32,12 +32,12 @@ app.use(<%= mount.path %>, <%- mount.code %>); <% if (view) { -%> // catch 404 and forward to error handler -app.use(function(req, res, next) { +app.use((req, res, next) => { next(createError(404)); }); // error handler -app.use(function(err, req, res, next) { +app.use((err, req, res, next) => { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; diff --git a/templates/js/www.ejs b/templates/js/www.ejs index 690fc488..a309083e 100644 --- a/templates/js/www.ejs +++ b/templates/js/www.ejs @@ -4,22 +4,22 @@ * Module dependencies. */ -var app = require('../app'); -var debug = require('debug')('<%- name %>:server'); -var http = require('http'); +const app = require('../app'); +const debug = require('debug')('<%- name %>:server'); +const http = require('http'); /** * Get port from environment and store in Express. */ -var port = normalizePort(process.env.PORT || '3000'); +const port = normalizePort(process.env.PORT || '3000'); app.set('port', port); /** * Create HTTP server. */ -var server = http.createServer(app); +const server = http.createServer(app); /** * Listen on provided port, on all network interfaces. @@ -34,7 +34,7 @@ server.on('listening', onListening); */ function normalizePort(val) { - var port = parseInt(val, 10); + const port = parseInt(val, 10); if (isNaN(port)) { // named pipe @@ -58,7 +58,7 @@ function onError(error) { throw error; } - var bind = typeof port === 'string' + const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; @@ -82,8 +82,8 @@ function onError(error) { */ function onListening() { - var addr = server.address(); - var bind = typeof addr === 'string' + const addr = server.address(); + const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; debug('Listening on ' + bind); diff --git a/test/cmd.js b/test/cmd.js index c0711a73..6c9a0b47 100644 --- a/test/cmd.js +++ b/test/cmd.js @@ -1,1213 +1,1419 @@ - -var assert = require('assert') -var AppRunner = require('./support/app-runner') -var exec = require('child_process').exec -var fs = require('fs') -var mkdirp = require('mkdirp') -var path = require('path') -var request = require('supertest') -var rimraf = require('rimraf') -var spawn = require('child_process').spawn -var utils = require('./support/utils') -var validateNpmName = require('validate-npm-package-name') - -var APP_START_STOP_TIMEOUT = 10000 -var PKG_PATH = path.resolve(__dirname, '..', 'package.json') -var BIN_PATH = path.resolve(path.dirname(PKG_PATH), require(PKG_PATH).bin.express) -var NPM_INSTALL_TIMEOUT = 300000 // 5 minutes -var TEMP_DIR = utils.tmpDir() +const assert = require('assert'); +const AppRunner = require('./support/app-runner'); +const exec = require('child_process').exec; +const fs = require('fs'); +const mkdirp = require('mkdirp'); +const path = require('path'); +const request = require('supertest'); +const rimraf = require('rimraf'); +const spawn = require('child_process').spawn; +const utils = require('./support/utils'); +const validateNpmName = require('validate-npm-package-name'); + +const APP_START_STOP_TIMEOUT = 10000; +const PKG_PATH = path.resolve(__dirname, '..', 'package.json'); +const BIN_PATH = path.resolve( + path.dirname(PKG_PATH), + require(PKG_PATH).bin.express, +); +const NPM_INSTALL_TIMEOUT = 300000; // 5 minutes +const TEMP_DIR = utils.tmpDir(); describe('express(1)', function () { after(function (done) { - this.timeout(30000) - rimraf(TEMP_DIR, done) - }) + this.timeout(30000); + rimraf(TEMP_DIR, done); + }); describe('(no args)', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app', function (done) { runRaw(ctx.dir, [], function (err, code, stdout, stderr) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - ctx.stderr = stderr - ctx.stdout = stdout - assert.strictEqual(ctx.files.length, 16) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + ctx.stderr = stderr; + ctx.stdout = stdout; + assert.strictEqual(ctx.files.length, 16); + done(); + }); + }); it('should print jade view warning', function () { - assert.strictEqual(ctx.stderr, "\n warning: the default view engine will not be jade in future releases\n warning: use `--view=jade' or `--help' for additional options\n\n") - }) + assert.strictEqual( + ctx.stderr, + "\n warning: the default view engine will not be jade in future releases\n warning: use `--view=jade' or `--help' for additional options\n\n", + ); + }); it('should provide debug instructions', function () { - assert.ok(/DEBUG=express-1-no-args:\* (?:& )?npm start/.test(ctx.stdout)) - }) + assert.ok(/DEBUG=express-1-no-args:\* (?:& )?npm start/.test(ctx.stdout)); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); + }); it('should have jade templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.jade'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/index.jade'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/layout.jade'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('views/error.jade'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/index.jade'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/layout.jade'), -1); + }); it('should have a package.json file', function () { - var file = path.resolve(ctx.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - assert.strictEqual(contents, '{\n' + - ' "name": "express-1-no-args",\n' + - ' "version": "0.0.0",\n' + - ' "private": true,\n' + - ' "scripts": {\n' + - ' "start": "node ./bin/www"\n' + - ' },\n' + - ' "dependencies": {\n' + - ' "cookie-parser": "~1.4.4",\n' + - ' "debug": "~2.6.9",\n' + - ' "express": "~4.16.1",\n' + - ' "http-errors": "~1.6.3",\n' + - ' "jade": "~1.11.0",\n' + - ' "morgan": "~1.9.1"\n' + - ' }\n' + - '}\n') - }) + const file = path.resolve(ctx.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + assert.strictEqual( + contents, + '{\n' + + ' "name": "express-1-no-args",\n' + + ' "version": "0.0.0",\n' + + ' "private": true,\n' + + ' "scripts": {\n' + + ' "start": "node ./bin/www"\n' + + ' },\n' + + ' "dependencies": {\n' + + ' "cookie-parser": "~1.4.4",\n' + + ' "debug": "~2.6.9",\n' + + ' "express": "~4.16.1",\n' + + ' "http-errors": "~1.6.3",\n' + + ' "jade": "~1.11.0",\n' + + ' "morgan": "~1.9.1"\n' + + ' }\n' + + '}\n', + ); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); it('should export an express app from app.js', function () { - var file = path.resolve(ctx.dir, 'app.js') - var app = require(file) - assert.strictEqual(typeof app, 'function') - assert.strictEqual(typeof app.handle, 'function') - }) + const file = path.resolve(ctx.dir, 'app.js'); + const app = require(file); + assert.strictEqual(typeof app, 'function'); + assert.strictEqual(typeof app.handle, 'function'); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) + .expect(404, /<h1>Not Found<\/h1>/, done); + }); + }); describe('when directory contains spaces', function () { - var ctx0 = setupTestEnvironment('foo bar (BAZ!)') + const ctx0 = setupTestEnvironment('foo bar (BAZ!)'); it('should create basic app', function (done) { run(ctx0.dir, [], function (err, output) { - if (err) return done(err) - assert.strictEqual(utils.parseCreatedFiles(output, ctx0.dir).length, 16) - done() - }) - }) + if (err) { + return done(err); + } + assert.strictEqual( + utils.parseCreatedFiles(output, ctx0.dir).length, + 16, + ); + done(); + }); + }); it('should have a valid npm package name', function () { - var file = path.resolve(ctx0.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - var name = JSON.parse(contents).name - assert.ok(validateNpmName(name).validForNewPackages, 'package name "' + name + '" is valid') - assert.strictEqual(name, 'foo-bar-baz') - }) - }) + const file = path.resolve(ctx0.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + const name = JSON.parse(contents).name; + assert.ok( + validateNpmName(name).validForNewPackages, + 'package name "' + name + '" is valid', + ); + assert.strictEqual(name, 'foo-bar-baz'); + }); + }); describe('when directory is not a valid name', function () { - var ctx1 = setupTestEnvironment('_') + const ctx1 = setupTestEnvironment('_'); it('should create basic app', function (done) { run(ctx1.dir, [], function (err, output) { - if (err) return done(err) - assert.strictEqual(utils.parseCreatedFiles(output, ctx1.dir).length, 16) - done() - }) - }) + if (err) { + return done(err); + } + assert.strictEqual( + utils.parseCreatedFiles(output, ctx1.dir).length, + 16, + ); + done(); + }); + }); it('should default to name "hello-world"', function () { - var file = path.resolve(ctx1.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - var name = JSON.parse(contents).name - assert.ok(validateNpmName(name).validForNewPackages) - assert.strictEqual(name, 'hello-world') - }) - }) - }) + const file = path.resolve(ctx1.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + const name = JSON.parse(contents).name; + assert.ok(validateNpmName(name).validForNewPackages); + assert.strictEqual(name, 'hello-world'); + }); + }); + }); describe('(unknown args)', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should exit with code 1', function (done) { + // eslint-disable-next-line no-unused-vars runRaw(ctx.dir, ['--foo'], function (err, code, stdout, stderr) { - if (err) return done(err) - assert.strictEqual(code, 1) - done() - }) - }) + if (err) { + return done(err); + } + assert.strictEqual(code, 1); + done(); + }); + }); it('should print usage', function (done) { runRaw(ctx.dir, ['--foo'], function (err, code, stdout, stderr) { - if (err) return done(err) - assert.ok(/Usage: express /.test(stdout)) - assert.ok(/--help/.test(stdout)) - assert.ok(/--version/.test(stdout)) - assert.ok(/error: unknown option/.test(stderr)) - done() - }) - }) + if (err) { + return done(err); + } + assert.ok(/Usage: express /.test(stdout)); + assert.ok(/--help/.test(stdout)); + assert.ok(/--version/.test(stdout)); + assert.ok(/error: unknown option/.test(stderr)); + done(); + }); + }); it('should print unknown option', function (done) { runRaw(ctx.dir, ['--foo'], function (err, code, stdout, stderr) { - if (err) return done(err) - assert.ok(/error: unknown option/.test(stderr)) - done() - }) - }) - }) + if (err) { + return done(err); + } + assert.ok(/error: unknown option/.test(stderr)); + done(); + }); + }); + }); describe('<dir>', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app in directory', function (done) { runRaw(ctx.dir, ['foo'], function (err, code, stdout, stderr) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - ctx.stderr = stderr - ctx.stdout = stdout - assert.strictEqual(ctx.files.length, 17) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + ctx.stderr = stderr; + ctx.stdout = stdout; + assert.strictEqual(ctx.files.length, 17); + done(); + }); + }); it('should provide change directory instructions', function () { - assert.ok(/cd foo/.test(ctx.stdout)) - }) + assert.ok(/cd foo/.test(ctx.stdout)); + }); it('should provide install instructions', function () { - assert.ok(/npm install/.test(ctx.stdout)) - }) + assert.ok(/npm install/.test(ctx.stdout)); + }); it('should provide debug instructions', function () { - assert.ok(/DEBUG=foo:\* (?:& )?npm start/.test(ctx.stdout)) - }) + assert.ok(/DEBUG=foo:\* (?:& )?npm start/.test(ctx.stdout)); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('foo/bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('foo/app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('foo/package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('foo/bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('foo/app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('foo/package.json'), -1); + }); it('should have jade templates', function () { - assert.notStrictEqual(ctx.files.indexOf('foo/views/error.jade'), -1) - assert.notStrictEqual(ctx.files.indexOf('foo/views/index.jade'), -1) - assert.notStrictEqual(ctx.files.indexOf('foo/views/layout.jade'), -1) - }) - }) + assert.notStrictEqual(ctx.files.indexOf('foo/views/error.jade'), -1); + assert.notStrictEqual(ctx.files.indexOf('foo/views/index.jade'), -1); + assert.notStrictEqual(ctx.files.indexOf('foo/views/layout.jade'), -1); + }); + }); describe('--css <engine>', function () { describe('(no engine)', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should exit with code 1', function (done) { + // eslint-disable-next-line no-unused-vars runRaw(ctx.dir, ['--css'], function (err, code, stdout, stderr) { - if (err) return done(err) - assert.strictEqual(code, 1) - done() - }) - }) + if (err) { + return done(err); + } + assert.strictEqual(code, 1); + done(); + }); + }); it('should print usage', function (done) { runRaw(ctx.dir, ['--css'], function (err, code, stdout) { - if (err) return done(err) - assert.ok(/Usage: express /.test(stdout)) - assert.ok(/--help/.test(stdout)) - assert.ok(/--version/.test(stdout)) - done() - }) - }) + if (err) { + return done(err); + } + assert.ok(/Usage: express /.test(stdout)); + assert.ok(/--help/.test(stdout)); + assert.ok(/--version/.test(stdout)); + done(); + }); + }); it('should print argument missing', function (done) { runRaw(ctx.dir, ['--css'], function (err, code, stdout, stderr) { - if (err) return done(err) - assert.ok(/error: option .* argument missing/.test(stderr)) - done() - }) - }) - }) + if (err) { + return done(err); + } + assert.ok(/error: option .* argument missing/.test(stderr)); + done(); + }); + }); + }); describe('less', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with less files', function (done) { run(ctx.dir, ['--css', 'less'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 16, 'should have 16 files') - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 16, 'should have 16 files'); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1, 'should have bin/www file') - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1, 'should have app.js file') - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1, 'should have package.json file') - }) + assert.notStrictEqual( + ctx.files.indexOf('bin/www'), + -1, + 'should have bin/www file', + ); + assert.notStrictEqual( + ctx.files.indexOf('app.js'), + -1, + 'should have app.js file', + ); + assert.notStrictEqual( + ctx.files.indexOf('package.json'), + -1, + 'should have package.json file', + ); + }); it('should have less files', function () { - assert.notStrictEqual(ctx.files.indexOf('public/stylesheets/style.less'), -1, 'should have style.less file') - }) + assert.notStrictEqual( + ctx.files.indexOf('public/stylesheets/style.less'), + -1, + 'should have style.less file', + ); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should respond with stylesheet', function (done) { request(this.app) .get('/stylesheets/style.css') - .expect(200, /sans-serif/, done) - }) - }) - }) + .expect(200, /sans-serif/, done); + }); + }); + }); describe('sass', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with sass files', function (done) { run(ctx.dir, ['--css', 'sass'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 16, 'should have 16 files') - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 16, 'should have 16 files'); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1, 'should have bin/www file') - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1, 'should have app.js file') - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1, 'should have package.json file') - }) + assert.notStrictEqual( + ctx.files.indexOf('bin/www'), + -1, + 'should have bin/www file', + ); + assert.notStrictEqual( + ctx.files.indexOf('app.js'), + -1, + 'should have app.js file', + ); + assert.notStrictEqual( + ctx.files.indexOf('package.json'), + -1, + 'should have package.json file', + ); + }); it('should have sass files', function () { - assert.notStrictEqual(ctx.files.indexOf('public/stylesheets/style.sass'), -1, 'should have style.sass file') - }) + assert.notStrictEqual( + ctx.files.indexOf('public/stylesheets/style.sass'), + -1, + 'should have style.sass file', + ); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should respond with stylesheet', function (done) { request(this.app) .get('/stylesheets/style.css') - .expect(200, /sans-serif/, done) - }) - }) - }) + .expect(200, /sans-serif/, done); + }); + }); + }); describe('stylus', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with stylus files', function (done) { run(ctx.dir, ['--css', 'stylus'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 16, 'should have 16 files') - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 16, 'should have 16 files'); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1, 'should have bin/www file') - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1, 'should have app.js file') - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1, 'should have package.json file') - }) + assert.notStrictEqual( + ctx.files.indexOf('bin/www'), + -1, + 'should have bin/www file', + ); + assert.notStrictEqual( + ctx.files.indexOf('app.js'), + -1, + 'should have app.js file', + ); + assert.notStrictEqual( + ctx.files.indexOf('package.json'), + -1, + 'should have package.json file', + ); + }); it('should have stylus files', function () { - assert.notStrictEqual(ctx.files.indexOf('public/stylesheets/style.styl'), -1, 'should have style.styl file') - }) + assert.notStrictEqual( + ctx.files.indexOf('public/stylesheets/style.styl'), + -1, + 'should have style.styl file', + ); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should respond with stylesheet', function (done) { request(this.app) .get('/stylesheets/style.css') - .expect(200, /sans-serif/, done) - }) - }) - }) - }) + .expect(200, /sans-serif/, done); + }); + }); + }); + }); describe('--ejs', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with ejs templates', function (done) { run(ctx.dir, ['--ejs'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 15, 'should have 15 files') - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 15, 'should have 15 files'); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1, 'should have bin/www file') - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1, 'should have app.js file') - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1, 'should have package.json file') - }) + assert.notStrictEqual( + ctx.files.indexOf('bin/www'), + -1, + 'should have bin/www file', + ); + assert.notStrictEqual( + ctx.files.indexOf('app.js'), + -1, + 'should have app.js file', + ); + assert.notStrictEqual( + ctx.files.indexOf('package.json'), + -1, + 'should have package.json file', + ); + }); it('should have ejs templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.ejs'), -1, 'should have views/error.ejs file') - assert.notStrictEqual(ctx.files.indexOf('views/index.ejs'), -1, 'should have views/index.ejs file') - }) - }) + assert.notStrictEqual( + ctx.files.indexOf('views/error.ejs'), + -1, + 'should have views/error.ejs file', + ); + assert.notStrictEqual( + ctx.files.indexOf('views/index.ejs'), + -1, + 'should have views/index.ejs file', + ); + }); + }); describe('--git', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with git files', function (done) { run(ctx.dir, ['--git'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 17, 'should have 17 files') - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 17, 'should have 17 files'); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1, 'should have bin/www file') - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1, 'should have app.js file') - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1, 'should have package.json file') - }) + assert.notStrictEqual( + ctx.files.indexOf('bin/www'), + -1, + 'should have bin/www file', + ); + assert.notStrictEqual( + ctx.files.indexOf('app.js'), + -1, + 'should have app.js file', + ); + assert.notStrictEqual( + ctx.files.indexOf('package.json'), + -1, + 'should have package.json file', + ); + }); it('should have .gitignore', function () { - assert.notStrictEqual(ctx.files.indexOf('.gitignore'), -1, 'should have .gitignore file') - }) + assert.notStrictEqual( + ctx.files.indexOf('.gitignore'), + -1, + 'should have .gitignore file', + ); + }); it('should have jade templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.jade'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/index.jade'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/layout.jade'), -1) - }) - }) + assert.notStrictEqual(ctx.files.indexOf('views/error.jade'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/index.jade'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/layout.jade'), -1); + }); + }); describe('-h', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should print usage', function (done) { run(ctx.dir, ['-h'], function (err, stdout) { - if (err) return done(err) - var files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(files.length, 0) - assert.ok(/Usage: express /.test(stdout)) - assert.ok(/--help/.test(stdout)) - assert.ok(/--version/.test(stdout)) - done() - }) - }) - }) + if (err) { + return done(err); + } + const files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(files.length, 0); + assert.ok(/Usage: express /.test(stdout)); + assert.ok(/--help/.test(stdout)); + assert.ok(/--version/.test(stdout)); + done(); + }); + }); + }); describe('--hbs', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with hbs templates', function (done) { run(ctx.dir, ['--hbs'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 16) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 16); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); + }); it('should have hbs in package dependencies', function () { - var file = path.resolve(ctx.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - var dependencies = JSON.parse(contents).dependencies - assert.ok(typeof dependencies.hbs === 'string') - }) + const file = path.resolve(ctx.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + const dependencies = JSON.parse(contents).dependencies; + assert.ok(typeof dependencies.hbs === 'string'); + }); it('should have hbs templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.hbs'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/index.hbs'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/layout.hbs'), -1) - }) - }) + assert.notStrictEqual(ctx.files.indexOf('views/error.hbs'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/index.hbs'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/layout.hbs'), -1); + }); + }); describe('--help', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should print usage', function (done) { run(ctx.dir, ['--help'], function (err, stdout) { - if (err) return done(err) - var files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(files.length, 0) - assert.ok(/Usage: express /.test(stdout)) - assert.ok(/--help/.test(stdout)) - assert.ok(/--version/.test(stdout)) - done() - }) - }) - }) + if (err) { + return done(err); + } + const files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(files.length, 0); + assert.ok(/Usage: express /.test(stdout)); + assert.ok(/--help/.test(stdout)); + assert.ok(/--version/.test(stdout)); + done(); + }); + }); + }); describe('--hogan', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with hogan templates', function (done) { run(ctx.dir, ['--hogan'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 15) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 15); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); + }); it('should have hjs in package dependencies', function () { - var file = path.resolve(ctx.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - var dependencies = JSON.parse(contents).dependencies - assert.ok(typeof dependencies.hjs === 'string') - }) + const file = path.resolve(ctx.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + const dependencies = JSON.parse(contents).dependencies; + assert.ok(typeof dependencies.hjs === 'string'); + }); it('should have hjs templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.hjs'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/index.hjs'), -1) - }) - }) + assert.notStrictEqual(ctx.files.indexOf('views/error.hjs'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/index.hjs'), -1); + }); + }); describe('--no-view', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app without view engine', function (done) { run(ctx.dir, ['--no-view'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 13) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 13); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); + }); it('should not have views directory', function () { - assert.strictEqual(ctx.files.indexOf('views'), -1) - }) + assert.strictEqual(ctx.files.indexOf('views'), -1); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /Cannot GET \/does_not_exist/, done) - }) - }) - }) + .expect(404, /Cannot GET \/does_not_exist/, done); + }); + }); + }); describe('--pug', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with pug templates', function (done) { run(ctx.dir, ['--pug'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 16) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 16); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); + }); it('should have pug in package dependencies', function () { - var file = path.resolve(ctx.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - var dependencies = JSON.parse(contents).dependencies - assert.ok(typeof dependencies.pug === 'string') - }) + const file = path.resolve(ctx.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + const dependencies = JSON.parse(contents).dependencies; + assert.ok(typeof dependencies.pug === 'string'); + }); it('should have pug templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.pug'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/index.pug'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/layout.pug'), -1) - }) - }) + assert.notStrictEqual(ctx.files.indexOf('views/error.pug'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/index.pug'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/layout.pug'), -1); + }); + }); describe('--view <engine>', function () { describe('(no engine)', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should exit with code 1', function (done) { + // eslint-disable-next-line no-unused-vars runRaw(ctx.dir, ['--view'], function (err, code, stdout, stderr) { - if (err) return done(err) - assert.strictEqual(code, 1) - done() - }) - }) + if (err) { + return done(err); + } + assert.strictEqual(code, 1); + done(); + }); + }); it('should print usage', function (done) { runRaw(ctx.dir, ['--view'], function (err, code, stdout) { - if (err) return done(err) - assert.ok(/Usage: express /.test(stdout)) - assert.ok(/--help/.test(stdout)) - assert.ok(/--version/.test(stdout)) - done() - }) - }) + if (err) { + return done(err); + } + assert.ok(/Usage: express /.test(stdout)); + assert.ok(/--help/.test(stdout)); + assert.ok(/--version/.test(stdout)); + done(); + }); + }); it('should print argument missing', function (done) { runRaw(ctx.dir, ['--view'], function (err, code, stdout, stderr) { - if (err) return done(err) - assert.ok(/error: option .* argument missing/.test(stderr)) - done() - }) - }) - }) + if (err) { + return done(err); + } + assert.ok(/error: option .* argument missing/.test(stderr)); + done(); + }); + }); + }); describe('dust', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with dust templates', function (done) { run(ctx.dir, ['--view', 'dust'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 15, 'should have 15 files') - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 15, 'should have 15 files'); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1, 'should have bin/www file') - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1, 'should have app.js file') - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1, 'should have package.json file') - }) + assert.notStrictEqual( + ctx.files.indexOf('bin/www'), + -1, + 'should have bin/www file', + ); + assert.notStrictEqual( + ctx.files.indexOf('app.js'), + -1, + 'should have app.js file', + ); + assert.notStrictEqual( + ctx.files.indexOf('package.json'), + -1, + 'should have package.json file', + ); + }); it('should have dust templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.dust'), -1, 'should have views/error.dust file') - assert.notStrictEqual(ctx.files.indexOf('views/index.dust'), -1, 'should have views/index.dust file') - }) + assert.notStrictEqual( + ctx.files.indexOf('views/error.dust'), + -1, + 'should have views/error.dust file', + ); + assert.notStrictEqual( + ctx.files.indexOf('views/index.dust'), + -1, + 'should have views/index.dust file', + ); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) - }) + .expect(404, /<h1>Not Found<\/h1>/, done); + }); + }); + }); describe('ejs', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with ejs templates', function (done) { run(ctx.dir, ['--view', 'ejs'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 15, 'should have 15 files') - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 15, 'should have 15 files'); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1, 'should have bin/www file') - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1, 'should have app.js file') - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1, 'should have package.json file') - }) + assert.notStrictEqual( + ctx.files.indexOf('bin/www'), + -1, + 'should have bin/www file', + ); + assert.notStrictEqual( + ctx.files.indexOf('app.js'), + -1, + 'should have app.js file', + ); + assert.notStrictEqual( + ctx.files.indexOf('package.json'), + -1, + 'should have package.json file', + ); + }); it('should have ejs templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.ejs'), -1, 'should have views/error.ejs file') - assert.notStrictEqual(ctx.files.indexOf('views/index.ejs'), -1, 'should have views/index.ejs file') - }) + assert.notStrictEqual( + ctx.files.indexOf('views/error.ejs'), + -1, + 'should have views/error.ejs file', + ); + assert.notStrictEqual( + ctx.files.indexOf('views/index.ejs'), + -1, + 'should have views/index.ejs file', + ); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) - }) + .expect(404, /<h1>Not Found<\/h1>/, done); + }); + }); + }); describe('hbs', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with hbs templates', function (done) { run(ctx.dir, ['--view', 'hbs'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 16) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 16); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); + }); it('should have hbs in package dependencies', function () { - var file = path.resolve(ctx.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - var dependencies = JSON.parse(contents).dependencies - assert.ok(typeof dependencies.hbs === 'string') - }) + const file = path.resolve(ctx.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + const dependencies = JSON.parse(contents).dependencies; + assert.ok(typeof dependencies.hbs === 'string'); + }); it('should have hbs templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.hbs'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/index.hbs'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/layout.hbs'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('views/error.hbs'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/index.hbs'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/layout.hbs'), -1); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) - }) + .expect(404, /<h1>Not Found<\/h1>/, done); + }); + }); + }); describe('hjs', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with hogan templates', function (done) { run(ctx.dir, ['--view', 'hjs'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 15) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 15); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); + }); it('should have hjs in package dependencies', function () { - var file = path.resolve(ctx.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - var dependencies = JSON.parse(contents).dependencies - assert.ok(typeof dependencies.hjs === 'string') - }) + const file = path.resolve(ctx.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + const dependencies = JSON.parse(contents).dependencies; + assert.ok(typeof dependencies.hjs === 'string'); + }); it('should have hjs templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.hjs'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/index.hjs'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('views/error.hjs'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/index.hjs'), -1); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) - }) + .expect(404, /<h1>Not Found<\/h1>/, done); + }); + }); + }); describe('pug', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with pug templates', function (done) { run(ctx.dir, ['--view', 'pug'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 16) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 16); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); + }); it('should have pug in package dependencies', function () { - var file = path.resolve(ctx.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - var dependencies = JSON.parse(contents).dependencies - assert.ok(typeof dependencies.pug === 'string') - }) + const file = path.resolve(ctx.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + const dependencies = JSON.parse(contents).dependencies; + assert.ok(typeof dependencies.pug === 'string'); + }); it('should have pug templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.pug'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/index.pug'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/layout.pug'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('views/error.pug'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/index.pug'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/layout.pug'), -1); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) - }) + .expect(404, /<h1>Not Found<\/h1>/, done); + }); + }); + }); describe('twig', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with twig templates', function (done) { run(ctx.dir, ['--view', 'twig'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 16) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 16); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); + }); it('should have twig in package dependencies', function () { - var file = path.resolve(ctx.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - var dependencies = JSON.parse(contents).dependencies - assert.ok(typeof dependencies.twig === 'string') - }) + const file = path.resolve(ctx.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + const dependencies = JSON.parse(contents).dependencies; + assert.ok(typeof dependencies.twig === 'string'); + }); it('should have twig templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.twig'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/index.twig'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/layout.twig'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('views/error.twig'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/index.twig'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/layout.twig'), -1); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) - }) + .expect(404, /<h1>Not Found<\/h1>/, done); + }); + }); + }); describe('vash', function () { - var ctx = setupTestEnvironment(this.fullTitle()) + const ctx = setupTestEnvironment(this.fullTitle()); it('should create basic app with vash templates', function (done) { run(ctx.dir, ['--view', 'vash'], function (err, stdout) { - if (err) return done(err) - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(ctx.files.length, 16) - done() - }) - }) + if (err) { + return done(err); + } + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); + assert.strictEqual(ctx.files.length, 16); + done(); + }); + }); it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); + }); it('should have vash in package dependencies', function () { - var file = path.resolve(ctx.dir, 'package.json') - var contents = fs.readFileSync(file, 'utf8') - var dependencies = JSON.parse(contents).dependencies - assert.ok(typeof dependencies.vash === 'string') - }) + const file = path.resolve(ctx.dir, 'package.json'); + const contents = fs.readFileSync(file, 'utf8'); + const dependencies = JSON.parse(contents).dependencies; + assert.ok(typeof dependencies.vash === 'string'); + }); it('should have vash templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.vash'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/index.vash'), -1) - assert.notStrictEqual(ctx.files.indexOf('views/layout.vash'), -1) - }) + assert.notStrictEqual(ctx.files.indexOf('views/error.vash'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/index.vash'), -1); + assert.notStrictEqual(ctx.files.indexOf('views/layout.vash'), -1); + }); it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT) - npmInstall(ctx.dir, done) - }) + this.timeout(NPM_INSTALL_TIMEOUT); + npmInstall(ctx.dir, done); + }); describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) + this.app = new AppRunner(ctx.dir); + }); after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.stop(done); + }); it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) + this.timeout(APP_START_STOP_TIMEOUT); + this.app.start(done); + }); it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) + .expect(200, /<title>Express<\/title>/, done); + }); it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) - }) - }) -}) + .expect(404, /<h1>Not Found<\/h1>/, done); + }); + }); + }); + }); +}); -function npmInstall (dir, callback) { - var env = utils.childEnvironment() +function npmInstall(dir, callback) { + const env = utils.childEnvironment(); exec('npm install', { cwd: dir, env: env }, function (err, stderr) { if (err) { - err.message += stderr - callback(err) - return + err.message += stderr; + callback(err); + return; } - callback() - }) + callback(); + }); } -function run (dir, args, callback) { +function run(dir, args, callback) { runRaw(dir, args, function (err, code, stdout, stderr) { if (err) { - return callback(err) + return callback(err); } - process.stderr.write(utils.stripWarnings(stderr)) + process.stderr.write(utils.stripWarnings(stderr)); try { - assert.strictEqual(utils.stripWarnings(stderr), '') - assert.strictEqual(code, 0) + assert.strictEqual(utils.stripWarnings(stderr), ''); + assert.strictEqual(code, 0); } catch (e) { - return callback(e) + return callback(e); } - callback(null, utils.stripColors(stdout)) - }) + callback(null, utils.stripColors(stdout)); + }); } -function runRaw (dir, args, callback) { - var argv = [BIN_PATH].concat(args) - var binp = process.argv[0] - var stderr = '' - var stdout = '' - - var child = spawn(binp, argv, { - cwd: dir - }) - - child.stdout.setEncoding('utf8') - child.stdout.on('data', function ondata (str) { - stdout += str - }) - child.stderr.setEncoding('utf8') - child.stderr.on('data', function ondata (str) { - stderr += str - }) - - child.on('close', onclose) - child.on('error', callback) - - function onclose (code) { - callback(null, code, stdout, stderr) +function runRaw(dir, args, callback) { + const argv = [BIN_PATH].concat(args); + const binp = process.argv[0]; + let stderr = ''; + let stdout = ''; + + const child = spawn(binp, argv, { + cwd: dir, + }); + + child.stdout.setEncoding('utf8'); + child.stdout.on('data', function ondata(str) { + stdout += str; + }); + child.stderr.setEncoding('utf8'); + child.stderr.on('data', function ondata(str) { + stderr += str; + }); + + child.on('close', onclose); + child.on('error', callback); + + function onclose(code) { + callback(null, code, stdout, stderr); } } -function setupTestEnvironment (name) { - var ctx = {} +function setupTestEnvironment(name) { + const ctx = {}; before('create environment', function (done) { - ctx.dir = path.join(TEMP_DIR, name.replace(/[<>]/g, '')) - mkdirp(ctx.dir, done) - }) + ctx.dir = path.join(TEMP_DIR, name.replace(/[<>]/g, '')); + mkdirp(ctx.dir, done); + }); after('cleanup environment', function (done) { - this.timeout(30000) - rimraf(ctx.dir, done) - }) + this.timeout(30000); + rimraf(ctx.dir, done); + }); - return ctx + return ctx; } diff --git a/test/support/app-runner.js b/test/support/app-runner.js index 5cc7ae20..47bcff6f 100644 --- a/test/support/app-runner.js +++ b/test/support/app-runner.js @@ -1,84 +1,87 @@ -'use strict' - -var exec = require('child_process').exec -var kill = require('tree-kill') -var net = require('net') -var utils = require('./utils') +'use strict'; + +const exec = require('child_process').exec; +const kill = require('tree-kill'); +const net = require('net'); +const utils = require('./utils'); + +class AppRunner { + constructor(dir) { + this.child = null; + this.dir = dir; + this.host = '127.0.0.1'; + this.port = 3000; + } + address() { + return { port: this.port }; + } -module.exports = AppRunner + start(callback) { + const app = this; + let done = false; + const env = utils.childEnvironment(); -function AppRunner (dir) { - this.child = null - this.dir = dir - this.host = '127.0.0.1' - this.port = 3000 -} + env.PORT = String(app.port); -AppRunner.prototype.address = function address () { - return { port: this.port } -} + this.child = exec('npm start', { + cwd: this.dir, + env: env, + }); -AppRunner.prototype.start = function start (callback) { - var app = this - var done = false - var env = utils.childEnvironment() + this.child.stderr.pipe(process.stderr, { end: false }); - env.PORT = String(app.port) + this.child.on('exit', function onExit(code) { + app.child = null; - this.child = exec('npm start', { - cwd: this.dir, - env: env - }) + if (!done) { + done = true; + callback(new Error('Unexpected app exit with code ' + code)); + } + }); - this.child.stderr.pipe(process.stderr, { end: false }) + function tryConnect() { + if (done || !app.child) { + return; + } - this.child.on('exit', function onExit (code) { - app.child = null + const socket = net.connect(app.port, app.host); - if (!done) { - done = true - callback(new Error('Unexpected app exit with code ' + code)) - } - }) + socket.on('connect', function onConnect() { + socket.end(); - function tryConnect () { - if (done || !app.child) return + if (!done) { + done = true; + callback(null); + } + }); - var socket = net.connect(app.port, app.host) + socket.on('error', function onError(err) { + socket.destroy(); - socket.on('connect', function onConnect () { - socket.end() + if (err.syscall !== 'connect') { + return callback(err); + } - if (!done) { - done = true - callback(null) - } - }) - - socket.on('error', function onError (err) { - socket.destroy() - - if (err.syscall !== 'connect') { - return callback(err) - } + setImmediate(tryConnect); + }); + } - setImmediate(tryConnect) - }) + setImmediate(tryConnect); } - setImmediate(tryConnect) -} - -AppRunner.prototype.stop = function stop (callback) { - if (!this.child) { - setImmediate(callback) - return - } + stop(callback) { + if (!this.child) { + setImmediate(callback); + return; + } - this.child.stderr.unpipe() - this.child.removeAllListeners('exit') + this.child.stderr.unpipe(); + this.child.removeAllListeners('exit'); - kill(this.child.pid, 'SIGTERM', callback) + kill(this.child.pid, 'SIGTERM', callback); - this.child = null + this.child = null; + } } + +module.exports = AppRunner; diff --git a/test/support/utils.js b/test/support/utils.js index 04b402ae..81c451c1 100644 --- a/test/support/utils.js +++ b/test/support/utils.js @@ -1,64 +1,64 @@ -'use strict' +'use strict'; -var fs = require('fs') -var os = require('os') -var path = require('path') -var uid = require('uid-safe') +const fs = require('fs'); +const os = require('os'); +const path = require('path'); +const uid = require('uid-safe'); -module.exports.childEnvironment = childEnvironment -module.exports.parseCreatedFiles = parseCreatedFiles -module.exports.stripColors = stripColors -module.exports.stripWarnings = stripWarnings -module.exports.tmpDir = tmpDir +module.exports.childEnvironment = childEnvironment; +module.exports.parseCreatedFiles = parseCreatedFiles; +module.exports.stripColors = stripColors; +module.exports.stripWarnings = stripWarnings; +module.exports.tmpDir = tmpDir; -function childEnvironment () { - var env = Object.create(null) +function childEnvironment() { + const env = Object.create(null); // copy the environment except for npm veriables - for (var key in process.env) { + for (let key in process.env) { if (key.substr(0, 4) !== 'npm_') { - env[key] = process.env[key] + env[key] = process.env[key]; } } - return env + return env; } -function parseCreatedFiles (output, dir) { - var files = [] - var lines = output.split(/[\r\n]+/) - var match +function parseCreatedFiles(output, dir) { + const files = []; + const lines = output.split(/[\r\n]+/); + let match; - for (var i = 0; i < lines.length; i++) { + for (let i = 0; i < lines.length; i++) { if ((match = /create.*?: (.*)$/.exec(lines[i]))) { - var file = match[1] + let file = match[1]; if (dir) { - file = path.resolve(dir, file) - file = path.relative(dir, file) + file = path.resolve(dir, file); + file = path.relative(dir, file); } - file = file.replace(/\\/g, '/') - files.push(file) + file = file.replace(/\\/g, '/'); + files.push(file); } } - return files + return files; } -function stripColors (str) { +function stripColors(str) { // eslint-disable-next-line no-control-regex - return str.replace(/\x1b\[(\d+)m/g, '_color_$1_') + return str.replace(/\x1b\[(\d+)m/g, '_color_$1_'); } -function stripWarnings (str) { - return str.replace(/\n(?:\x20{2}warning: [^\n]+\n)+\n/g, '') +function stripWarnings(str) { + return str.replace(/\n(?:\x20{2}warning: [^\n]+\n)+\n/g, ''); } -function tmpDir () { - var dirname = path.join(os.tmpdir(), uid.sync(8)) +function tmpDir() { + const dirname = path.join(os.tmpdir(), uid.sync(8)); - fs.mkdirSync(dirname, { mode: parseInt('0700', 8) }) + fs.mkdirSync(dirname, { mode: parseInt('0700', 8) }); - return dirname + return dirname; } From efbc60972b703c86b604a29a60f760a7deebb75c Mon Sep 17 00:00:00 2001 From: redaktice <redaktice@gmail.com> Date: Tue, 6 Oct 2020 18:43:13 -0600 Subject: [PATCH 2/3] Reverting back to standard eslint format after PR review --- .eslintrc.yml | 4 +- bin/express-cli.js | 480 ++++++------ test/cmd.js | 1488 ++++++++++++++++++------------------ test/support/app-runner.js | 94 +-- test/support/utils.js | 64 +- 5 files changed, 1064 insertions(+), 1066 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index 38242dcd..21dacb60 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,7 +1,5 @@ root: true -extends: - - 'eslint:recommended' - - 'plugin:node/recommended' +extends: standard rules: no-param-reassign: error no-shadow: error diff --git a/bin/express-cli.js b/bin/express-cli.js index bede3529..5b817df7 100755 --- a/bin/express-cli.js +++ b/bin/express-cli.js @@ -1,48 +1,48 @@ #!/usr/bin/env node -const ejs = require('ejs'); -const fs = require('fs'); -const minimatch = require('minimatch'); -const mkdirp = require('mkdirp'); -const path = require('path'); -const program = require('commander'); -const readline = require('readline'); -const sortedObject = require('sorted-object'); -const util = require('util'); - -const MODE_0666 = parseInt('0666', 8); -const MODE_0755 = parseInt('0755', 8); -const TEMPLATE_DIR = path.join(__dirname, '..', 'templates'); -const VERSION = require('../package').version; - -const _exit = process.exit; +const ejs = require('ejs') +const fs = require('fs') +const minimatch = require('minimatch') +const mkdirp = require('mkdirp') +const path = require('path') +const program = require('commander') +const readline = require('readline') +const sortedObject = require('sorted-object') +const util = require('util') + +const MODE_0666 = parseInt('0666', 8) +const MODE_0755 = parseInt('0755', 8) +const TEMPLATE_DIR = path.join(__dirname, '..', 'templates') +const VERSION = require('../package').version + +const _exit = process.exit // Re-assign process.exit because of commander // TODO: Switch to a different command framework -process.exit = exit; +process.exit = exit // CLI around(program, 'optionMissingArgument', function (fn, args) { - program.outputHelp(); - fn.apply(this, args); - return { args: [], unknown: [] }; -}); + program.outputHelp() + fn.apply(this, args) + return { args: [], unknown: [] } +}) before(program, 'outputHelp', function () { // track if help was shown for unknown option - this._helpShown = true; -}); + this._helpShown = true +}) before(program, 'unknownOption', function () { // allow unknown options if help was shown, to prevent trailing error - this._allowUnknownOption = this._helpShown; + this._allowUnknownOption = this._helpShown // show help if not yet shown if (!this._helpShown) { - program.outputHelp(); + program.outputHelp() } -}); +}) program .name('express') @@ -51,103 +51,103 @@ program .option( '-e, --ejs', 'add ejs engine support', - renamedOption('--ejs', '--view=ejs'), + renamedOption('--ejs', '--view=ejs') ) .option( ' --pug', 'add pug engine support', - renamedOption('--pug', '--view=pug'), + renamedOption('--pug', '--view=pug') ) .option( ' --hbs', 'add handlebars engine support', - renamedOption('--hbs', '--view=hbs'), + renamedOption('--hbs', '--view=hbs') ) .option( '-H, --hogan', 'add hogan.js engine support', - renamedOption('--hogan', '--view=hogan'), + renamedOption('--hogan', '--view=hogan') ) .option( '-v, --view <engine>', - 'add view <engine> support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)', + 'add view <engine> support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)' ) .option(' --no-view', 'use static html instead of view engine') .option( '-c, --css <engine>', - 'add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)', + 'add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)' ) .option(' --git', 'add .gitignore') .option('-f, --force', 'force on non-empty directory') - .parse(process.argv); + .parse(process.argv) if (!exit.exited) { - main(); + main() } /** - * Install an around function; AOP. + * Install an around function AOP. */ -function around(obj, method, fn) { - const old = obj[method]; +function around (obj, method, fn) { + const old = obj[method] obj[method] = function () { - const args = new Array(arguments.length); + const args = new Array(arguments.length) for (let i = 0; i < args.length; i++) { - args[i] = arguments[i]; + args[i] = arguments[i] } - return fn.call(this, old, args); - }; + return fn.call(this, old, args) + } } /** - * Install a before function; AOP. + * Install a before function AOP. */ -function before(obj, method, fn) { - const old = obj[method]; +function before (obj, method, fn) { + const old = obj[method] obj[method] = function () { - fn.call(this); - old.apply(this, arguments); - }; + fn.call(this) + old.apply(this, arguments) + } } /** * Prompt for confirmation on STDOUT/STDIN */ -function confirm(msg, callback) { +function confirm (msg, callback) { const rl = readline.createInterface({ input: process.stdin, - output: process.stdout, - }); + output: process.stdout + }) rl.question(msg, (input) => { - rl.close(); - callback(/^y|yes|ok|true$/i.test(input)); - }); + rl.close() + callback(/^y|yes|ok|true$/i.test(input)) + }) } /** * Copy file from template directory. */ -function copyTemplate(original, to) { - write(to, fs.readFileSync(path.join(TEMPLATE_DIR, original), 'utf-8')); +function copyTemplate (original, to) { + write(to, fs.readFileSync(path.join(TEMPLATE_DIR, original), 'utf-8')) } /** * Copy multiple files from template directory. */ -function copyTemplateMulti(fromDir, toDir, nameGlob) { +function copyTemplateMulti (fromDir, toDir, nameGlob) { fs.readdirSync(path.join(TEMPLATE_DIR, fromDir)) .filter(minimatch.filter(nameGlob, { matchBase: true })) .forEach((name) => { - copyTemplate(path.join(fromDir, name), path.join(toDir, name)); - }); + copyTemplate(path.join(fromDir, name), path.join(toDir, name)) + }) } /** @@ -157,8 +157,8 @@ function copyTemplateMulti(fromDir, toDir, nameGlob) { * @param {string} dir */ -function createApplication(name, dir) { - console.log(); +function createApplication (name, dir) { + console.log() // Package const pkg = { @@ -166,223 +166,223 @@ function createApplication(name, dir) { version: '0.0.0', private: true, scripts: { - start: 'node ./bin/www', + start: 'node ./bin/www' }, dependencies: { debug: '~2.6.9', - express: '~4.16.1', - }, - }; + express: '~4.16.1' + } + } // JavaScript - const app = loadTemplate('js/app.js'); - const www = loadTemplate('js/www'); + const app = loadTemplate('js/app.js') + const www = loadTemplate('js/www') // App name - www.locals.name = name; + www.locals.name = name // App modules - app.locals.localModules = Object.create(null); - app.locals.modules = Object.create(null); - app.locals.mounts = []; - app.locals.uses = []; + app.locals.localModules = Object.create(null) + app.locals.modules = Object.create(null) + app.locals.mounts = [] + app.locals.uses = [] // Request logger - app.locals.modules.logger = 'morgan'; - app.locals.uses.push("logger('dev')"); - pkg.dependencies.morgan = '~1.9.1'; + app.locals.modules.logger = 'morgan' + app.locals.uses.push("logger('dev')") + pkg.dependencies.morgan = '~1.9.1' // Body parsers - app.locals.uses.push('express.json()'); - app.locals.uses.push('express.urlencoded({ extended: false })'); + app.locals.uses.push('express.json()') + app.locals.uses.push('express.urlencoded({ extended: false })') // Cookie parser - app.locals.modules.cookieParser = 'cookie-parser'; - app.locals.uses.push('cookieParser()'); - pkg.dependencies['cookie-parser'] = '~1.4.4'; + app.locals.modules.cookieParser = 'cookie-parser' + app.locals.uses.push('cookieParser()') + pkg.dependencies['cookie-parser'] = '~1.4.4' if (dir !== '.') { - mkdir(dir, '.'); + mkdir(dir, '.') } - mkdir(dir, 'public'); - mkdir(dir, 'public/javascripts'); - mkdir(dir, 'public/images'); - mkdir(dir, 'public/stylesheets'); + mkdir(dir, 'public') + mkdir(dir, 'public/javascripts') + mkdir(dir, 'public/images') + mkdir(dir, 'public/stylesheets') // copy css templates switch (program.css) { case 'less': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.less'); - break; + copyTemplateMulti('css', dir + '/public/stylesheets', '*.less') + break case 'stylus': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.styl'); - break; + copyTemplateMulti('css', dir + '/public/stylesheets', '*.styl') + break case 'compass': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.scss'); - break; + copyTemplateMulti('css', dir + '/public/stylesheets', '*.scss') + break case 'sass': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.sass'); - break; + copyTemplateMulti('css', dir + '/public/stylesheets', '*.sass') + break default: - copyTemplateMulti('css', dir + '/public/stylesheets', '*.css'); - break; + copyTemplateMulti('css', dir + '/public/stylesheets', '*.css') + break } // copy route templates - mkdir(dir, 'routes'); - copyTemplateMulti('js/routes', dir + '/routes', '*.js'); + mkdir(dir, 'routes') + copyTemplateMulti('js/routes', dir + '/routes', '*.js') if (program.view) { // Copy view templates - mkdir(dir, 'views'); - pkg.dependencies['http-errors'] = '~1.6.3'; + mkdir(dir, 'views') + pkg.dependencies['http-errors'] = '~1.6.3' switch (program.view) { case 'dust': - copyTemplateMulti('views', dir + '/views', '*.dust'); - break; + copyTemplateMulti('views', dir + '/views', '*.dust') + break case 'ejs': - copyTemplateMulti('views', dir + '/views', '*.ejs'); - break; + copyTemplateMulti('views', dir + '/views', '*.ejs') + break case 'hbs': - copyTemplateMulti('views', dir + '/views', '*.hbs'); - break; + copyTemplateMulti('views', dir + '/views', '*.hbs') + break case 'hjs': - copyTemplateMulti('views', dir + '/views', '*.hjs'); - break; + copyTemplateMulti('views', dir + '/views', '*.hjs') + break case 'jade': - copyTemplateMulti('views', dir + '/views', '*.jade'); - break; + copyTemplateMulti('views', dir + '/views', '*.jade') + break case 'pug': - copyTemplateMulti('views', dir + '/views', '*.pug'); - break; + copyTemplateMulti('views', dir + '/views', '*.pug') + break case 'twig': - copyTemplateMulti('views', dir + '/views', '*.twig'); - break; + copyTemplateMulti('views', dir + '/views', '*.twig') + break case 'vash': - copyTemplateMulti('views', dir + '/views', '*.vash'); - break; + copyTemplateMulti('views', dir + '/views', '*.vash') + break } } else { // Copy extra public files - copyTemplate('js/index.html', path.join(dir, 'public/index.html')); + copyTemplate('js/index.html', path.join(dir, 'public/index.html')) } // CSS Engine support switch (program.css) { case 'compass': - app.locals.modules.compass = 'node-compass'; - app.locals.uses.push("compass({ mode: 'expanded' })"); - pkg.dependencies['node-compass'] = '0.2.3'; - break; + app.locals.modules.compass = 'node-compass' + app.locals.uses.push("compass({ mode: 'expanded' })") + pkg.dependencies['node-compass'] = '0.2.3' + break case 'less': - app.locals.modules.lessMiddleware = 'less-middleware'; - app.locals.uses.push("lessMiddleware(path.join(__dirname, 'public'))"); - pkg.dependencies['less-middleware'] = '~2.2.1'; - break; + app.locals.modules.lessMiddleware = 'less-middleware' + app.locals.uses.push("lessMiddleware(path.join(__dirname, 'public'))") + pkg.dependencies['less-middleware'] = '~2.2.1' + break case 'sass': - app.locals.modules.sassMiddleware = 'node-sass-middleware'; + app.locals.modules.sassMiddleware = 'node-sass-middleware' app.locals.uses.push( - "sassMiddleware({\n src: path.join(__dirname, 'public'),\n dest: path.join(__dirname, 'public'),\n indentedSyntax: true, // true = .sass and false = .scss\n sourceMap: true\n})", - ); - pkg.dependencies['node-sass-middleware'] = '0.11.0'; - break; + "sassMiddleware({\n src: path.join(__dirname, 'public'),\n dest: path.join(__dirname, 'public'),\n indentedSyntax: true, // true = .sass and false = .scss\n sourceMap: true\n})" + ) + pkg.dependencies['node-sass-middleware'] = '0.11.0' + break case 'stylus': - app.locals.modules.stylus = 'stylus'; - app.locals.uses.push("stylus.middleware(path.join(__dirname, 'public'))"); - pkg.dependencies['stylus'] = '0.54.5'; - break; + app.locals.modules.stylus = 'stylus' + app.locals.uses.push("stylus.middleware(path.join(__dirname, 'public'))") + pkg.dependencies['stylus'] = '0.54.5' + break } // Index router mount - app.locals.localModules.indexRouter = './routes/index'; - app.locals.mounts.push({ path: '/', code: 'indexRouter' }); + app.locals.localModules.indexRouter = './routes/index' + app.locals.mounts.push({ path: '/', code: 'indexRouter' }) // User router mount - app.locals.localModules.usersRouter = './routes/users'; - app.locals.mounts.push({ path: '/users', code: 'usersRouter' }); + app.locals.localModules.usersRouter = './routes/users' + app.locals.mounts.push({ path: '/users', code: 'usersRouter' }) // Template support switch (program.view) { case 'dust': - app.locals.modules.adaro = 'adaro'; + app.locals.modules.adaro = 'adaro' app.locals.view = { engine: 'dust', - render: 'adaro.dust()', - }; - pkg.dependencies.adaro = '~1.0.4'; - break; + render: 'adaro.dust()' + } + pkg.dependencies.adaro = '~1.0.4' + break case 'ejs': - app.locals.view = { engine: 'ejs' }; - pkg.dependencies.ejs = '~2.6.1'; - break; + app.locals.view = { engine: 'ejs' } + pkg.dependencies.ejs = '~2.6.1' + break case 'hbs': - app.locals.view = { engine: 'hbs' }; - pkg.dependencies.hbs = '~4.0.4'; - break; + app.locals.view = { engine: 'hbs' } + pkg.dependencies.hbs = '~4.0.4' + break case 'hjs': - app.locals.view = { engine: 'hjs' }; - pkg.dependencies.hjs = '~0.0.6'; - break; + app.locals.view = { engine: 'hjs' } + pkg.dependencies.hjs = '~0.0.6' + break case 'jade': - app.locals.view = { engine: 'jade' }; - pkg.dependencies.jade = '~1.11.0'; - break; + app.locals.view = { engine: 'jade' } + pkg.dependencies.jade = '~1.11.0' + break case 'pug': - app.locals.view = { engine: 'pug' }; - pkg.dependencies.pug = '2.0.0-beta11'; - break; + app.locals.view = { engine: 'pug' } + pkg.dependencies.pug = '2.0.0-beta11' + break case 'twig': - app.locals.view = { engine: 'twig' }; - pkg.dependencies.twig = '~0.10.3'; - break; + app.locals.view = { engine: 'twig' } + pkg.dependencies.twig = '~0.10.3' + break case 'vash': - app.locals.view = { engine: 'vash' }; - pkg.dependencies.vash = '~0.12.6'; - break; + app.locals.view = { engine: 'vash' } + pkg.dependencies.vash = '~0.12.6' + break default: - app.locals.view = false; - break; + app.locals.view = false + break } // Static files - app.locals.uses.push("express.static(path.join(__dirname, 'public'))"); + app.locals.uses.push("express.static(path.join(__dirname, 'public'))") if (program.git) { - copyTemplate('js/gitignore', path.join(dir, '.gitignore')); + copyTemplate('js/gitignore', path.join(dir, '.gitignore')) } // sort dependencies like npm(1) - pkg.dependencies = sortedObject(pkg.dependencies); + pkg.dependencies = sortedObject(pkg.dependencies) // write files - write(path.join(dir, 'app.js'), app.render()); - write(path.join(dir, 'package.json'), JSON.stringify(pkg, null, 2) + '\n'); - mkdir(dir, 'bin'); - write(path.join(dir, 'bin/www'), www.render(), MODE_0755); + write(path.join(dir, 'app.js'), app.render()) + write(path.join(dir, 'package.json'), JSON.stringify(pkg, null, 2) + '\n') + mkdir(dir, 'bin') + write(path.join(dir, 'bin/www'), www.render(), MODE_0755) - const prompt = launchedFromCmd() ? '>' : '$'; + const prompt = launchedFromCmd() ? '>' : '$' if (dir !== '.') { - console.log(); + console.log() console.log(` change directory: - ${prompt} cd ${dir}`); + ${prompt} cd ${dir}`) } console.log(` install dependencies: ${prompt} npm install - run the app:`); + run the app:`) if (launchedFromCmd()) { - console.log(` ${prompt} SET DEBUG=${name}:* & npm start'`); + console.log(` ${prompt} SET DEBUG=${name}:* & npm start'`) } else { - console.log(` ${prompt} DEBUG=${name}:* npm start`); + console.log(` ${prompt} DEBUG=${name}:* npm start`) } - console.log(); + console.log() } /** @@ -391,12 +391,12 @@ function createApplication(name, dir) { * @param {String} pathName */ -function createAppName(pathName) { +function createAppName (pathName) { return path .basename(pathName) .replace(/[^A-Za-z0-9.-]+/g, '-') .replace(/^[-_.]+|-+$/g, '') - .toLowerCase(); + .toLowerCase() } /** @@ -406,95 +406,95 @@ function createAppName(pathName) { * @param {Function} fn */ -function emptyDirectory(dir, fn) { +function emptyDirectory (dir, fn) { fs.readdir(dir, (err, files) => { if (err && err.code !== 'ENOENT') { - throw err; + throw err } - fn(!files || !files.length); - }); + fn(!files || !files.length) + }) } /** * Graceful exit for async STDIO */ -function exit(code) { +function exit (code) { // flush output for Node.js Windows pipe bug // https://github.com/joyent/node/issues/6247 is just one bug example // https://github.com/visionmedia/mocha/issues/333 has a good discussion - function done() { + function done () { if (!draining--) { - _exit(code); + _exit(code) } } - let draining = 0; - const streams = [process.stdout, process.stderr]; + let draining = 0 + const streams = [process.stdout, process.stderr] - exit.exited = true; + exit.exited = true streams.forEach((stream) => { // submit empty write request and wait for completion - draining += 1; - stream.write('', done); - }); + draining += 1 + stream.write('', done) + }) - done(); + done() } /** * Determine if launched from cmd.exe */ -function launchedFromCmd() { - return process.platform === 'win32' && process.env._ === undefined; +function launchedFromCmd () { + return process.platform === 'win32' && process.env._ === undefined } /** * Load template file. */ -function loadTemplate(name) { +function loadTemplate (name) { const contents = fs.readFileSync( path.join(__dirname, '..', 'templates', name + '.ejs'), - 'utf-8', - ); - const locals = Object.create(null); + 'utf-8' + ) + const locals = Object.create(null) - function render() { + function render () { return ejs.render(contents, locals, { - escape: util.inspect, - }); + escape: util.inspect + }) } return { locals, - render, - }; + render + } } /** * Main program. */ -function main() { +function main () { // Path - const destinationPath = program.args.shift() || '.'; + const destinationPath = program.args.shift() || '.' // App name - const appName = createAppName(path.resolve(destinationPath)) || 'hello-world'; + const appName = createAppName(path.resolve(destinationPath)) || 'hello-world' // View engine if (program.view === true) { if (program.ejs) { - program.view = 'ejs'; + program.view = 'ejs' } else if (program.hbs) { - program.view = 'hbs'; + program.view = 'hbs' } else if (program.hogan) { - program.view = 'hjs'; + program.view = 'hjs' } else if (program.pug) { - program.view = 'pug'; + program.view = 'pug' } } @@ -502,27 +502,27 @@ function main() { if (program.view === true) { warning( 'the default view engine will not be jade in future releases\n' + - "use `--view=jade' or `--help' for additional options", - ); - program.view = 'jade'; + "use `--view=jade' or `--help' for additional options" + ) + program.view = 'jade' } // Generate application emptyDirectory(destinationPath, (empty) => { if (empty || program.force) { - createApplication(appName, destinationPath); + createApplication(appName, destinationPath) } else { confirm('destination is not empty, continue? [y/N] ', (ok) => { if (ok) { - process.stdin.destroy(); - createApplication(appName, destinationPath); + process.stdin.destroy() + createApplication(appName, destinationPath) } else { - console.error('aborting'); - exit(1); + console.error('aborting') + exit(1) } - }); + }) } - }); + }) } /** @@ -532,11 +532,11 @@ function main() { * @param {string} dir */ -function mkdir(base, dir) { - const loc = path.join(base, dir); +function mkdir (base, dir) { + const loc = path.join(base, dir) - console.log(` \x1b[36mcreate\x1b[0m : ${loc}${path.sep}`); - mkdirp.sync(loc, MODE_0755); + console.log(` \x1b[36mcreate\x1b[0m : ${loc}${path.sep}`) + mkdirp.sync(loc, MODE_0755) } /** @@ -546,17 +546,17 @@ function mkdir(base, dir) { * @param {String} newName */ -function renamedOption(originalName, newName) { +function renamedOption (originalName, newName) { return (val) => { warning( util.format( "option `%s' has been renamed to `%s'", originalName, - newName, - ), - ); - return val; - }; + newName + ) + ) + return val + } } /** @@ -565,12 +565,12 @@ function renamedOption(originalName, newName) { * @param {String} message */ -function warning(message) { - console.error(); +function warning (message) { + console.error() message.split('\n').forEach((line) => { - console.error(` warning: ${line}`); - }); - console.error(); + console.error(` warning: ${line}`) + }) + console.error() } /** @@ -580,7 +580,7 @@ function warning(message) { * @param {String} str */ -function write(file, str, mode) { - fs.writeFileSync(file, str, { mode: mode || MODE_0666 }); - console.log(` \x1b[36mcreate\x1b[0m : ${file}`); +function write (file, str, mode) { + fs.writeFileSync(file, str, { mode: mode || MODE_0666 }) + console.log(` \x1b[36mcreate\x1b[0m : ${file}`) } diff --git a/test/cmd.js b/test/cmd.js index 6c9a0b47..a2cac635 100644 --- a/test/cmd.js +++ b/test/cmd.js @@ -1,72 +1,72 @@ -const assert = require('assert'); -const AppRunner = require('./support/app-runner'); -const exec = require('child_process').exec; -const fs = require('fs'); -const mkdirp = require('mkdirp'); -const path = require('path'); -const request = require('supertest'); -const rimraf = require('rimraf'); -const spawn = require('child_process').spawn; -const utils = require('./support/utils'); -const validateNpmName = require('validate-npm-package-name'); - -const APP_START_STOP_TIMEOUT = 10000; -const PKG_PATH = path.resolve(__dirname, '..', 'package.json'); +const assert = require('assert') +const AppRunner = require('./support/app-runner') +const exec = require('child_process').exec +const fs = require('fs') +const mkdirp = require('mkdirp') +const path = require('path') +const request = require('supertest') +const rimraf = require('rimraf') +const spawn = require('child_process').spawn +const utils = require('./support/utils') +const validateNpmName = require('validate-npm-package-name') + +const APP_START_STOP_TIMEOUT = 10000 +const PKG_PATH = path.resolve(__dirname, '..', 'package.json') const BIN_PATH = path.resolve( path.dirname(PKG_PATH), - require(PKG_PATH).bin.express, -); -const NPM_INSTALL_TIMEOUT = 300000; // 5 minutes -const TEMP_DIR = utils.tmpDir(); + require(PKG_PATH).bin.express +) +const NPM_INSTALL_TIMEOUT = 300000 // 5 minutes +const TEMP_DIR = utils.tmpDir() describe('express(1)', function () { after(function (done) { - this.timeout(30000); - rimraf(TEMP_DIR, done); - }); + this.timeout(30000) + rimraf(TEMP_DIR, done) + }) describe('(no args)', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app', function (done) { runRaw(ctx.dir, [], function (err, code, stdout, stderr) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - ctx.stderr = stderr; - ctx.stdout = stdout; - assert.strictEqual(ctx.files.length, 16); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + ctx.stderr = stderr + ctx.stdout = stdout + assert.strictEqual(ctx.files.length, 16) + done() + }) + }) it('should print jade view warning', function () { assert.strictEqual( ctx.stderr, - "\n warning: the default view engine will not be jade in future releases\n warning: use `--view=jade' or `--help' for additional options\n\n", - ); - }); + "\n warning: the default view engine will not be jade in future releases\n warning: use `--view=jade' or `--help' for additional options\n\n" + ) + }) it('should provide debug instructions', function () { - assert.ok(/DEBUG=express-1-no-args:\* (?:& )?npm start/.test(ctx.stdout)); - }); + assert.ok(/DEBUG=express-1-no-args:\* (?:& )?npm start/.test(ctx.stdout)) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) it('should have jade templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.jade'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/index.jade'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/layout.jade'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('views/error.jade'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.jade'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/layout.jade'), -1) + }) it('should have a package.json file', function () { - const file = path.resolve(ctx.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); + const file = path.resolve(ctx.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') assert.strictEqual( contents, '{\n' + @@ -84,1336 +84,1336 @@ describe('express(1)', function () { ' "jade": "~1.11.0",\n' + ' "morgan": "~1.9.1"\n' + ' }\n' + - '}\n', - ); - }); + '}\n' + ) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) it('should export an express app from app.js', function () { - const file = path.resolve(ctx.dir, 'app.js'); - const app = require(file); - assert.strictEqual(typeof app, 'function'); - assert.strictEqual(typeof app.handle, 'function'); - }); + const file = path.resolve(ctx.dir, 'app.js') + const app = require(file) + assert.strictEqual(typeof app, 'function') + assert.strictEqual(typeof app.handle, 'function') + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done); - }); - }); + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) describe('when directory contains spaces', function () { - const ctx0 = setupTestEnvironment('foo bar (BAZ!)'); + const ctx0 = setupTestEnvironment('foo bar (BAZ!)') it('should create basic app', function (done) { run(ctx0.dir, [], function (err, output) { if (err) { - return done(err); + return done(err) } assert.strictEqual( utils.parseCreatedFiles(output, ctx0.dir).length, - 16, - ); - done(); - }); - }); + 16 + ) + done() + }) + }) it('should have a valid npm package name', function () { - const file = path.resolve(ctx0.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); - const name = JSON.parse(contents).name; + const file = path.resolve(ctx0.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const name = JSON.parse(contents).name assert.ok( validateNpmName(name).validForNewPackages, - 'package name "' + name + '" is valid', - ); - assert.strictEqual(name, 'foo-bar-baz'); - }); - }); + 'package name "' + name + '" is valid' + ) + assert.strictEqual(name, 'foo-bar-baz') + }) + }) describe('when directory is not a valid name', function () { - const ctx1 = setupTestEnvironment('_'); + const ctx1 = setupTestEnvironment('_') it('should create basic app', function (done) { run(ctx1.dir, [], function (err, output) { if (err) { - return done(err); + return done(err) } assert.strictEqual( utils.parseCreatedFiles(output, ctx1.dir).length, - 16, - ); - done(); - }); - }); + 16 + ) + done() + }) + }) it('should default to name "hello-world"', function () { - const file = path.resolve(ctx1.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); - const name = JSON.parse(contents).name; - assert.ok(validateNpmName(name).validForNewPackages); - assert.strictEqual(name, 'hello-world'); - }); - }); - }); + const file = path.resolve(ctx1.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const name = JSON.parse(contents).name + assert.ok(validateNpmName(name).validForNewPackages) + assert.strictEqual(name, 'hello-world') + }) + }) + }) describe('(unknown args)', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should exit with code 1', function (done) { // eslint-disable-next-line no-unused-vars runRaw(ctx.dir, ['--foo'], function (err, code, stdout, stderr) { if (err) { - return done(err); + return done(err) } - assert.strictEqual(code, 1); - done(); - }); - }); + assert.strictEqual(code, 1) + done() + }) + }) it('should print usage', function (done) { runRaw(ctx.dir, ['--foo'], function (err, code, stdout, stderr) { if (err) { - return done(err); + return done(err) } - assert.ok(/Usage: express /.test(stdout)); - assert.ok(/--help/.test(stdout)); - assert.ok(/--version/.test(stdout)); - assert.ok(/error: unknown option/.test(stderr)); - done(); - }); - }); + assert.ok(/Usage: express /.test(stdout)) + assert.ok(/--help/.test(stdout)) + assert.ok(/--version/.test(stdout)) + assert.ok(/error: unknown option/.test(stderr)) + done() + }) + }) it('should print unknown option', function (done) { runRaw(ctx.dir, ['--foo'], function (err, code, stdout, stderr) { if (err) { - return done(err); + return done(err) } - assert.ok(/error: unknown option/.test(stderr)); - done(); - }); - }); - }); + assert.ok(/error: unknown option/.test(stderr)) + done() + }) + }) + }) describe('<dir>', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app in directory', function (done) { runRaw(ctx.dir, ['foo'], function (err, code, stdout, stderr) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - ctx.stderr = stderr; - ctx.stdout = stdout; - assert.strictEqual(ctx.files.length, 17); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + ctx.stderr = stderr + ctx.stdout = stdout + assert.strictEqual(ctx.files.length, 17) + done() + }) + }) it('should provide change directory instructions', function () { - assert.ok(/cd foo/.test(ctx.stdout)); - }); + assert.ok(/cd foo/.test(ctx.stdout)) + }) it('should provide install instructions', function () { - assert.ok(/npm install/.test(ctx.stdout)); - }); + assert.ok(/npm install/.test(ctx.stdout)) + }) it('should provide debug instructions', function () { - assert.ok(/DEBUG=foo:\* (?:& )?npm start/.test(ctx.stdout)); - }); + assert.ok(/DEBUG=foo:\* (?:& )?npm start/.test(ctx.stdout)) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('foo/bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('foo/app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('foo/package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('foo/bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('foo/app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('foo/package.json'), -1) + }) it('should have jade templates', function () { - assert.notStrictEqual(ctx.files.indexOf('foo/views/error.jade'), -1); - assert.notStrictEqual(ctx.files.indexOf('foo/views/index.jade'), -1); - assert.notStrictEqual(ctx.files.indexOf('foo/views/layout.jade'), -1); - }); - }); + assert.notStrictEqual(ctx.files.indexOf('foo/views/error.jade'), -1) + assert.notStrictEqual(ctx.files.indexOf('foo/views/index.jade'), -1) + assert.notStrictEqual(ctx.files.indexOf('foo/views/layout.jade'), -1) + }) + }) describe('--css <engine>', function () { describe('(no engine)', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should exit with code 1', function (done) { // eslint-disable-next-line no-unused-vars runRaw(ctx.dir, ['--css'], function (err, code, stdout, stderr) { if (err) { - return done(err); + return done(err) } - assert.strictEqual(code, 1); - done(); - }); - }); + assert.strictEqual(code, 1) + done() + }) + }) it('should print usage', function (done) { runRaw(ctx.dir, ['--css'], function (err, code, stdout) { if (err) { - return done(err); + return done(err) } - assert.ok(/Usage: express /.test(stdout)); - assert.ok(/--help/.test(stdout)); - assert.ok(/--version/.test(stdout)); - done(); - }); - }); + assert.ok(/Usage: express /.test(stdout)) + assert.ok(/--help/.test(stdout)) + assert.ok(/--version/.test(stdout)) + done() + }) + }) it('should print argument missing', function (done) { runRaw(ctx.dir, ['--css'], function (err, code, stdout, stderr) { if (err) { - return done(err); + return done(err) } - assert.ok(/error: option .* argument missing/.test(stderr)); - done(); - }); - }); - }); + assert.ok(/error: option .* argument missing/.test(stderr)) + done() + }) + }) + }) describe('less', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with less files', function (done) { run(ctx.dir, ['--css', 'less'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 16, 'should have 16 files'); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 16, 'should have 16 files') + done() + }) + }) it('should have basic files', function () { assert.notStrictEqual( ctx.files.indexOf('bin/www'), -1, - 'should have bin/www file', - ); + 'should have bin/www file' + ) assert.notStrictEqual( ctx.files.indexOf('app.js'), -1, - 'should have app.js file', - ); + 'should have app.js file' + ) assert.notStrictEqual( ctx.files.indexOf('package.json'), -1, - 'should have package.json file', - ); - }); + 'should have package.json file' + ) + }) it('should have less files', function () { assert.notStrictEqual( ctx.files.indexOf('public/stylesheets/style.less'), -1, - 'should have style.less file', - ); - }); + 'should have style.less file' + ) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should respond with stylesheet', function (done) { request(this.app) .get('/stylesheets/style.css') - .expect(200, /sans-serif/, done); - }); - }); - }); + .expect(200, /sans-serif/, done) + }) + }) + }) describe('sass', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with sass files', function (done) { run(ctx.dir, ['--css', 'sass'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 16, 'should have 16 files'); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 16, 'should have 16 files') + done() + }) + }) it('should have basic files', function () { assert.notStrictEqual( ctx.files.indexOf('bin/www'), -1, - 'should have bin/www file', - ); + 'should have bin/www file' + ) assert.notStrictEqual( ctx.files.indexOf('app.js'), -1, - 'should have app.js file', - ); + 'should have app.js file' + ) assert.notStrictEqual( ctx.files.indexOf('package.json'), -1, - 'should have package.json file', - ); - }); + 'should have package.json file' + ) + }) it('should have sass files', function () { assert.notStrictEqual( ctx.files.indexOf('public/stylesheets/style.sass'), -1, - 'should have style.sass file', - ); - }); + 'should have style.sass file' + ) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should respond with stylesheet', function (done) { request(this.app) .get('/stylesheets/style.css') - .expect(200, /sans-serif/, done); - }); - }); - }); + .expect(200, /sans-serif/, done) + }) + }) + }) describe('stylus', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with stylus files', function (done) { run(ctx.dir, ['--css', 'stylus'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 16, 'should have 16 files'); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 16, 'should have 16 files') + done() + }) + }) it('should have basic files', function () { assert.notStrictEqual( ctx.files.indexOf('bin/www'), -1, - 'should have bin/www file', - ); + 'should have bin/www file' + ) assert.notStrictEqual( ctx.files.indexOf('app.js'), -1, - 'should have app.js file', - ); + 'should have app.js file' + ) assert.notStrictEqual( ctx.files.indexOf('package.json'), -1, - 'should have package.json file', - ); - }); + 'should have package.json file' + ) + }) it('should have stylus files', function () { assert.notStrictEqual( ctx.files.indexOf('public/stylesheets/style.styl'), -1, - 'should have style.styl file', - ); - }); + 'should have style.styl file' + ) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should respond with stylesheet', function (done) { request(this.app) .get('/stylesheets/style.css') - .expect(200, /sans-serif/, done); - }); - }); - }); - }); + .expect(200, /sans-serif/, done) + }) + }) + }) + }) describe('--ejs', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with ejs templates', function (done) { run(ctx.dir, ['--ejs'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 15, 'should have 15 files'); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 15, 'should have 15 files') + done() + }) + }) it('should have basic files', function () { assert.notStrictEqual( ctx.files.indexOf('bin/www'), -1, - 'should have bin/www file', - ); + 'should have bin/www file' + ) assert.notStrictEqual( ctx.files.indexOf('app.js'), -1, - 'should have app.js file', - ); + 'should have app.js file' + ) assert.notStrictEqual( ctx.files.indexOf('package.json'), -1, - 'should have package.json file', - ); - }); + 'should have package.json file' + ) + }) it('should have ejs templates', function () { assert.notStrictEqual( ctx.files.indexOf('views/error.ejs'), -1, - 'should have views/error.ejs file', - ); + 'should have views/error.ejs file' + ) assert.notStrictEqual( ctx.files.indexOf('views/index.ejs'), -1, - 'should have views/index.ejs file', - ); - }); - }); + 'should have views/index.ejs file' + ) + }) + }) describe('--git', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with git files', function (done) { run(ctx.dir, ['--git'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 17, 'should have 17 files'); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 17, 'should have 17 files') + done() + }) + }) it('should have basic files', function () { assert.notStrictEqual( ctx.files.indexOf('bin/www'), -1, - 'should have bin/www file', - ); + 'should have bin/www file' + ) assert.notStrictEqual( ctx.files.indexOf('app.js'), -1, - 'should have app.js file', - ); + 'should have app.js file' + ) assert.notStrictEqual( ctx.files.indexOf('package.json'), -1, - 'should have package.json file', - ); - }); + 'should have package.json file' + ) + }) it('should have .gitignore', function () { assert.notStrictEqual( ctx.files.indexOf('.gitignore'), -1, - 'should have .gitignore file', - ); - }); + 'should have .gitignore file' + ) + }) it('should have jade templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.jade'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/index.jade'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/layout.jade'), -1); - }); - }); + assert.notStrictEqual(ctx.files.indexOf('views/error.jade'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.jade'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/layout.jade'), -1) + }) + }) describe('-h', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should print usage', function (done) { run(ctx.dir, ['-h'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - const files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(files.length, 0); - assert.ok(/Usage: express /.test(stdout)); - assert.ok(/--help/.test(stdout)); - assert.ok(/--version/.test(stdout)); - done(); - }); - }); - }); + const files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(files.length, 0) + assert.ok(/Usage: express /.test(stdout)) + assert.ok(/--help/.test(stdout)) + assert.ok(/--version/.test(stdout)) + done() + }) + }) + }) describe('--hbs', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with hbs templates', function (done) { run(ctx.dir, ['--hbs'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 16); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 16) + done() + }) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) it('should have hbs in package dependencies', function () { - const file = path.resolve(ctx.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); - const dependencies = JSON.parse(contents).dependencies; - assert.ok(typeof dependencies.hbs === 'string'); - }); + const file = path.resolve(ctx.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const dependencies = JSON.parse(contents).dependencies + assert.ok(typeof dependencies.hbs === 'string') + }) it('should have hbs templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.hbs'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/index.hbs'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/layout.hbs'), -1); - }); - }); + assert.notStrictEqual(ctx.files.indexOf('views/error.hbs'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.hbs'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/layout.hbs'), -1) + }) + }) describe('--help', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should print usage', function (done) { run(ctx.dir, ['--help'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - const files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(files.length, 0); - assert.ok(/Usage: express /.test(stdout)); - assert.ok(/--help/.test(stdout)); - assert.ok(/--version/.test(stdout)); - done(); - }); - }); - }); + const files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(files.length, 0) + assert.ok(/Usage: express /.test(stdout)) + assert.ok(/--help/.test(stdout)) + assert.ok(/--version/.test(stdout)) + done() + }) + }) + }) describe('--hogan', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with hogan templates', function (done) { run(ctx.dir, ['--hogan'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 15); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 15) + done() + }) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) it('should have hjs in package dependencies', function () { - const file = path.resolve(ctx.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); - const dependencies = JSON.parse(contents).dependencies; - assert.ok(typeof dependencies.hjs === 'string'); - }); + const file = path.resolve(ctx.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const dependencies = JSON.parse(contents).dependencies + assert.ok(typeof dependencies.hjs === 'string') + }) it('should have hjs templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.hjs'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/index.hjs'), -1); - }); - }); + assert.notStrictEqual(ctx.files.indexOf('views/error.hjs'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.hjs'), -1) + }) + }) describe('--no-view', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app without view engine', function (done) { run(ctx.dir, ['--no-view'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 13); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 13) + done() + }) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) it('should not have views directory', function () { - assert.strictEqual(ctx.files.indexOf('views'), -1); - }); + assert.strictEqual(ctx.files.indexOf('views'), -1) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /Cannot GET \/does_not_exist/, done); - }); - }); - }); + .expect(404, /Cannot GET \/does_not_exist/, done) + }) + }) + }) describe('--pug', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with pug templates', function (done) { run(ctx.dir, ['--pug'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 16); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 16) + done() + }) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) it('should have pug in package dependencies', function () { - const file = path.resolve(ctx.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); - const dependencies = JSON.parse(contents).dependencies; - assert.ok(typeof dependencies.pug === 'string'); - }); + const file = path.resolve(ctx.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const dependencies = JSON.parse(contents).dependencies + assert.ok(typeof dependencies.pug === 'string') + }) it('should have pug templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.pug'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/index.pug'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/layout.pug'), -1); - }); - }); + assert.notStrictEqual(ctx.files.indexOf('views/error.pug'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.pug'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/layout.pug'), -1) + }) + }) describe('--view <engine>', function () { describe('(no engine)', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should exit with code 1', function (done) { // eslint-disable-next-line no-unused-vars runRaw(ctx.dir, ['--view'], function (err, code, stdout, stderr) { if (err) { - return done(err); + return done(err) } - assert.strictEqual(code, 1); - done(); - }); - }); + assert.strictEqual(code, 1) + done() + }) + }) it('should print usage', function (done) { runRaw(ctx.dir, ['--view'], function (err, code, stdout) { if (err) { - return done(err); + return done(err) } - assert.ok(/Usage: express /.test(stdout)); - assert.ok(/--help/.test(stdout)); - assert.ok(/--version/.test(stdout)); - done(); - }); - }); + assert.ok(/Usage: express /.test(stdout)) + assert.ok(/--help/.test(stdout)) + assert.ok(/--version/.test(stdout)) + done() + }) + }) it('should print argument missing', function (done) { runRaw(ctx.dir, ['--view'], function (err, code, stdout, stderr) { if (err) { - return done(err); + return done(err) } - assert.ok(/error: option .* argument missing/.test(stderr)); - done(); - }); - }); - }); + assert.ok(/error: option .* argument missing/.test(stderr)) + done() + }) + }) + }) describe('dust', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with dust templates', function (done) { run(ctx.dir, ['--view', 'dust'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 15, 'should have 15 files'); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 15, 'should have 15 files') + done() + }) + }) it('should have basic files', function () { assert.notStrictEqual( ctx.files.indexOf('bin/www'), -1, - 'should have bin/www file', - ); + 'should have bin/www file' + ) assert.notStrictEqual( ctx.files.indexOf('app.js'), -1, - 'should have app.js file', - ); + 'should have app.js file' + ) assert.notStrictEqual( ctx.files.indexOf('package.json'), -1, - 'should have package.json file', - ); - }); + 'should have package.json file' + ) + }) it('should have dust templates', function () { assert.notStrictEqual( ctx.files.indexOf('views/error.dust'), -1, - 'should have views/error.dust file', - ); + 'should have views/error.dust file' + ) assert.notStrictEqual( ctx.files.indexOf('views/index.dust'), -1, - 'should have views/index.dust file', - ); - }); + 'should have views/index.dust file' + ) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done); - }); - }); - }); + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) + }) describe('ejs', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with ejs templates', function (done) { run(ctx.dir, ['--view', 'ejs'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 15, 'should have 15 files'); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 15, 'should have 15 files') + done() + }) + }) it('should have basic files', function () { assert.notStrictEqual( ctx.files.indexOf('bin/www'), -1, - 'should have bin/www file', - ); + 'should have bin/www file' + ) assert.notStrictEqual( ctx.files.indexOf('app.js'), -1, - 'should have app.js file', - ); + 'should have app.js file' + ) assert.notStrictEqual( ctx.files.indexOf('package.json'), -1, - 'should have package.json file', - ); - }); + 'should have package.json file' + ) + }) it('should have ejs templates', function () { assert.notStrictEqual( ctx.files.indexOf('views/error.ejs'), -1, - 'should have views/error.ejs file', - ); + 'should have views/error.ejs file' + ) assert.notStrictEqual( ctx.files.indexOf('views/index.ejs'), -1, - 'should have views/index.ejs file', - ); - }); + 'should have views/index.ejs file' + ) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done); - }); - }); - }); + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) + }) describe('hbs', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with hbs templates', function (done) { run(ctx.dir, ['--view', 'hbs'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 16); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 16) + done() + }) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) it('should have hbs in package dependencies', function () { - const file = path.resolve(ctx.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); - const dependencies = JSON.parse(contents).dependencies; - assert.ok(typeof dependencies.hbs === 'string'); - }); + const file = path.resolve(ctx.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const dependencies = JSON.parse(contents).dependencies + assert.ok(typeof dependencies.hbs === 'string') + }) it('should have hbs templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.hbs'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/index.hbs'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/layout.hbs'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('views/error.hbs'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.hbs'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/layout.hbs'), -1) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done); - }); - }); - }); + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) + }) describe('hjs', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with hogan templates', function (done) { run(ctx.dir, ['--view', 'hjs'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 15); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 15) + done() + }) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) it('should have hjs in package dependencies', function () { - const file = path.resolve(ctx.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); - const dependencies = JSON.parse(contents).dependencies; - assert.ok(typeof dependencies.hjs === 'string'); - }); + const file = path.resolve(ctx.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const dependencies = JSON.parse(contents).dependencies + assert.ok(typeof dependencies.hjs === 'string') + }) it('should have hjs templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.hjs'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/index.hjs'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('views/error.hjs'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.hjs'), -1) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done); - }); - }); - }); + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) + }) describe('pug', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with pug templates', function (done) { run(ctx.dir, ['--view', 'pug'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 16); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 16) + done() + }) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) it('should have pug in package dependencies', function () { - const file = path.resolve(ctx.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); - const dependencies = JSON.parse(contents).dependencies; - assert.ok(typeof dependencies.pug === 'string'); - }); + const file = path.resolve(ctx.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const dependencies = JSON.parse(contents).dependencies + assert.ok(typeof dependencies.pug === 'string') + }) it('should have pug templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.pug'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/index.pug'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/layout.pug'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('views/error.pug'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.pug'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/layout.pug'), -1) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done); - }); - }); - }); + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) + }) describe('twig', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with twig templates', function (done) { run(ctx.dir, ['--view', 'twig'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 16); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 16) + done() + }) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) it('should have twig in package dependencies', function () { - const file = path.resolve(ctx.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); - const dependencies = JSON.parse(contents).dependencies; - assert.ok(typeof dependencies.twig === 'string'); - }); + const file = path.resolve(ctx.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const dependencies = JSON.parse(contents).dependencies + assert.ok(typeof dependencies.twig === 'string') + }) it('should have twig templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.twig'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/index.twig'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/layout.twig'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('views/error.twig'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.twig'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/layout.twig'), -1) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done); - }); - }); - }); + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) + }) describe('vash', function () { - const ctx = setupTestEnvironment(this.fullTitle()); + const ctx = setupTestEnvironment(this.fullTitle()) it('should create basic app with vash templates', function (done) { run(ctx.dir, ['--view', 'vash'], function (err, stdout) { if (err) { - return done(err); + return done(err) } - ctx.files = utils.parseCreatedFiles(stdout, ctx.dir); - assert.strictEqual(ctx.files.length, 16); - done(); - }); - }); + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 16) + done() + }) + }) it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1); - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1); - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) it('should have vash in package dependencies', function () { - const file = path.resolve(ctx.dir, 'package.json'); - const contents = fs.readFileSync(file, 'utf8'); - const dependencies = JSON.parse(contents).dependencies; - assert.ok(typeof dependencies.vash === 'string'); - }); + const file = path.resolve(ctx.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const dependencies = JSON.parse(contents).dependencies + assert.ok(typeof dependencies.vash === 'string') + }) it('should have vash templates', function () { - assert.notStrictEqual(ctx.files.indexOf('views/error.vash'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/index.vash'), -1); - assert.notStrictEqual(ctx.files.indexOf('views/layout.vash'), -1); - }); + assert.notStrictEqual(ctx.files.indexOf('views/error.vash'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.vash'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/layout.vash'), -1) + }) it('should have installable dependencies', function (done) { - this.timeout(NPM_INSTALL_TIMEOUT); - npmInstall(ctx.dir, done); - }); + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) describe('npm start', function () { before('start app', function () { - this.app = new AppRunner(ctx.dir); - }); + this.app = new AppRunner(ctx.dir) + }) after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.stop(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT); - this.app.start(done); - }); + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) it('should respond to HTTP request', function (done) { request(this.app) .get('/') - .expect(200, /<title>Express<\/title>/, done); - }); + .expect(200, /<title>Express<\/title>/, done) + }) it('should generate a 404', function (done) { request(this.app) .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done); - }); - }); - }); - }); -}); + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) + }) + }) +}) -function npmInstall(dir, callback) { - const env = utils.childEnvironment(); +function npmInstall (dir, callback) { + const env = utils.childEnvironment() exec('npm install', { cwd: dir, env: env }, function (err, stderr) { if (err) { - err.message += stderr; - callback(err); - return; + err.message += stderr + callback(err) + return } - callback(); - }); + callback() + }) } -function run(dir, args, callback) { +function run (dir, args, callback) { runRaw(dir, args, function (err, code, stdout, stderr) { if (err) { - return callback(err); + return callback(err) } - process.stderr.write(utils.stripWarnings(stderr)); + process.stderr.write(utils.stripWarnings(stderr)) try { - assert.strictEqual(utils.stripWarnings(stderr), ''); - assert.strictEqual(code, 0); + assert.strictEqual(utils.stripWarnings(stderr), '') + assert.strictEqual(code, 0) } catch (e) { - return callback(e); + return callback(e) } - callback(null, utils.stripColors(stdout)); - }); + callback(null, utils.stripColors(stdout)) + }) } -function runRaw(dir, args, callback) { - const argv = [BIN_PATH].concat(args); - const binp = process.argv[0]; - let stderr = ''; - let stdout = ''; +function runRaw (dir, args, callback) { + const argv = [BIN_PATH].concat(args) + const binp = process.argv[0] + let stderr = '' + let stdout = '' const child = spawn(binp, argv, { - cwd: dir, - }); - - child.stdout.setEncoding('utf8'); - child.stdout.on('data', function ondata(str) { - stdout += str; - }); - child.stderr.setEncoding('utf8'); - child.stderr.on('data', function ondata(str) { - stderr += str; - }); - - child.on('close', onclose); - child.on('error', callback); - - function onclose(code) { - callback(null, code, stdout, stderr); + cwd: dir + }) + + child.stdout.setEncoding('utf8') + child.stdout.on('data', function ondata (str) { + stdout += str + }) + child.stderr.setEncoding('utf8') + child.stderr.on('data', function ondata (str) { + stderr += str + }) + + child.on('close', onclose) + child.on('error', callback) + + function onclose (code) { + callback(null, code, stdout, stderr) } } -function setupTestEnvironment(name) { - const ctx = {}; +function setupTestEnvironment (name) { + const ctx = {} before('create environment', function (done) { - ctx.dir = path.join(TEMP_DIR, name.replace(/[<>]/g, '')); - mkdirp(ctx.dir, done); - }); + ctx.dir = path.join(TEMP_DIR, name.replace(/[<>]/g, '')) + mkdirp(ctx.dir, done) + }) after('cleanup environment', function (done) { - this.timeout(30000); - rimraf(ctx.dir, done); - }); + this.timeout(30000) + rimraf(ctx.dir, done) + }) - return ctx; + return ctx } diff --git a/test/support/app-runner.js b/test/support/app-runner.js index 47bcff6f..516be23c 100644 --- a/test/support/app-runner.js +++ b/test/support/app-runner.js @@ -1,87 +1,87 @@ -'use strict'; +'use strict' -const exec = require('child_process').exec; -const kill = require('tree-kill'); -const net = require('net'); -const utils = require('./utils'); +const exec = require('child_process').exec +const kill = require('tree-kill') +const net = require('net') +const utils = require('./utils') class AppRunner { - constructor(dir) { - this.child = null; - this.dir = dir; - this.host = '127.0.0.1'; - this.port = 3000; + constructor (dir) { + this.child = null + this.dir = dir + this.host = '127.0.0.1' + this.port = 3000 } - address() { - return { port: this.port }; + address () { + return { port: this.port } } - start(callback) { - const app = this; - let done = false; - const env = utils.childEnvironment(); + start (callback) { + const app = this + let done = false + const env = utils.childEnvironment() - env.PORT = String(app.port); + env.PORT = String(app.port) this.child = exec('npm start', { cwd: this.dir, - env: env, - }); + env: env + }) - this.child.stderr.pipe(process.stderr, { end: false }); + this.child.stderr.pipe(process.stderr, { end: false }) - this.child.on('exit', function onExit(code) { - app.child = null; + this.child.on('exit', function onExit (code) { + app.child = null if (!done) { - done = true; - callback(new Error('Unexpected app exit with code ' + code)); + done = true + callback(new Error('Unexpected app exit with code ' + code)) } - }); + }) - function tryConnect() { + function tryConnect () { if (done || !app.child) { - return; + return } - const socket = net.connect(app.port, app.host); + const socket = net.connect(app.port, app.host) - socket.on('connect', function onConnect() { - socket.end(); + socket.on('connect', function onConnect () { + socket.end() if (!done) { - done = true; - callback(null); + done = true + callback(null) } - }); + }) - socket.on('error', function onError(err) { - socket.destroy(); + socket.on('error', function onError (err) { + socket.destroy() if (err.syscall !== 'connect') { - return callback(err); + return callback(err) } - setImmediate(tryConnect); - }); + setImmediate(tryConnect) + }) } - setImmediate(tryConnect); + setImmediate(tryConnect) } - stop(callback) { + stop (callback) { if (!this.child) { - setImmediate(callback); - return; + setImmediate(callback) + return } - this.child.stderr.unpipe(); - this.child.removeAllListeners('exit'); + this.child.stderr.unpipe() + this.child.removeAllListeners('exit') - kill(this.child.pid, 'SIGTERM', callback); + kill(this.child.pid, 'SIGTERM', callback) - this.child = null; + this.child = null } } -module.exports = AppRunner; +module.exports = AppRunner diff --git a/test/support/utils.js b/test/support/utils.js index 81c451c1..16295e22 100644 --- a/test/support/utils.js +++ b/test/support/utils.js @@ -1,64 +1,64 @@ -'use strict'; +'use strict' -const fs = require('fs'); -const os = require('os'); -const path = require('path'); -const uid = require('uid-safe'); +const fs = require('fs') +const os = require('os') +const path = require('path') +const uid = require('uid-safe') -module.exports.childEnvironment = childEnvironment; -module.exports.parseCreatedFiles = parseCreatedFiles; -module.exports.stripColors = stripColors; -module.exports.stripWarnings = stripWarnings; -module.exports.tmpDir = tmpDir; +module.exports.childEnvironment = childEnvironment +module.exports.parseCreatedFiles = parseCreatedFiles +module.exports.stripColors = stripColors +module.exports.stripWarnings = stripWarnings +module.exports.tmpDir = tmpDir -function childEnvironment() { - const env = Object.create(null); +function childEnvironment () { + const env = Object.create(null) // copy the environment except for npm veriables for (let key in process.env) { if (key.substr(0, 4) !== 'npm_') { - env[key] = process.env[key]; + env[key] = process.env[key] } } - return env; + return env } -function parseCreatedFiles(output, dir) { - const files = []; - const lines = output.split(/[\r\n]+/); - let match; +function parseCreatedFiles (output, dir) { + const files = [] + const lines = output.split(/[\r\n]+/) + let match for (let i = 0; i < lines.length; i++) { if ((match = /create.*?: (.*)$/.exec(lines[i]))) { - let file = match[1]; + let file = match[1] if (dir) { - file = path.resolve(dir, file); - file = path.relative(dir, file); + file = path.resolve(dir, file) + file = path.relative(dir, file) } - file = file.replace(/\\/g, '/'); - files.push(file); + file = file.replace(/\\/g, '/') + files.push(file) } } - return files; + return files } -function stripColors(str) { +function stripColors (str) { // eslint-disable-next-line no-control-regex - return str.replace(/\x1b\[(\d+)m/g, '_color_$1_'); + return str.replace(/\x1b\[(\d+)m/g, '_color_$1_') } -function stripWarnings(str) { - return str.replace(/\n(?:\x20{2}warning: [^\n]+\n)+\n/g, ''); +function stripWarnings (str) { + return str.replace(/\n(?:\x20{2}warning: [^\n]+\n)+\n/g, '') } -function tmpDir() { - const dirname = path.join(os.tmpdir(), uid.sync(8)); +function tmpDir () { + const dirname = path.join(os.tmpdir(), uid.sync(8)) - fs.mkdirSync(dirname, { mode: parseInt('0700', 8) }); + fs.mkdirSync(dirname, { mode: parseInt('0700', 8) }) - return dirname; + return dirname } From 229214d2136a021d2f406a03c466d3128582465f Mon Sep 17 00:00:00 2001 From: redaktice <peter.rgail@gmail.com> Date: Tue, 13 Oct 2020 20:41:15 -0600 Subject: [PATCH 3/3] Making es5 a CLI arg --- README.md | 1 + bin/express-cli.js | 16 +- templates/js/app.js.ejs | 41 +- templates/js/routes/index.ejs | 18 + templates/js/routes/index.js | 9 - templates/js/routes/users.ejs | 19 + templates/js/routes/users.js | 9 - templates/js/www.ejs | 106 ++++- test/cmd.js | 701 +++++++++++++--------------------- 9 files changed, 445 insertions(+), 475 deletions(-) create mode 100644 templates/js/routes/index.ejs delete mode 100644 templates/js/routes/index.js create mode 100644 templates/js/routes/users.ejs delete mode 100644 templates/js/routes/users.js diff --git a/README.md b/README.md index ca18976e..50e8a494 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ This generator can also be further configured with the following command line fl --version output the version number -e, --ejs add ejs engine support + --es5 use ES5 syntax (defaults to ES2015 syntax) --pug add pug engine support --hbs add handlebars engine support -H, --hogan add hogan.js engine support diff --git a/bin/express-cli.js b/bin/express-cli.js index 5b817df7..a06702c8 100755 --- a/bin/express-cli.js +++ b/bin/express-cli.js @@ -53,6 +53,7 @@ program 'add ejs engine support', renamedOption('--ejs', '--view=ejs') ) + .option(' --es5', 'use ES5 syntax (defaults to ES2015 syntax)') .option( ' --pug', 'add pug engine support', @@ -177,10 +178,18 @@ function createApplication (name, dir) { // JavaScript const app = loadTemplate('js/app.js') const www = loadTemplate('js/www') + const index = loadTemplate('js/routes/index') + const users = loadTemplate('js/routes/users') // App name www.locals.name = name + // ES2015 Syntax + app.locals.es5 = program.es5 + www.locals.es5 = program.es5 + index.locals.es5 = program.es5 + users.locals.es5 = program.es5 + // App modules app.locals.localModules = Object.create(null) app.locals.modules = Object.create(null) @@ -229,10 +238,6 @@ function createApplication (name, dir) { break } - // copy route templates - mkdir(dir, 'routes') - copyTemplateMulti('js/routes', dir + '/routes', '*.js') - if (program.view) { // Copy view templates mkdir(dir, 'views') @@ -360,6 +365,9 @@ function createApplication (name, dir) { write(path.join(dir, 'package.json'), JSON.stringify(pkg, null, 2) + '\n') mkdir(dir, 'bin') write(path.join(dir, 'bin/www'), www.render(), MODE_0755) + mkdir(dir, 'routes') + write(path.join(dir, 'routes/index.js'), index.render()) + write(path.join(dir, 'routes/users.js'), users.render()) const prompt = launchedFromCmd() ? '>' : '$' diff --git a/templates/js/app.js.ejs b/templates/js/app.js.ejs index 0b9ea581..3e35b94b 100644 --- a/templates/js/app.js.ejs +++ b/templates/js/app.js.ejs @@ -1,17 +1,37 @@ -<% if (view) { -%> +<% if (view && es5) { -%> +var createError = require('http-errors'); +<% } else if (view) { -%> const createError = require('http-errors'); <% } -%> + +<% if (es5) { -%> +var express = require('express'); +var path = require('path'); +<% } else { -%> const express = require('express'); const path = require('path'); +<% } -%> <% Object.keys(modules).sort().forEach(function (variable) { -%> +<% if (es5) { -%> +var <%- variable %> = require('<%- modules[variable] %>'); +<% } else { -%> const <%- variable %> = require('<%- modules[variable] %>'); +<% } -%> <% }); -%> <% Object.keys(localModules).sort().forEach(function (variable) { -%> +<% if (es5) { -%> +var <%- variable %> = require('<%- localModules[variable] %>'); +<% } else { -%> const <%- variable %> = require('<%- localModules[variable] %>'); +<% } -%> <% }); -%> +<% if (es5) { -%> +var app = express(); +<% } else { -%> const app = express(); +<% } -%> <% if (view) { -%> // view engine setup @@ -30,7 +50,24 @@ app.use(<%- use %>); app.use(<%= mount.path %>, <%- mount.code %>); <% }); -%> -<% if (view) { -%> +<% if (view && es5) { -%> +// catch 404 and forward to error handler +app.use(function (req, res, next) { + next(createError(404)); +}); + +// error handler +app.use(function (err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.render('error'); +}); + +<% } else if (view) { -%> // catch 404 and forward to error handler app.use((req, res, next) => { next(createError(404)); diff --git a/templates/js/routes/index.ejs b/templates/js/routes/index.ejs new file mode 100644 index 00000000..fab2a85e --- /dev/null +++ b/templates/js/routes/index.ejs @@ -0,0 +1,18 @@ +<% if (es5) { -%> +var express = require('express'); +var router = express.Router(); + +/* GET home page. */ +router.get('/', function(req, res, next) { + res.render('index', { title: 'Express' }); +}); +<% } else { -%> +const express = require('express'); +const router = express.Router(); + +/* GET home page. */ +router.get('/', (req, res, next) => { + res.render('index', { title: 'Express' }); +}); +<% } -%> +module.exports = router; diff --git a/templates/js/routes/index.js b/templates/js/routes/index.js deleted file mode 100644 index ecca96a5..00000000 --- a/templates/js/routes/index.js +++ /dev/null @@ -1,9 +0,0 @@ -var express = require('express'); -var router = express.Router(); - -/* GET home page. */ -router.get('/', function(req, res, next) { - res.render('index', { title: 'Express' }); -}); - -module.exports = router; diff --git a/templates/js/routes/users.ejs b/templates/js/routes/users.ejs new file mode 100644 index 00000000..b1916e77 --- /dev/null +++ b/templates/js/routes/users.ejs @@ -0,0 +1,19 @@ +<% if (es5) { -%> +var express = require('express'); +var router = express.Router(); + +/* GET users listing. */ +router.get('/', function(req, res, next) { + res.send('respond with a resource'); +}); +<% } else { -%> +const express = require('express'); +const router = express.Router(); + +/* GET users listing. */ +router.get('/', (req, res, next) => { + res.send('respond with a resource'); +}); +<% } -%> + +module.exports = router; diff --git a/templates/js/routes/users.js b/templates/js/routes/users.js deleted file mode 100644 index 623e4302..00000000 --- a/templates/js/routes/users.js +++ /dev/null @@ -1,9 +0,0 @@ -var express = require('express'); -var router = express.Router(); - -/* GET users listing. */ -router.get('/', function(req, res, next) { - res.send('respond with a resource'); -}); - -module.exports = router; diff --git a/templates/js/www.ejs b/templates/js/www.ejs index a309083e..649d8e57 100644 --- a/templates/js/www.ejs +++ b/templates/js/www.ejs @@ -4,22 +4,22 @@ * Module dependencies. */ -const app = require('../app'); -const debug = require('debug')('<%- name %>:server'); -const http = require('http'); - +<% if (es5) { -%> +var app = require('../app'); +var debug = require('debug')('<%- name %>:server'); +var http = require('http'); /** * Get port from environment and store in Express. */ -const port = normalizePort(process.env.PORT || '3000'); +var port = normalizePort(process.env.PORT || '3000'); app.set('port', port); /** * Create HTTP server. */ -const server = http.createServer(app); +var server = http.createServer(app); /** * Listen on provided port, on all network interfaces. @@ -34,7 +34,7 @@ server.on('listening', onListening); */ function normalizePort(val) { - const port = parseInt(val, 10); + var port = parseInt(val, 10); if (isNaN(port)) { // named pipe @@ -58,7 +58,7 @@ function onError(error) { throw error; } - const bind = typeof port === 'string' + var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; @@ -82,9 +82,95 @@ function onError(error) { */ function onListening() { - const addr = server.address(); - const bind = typeof addr === 'string' + var addr = server.address(); + var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; debug('Listening on ' + bind); } + +<% } else { -%> + const app = require('../app'); + const debug = require('debug')('<%- name %>:server'); + const http = require('http'); + /** + * Get port from environment and store in Express. + */ + + const port = normalizePort(process.env.PORT || '3000'); + app.set('port', port); + + /** + * Create HTTP server. + */ + + const server = http.createServer(app); + + /** + * Listen on provided port, on all network interfaces. + */ + + server.listen(port); + server.on('error', onError); + server.on('listening', onListening); + + /** + * Normalize a port into a number, string, or false. + */ + + function normalizePort(val) { + const port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; + } + + /** + * Event listener for HTTP server "error" event. + */ + + function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + const bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } + } + + /** + * Event listener for HTTP server "listening" event. + */ + + function onListening() { + const addr = server.address(); + const bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); + } +<% } -%> \ No newline at end of file diff --git a/test/cmd.js b/test/cmd.js index a2cac635..6553e924 100644 --- a/test/cmd.js +++ b/test/cmd.js @@ -52,11 +52,7 @@ describe('express(1)', function () { assert.ok(/DEBUG=express-1-no-args:\* (?:& )?npm start/.test(ctx.stdout)) }) - it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + checkBasicFiles(ctx) it('should have jade templates', function () { assert.notStrictEqual(ctx.files.indexOf('views/error.jade'), -1) @@ -182,32 +178,161 @@ describe('express(1)', function () { }) }) - describe('(unknown args)', function () { + describe('--es5', function () { const ctx = setupTestEnvironment(this.fullTitle()) - it('should exit with code 1', function (done) { - // eslint-disable-next-line no-unused-vars - runRaw(ctx.dir, ['--foo'], function (err, code, stdout, stderr) { + it('should create basic app', function (done) { + runRaw(ctx.dir, ['--es5'], function (err, code, stdout, stderr) { if (err) { return done(err) } - assert.strictEqual(code, 1) + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + ctx.stderr = stderr + ctx.stdout = stdout + assert.strictEqual(ctx.files.length, 16) done() }) }) - it('should print usage', function (done) { - runRaw(ctx.dir, ['--foo'], function (err, code, stdout, stderr) { - if (err) { - return done(err) - } - assert.ok(/Usage: express /.test(stdout)) - assert.ok(/--help/.test(stdout)) - assert.ok(/--version/.test(stdout)) - assert.ok(/error: unknown option/.test(stderr)) - done() + it('should print jade view warning', function () { + assert.strictEqual( + ctx.stderr, + "\n warning: the default view engine will not be jade in future releases\n warning: use `--view=jade' or `--help' for additional options\n\n" + ) + }) + + checkBasicFiles(ctx) + + it('should have jade templates', function () { + assert.notStrictEqual(ctx.files.indexOf('views/error.jade'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.jade'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/layout.jade'), -1) + }) + + it('should have a package.json file', function () { + const file = path.resolve(ctx.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + assert.strictEqual( + contents, + '{\n' + + ' "name": "express-1---es5",\n' + + ' "version": "0.0.0",\n' + + ' "private": true,\n' + + ' "scripts": {\n' + + ' "start": "node ./bin/www"\n' + + ' },\n' + + ' "dependencies": {\n' + + ' "cookie-parser": "~1.4.4",\n' + + ' "debug": "~2.6.9",\n' + + ' "express": "~4.16.1",\n' + + ' "http-errors": "~1.6.3",\n' + + ' "jade": "~1.11.0",\n' + + ' "morgan": "~1.9.1"\n' + + ' }\n' + + '}\n' + ) + }) + + it('should have installable dependencies', function (done) { + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) + + it('should export an express app from app.js', function () { + const file = path.resolve(ctx.dir, 'app.js') + const app = require(file) + assert.strictEqual(typeof app, 'function') + assert.strictEqual(typeof app.handle, 'function') + }) + + describe('npm start', function () { + before('start app', function () { + this.app = new AppRunner(ctx.dir) + }) + + after('stop app', function (done) { + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) + + it('should start app', function (done) { + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) + + it('should respond to HTTP request', function (done) { + request(this.app) + .get('/') + .expect(200, /<title>Express<\/title>/, done) + }) + + it('should generate a 404', function (done) { + request(this.app) + .get('/does_not_exist') + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) + + describe('when directory contains spaces', function () { + const ctx0 = setupTestEnvironment('foo bar (BAZ!)') + + it('should create basic app', function (done) { + run(ctx0.dir, [], function (err, output) { + if (err) { + return done(err) + } + assert.strictEqual( + utils.parseCreatedFiles(output, ctx0.dir).length, + 16 + ) + done() + }) + }) + + it('should have a valid npm package name', function () { + const file = path.resolve(ctx0.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const name = JSON.parse(contents).name + assert.ok( + validateNpmName(name).validForNewPackages, + 'package name "' + name + '" is valid' + ) + assert.strictEqual(name, 'foo-bar-baz') + }) + }) + + describe('when directory is not a valid name', function () { + const ctx1 = setupTestEnvironment('_') + + it('should create basic app', function (done) { + run(ctx1.dir, [], function (err, output) { + if (err) { + return done(err) + } + assert.strictEqual( + utils.parseCreatedFiles(output, ctx1.dir).length, + 16 + ) + done() + }) + }) + + it('should default to name "hello-world"', function () { + const file = path.resolve(ctx1.dir, 'package.json') + const contents = fs.readFileSync(file, 'utf8') + const name = JSON.parse(contents).name + assert.ok(validateNpmName(name).validForNewPackages) + assert.strictEqual(name, 'hello-world') }) }) + }) + + describe('(unknown args)', function () { + const ctx = setupTestEnvironment(this.fullTitle()) + + checkAppExits(ctx, '--foo') + + checkMessage(ctx, '--foo', { runRaw: true, isUnknownArg: true }) it('should print unknown option', function (done) { runRaw(ctx.dir, ['--foo'], function (err, code, stdout, stderr) { @@ -265,28 +390,9 @@ describe('express(1)', function () { describe('(no engine)', function () { const ctx = setupTestEnvironment(this.fullTitle()) - it('should exit with code 1', function (done) { - // eslint-disable-next-line no-unused-vars - runRaw(ctx.dir, ['--css'], function (err, code, stdout, stderr) { - if (err) { - return done(err) - } - assert.strictEqual(code, 1) - done() - }) - }) + checkAppExits(ctx, '--css') - it('should print usage', function (done) { - runRaw(ctx.dir, ['--css'], function (err, code, stdout) { - if (err) { - return done(err) - } - assert.ok(/Usage: express /.test(stdout)) - assert.ok(/--help/.test(stdout)) - assert.ok(/--version/.test(stdout)) - done() - }) - }) + checkMessage(ctx, '--css', { runRaw: true }) it('should print argument missing', function (done) { runRaw(ctx.dir, ['--css'], function (err, code, stdout, stderr) { @@ -313,23 +419,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual( - ctx.files.indexOf('bin/www'), - -1, - 'should have bin/www file' - ) - assert.notStrictEqual( - ctx.files.indexOf('app.js'), - -1, - 'should have app.js file' - ) - assert.notStrictEqual( - ctx.files.indexOf('package.json'), - -1, - 'should have package.json file' - ) - }) + checkBasicFiles(ctx) it('should have less files', function () { assert.notStrictEqual( @@ -387,23 +477,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual( - ctx.files.indexOf('bin/www'), - -1, - 'should have bin/www file' - ) - assert.notStrictEqual( - ctx.files.indexOf('app.js'), - -1, - 'should have app.js file' - ) - assert.notStrictEqual( - ctx.files.indexOf('package.json'), - -1, - 'should have package.json file' - ) - }) + checkBasicFiles(ctx) it('should have sass files', function () { assert.notStrictEqual( @@ -461,23 +535,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual( - ctx.files.indexOf('bin/www'), - -1, - 'should have bin/www file' - ) - assert.notStrictEqual( - ctx.files.indexOf('app.js'), - -1, - 'should have app.js file' - ) - assert.notStrictEqual( - ctx.files.indexOf('package.json'), - -1, - 'should have package.json file' - ) - }) + checkBasicFiles(ctx) it('should have stylus files', function () { assert.notStrictEqual( @@ -536,23 +594,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual( - ctx.files.indexOf('bin/www'), - -1, - 'should have bin/www file' - ) - assert.notStrictEqual( - ctx.files.indexOf('app.js'), - -1, - 'should have app.js file' - ) - assert.notStrictEqual( - ctx.files.indexOf('package.json'), - -1, - 'should have package.json file' - ) - }) + checkBasicFiles(ctx) it('should have ejs templates', function () { assert.notStrictEqual( @@ -582,23 +624,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual( - ctx.files.indexOf('bin/www'), - -1, - 'should have bin/www file' - ) - assert.notStrictEqual( - ctx.files.indexOf('app.js'), - -1, - 'should have app.js file' - ) - assert.notStrictEqual( - ctx.files.indexOf('package.json'), - -1, - 'should have package.json file' - ) - }) + checkBasicFiles(ctx) it('should have .gitignore', function () { assert.notStrictEqual( @@ -618,19 +644,7 @@ describe('express(1)', function () { describe('-h', function () { const ctx = setupTestEnvironment(this.fullTitle()) - it('should print usage', function (done) { - run(ctx.dir, ['-h'], function (err, stdout) { - if (err) { - return done(err) - } - const files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(files.length, 0) - assert.ok(/Usage: express /.test(stdout)) - assert.ok(/--help/.test(stdout)) - assert.ok(/--version/.test(stdout)) - done() - }) - }) + checkMessage(ctx, '-h', { numFiles: 0 }) }) describe('--hbs', function () { @@ -647,11 +661,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + checkBasicFiles(ctx) it('should have hbs in package dependencies', function () { const file = path.resolve(ctx.dir, 'package.json') @@ -670,19 +680,7 @@ describe('express(1)', function () { describe('--help', function () { const ctx = setupTestEnvironment(this.fullTitle()) - it('should print usage', function (done) { - run(ctx.dir, ['--help'], function (err, stdout) { - if (err) { - return done(err) - } - const files = utils.parseCreatedFiles(stdout, ctx.dir) - assert.strictEqual(files.length, 0) - assert.ok(/Usage: express /.test(stdout)) - assert.ok(/--help/.test(stdout)) - assert.ok(/--version/.test(stdout)) - done() - }) - }) + checkMessage(ctx, '--help', { numFiles: 0 }) }) describe('--hogan', function () { @@ -699,11 +697,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + checkBasicFiles(ctx) it('should have hjs in package dependencies', function () { const file = path.resolve(ctx.dir, 'package.json') @@ -732,11 +726,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + checkBasicFiles(ctx) it('should not have views directory', function () { assert.strictEqual(ctx.files.indexOf('views'), -1) @@ -790,11 +780,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + checkBasicFiles(ctx) it('should have pug in package dependencies', function () { const file = path.resolve(ctx.dir, 'package.json') @@ -814,28 +800,9 @@ describe('express(1)', function () { describe('(no engine)', function () { const ctx = setupTestEnvironment(this.fullTitle()) - it('should exit with code 1', function (done) { - // eslint-disable-next-line no-unused-vars - runRaw(ctx.dir, ['--view'], function (err, code, stdout, stderr) { - if (err) { - return done(err) - } - assert.strictEqual(code, 1) - done() - }) - }) + checkAppExits(ctx, '--view') - it('should print usage', function (done) { - runRaw(ctx.dir, ['--view'], function (err, code, stdout) { - if (err) { - return done(err) - } - assert.ok(/Usage: express /.test(stdout)) - assert.ok(/--help/.test(stdout)) - assert.ok(/--version/.test(stdout)) - done() - }) - }) + checkMessage(ctx, '--view', { runRaw: true }) it('should print argument missing', function (done) { runRaw(ctx.dir, ['--view'], function (err, code, stdout, stderr) { @@ -862,23 +829,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual( - ctx.files.indexOf('bin/www'), - -1, - 'should have bin/www file' - ) - assert.notStrictEqual( - ctx.files.indexOf('app.js'), - -1, - 'should have app.js file' - ) - assert.notStrictEqual( - ctx.files.indexOf('package.json'), - -1, - 'should have package.json file' - ) - }) + checkBasicFiles(ctx) it('should have dust templates', function () { assert.notStrictEqual( @@ -898,33 +849,7 @@ describe('express(1)', function () { npmInstall(ctx.dir, done) }) - describe('npm start', function () { - before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) - - after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) - - it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) - - it('should respond to HTTP request', function (done) { - request(this.app) - .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) - - it('should generate a 404', function (done) { - request(this.app) - .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) + checkAppStart(ctx) }) describe('ejs', function () { @@ -941,23 +866,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual( - ctx.files.indexOf('bin/www'), - -1, - 'should have bin/www file' - ) - assert.notStrictEqual( - ctx.files.indexOf('app.js'), - -1, - 'should have app.js file' - ) - assert.notStrictEqual( - ctx.files.indexOf('package.json'), - -1, - 'should have package.json file' - ) - }) + checkBasicFiles(ctx) it('should have ejs templates', function () { assert.notStrictEqual( @@ -977,33 +886,7 @@ describe('express(1)', function () { npmInstall(ctx.dir, done) }) - describe('npm start', function () { - before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) - - after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) - - it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) - - it('should respond to HTTP request', function (done) { - request(this.app) - .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) - - it('should generate a 404', function (done) { - request(this.app) - .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) + checkAppStart(ctx) }) describe('hbs', function () { @@ -1020,11 +903,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + checkBasicFiles(ctx) it('should have hbs in package dependencies', function () { const file = path.resolve(ctx.dir, 'package.json') @@ -1044,33 +923,7 @@ describe('express(1)', function () { npmInstall(ctx.dir, done) }) - describe('npm start', function () { - before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) - - after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) - - it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) - - it('should respond to HTTP request', function (done) { - request(this.app) - .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) - - it('should generate a 404', function (done) { - request(this.app) - .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) + checkAppStart(ctx) }) describe('hjs', function () { @@ -1087,11 +940,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + checkBasicFiles(ctx) it('should have hjs in package dependencies', function () { const file = path.resolve(ctx.dir, 'package.json') @@ -1110,33 +959,7 @@ describe('express(1)', function () { npmInstall(ctx.dir, done) }) - describe('npm start', function () { - before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) - - after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) - - it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) - - it('should respond to HTTP request', function (done) { - request(this.app) - .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) - - it('should generate a 404', function (done) { - request(this.app) - .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) + checkAppStart(ctx) }) describe('pug', function () { @@ -1153,11 +976,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + checkBasicFiles(ctx) it('should have pug in package dependencies', function () { const file = path.resolve(ctx.dir, 'package.json') @@ -1177,33 +996,7 @@ describe('express(1)', function () { npmInstall(ctx.dir, done) }) - describe('npm start', function () { - before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) - - after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) - - it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) - - it('should respond to HTTP request', function (done) { - request(this.app) - .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) - - it('should generate a 404', function (done) { - request(this.app) - .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) + checkAppStart(ctx) }) describe('twig', function () { @@ -1220,11 +1013,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + checkBasicFiles(ctx) it('should have twig in package dependencies', function () { const file = path.resolve(ctx.dir, 'package.json') @@ -1244,33 +1033,7 @@ describe('express(1)', function () { npmInstall(ctx.dir, done) }) - describe('npm start', function () { - before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) - - after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) - - it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) - - it('should respond to HTTP request', function (done) { - request(this.app) - .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) - - it('should generate a 404', function (done) { - request(this.app) - .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) + checkAppStart(ctx) }) describe('vash', function () { @@ -1287,11 +1050,7 @@ describe('express(1)', function () { }) }) - it('should have basic files', function () { - assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) - assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) - assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) - }) + checkBasicFiles(ctx) it('should have vash in package dependencies', function () { const file = path.resolve(ctx.dir, 'package.json') @@ -1311,33 +1070,7 @@ describe('express(1)', function () { npmInstall(ctx.dir, done) }) - describe('npm start', function () { - before('start app', function () { - this.app = new AppRunner(ctx.dir) - }) - - after('stop app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.stop(done) - }) - - it('should start app', function (done) { - this.timeout(APP_START_STOP_TIMEOUT) - this.app.start(done) - }) - - it('should respond to HTTP request', function (done) { - request(this.app) - .get('/') - .expect(200, /<title>Express<\/title>/, done) - }) - - it('should generate a 404', function (done) { - request(this.app) - .get('/does_not_exist') - .expect(404, /<h1>Not Found<\/h1>/, done) - }) - }) + checkAppStart(ctx) }) }) }) @@ -1417,3 +1150,89 @@ function setupTestEnvironment (name) { return ctx } + +function checkAppExits (ctx, arg) { + it('should exit with code 1', function (done) { + // eslint-disable-next-line no-unused-vars + runRaw(ctx.dir, [arg], function (err, code, stdout, stderr) { + if (err) { + return done(err) + } + assert.strictEqual(code, 1) + done() + }) + }) +} + +function checkMessage (ctx, arg, options = {}) { + it('should print usage', function (done) { + if (options.runRaw) { + runRaw(ctx.dir, [arg], function (err, code, stdout, stderr) { + if (err) { + return done(err) + } + checkMessageContent(ctx, { stdout, stderr }, options) + done() + }) + } else { + run(ctx.dir, [arg], function (err, stdout) { + if (err) { + return done(err) + } + checkMessageContent(ctx, { stdout }, options) + done() + }) + } + }) +} + +function checkMessageContent (ctx, { stdout, stderr }, { isUnknownArg = false, expectedFileNum = null }) { + if (expectedFileNum) { + const files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(files.length, expectedFileNum) + } + assert.ok(/Usage: express /.test(stdout)) + assert.ok(/--help/.test(stdout)) + assert.ok(/--version/.test(stdout)) + if (isUnknownArg) { + assert.ok(/error: unknown option/.test(stderr)) + } +} + +function checkBasicFiles (ctx) { + it('should have basic files', function () { + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) +} + +function checkAppStart (ctx) { + describe('npm start', function () { + before('start app', function () { + this.app = new AppRunner(ctx.dir) + }) + + after('stop app', function (done) { + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) + + it('should start app', function (done) { + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) + + it('should respond to HTTP request', function (done) { + request(this.app) + .get('/') + .expect(200, /<title>Express<\/title>/, done) + }) + + it('should generate a 404', function (done) { + request(this.app) + .get('/does_not_exist') + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) +}