🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Book a DemoInstallSign in
Socket

start-server-and-test

Package Overview
Dependencies
Maintainers
1
Versions
80
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

start-server-and-test - npm Package Compare versions

Comparing version

to
1.15.5

LICENSE

31

package.json
{
"name": "start-server-and-test",
"description": "Starts server, waits for URL, then runs test command; when the tests end, shuts down server",
"version": "1.12.0",
"version": "1.15.5",
"author": "Gleb Bahmutov <gleb.bahmutov@gmail.com>",

@@ -51,3 +51,3 @@ "bugs": "https://github.com/bahmutov/start-server-and-test/issues",

"publishConfig": {
"registry": "http://registry.npmjs.org/"
"registry": "https://registry.npmjs.org/"
},

@@ -77,2 +77,4 @@ "repository": {

"start-fail": "node test/server-fail.js",
"start-304": "node test/server-304.js",
"start-403": "node test/server-403.js",
"start-cross-env": "cross-env FOO=bar node test/server.js",

@@ -83,2 +85,3 @@ "test2": "curl http://127.0.0.1:9000",

"message": "echo Hi there 👋",
"message2": "echo Hi there 2 👋",
"demo": "node src/bin/start.js http://127.0.0.1:9000 message",

@@ -95,7 +98,18 @@ "demo2": "node src/bin/start.js start http://127.0.0.1:9000 test2",

"demo11": "node src/bin/start.js http-get://127.0.0.1:9000",
"demo12": "node src/bin/start.js start-304 9000 test2",
"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",
"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'"
"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'",
"demo-multiple-test-commands": "node src/bin/start.js 9000 'npm run message && npm run message2'",
"demo-json-server": "WAIT_ON_TIMEOUT=10000 DEBUG=start-server-and-test node src/bin/start.js 'json-server test/data.json' localhost:3000 'echo json-server working'",
"demo-ip6": "WAIT_ON_TIMEOUT=10000 DEBUG=start-server-and-test node src/bin/start.js 'node test/ip6.mjs' localhost:8000 'echo server with ::1 working'",
"demo-zero": "WAIT_ON_TIMEOUT=10000 node src/bin/start.js 'node test/zero.mjs' 8000 'echo server with 0.0.0.0 working'",
"demo-zero-127": "WAIT_ON_TIMEOUT=10000 node src/bin/start.js 'node test/zero.mjs' http://127.0.0.1:8000 'echo server with 0.0.0.0 working'",
"demo-zero-explicit": "node src/bin/start.js 'node test/zero.mjs' http://0.0.0.0:8000 'echo server with 0.0.0.0 working'"
},
"devDependencies": {
"@types/node": "^18.14.1",
"ban-sensitive-files": "1.9.7",

@@ -109,2 +123,3 @@ "chai": "4.2.0",

"got": "9.6.0",
"json-server": "^0.17.1",
"license-checker": "24.1.0",

@@ -120,13 +135,13 @@ "minimist": "1.2.5",

"snap-shot-it": "6.3.5",
"standard": "13.1.0",
"travis-deploy-once": "5.0.11"
"standard": "13.1.0"
},
"dependencies": {
"arg": "^5.0.2",
"bluebird": "3.7.2",
"check-more-types": "2.24.0",
"debug": "4.3.1",
"execa": "3.4.0",
"debug": "4.3.4",
"execa": "5.1.1",
"lazy-ass": "1.6.0",
"ps-tree": "1.2.0",
"wait-on": "5.2.1"
"wait-on": "7.0.1"
},

@@ -133,0 +148,0 @@ "release": {

@@ -83,5 +83,6 @@ # start-server-and-test

```
start-server-and-test start http://localhost:8080 test
server-test start http://localhost:8080 test
server-test http://localhost:8080 test
start-server-and-test start http://127.0.0.1:8080 test
server-test start http://127.0.0.1:8080 test
server-test http://127.0.0.1:8080 test
server-test 127.0.0.1:8080 test
start-test :8080 test

@@ -92,2 +93,4 @@ start-test 8080 test

**Tip:** I highly recommend you specify the full url instead of the port, see the `localhost vs 0.0.0.0 vs 127.0.0.1` section later in this README.
### Options

@@ -107,3 +110,3 @@

You can also shorten local url to just port, the code below is equivalent to checking `http://localhost:8080`.
You can also shorten local url to just port, the code below is equivalent to checking `http://127.0.0.1:8080`.

@@ -158,2 +161,29 @@ ```json

If you want to start the server, wait for it to respond, and then run multiple test commands (and stop the server after they finish), you should be able to use `&&` to separate the test commands:
```json
{
"scripts": {
"start": "npm start",
"test:unit": "mocha test.js",
"test:e2e": "mocha e2e.js",
"ci": "start-test 9000 'npm run test:unit && npm run test:e2e'"
}
}
```
The above script `ci` after the `127.0.0.1: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.
Default expected value is 200.
## `npx` and `yarn`

@@ -178,3 +208,3 @@

starting server using command "http-server -c-1 ."
and when url "http://localhost:8080" is responding
and when url "http://127.0.0.1:8080" is responding
running tests using command "cypress run"

@@ -192,3 +222,3 @@ Starting up http-server, serving .

starting server using command "http-server -c-1 ."
and when url "http://localhost:8080" is responding
and when url "http://127.0.0.1:8080" is responding
running tests using command "cypress run"

@@ -199,2 +229,18 @@ Starting up http-server, serving .

## localhost vs 0.0.0.0 vs 127.0.0.1
The latest versions of Node and some web servers listen on host `0.0.0.0` which _no longer means localhost_. Thus if you specify _just the port number_, like `:3000`, this package will try `http://127.0.0.1:3000` to ping the server. A good practice is to specify the full URL you would like to ping.
```
# same as "http://127.0.0.1:3000"
start-server start 3000 test
# better
start-server start http://127.0.0.1:3000 test
# or
start-server start http://0.0.0.0:3000 test
# of course, if your server is listening on localhost
# you can still set the URL
start-server start http://localhost:3000 test
```
## Note for yarn users

@@ -214,12 +260,41 @@

If you are using [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server) (directly or via `angular/cli` or other boilerplates) then please use the following URL form to check
Also applies to **Vite** users!
If you are using [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server) (directly or via `angular/cli` or other boilerplates) then the server does not respond to HEAD requests from `start-server-and-test`. You can check if the server responds to the HEAD requests by starting the server and pinging it from another terminal using `curl`
```
# from the first terminal start the server
$ npm start
# from the second terminal call the server with HEAD request
$ curl --head http://localhost:3000
```
If the server responds with 404, then it does not handle the HEAD requests. You have two solutions:
### Use HTTP GET requests
You can force the `start-server-and-test` to ping the server using GET requests using the `http-get://` prefix:
```
start-server-and-test http-get://localhost:8080
```
This is because under the hood this module uses [wait-on](https://github.com/jeffbski/wait-on) to ping the server. Wait-on uses `HEAD` by default, but `webpack-dev-server` does not respond to `HEAD` only to `GET` requests. Thus you need to use `http-get://` URL format to force `wait-on` to use `GET` probe.
### Ping a specific resource
You can even wait on the bundle JavaScript url instead of the page url, see discussion in this [issue #4](https://github.com/bahmutov/start-server-and-test/issues/4)
As an alternative to using GET method to request the root page, you can try pinging a specific resource, see the discussion in the [issue #4](https://github.com/bahmutov/start-server-and-test/issues/4).
```
# maybe the server responds to HEAD requests to the HTML page
start-server-and-test http://localhost:3000/index.html
# or maybe the server responds to HEAD requests to JS resource
start-server-and-test http://localhost:8080/app.js
```
### Explanation
You can watch the explanation in the video [Debug a Problem in start-server-and-test](https://youtu.be/rxyZOxYCsAk).
Under the hood this module uses [wait-on](https://github.com/jeffbski/wait-on) to ping the server. Wait-on uses `HEAD` by default, but `webpack-dev-server` does not respond to `HEAD` only to `GET` requests. Thus you need to use `http-get://` URL format to force `wait-on` to use `GET` probe or ask for a particular resource.
### Debugging

@@ -229,5 +304,14 @@

```
$ DEBUG=start-server-and-test npm run test
start-server-and-test parsing CLI arguments: [ 'dev', '3000', 'subtask' ] +0ms
start-server-and-test parsed args: { services: [ { start: 'npm run dev', url: [Array] } ], test: 'npm run subtask' }
...
making HTTP(S) head request to url:http://127.0.0.1:3000 ...
HTTP(S) error for http://127.0.0.1:3000 Error: Request failed with status code 404
```
### Disable HTTPS certificate checks
To see disable HTTPS checks for `wait-on`, run with environment variable `START_SERVER_AND_TEST_INSECURE=1`.
To disable HTTPS checks for `wait-on`, run with environment variable `START_SERVER_AND_TEST_INSECURE=1`.

@@ -238,2 +322,6 @@ ### Timeout

### Interval
This utility will check for a server response every two seconds (default). Setting an environment variable `WAIT_ON_INTERVAL=600000` (milliseconds) sets the interval for example to 10 minutes.
### Starting two servers

@@ -262,2 +350,14 @@

## Note for Apollo Server users
When passing a simple GET request to Apollo Server it will respond with a 405 error. To get around this problem you need to pass a valid GraphQL query into the query parameter. Passing in a basic schema introspection query will work to determine the presence of an Apollo Server. You can configure your npm script like so:
```json
{
"scripts": {
"ci": "start-server-and-test start 'http-get://localhost:4000/graphql?query={ __schema { queryType { name } } }' test"
}
}
```
### Small print

@@ -278,25 +378,4 @@

Copyright (c) 2017 Gleb Bahmutov &lt;gleb.bahmutov@gmail.com&gt;
See [LICENSE](./LICENSE)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
[npm-icon]: https://nodei.co/npm/start-server-and-test.svg?downloads=true

@@ -303,0 +382,0 @@ [npm-url]: https://npmjs.org/package/start-server-and-test

@@ -5,6 +5,9 @@ #!/usr/bin/env node

const args = process.argv.slice(2)
const startAndTest = require('..').startAndTest
const utils = require('../utils')
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)

@@ -19,7 +22,11 @@ const parsed = utils.getArguments(args)

utils.printArguments({ services, test })
if (!namedArguments.expect) {
namedArguments.expect = 200
}
startAndTest({ services, test }).catch(e => {
utils.printArguments({ services, test, namedArguments })
startAndTest({ services, test, namedArguments }).catch(e => {
console.error(e)
process.exit(1)
})

@@ -16,2 +16,4 @@ // @ts-check

const fiveMinutes = 5 * 60 * 1000
const twoSeconds = 2000
const waitOnTimeout = process.env.WAIT_ON_TIMEOUT

@@ -21,2 +23,6 @@ ? Number(process.env.WAIT_ON_TIMEOUT)

const waitOnInterval = process.env.WAIT_ON_INTERVAL
? Number(process.env.WAIT_ON_INTERVAL)
: twoSeconds
const isDebug = () =>

@@ -27,3 +33,3 @@ process.env.DEBUG && process.env.DEBUG.indexOf('start-server-and-test') !== -1

function waitAndRun ({ start, url, runFn }) {
function waitAndRun ({ start, url, runFn, namedArguments }) {
la(is.unemptyString(start), 'missing start script name', start)

@@ -36,2 +42,7 @@ la(is.fn(runFn), 'missing test script name', runFn)

)
const isSuccessfulHttpCode = status =>
(status >= 200 && status < 300) || status === 304
const validateStatus = namedArguments.expect
? status => status === namedArguments.expect
: isSuccessfulHttpCode

@@ -81,3 +92,3 @@ debug('starting server with command "%s", verbose mode?', start, isDebug())

resources: Array.isArray(url) ? url : [url],
interval: 2000,
interval: waitOnInterval,
window: 1000,

@@ -90,3 +101,4 @@ timeout: waitOnTimeout,

Accept: 'text/html, application/json, text/plain, */*'
}
},
validateStatus
}

@@ -122,3 +134,3 @@ debug('wait-on options %o', options)

*/
function startAndTest ({ services, test }) {
function startAndTest ({ services, test, namedArguments }) {
if (services.length === 0) {

@@ -128,2 +140,8 @@ throw new Error('Got zero services to start ...')

la(
is.number(namedArguments.expect),
'expected status should be a number',
namedArguments.expect
)
if (services.length === 1) {

@@ -135,2 +153,3 @@ const runTests = runTheTests(test)

url: services[0].url,
namedArguments,
runFn: runTests

@@ -143,5 +162,6 @@ })

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 })
}

@@ -148,0 +168,0 @@ })

@@ -5,4 +5,71 @@ const la = require('lazy-ass')

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(namedArguments, {
permissive: true,
argv: cliArguments
})
debug('initial parsed arguments %o', args)
// all other arguments
const cliArgs = args._
let concatModeChar = false
const indicationChars = ["'", '"', '`']
const combinedArgs = []
for (let i = 0; i < cliArgs.length; i++) {
let arg = cliArgs[i]
if (
!concatModeChar &&
indicationChars.some(char => cliArgs[i].startsWith(char))
) {
arg = arg.slice(1)
}
if (concatModeChar && cliArgs[i].endsWith(concatModeChar)) {
arg = arg.slice(0, -1)
}
if (concatModeChar && combinedArgs.length) {
combinedArgs[combinedArgs.length - 1] += ' ' + arg
} else {
combinedArgs.push(arg)
}
if (
!concatModeChar &&
indicationChars.some(char => cliArgs[i].startsWith(char))
) {
concatModeChar = cliArgs[i][0]
}
if (concatModeChar && cliArgs[i].endsWith(concatModeChar)) {
concatModeChar = false
}
}
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.

@@ -126,4 +193,13 @@ * If start command is NPM script name defined in the package.json

/**
* Returns the host to ping if the user specified just the port.
* For a long time, the safest bet was "localhost", but now modern
* web servers seem to bind to "0.0.0.0", which means
* the "127.0.0.1" works better
*/
const getHost = () => '127.0.0.1'
const normalizeUrl = input => {
const str = is.string(input) ? input.split('|') : [input]
const defaultHost = getHost()

@@ -136,3 +212,3 @@ return str.map(s => {

if (is.number(s) && is.port(s)) {
return `http://localhost:${s}`
return `http://${defaultHost}:${s}`
}

@@ -144,8 +220,12 @@

if (s.startsWith('localhost') || s.startsWith('127.0.0.1') || s.startsWith('0.0.0.0')) {
return `http://${s}`
}
if (is.port(parseInt(s))) {
return `http://localhost:${s}`
return `http://${defaultHost}:${s}`
}
if (s[0] === ':') {
return `http://localhost${s}`
return `http://${defaultHost}${s}`
}

@@ -157,11 +237,26 @@ // for anything else, return original argument

function printArguments ({ services, test }) {
function printArguments ({ services, test, namedArguments }) {
la(
is.number(namedArguments.expect),
'expected status code should be a number',
namedArguments.expect
)
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
)
})
if (process.env.WAIT_ON_INTERVAL !== undefined) {
console.log('WAIT_ON_INTERVAL is set to', process.env.WAIT_ON_INTERVAL)
}
if (process.env.WAIT_ON_TIMEOUT !== undefined) {
console.log('WAIT_ON_TIMEOUT is set to', process.env.WAIT_ON_TIMEOUT)
}
console.log('running tests using command "%s"', test)

@@ -174,3 +269,5 @@ console.log('')

const UTILS = {
crossArguments,
getArguments,
getNamedArguments,
isPackageScriptName,

@@ -177,0 +274,0 @@ isUrlOrPort,