From 17a427c43f4f23266fcb5f67d35a474027acf4c6 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Mon, 5 Dec 2022 16:27:34 -0500 Subject: [PATCH] feat: use the --expect parameter to specify HTTP response code (#343) * feat: add --expect argument parsing * feat: specify the --expected http status code * chore: update the README --- .github/workflows/ci.yml | 3 +++ README.md | 10 ++++++++++ package.json | 4 ++-- src/bin/start.js | 9 ++++++--- src/index.js | 16 +++++++++++----- src/utils.js | 38 ++++++++++++++++++++++++++------------ 6 files changed, 58 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db69990..f856ef1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,6 +54,9 @@ jobs: - name: Run demo multiple 📊 run: npm run demo-multiple + - name: Run demo expect 403 code 📊 + run: npm run demo-expect-403 + - name: Semantic Release 🚀 if: github.ref == 'refs/heads/master' uses: cycjimmy/semantic-release-action@v3 diff --git a/README.md b/README.md index f2c2354..6842bd3 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,16 @@ If you want to start the server, wait for it to respond, and then run multiple t The above script `ci` after the `localhost:9000` responds executes the `npm run test:unit` command. Then when it finishes it runs `npm run test:e2e`. If the first or second command fails, the `ci` script fails. Of course, your mileage on Windows might vary. +#### expected + +The server might respond, but require authorization, returning an error HTTP code by default. You can still know that the server is responding by using `--expect` argument (or its alias `--expected`): + +``` +$ start-test --expect 403 start :9000 test:e2e +``` + +See `demo-expect-403` NPM script. + ## `npx` and `yarn` If you have [npx](https://www.npmjs.com/package/npx) available, you can execute locally installed tools from the shell. For example, if the `package.json` has the following local tools: diff --git a/package.json b/package.json index 065fc77..e5f6139 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "main": "src/", "private": false, "publishConfig": { - "registry": "http://registry.npmjs.org/" + "registry": "https://registry.npmjs.org/" }, "repository": { "type": "git", @@ -93,7 +93,7 @@ "demo10": "node src/bin/start.js start-fail http://127.0.0.1:9000 test", "demo11": "node src/bin/start.js http-get://127.0.0.1:9000", "demo12": "node src/bin/start.js start-304 9000 test2", - "demo13": "node src/bin/start.js --expect 403 start-403 9000 'echo Waited'", + "demo-expect-403": "node src/bin/start.js --expect 403 start-403 9000 'echo Waited'", "demo-interval": "WAIT_ON_INTERVAL=1000 node src/bin/start.js start http://127.0.0.1:9000 test2", "demo-timeout": "WAIT_ON_TIMEOUT=10000 node src/bin/start.js start http://127.0.0.1:9000 test2", "demo-cross-env": "node src/bin/start.js start-cross-env 9000", diff --git a/src/bin/start.js b/src/bin/start.js index b2f5768..a1b3b47 100755 --- a/src/bin/start.js +++ b/src/bin/start.js @@ -4,8 +4,11 @@ const debug = require('debug')('start-server-and-test') const startAndTest = require('..').startAndTest const utils = require('../utils') -const args = utils.crossArguments(process.argv.slice(2)) +const namedArguments = utils.getNamedArguments(process.argv.slice(2)) +debug('named arguments: %o', namedArguments) + +const args = utils.crossArguments(process.argv.slice(2)) debug('parsing CLI arguments: %o', args) const parsed = utils.getArguments(args) debug('parsed args: %o', parsed) @@ -15,9 +18,9 @@ if (!Array.isArray(services)) { throw new Error(`Could not parse arguments %o, got %o`, args, parsed) } -utils.printArguments({ services, test }) +utils.printArguments({ services, test, namedArguments }) -startAndTest({ services, test }).catch(e => { +startAndTest({ services, test, namedArguments }).catch(e => { console.error(e) process.exit(1) }) diff --git a/src/index.js b/src/index.js index 1f561d5..86c5d38 100644 --- a/src/index.js +++ b/src/index.js @@ -28,7 +28,7 @@ const isDebug = () => const isInsecure = () => process.env.START_SERVER_AND_TEST_INSECURE -function waitAndRun ({ start, url, runFn }) { +function waitAndRun ({ start, url, runFn, namedArguments }) { la(is.unemptyString(start), 'missing start script name', start) la(is.fn(runFn), 'missing test script name', runFn) la( @@ -36,6 +36,11 @@ function waitAndRun ({ start, url, runFn }) { 'missing url to wait on', url ) + const isSuccessfulHttpCode = status => + (status >= 200 && status < 300) || status === 304 + const validateStatus = namedArguments.expect + ? status => status === namedArguments.expect + : isSuccessfulHttpCode debug('starting server with command "%s", verbose mode?', start, isDebug()) @@ -89,8 +94,7 @@ function waitAndRun ({ start, url, runFn }) { headers: { Accept: 'text/html, application/json, text/plain, */*' }, - validateStatus: status => - (status >= 200 && status < 300) || status === 304 + validateStatus } debug('wait-on options %o', options) @@ -121,7 +125,7 @@ const runTheTests = testCommand => () => { * 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 }) { +function startAndTest ({ services, test, namedArguments }) { if (services.length === 0) { throw new Error('Got zero services to start ...') } @@ -132,6 +136,7 @@ function startAndTest ({ services, test }) { return waitAndRun({ start: services[0].start, url: services[0].url, + namedArguments, runFn: runTests }) } @@ -139,9 +144,10 @@ function startAndTest ({ services, test }) { return waitAndRun({ start: services[0].start, url: services[0].url, + namedArguments, runFn: () => { debug('previous service started, now going to the next one') - return startAndTest({ services: services.slice(1), test }) + return startAndTest({ services: services.slice(1), test, namedArguments }) } }) } diff --git a/src/utils.js b/src/utils.js index 6ec9a97..1bd3885 100644 --- a/src/utils.js +++ b/src/utils.js @@ -5,21 +5,20 @@ const { existsSync } = require('fs') const arg = require('arg') const debug = require('debug')('start-server-and-test') +const namedArguments = { + '--expect': Number +} + /** * Returns new array of command line arguments * where leading and trailing " and ' are indicating * the beginning and end of an argument. */ const crossArguments = cliArguments => { - const args = arg( - { - '--expect': Number - }, - { - permissive: true, - argv: cliArguments - } - ) + const args = arg(namedArguments, { + permissive: true, + argv: cliArguments + }) debug('initial parsed arguments %o', args) // all other arguments const cliArgs = args._ @@ -58,6 +57,19 @@ const crossArguments = cliArguments => { return combinedArgs } +const getNamedArguments = cliArgs => { + const args = arg(namedArguments, { + permissive: true, + argv: cliArgs + }) + debug('initial parsed arguments %o', args) + return { + expect: args['--expect'], + // aliases + '--expected': '--expect' + } +} + /** * Returns parsed command line arguments. * If start command is NPM script name defined in the package.json @@ -205,12 +217,13 @@ const normalizeUrl = input => { }) } -function printArguments ({ services, test }) { +function printArguments ({ services, test, namedArguments }) { 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 + 'and when url "%s" is responding with HTTP status code %d', + service.url, + namedArguments.expect ) }) @@ -231,6 +244,7 @@ function printArguments ({ services, test }) { const UTILS = { crossArguments, getArguments, + getNamedArguments, isPackageScriptName, isUrlOrPort, normalizeUrl,