UNPKG

11.9 kBMarkdownView Raw
1# start-server-and-test
2
3> Starts server, waits for URL, then runs test command; when the tests end, shuts down server
4
5[![NPM][npm-icon] ][npm-url]
6
7[![Build status][ci-image] ][ci-url]
8[![semantic-release][semantic-image] ][semantic-url]
9[![js-standard-style][standard-image]][standard-url]
10[![renovate-app badge][renovate-badge]][renovate-app]
11
12## Install
13
14Requires [Node](https://nodejs.org/en/) version 8.9 or above.
15
16```sh
17npm install --save-dev start-server-and-test
18```
19
20## Use
21
22This command is meant to be used with NPM script commands. If you have a "start server", and "test" script names for example, you can start the server, wait for a url to respond, then run tests. When the test process exits, the server is shut down.
23
24```json
25{
26 "scripts": {
27 "start-server": "npm start",
28 "test": "mocha e2e-spec.js",
29 "ci": "start-server-and-test start-server http://localhost:8080 test"
30 }
31}
32```
33
34To execute all tests simply run `npm run ci`.
35
36### Commands
37
38In addition to using NPM script names, you can pass entire commands (surround them with quotes so it is still a single string) that will be executed "as is". For example, to start globally installed `http-server` before running and recording [Cypress.io](https://www.cypress.io) tests you can use
39
40```shell
41# run http-server, then when port 8000 responds run Cypress tests
42start-server-and-test 'http-server -c-1 --silent' 8000 './node_modules/.bin/cypress run --record'
43```
44
45Because `npm` scripts execute with `./node_modules/.bin` in the `$PATH`, you can mix global and locally installed tools when using commands inside `package.json` file. For example, if you want to run a single spec file:
46
47```json
48{
49 "scripts": {
50 "ci": "start-server-and-test 'http-server -c-1 --silent' 8080 'cypress run --spec cypress/integration/location.spec.js'"
51 }
52}
53```
54
55Or you can move `http-server` part into its own `start` script, which is used by default and have the equivalent JSON
56
57```json
58{
59 "scripts": {
60 "start": "http-server -c-1 --silent",
61 "ci": "start-server-and-test 8080 'cypress run --spec cypress/integration/location.spec.js'"
62 }
63}
64```
65
66Here is another example that uses Mocha
67
68```json
69{
70 "scripts": {
71 "ci": "start-server-and-test 'http-server -c-1 --silent' 8080 'mocha e2e-spec.js'"
72 }
73}
74```
75
76### Alias
77
78You can use either `start-server-and-test`, `server-test` or `start-test` commands in your scripts.
79
80You can use `:` in front of port number like `server-test :8080`, so all these are equivalent
81
82```
83start-server-and-test start http://localhost:8080 test
84server-test start http://localhost:8080 test
85server-test http://localhost:8080 test
86start-test :8080 test
87start-test 8080 test
88start-test 8080
89```
90
91### Options
92
93If you use convention and name your scripts "start" and "test" you can simply provide URL
94
95```json
96{
97 "scripts": {
98 "start": "npm start",
99 "test": "mocha e2e-spec.js",
100 "ci": "start-server-and-test http://localhost:8080"
101 }
102}
103```
104
105You can also shorten local url to just port, the code below is equivalent to checking `http://localhost:8080`.
106
107```json
108{
109 "scripts": {
110 "start": "npm start",
111 "test": "mocha e2e-spec.js",
112 "ci": "server-test 8080"
113 }
114}
115```
116
117You can provide first start command, port (or url) and implicit `test` command
118
119```json
120{
121 "scripts": {
122 "start-it": "npm start",
123 "test": "mocha e2e-spec.js",
124 "ci": "server-test start-it 8080"
125 }
126}
127```
128
129You can provide port number and custom test command, in that case `npm start` is assumed to start the server.
130
131```json
132{
133 "scripts": {
134 "start": "npm start",
135 "test-it": "mocha e2e-spec.js",
136 "ci": "server-test :9000 test-it"
137 }
138}
139```
140
141You can provide multiple resources to wait on, separated by a pipe `|`. _(be sure to wrap in quotes)_
142
143```json
144{
145 "scripts": {
146 "start": "npm start",
147 "test-it": "mocha e2e-spec.js",
148 "ci": "server-test \"8080|http://foo.com\""
149 }
150}
151```
152
153or for multiple ports simply: `server-test '8000|9000' test`.
154
155If 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:
156
157```json
158{
159 "scripts": {
160 "start": "npm start",
161 "test:unit": "mocha test.js",
162 "test:e2e": "mocha e2e.js",
163 "ci": "start-test 9000 'npm run test:unit && npm run test:e2e'"
164 }
165}
166```
167
168The 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.
169
170#### expected
171
172The 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`):
173
174```
175$ start-test --expect 403 start :9000 test:e2e
176```
177
178See `demo-expect-403` NPM script.
179
180## `npx` and `yarn`
181
182If 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:
183
184```json
185{
186 "devDependencies": {
187 "cypress": "3.2.0",
188 "http-server": "0.11.1",
189 "start-server-and-test": "1.9.0"
190 }
191}
192```
193
194Then you can execute tests simply:
195
196```text
197$ npx start-test 'http-server -c-1 .' 8080 'cypress run'
198starting server using command "http-server -c-1 ."
199and when url "http://localhost:8080" is responding
200running tests using command "cypress run"
201Starting up http-server, serving .
202...
203```
204
205Similarly, you can use [yarn](https://yarnpkg.com/en/) to call locally installed tools
206
207```text
208$ yarn start-test 'http-server -c-1 .' 8080 'cypress run'
209yarn run v1.13.0
210$ /private/tmp/test-t/node_modules/.bin/start-test 'http-server -c-1 .' 8080 'cypress run'
211starting server using command "http-server -c-1 ."
212and when url "http://localhost:8080" is responding
213running tests using command "cypress run"
214Starting up http-server, serving .
215...
216```
217
218## Note for yarn users
219
220By default, npm is used to run scripts, however you can specify that yarn is used as follows:
221
222```json
223"scripts": {
224 "start-server": "yarn start",
225 "test": "mocha e2e-spec.js",
226 "ci": "start-server-and-test 'yarn start-server' http://localhost:8080 'yarn test'"
227}
228```
229
230## Note for webpack-dev-server users
231
232Also applies to **Vite** users!
233
234If 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`
235
236```
237# from the first terminal start the server
238$ npm start
239# from the second terminal call the server with HEAD request
240$ curl --head http://localhost:3000
241```
242
243If the server responds with 404, then it does not handle the HEAD requests. You have two solutions:
244
245### Use HTTP GET requests
246
247You can force the `start-server-and-test` to ping the server using GET requests using the `http-get://` prefix:
248
249
250```
251start-server-and-test http-get://localhost:8080
252```
253
254### Ping a specific resource
255
256As 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).
257
258```
259# maybe the server responds to HEAD requests to the HTML page
260start-server-and-test http://localhost:3000/index.html
261# or maybe the server responds to HEAD requests to JS resource
262start-server-and-test http://localhost:8080/app.js
263```
264
265### Explanation
266
267You can watch the explanation in the video [Debug a Problem in start-server-and-test](https://youtu.be/rxyZOxYCsAk).
268
269Under 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.
270
271### Debugging
272
273To see diagnostic messages, run with environment variable `DEBUG=start-server-and-test`
274
275```
276$ DEBUG=start-server-and-test npm run test
277 start-server-and-test parsing CLI arguments: [ 'dev', '3000', 'subtask' ] +0ms
278 start-server-and-test parsed args: { services: [ { start: 'npm run dev', url: [Array] } ], test: 'npm run subtask' }
279...
280making HTTP(S) head request to url:http://localhost:3000 ...
281 HTTP(S) error for http://localhost:3000 Error: Request failed with status code 404
282```
283
284### Disable HTTPS certificate checks
285
286To disable HTTPS checks for `wait-on`, run with environment variable `START_SERVER_AND_TEST_INSECURE=1`.
287
288### Timeout
289
290This utility will wait for maximum of 5 minutes while checking for the server to respond (default). Setting an environment variable `WAIT_ON_TIMEOUT=600000` (milliseconds) sets the timeout for example to 10 minutes.
291
292### Interval
293
294This 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.
295
296### Starting two servers
297
298Sometimes you need to start one API server and one webserver in order to test the application. Use the syntax:
299
300```
301start-test <first command> <first resource> <second command> <second resource> <test command>
302```
303
304For example if API runs at port 3000 and server runs at port 8080:
305
306```json
307{
308 "scripts": {
309 "test": "node src/test",
310 "start:api": "node src/api",
311 "start:server": "node src/server",
312 "test:all": "start-test start:api 3000 start:server 8080 test"
313 }
314}
315```
316
317In 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
318
319## Note for Apollo Server users
320
321When 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:
322
323```json
324{
325 "scripts": {
326 "ci": "start-server-and-test start 'http-get://localhost:4000/graphql?query={ __schema { queryType { name } } }' test"
327 }
328}
329```
330
331### Small print
332
333Author: Gleb Bahmutov &lt;gleb.bahmutov@gmail.com&gt; &copy; 2017
334
335* [@bahmutov](https://twitter.com/bahmutov)
336* [glebbahmutov.com](https://glebbahmutov.com)
337* [blog](https://glebbahmutov.com/blog)
338
339License: MIT - do anything with the code, but don't blame me if it does not work.
340
341Support: if you find any problems with this module, email / tweet /
342[open issue](https://github.com/bahmutov/start-server-and-test/issues) on Github
343
344## MIT License
345
346See [LICENSE](./LICENSE)
347
348[npm-icon]: https://nodei.co/npm/start-server-and-test.svg?downloads=true
349[npm-url]: https://npmjs.org/package/start-server-and-test
350[ci-image]: https://github.com/bahmutov/start-server-and-test/workflows/ci/badge.svg?branch=master
351[ci-url]: https://github.com/bahmutov/start-server-and-test/actions
352[semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
353[semantic-url]: https://github.com/semantic-release/semantic-release
354[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg
355[standard-url]: http://standardjs.com/
356[renovate-badge]: https://img.shields.io/badge/renovate-app-blue.svg
357[renovate-app]: https://renovateapp.com/