From bb80aeafc722a1b8a2efffd2fd0b1a557badd1fc Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 17:57:01 -0400 Subject: [PATCH 01/14] chore: start refactoring start and url parameters --- __snapshots__/utils-spec.js | 94 +++++++++++++++++++++++++------------ package.json | 1 + src/bin/start.js | 7 ++- src/utils-spec.js | 5 ++ src/utils.js | 14 +++++- 5 files changed, 89 insertions(+), 32 deletions(-) diff --git a/__snapshots__/utils-spec.js b/__snapshots__/utils-spec.js index 84f69294..38167a7b 100644 --- a/__snapshots__/utils-spec.js +++ b/__snapshots__/utils-spec.js @@ -1,73 +1,109 @@ exports['utils getArguments handles 3 arguments with http-get url 1'] = { - "start": "npm run start", - "url": [ - "http-get://localhost:8080" + "services": [ + { + "start": "npm run start", + "url": [ + "http-get://localhost:8080" + ] + } ], "test": "npm run test" } exports['utils getArguments returns 3 arguments 1'] = { - "start": "npm run start", - "url": [ - "http://localhost:8080" + "services": [ + { + "start": "npm run start", + "url": [ + "http://localhost:8080" + ] + } ], "test": "npm run test" } exports['utils getArguments returns 3 arguments with url 1'] = { - "start": "npm run start", - "url": [ - "http://localhost:8080" + "services": [ + { + "start": "npm run start", + "url": [ + "http://localhost:8080" + ] + } ], "test": "npm run test" } exports['utils getArguments understands custom commands 1'] = { - "start": "custom-command --with argument", - "url": [ - "http://localhost:3000" + "services": [ + { + "start": "custom-command --with argument", + "url": [ + "http://localhost:3000" + ] + } ], "test": "test-command --x=1" } exports['utils getArguments understands several ports 1'] = { - "start": "npm run start", - "url": [ - "http://localhost:3000", - "http://localhost:4000", - "http://localhost:5000" + "services": [ + { + "start": "npm run start", + "url": [ + "http://localhost:3000", + "http://localhost:4000", + "http://localhost:5000" + ] + } ], "test": "npm run test" } exports['utils getArguments understands single :port 1'] = { - "start": "npm run start", - "url": [ - "http://localhost:3000" + "services": [ + { + "start": "npm run start", + "url": [ + "http://localhost:3000" + ] + } ], "test": "npm run test" } exports['utils getArguments understands single port 1'] = { - "start": "npm run start", - "url": [ - "http://localhost:3000" + "services": [ + { + "start": "npm run start", + "url": [ + "http://localhost:3000" + ] + } ], "test": "npm run test" } exports['utils getArguments understands start plus url 1'] = { - "start": "start-server", - "url": [ - "http://localhost:6000" + "services": [ + { + "start": "start-server", + "url": [ + "http://localhost:6000" + ] + } ], "test": "npm run test" } exports['utils getArguments understands url plus test 1'] = { - "start": "npm run start", - "url": [ - "http://localhost:6000" + "services": [ + { + "start": "npm run start", + "url": [ + "http://localhost:6000" + ] + } ], "test": "npm run test" } diff --git a/package.json b/package.json index 430ad10f..91aed075 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "demo11": "node src/bin/start.js http-get://127.0.0.1:9000", "demo-cross-env": "node src/bin/start.js start-cross-env 9000", "demo-commands": "node src/bin/start.js 'node test/server.js --port 8800' 8800 'node test/client --port 8800'", + "demo-multiple": "node src/bin/start.js 'node test/server --port 6000' 6000 'node test/server --port 6010' 6010 'curl http://127.0.0.1:6000 && curl http://127.0.0.1:6010'", "travis-deploy-once": "travis-deploy-once" }, "devDependencies": { diff --git a/src/bin/start.js b/src/bin/start.js index 06fd8f48..193cf2cd 100755 --- a/src/bin/start.js +++ b/src/bin/start.js @@ -9,7 +9,12 @@ const utils = require('../utils') debug('parsing CLI arguments: %o', args) const parsed = utils.getArguments(args) debug('parsed args: %o', parsed) -const { start, test, url } = parsed + +const { services, test } = parsed +if (!Array.isArray(services)) { + throw new Error(`Could not parse arguments %o, got %o`, args, parsed) +} +const { start, url } = services[0] console.log('starting server using command "%s"', start) console.log('and when url "%s" is responding with HTTP status code 200', url) diff --git a/src/utils-spec.js b/src/utils-spec.js index 1afa679d..1e495b4a 100644 --- a/src/utils-spec.js +++ b/src/utils-spec.js @@ -3,6 +3,7 @@ /* eslint-env mocha */ const la = require('lazy-ass') const snapshot = require('snap-shot-it') +const debug = require('debug')('test') function arrayEq (a, b) { return a.length === b.length && a.every((el, index) => el === b[index]) @@ -28,6 +29,10 @@ describe('utils', () => { context('getArguments', () => { const getArguments = utils.getArguments + it('allows 5 arguments', () => { + debug(getArguments(['start', '6000', 'start:web', '6010', 'test'])) + }) + it('returns 3 arguments', () => { snapshot(getArguments(['start', '8080', 'test'])) }) diff --git a/src/utils.js b/src/utils.js index 1f342665..9310a2ff 100644 --- a/src/utils.js +++ b/src/utils.js @@ -31,6 +31,10 @@ const getArguments = cliArgs => { start = cliArgs[0] url = normalizeUrl(cliArgs[1]) } + } else if (cliArgs.length === 5) { + start = cliArgs[0] + url = normalizeUrl(cliArgs[1]) + test = cliArgs[4] } else { la( cliArgs.length === 3, @@ -51,9 +55,15 @@ const getArguments = cliArgs => { test = `npm run ${test}` } - return { + const service = { start, - url, + url + } + + const services = [service] + + return { + services, test } } From 85b6f7d7e6069629df4b10c27591a6b144709329 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 18:04:12 -0400 Subject: [PATCH 02/14] chore: refactor a little more --- __snapshots__/utils-spec.js | 44 ++++++++++++++++++++++++++++++------- src/utils-spec.js | 10 +++++++-- src/utils.js | 10 ++++++--- 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/__snapshots__/utils-spec.js b/__snapshots__/utils-spec.js index 38167a7b..c5c53f9c 100644 --- a/__snapshots__/utils-spec.js +++ b/__snapshots__/utils-spec.js @@ -1,3 +1,24 @@ +exports['utils getArguments allows 5 arguments 1'] = { + "args": [ + "start", + "6000", + "start:web", + "6010", + "test" + ], + "parsed": { + "services": [ + { + "start": "npm run start", + "url": [ + "http://localhost:6000" + ] + } + ], + "test": "npm run test" + } +} + exports['utils getArguments handles 3 arguments with http-get url 1'] = { "services": [ { @@ -11,15 +32,22 @@ exports['utils getArguments handles 3 arguments with http-get url 1'] = { } exports['utils getArguments returns 3 arguments 1'] = { - "services": [ - { - "start": "npm run start", - "url": [ - "http://localhost:8080" - ] - } + "args": [ + "start", + "8080", + "test" ], - "test": "npm run test" + "parsed": { + "services": [ + { + "start": "npm run start", + "url": [ + "http://localhost:8080" + ] + } + ], + "test": "npm run test" + } } exports['utils getArguments returns 3 arguments with url 1'] = { diff --git a/src/utils-spec.js b/src/utils-spec.js index 1e495b4a..bda930a7 100644 --- a/src/utils-spec.js +++ b/src/utils-spec.js @@ -30,11 +30,17 @@ describe('utils', () => { const getArguments = utils.getArguments it('allows 5 arguments', () => { - debug(getArguments(['start', '6000', 'start:web', '6010', 'test'])) + const args = ['start', '6000', 'start:web', '6010', 'test'] + const parsed = getArguments(args) + debug('from %o', args) + debug('parsed %o', parsed) + snapshot({ args, parsed }) }) it('returns 3 arguments', () => { - snapshot(getArguments(['start', '8080', 'test'])) + const args = ['start', '8080', 'test'] + const parsed = getArguments(args) + snapshot({ args, parsed }) }) it('returns 3 arguments with url', () => { diff --git a/src/utils.js b/src/utils.js index 9310a2ff..fb6644c3 100644 --- a/src/utils.js +++ b/src/utils.js @@ -47,11 +47,11 @@ const getArguments = cliArgs => { test = cliArgs[2] } - if (isPackageScriptName(start)) { + if (UTILS.isPackageScriptName(start)) { start = `npm run ${start}` } - if (isPackageScriptName(test)) { + if (UTILS.isPackageScriptName(test)) { test = `npm run ${test}` } @@ -140,9 +140,13 @@ const normalizeUrl = input => { }) } -module.exports = { +// placing functions into a common object +// makes them methods for easy stubbing +const UTILS = { getArguments, isPackageScriptName, isUrlOrPort, normalizeUrl } + +module.exports = UTILS From 2c1a4bf579b612cec8dc70f34a6c70d140f1bb7d Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 18:06:30 -0400 Subject: [PATCH 03/14] chore: add sinon and global sandbox --- package-lock.json | 497 ++++++++++++++++++++++++++++++++++++++++++++-- package.json | 3 +- test/helper.js | 7 + 3 files changed, 486 insertions(+), 21 deletions(-) create mode 100644 test/helper.js diff --git a/package-lock.json b/package-lock.json index 3688f913..7aaae295 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3028,6 +3028,51 @@ } } }, + "@sinonjs/commons": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", + "integrity": "sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz", + "integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, "@szmarczak/http-timer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.1.tgz", @@ -4604,9 +4649,9 @@ } }, "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -9001,6 +9046,12 @@ "object.assign": "^4.1.0" } }, + "just-extend": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", + "dev": true + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -9951,9 +10002,9 @@ "dev": true }, "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -10147,6 +10198,19 @@ "integrity": "sha1-2Tli9sUvLBVYwPvabVEoGfHv4cQ=", "dev": true }, + "nise": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.3.tgz", + "integrity": "sha512-EGlhjm7/4KvmmE6B/UFsKh7eHykRl9VH+au8dduHLCyWUO/hr7+N+WtTvDUwc9zHuM1IaIJs/0lQ6Ag1jDkQSg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, "node-emoji": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", @@ -14151,9 +14215,9 @@ } }, "es-abstract": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", - "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", @@ -14681,6 +14745,23 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } + }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", @@ -16473,6 +16554,44 @@ } } }, + "sinon": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz", + "integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.2", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.0.3", + "diff": "^4.0.2", + "nise": "^4.0.1", + "supports-color": "^7.1.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", @@ -17559,14 +17678,111 @@ "strip-ansi": "^4.0.0" } }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } + } + }, "string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" }, "dependencies": { "define-properties": { @@ -17578,6 +17794,75 @@ "object-keys": "^1.0.12" } }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -17587,13 +17872,14 @@ } }, "string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" }, "dependencies": { "define-properties": { @@ -17605,6 +17891,171 @@ "object-keys": "^1.0.12" } }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -18223,6 +18674,12 @@ "prelude-ls": "~1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", @@ -19221,9 +19678,9 @@ "dev": true }, "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" diff --git a/package.json b/package.json index 91aed075..778ae9ef 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "pretty": "prettier-standard 'src/**/*.js'", "size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";", "test": "npm run unit", - "unit": "mocha src/*-spec.js", + "unit": "mocha test/helper src/*-spec.js", "unused-deps": "dependency-check --unused --no-dev .", "semantic-release": "semantic-release", "start": "node test/server.js", @@ -108,6 +108,7 @@ "prettier-standard": "8.0.1", "semantic-release": "15.13.24", "simple-commit-message": "4.0.13", + "sinon": "9.0.2", "snap-shot-it": "6.3.5", "standard": "13.1.0", "travis-deploy-once": "5.0.11" diff --git a/test/helper.js b/test/helper.js new file mode 100644 index 00000000..59252c6d --- /dev/null +++ b/test/helper.js @@ -0,0 +1,7 @@ +const sinon = require('sinon') +before(() => { + global.sandbox = sinon.createSandbox() +}) +beforeEach(() => { + global.sandbox.restore() +}) From 4c7ff457f4421423fb5fe03e2a371c5c0b372632 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 18:13:38 -0400 Subject: [PATCH 04/14] chore: add sinon --- package-lock.json | 53 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 5 +++++ src/utils-spec.js | 14 +++++++++++++ test/helper.js | 7 +++++++ 4 files changed, 79 insertions(+) diff --git a/package-lock.json b/package-lock.json index 7aaae295..ae79b411 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3471,6 +3471,12 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "assign": { "version": "0.1.7", "resolved": "http://registry.npmjs.org/assign/-/assign-0.1.7.tgz", @@ -4569,6 +4575,20 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, "chalk": { "version": "2.3.2", "resolved": "http://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", @@ -4609,6 +4629,12 @@ } } }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "check-more-types": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", @@ -5594,6 +5620,15 @@ "mimic-response": "^1.0.0" } }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-extend": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", @@ -7608,6 +7643,12 @@ "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, "get-stdin": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", @@ -14779,6 +14820,12 @@ } } }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, "pause-stream": { "version": "0.0.11", "resolved": "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", @@ -16592,6 +16639,12 @@ } } }, + "sinon-chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.5.0.tgz", + "integrity": "sha512-IifbusYiQBpUxxFJkR3wTU68xzBN0+bxCScEaKMjBvAQERg6FnTTc1F17rseLb1tjmkJ23730AXpFI0c47FgAg==", + "dev": true + }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", diff --git a/package.json b/package.json index 778ae9ef..cf40b113 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ }, "devDependencies": { "ban-sensitive-files": "1.9.7", + "chai": "4.2.0", "cross-env": "7.0.2", "dependency-check": "3.4.1", "deps-ok": "1.4.1", @@ -109,6 +110,7 @@ "semantic-release": "15.13.24", "simple-commit-message": "4.0.13", "sinon": "9.0.2", + "sinon-chai": "3.5.0", "snap-shot-it": "6.3.5", "standard": "13.1.0", "travis-deploy-once": "5.0.11" @@ -132,5 +134,8 @@ } ] } + }, + "standard": { + "globals": ["sandbox", "expect"] } } diff --git a/src/utils-spec.js b/src/utils-spec.js index bda930a7..eaba9ad0 100644 --- a/src/utils-spec.js +++ b/src/utils-spec.js @@ -73,6 +73,20 @@ describe('utils', () => { snapshot(getArguments(['3000|4000|5000'])) }) + it('asks if command is a script name', () => { + const args = ['custom-command-name', '3000', 'some-test-command'] + const isPackageScriptName = sandbox + .stub(utils, 'isPackageScriptName') + .returns(false) + const parsed = getArguments(args) + debug('from %o', args) + debug('parsed %o', parsed) + /* eslint-disable-next-line no-unused-expressions */ + expect(isPackageScriptName).to.have.been.calledTwice + expect(isPackageScriptName).to.have.been.calledWith('custom-command-name') + expect(isPackageScriptName).to.have.been.calledWith('some-test-command') + }) + it('understands custom commands', () => { // these commands are NOT script names in the package.json // thus they will be run as is diff --git a/test/helper.js b/test/helper.js index 59252c6d..0ba851ba 100644 --- a/test/helper.js +++ b/test/helper.js @@ -1,4 +1,11 @@ +// https://glebbahmutov.com/blog/mocha-and-sinon/ +const chai = require('chai') +const sinonChai = require('sinon-chai') const sinon = require('sinon') + +chai.use(sinonChai) +global.expect = chai.expect + before(() => { global.sandbox = sinon.createSandbox() }) From 3f0d52bc35eecc4717173393a58af30598bc9679 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 18:17:44 -0400 Subject: [PATCH 05/14] chore: normalize all start commands --- src/utils.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/utils.js b/src/utils.js index fb6644c3..92157ed4 100644 --- a/src/utils.js +++ b/src/utils.js @@ -47,14 +47,6 @@ const getArguments = cliArgs => { test = cliArgs[2] } - if (UTILS.isPackageScriptName(start)) { - start = `npm run ${start}` - } - - if (UTILS.isPackageScriptName(test)) { - test = `npm run ${test}` - } - const service = { start, url @@ -62,12 +54,22 @@ const getArguments = cliArgs => { const services = [service] + services.forEach((service) => { + service.start = normalizeCommand(service.start) + }) + + test = normalizeCommand(test) + return { services, test } } +function normalizeCommand (command) { + return UTILS.isPackageScriptName(command) ? `npm run ${command}` : command +} + /** * Returns true if the given string is a name of a script in the package.json file * in the current working directory From b3d39cc171c161a383e181e66784b935548d5d23 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 18:18:00 -0400 Subject: [PATCH 06/14] lint --- src/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.js b/src/utils.js index 92157ed4..9ba8b80a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -54,7 +54,7 @@ const getArguments = cliArgs => { const services = [service] - services.forEach((service) => { + services.forEach(service => { service.start = normalizeCommand(service.start) }) From 2b7dd416b8d02068e1d0b7dc0d5d0aacc180e427 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 18:24:15 -0400 Subject: [PATCH 07/14] chore: parse second service --- __snapshots__/utils-spec.js | 6 ++++++ src/utils-spec.js | 1 + src/utils.js | 38 ++++++++++++++++++++----------------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/__snapshots__/utils-spec.js b/__snapshots__/utils-spec.js index c5c53f9c..15a39c2c 100644 --- a/__snapshots__/utils-spec.js +++ b/__snapshots__/utils-spec.js @@ -13,6 +13,12 @@ exports['utils getArguments allows 5 arguments 1'] = { "url": [ "http://localhost:6000" ] + }, + { + "start": "start:web", + "url": [ + "http://localhost:6010" + ] } ], "test": "npm run test" diff --git a/src/utils-spec.js b/src/utils-spec.js index eaba9ad0..aad7b38c 100644 --- a/src/utils-spec.js +++ b/src/utils-spec.js @@ -34,6 +34,7 @@ describe('utils', () => { const parsed = getArguments(args) debug('from %o', args) debug('parsed %o', parsed) + debug('services %o', parsed.services) snapshot({ args, parsed }) }) diff --git a/src/utils.js b/src/utils.js index 9ba8b80a..32a7bb9d 100644 --- a/src/utils.js +++ b/src/utils.js @@ -10,30 +10,41 @@ const { join } = require('path') const getArguments = cliArgs => { la(is.strings(cliArgs), 'expected list of strings', cliArgs) - let start = 'start' + const service = { + start: 'start', + url: undefined + } + const services = [service] + let test = 'test' - let url if (cliArgs.length === 1 && isUrlOrPort(cliArgs[0])) { // passed just single url or port number, for example // "start": "http://localhost:8080" - url = normalizeUrl(cliArgs[0]) + service.url = normalizeUrl(cliArgs[0]) } else if (cliArgs.length === 2) { if (isUrlOrPort(cliArgs[0])) { // passed port and custom test command // like ":8080 test-ci" - url = normalizeUrl(cliArgs[0]) + service.url = normalizeUrl(cliArgs[0]) test = cliArgs[1] } if (isUrlOrPort(cliArgs[1])) { // passed start command and url/port // like "start-server 8080" - start = cliArgs[0] - url = normalizeUrl(cliArgs[1]) + service.start = cliArgs[0] + service.url = normalizeUrl(cliArgs[1]) } } else if (cliArgs.length === 5) { - start = cliArgs[0] - url = normalizeUrl(cliArgs[1]) + service.start = cliArgs[0] + service.url = normalizeUrl(cliArgs[1]) + + const secondService = { + start: cliArgs[2], + url: normalizeUrl(cliArgs[3]) + } + services.push(secondService) + test = cliArgs[4] } else { la( @@ -42,18 +53,11 @@ const getArguments = cliArgs => { 'example: start-test start 8080 test\n', 'see https://github.com/bahmutov/start-server-and-test#use\n' ) - start = cliArgs[0] - url = normalizeUrl(cliArgs[1]) + service.start = cliArgs[0] + service.url = normalizeUrl(cliArgs[1]) test = cliArgs[2] } - const service = { - start, - url - } - - const services = [service] - services.forEach(service => { service.start = normalizeCommand(service.start) }) From 27458538ef2ae466365cc09dad673eb7241a403e Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 18:33:36 -0400 Subject: [PATCH 08/14] add another test --- __snapshots__/utils-spec.js | 27 +++++++++++++++++++++++++++ src/utils-spec.js | 10 ++++++++++ 2 files changed, 37 insertions(+) diff --git a/__snapshots__/utils-spec.js b/__snapshots__/utils-spec.js index 15a39c2c..d0606be1 100644 --- a/__snapshots__/utils-spec.js +++ b/__snapshots__/utils-spec.js @@ -25,6 +25,33 @@ exports['utils getArguments allows 5 arguments 1'] = { } } +exports['utils getArguments determines NPM script for each command 1'] = { + "args": [ + "startA", + "6000", + "startB", + "6010", + "testC" + ], + "parsed": { + "services": [ + { + "start": "npm run startA", + "url": [ + "http://localhost:6000" + ] + }, + { + "start": "npm run startB", + "url": [ + "http://localhost:6010" + ] + } + ], + "test": "npm run testC" + } +} + exports['utils getArguments handles 3 arguments with http-get url 1'] = { "services": [ { diff --git a/src/utils-spec.js b/src/utils-spec.js index aad7b38c..5f347cf1 100644 --- a/src/utils-spec.js +++ b/src/utils-spec.js @@ -38,6 +38,16 @@ describe('utils', () => { snapshot({ args, parsed }) }) + it('determines NPM script for each command', () => { + sandbox.stub(utils, 'isPackageScriptName').returns(true) + const args = ['startA', '6000', 'startB', '6010', 'testC'] + const parsed = getArguments(args) + debug('from %o', args) + debug('parsed %o', parsed) + debug('services %o', parsed.services) + snapshot({ args, parsed }) + }) + it('returns 3 arguments', () => { const args = ['start', '8080', 'test'] const parsed = getArguments(args) From ba1d344e9b128df214fc7aa0a2ce344735228746 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 18:51:10 -0400 Subject: [PATCH 09/14] move print into utils --- package.json | 3 ++- src/bin/start.js | 8 +++++--- src/utils.js | 11 ++++++++++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cf40b113..745b0bd9 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,8 @@ "test2": "curl http://127.0.0.1:9000", "test3": "curl http://127.0.0.1:9000 && curl http://127.0.0.1:9001", "test4": "curl --insecure https://127.0.0.1:9000", - "demo": "node src/bin/start.js http://127.0.0.1:9000", + "message": "echo Hi there 👋", + "demo": "node src/bin/start.js http://127.0.0.1:9000 message", "demo2": "node src/bin/start.js start http://127.0.0.1:9000 test2", "demo3": "node src/bin/start.js start-with-child http://127.0.0.1:9000 test", "demo4": "node src/bin/start.js 9000", diff --git a/src/bin/start.js b/src/bin/start.js index 193cf2cd..e79e7232 100755 --- a/src/bin/start.js +++ b/src/bin/start.js @@ -14,11 +14,13 @@ const { services, test } = parsed if (!Array.isArray(services)) { throw new Error(`Could not parse arguments %o, got %o`, args, parsed) } + +utils.printArguments({ services, test }) const { start, url } = services[0] -console.log('starting server using command "%s"', start) -console.log('and when url "%s" is responding with HTTP status code 200', url) -console.log('running tests using command "%s"', test) +// console.log('starting server using command "%s"', start) +// console.log('and when url "%s" is responding with HTTP status code 200', url) +// console.log('running tests using command "%s"', test) startAndTest({ start, url, test }).catch(e => { console.error(e) diff --git a/src/utils.js b/src/utils.js index 32a7bb9d..4c543f76 100644 --- a/src/utils.js +++ b/src/utils.js @@ -146,13 +146,22 @@ const normalizeUrl = input => { }) } +function printArguments ({ services, test }) { + const { start, url } = services[0] + + console.log('starting server using command "%s"', start) + console.log('and when url "%s" is responding with HTTP status code 200', url) + console.log('running tests using command "%s"', test) +} + // placing functions into a common object // makes them methods for easy stubbing const UTILS = { getArguments, isPackageScriptName, isUrlOrPort, - normalizeUrl + normalizeUrl, + printArguments } module.exports = UTILS From 7d7b37fd64e318941a9019fd4182f63ff626a953 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 18:57:30 -0400 Subject: [PATCH 10/14] print multiple services --- src/utils.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/utils.js b/src/utils.js index 4c543f76..e1969ee0 100644 --- a/src/utils.js +++ b/src/utils.js @@ -147,11 +147,13 @@ const normalizeUrl = input => { } function printArguments ({ services, test }) { - const { start, url } = services[0] + services.forEach((service, k) => { + console.log('%d: starting server using command "%s"', k + 1, service.start) + console.log('and when url "%s" is responding with HTTP status code 200', service.url) + }) - console.log('starting server using command "%s"', start) - console.log('and when url "%s" is responding with HTTP status code 200', url) console.log('running tests using command "%s"', test) + console.log('') } // placing functions into a common object From 43bbad1b5cfccd94a67ee4f1df69a791f0183ff7 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 19:07:37 -0400 Subject: [PATCH 11/14] refactoring --- src/bin/start.js | 2 +- src/index.js | 31 ++++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/bin/start.js b/src/bin/start.js index e79e7232..515e6901 100755 --- a/src/bin/start.js +++ b/src/bin/start.js @@ -3,7 +3,7 @@ const debug = require('debug')('start-server-and-test') const args = process.argv.slice(2) -const startAndTest = require('..') +const startAndTest = require('..').startAndTest const utils = require('../utils') debug('parsing CLI arguments: %o', args) diff --git a/src/index.js b/src/index.js index b7a02fc4..ed0f02ff 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,4 @@ +// @ts-check 'use strict' const la = require('lazy-ass') @@ -21,9 +22,9 @@ const isDebug = () => const isInsecure = () => process.env.START_SERVER_AND_TEST_INSECURE -function startAndTest ({ start, url, test }) { +function waitAndRun ({ start, url, runFn }) { la(is.unemptyString(start), 'missing start script name', start) - la(is.unemptyString(test), 'missing test script name', test) + la(is.fn(runFn), 'missing test script name', runFn) la( is.unemptyString(url) || is.unemptyArray(url), 'missing url to wait on', @@ -94,15 +95,27 @@ function startAndTest ({ start, url, test }) { }) }) - function runTests () { - debug('running test script command: %s', test) - return execa(test, { shell: true, stdio: 'inherit' }) - } - return waited .tapCatch(stopServer) - .then(runTests) + .then(runFn) .finally(stopServer) } -module.exports = startAndTest +const runTheTests = (testCommand) => () => { + debug('running test script command: %s', testCommand) + return execa(testCommand, { shell: true, stdio: 'inherit' }) +} + +function startAndTest ({ start, url, test }) { + const runTests = runTheTests(test) + + return waitAndRun({ + start, + url, + runFn: runTests + }) +} + +module.exports = { + startAndTest +} From af686e199cc8273d69dd24a4b668ce5318ea7d51 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 19:18:05 -0400 Subject: [PATCH 12/14] feat: support 2 services at once --- src/bin/start.js | 7 +------ src/index.js | 27 +++++++++++++++++++++------ src/utils.js | 5 ++++- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/bin/start.js b/src/bin/start.js index 515e6901..22264336 100755 --- a/src/bin/start.js +++ b/src/bin/start.js @@ -16,13 +16,8 @@ if (!Array.isArray(services)) { } utils.printArguments({ services, test }) -const { start, url } = services[0] -// console.log('starting server using command "%s"', start) -// console.log('and when url "%s" is responding with HTTP status code 200', url) -// console.log('running tests using command "%s"', test) - -startAndTest({ start, url, test }).catch(e => { +startAndTest({ services, test }).catch(e => { console.error(e) process.exit(1) }) diff --git a/src/index.js b/src/index.js index ed0f02ff..3846c104 100644 --- a/src/index.js +++ b/src/index.js @@ -101,18 +101,33 @@ function waitAndRun ({ start, url, runFn }) { .finally(stopServer) } -const runTheTests = (testCommand) => () => { +const runTheTests = testCommand => () => { debug('running test script command: %s', testCommand) return execa(testCommand, { shell: true, stdio: 'inherit' }) } -function startAndTest ({ start, url, test }) { - const runTests = runTheTests(test) +function startAndTest ({ services, test }) { + if (services.length === 0) { + throw new Error('Got zero services to start ...') + } + + if (services.length === 1) { + const runTests = runTheTests(test) + debug('single service "%s" to run and test', services[0].start) + return waitAndRun({ + start: services[0].start, + url: services[0].url, + runFn: runTests + }) + } return waitAndRun({ - start, - url, - runFn: runTests + start: services[0].start, + url: services[0].url, + runFn: () => { + debug('previous service started, now going to the next one') + return startAndTest({ services: services.slice(1), test }) + } }) } diff --git a/src/utils.js b/src/utils.js index e1969ee0..3891a00a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -149,7 +149,10 @@ const normalizeUrl = input => { function printArguments ({ services, test }) { services.forEach((service, k) => { console.log('%d: starting server using command "%s"', k + 1, service.start) - console.log('and when url "%s" is responding with HTTP status code 200', service.url) + console.log( + 'and when url "%s" is responding with HTTP status code 200', + service.url + ) }) console.log('running tests using command "%s"', test) From bfca855f759be4f3757d69e36c5007dec9de84f9 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 19:19:39 -0400 Subject: [PATCH 13/14] add to Travis CI --- .travis.yml | 3 ++- src/index.js | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5bc54516..a9ac0288 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ cache: notifications: email: true node_js: - - '8' + - '12' script: - npm test - npm run demo @@ -20,6 +20,7 @@ script: - START_SERVER_AND_TEST_INSECURE=1 npm run demo9 - npm run demo-cross-env - npm run demo-commands + - npm run demo-multiple after_success: - npm run travis-deploy-once "npm run semantic-release" branches: diff --git a/src/index.js b/src/index.js index 3846c104..71eb2e93 100644 --- a/src/index.js +++ b/src/index.js @@ -106,6 +106,10 @@ const runTheTests = testCommand => () => { return execa(testCommand, { shell: true, stdio: 'inherit' }) } +/** + * Starts a single service and runs tests or recursively + * runs a service, then goes to the next list, until it reaches 1 service and runs test. + */ function startAndTest ({ services, test }) { if (services.length === 0) { throw new Error('Got zero services to start ...') From d99449a7523ff65bcca91e6b1aaadd279d38e26f Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Tue, 14 Apr 2020 19:32:17 -0400 Subject: [PATCH 14/14] update README --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7a45d626..ff49ee40 100644 --- a/README.md +++ b/README.md @@ -216,7 +216,13 @@ This utility will wait for maximum of 5 minutes while checking for the server to ### Starting two servers -Sometimes you need to start one API server and one webserver in order to test the application. Just have two commands cascade. First command should wait on the webserver script, which in turn uses `start-server-and-test` to start the API server before running the webserver. Something like this +Sometimes you need to start one API server and one webserver in order to test the application. Use the syntax: + +``` +start-test +``` + +For example if API runs at port 3000 and server runs at port 8080: ```json { @@ -224,13 +230,12 @@ Sometimes you need to start one API server and one webserver in order to test th "test": "node src/test", "start:api": "node src/api", "start:server": "node src/server", - "start:server-and-api": "start-test start:api 7600 start:server", - "test:all": "start-test start:server-and-api 5000 test" + "test:all": "start-test start:api 3000 start:server 8080 test" } } ``` -In the above example you would run `npm run test:all` to start both servers and run the test. See repo [start-two-servers-example](https://github.com/bahmutov/start-two-servers-example) for full example +In the above example you would run `npm run test:all` to start the API first, then when it responds, start the server, and when the server is responding, it would run the tests. After the tests finish, it will shut down both servers. See the repo [start-two-servers-example](https://github.com/bahmutov/start-two-servers-example) for full example ### Small print