How do I make "npm run start" exit with a code 0?

Viewed 1578

I'm using an application built using React and JS. Using Azure DevOps to build a CI/CD pipeline to build, test and deploy the application to an Azure Service.

In my CI pipeline, I need to run functional tests written using Cypress. The "e2e:local" tests run on the application hosted on localhost. Running the script "npm start" individually requires a manual input (Ctrl+C) within the terminal to exit out of the process, so running "npm start" as a standalone step within the pipeline will make it run forever. Hence I've used "npm concurrently" to run both "npm run start" and the functional tests "npm run e2e"local".

"scripts": {
        "nx": "nx",
        "start": "nx serve",
        "build": "nx build",
        "test": "nx test",
        "e2e:local": "nx run haven-e2e:e2e --baseUrl=http://localhost:4200",
        "e2e:localhost": "concurrently --kill-others \"npm run start\" \"npm run e2e:local\"
} 

Running "npm run e2e:localhost" on my local machine , serves the application on localhost:4200 and runs the functional tests. Logs below are from the scripts run on a local machine.

> Executing task: npm run e2e:localhost <
        
        
        > didit-tech-challenge@0.0.0 e2e:localhost
        > concurrently --success -k "npm run start" "npm run e2e:local"
        
        [0] 
        [0] > challenge@0.0.0 start
        [0] > nx serve
        [0]
        [1]
        [1] > challenge@0.0.0 e2e:local
        [1] > nx run haven-e2e:e2e --baseUrl=http://localhost:4200
        [1]
        [0] 
        [0] > nx run haven:serve 
        [1] 
        [1] > nx run haven-e2e:e2e --baseUrl=http://localhost:4200 
        [1] 
        [0] Starting type checking service...
        [0] Using 6 workers with 2048MB memory limit
        [0] 
        [0] >  NX  Web Development Server is listening at http://localhost:4200/
        [0]
        [1] 
        [1] ====================================================================================================
        [1]
        [1]   (Run Starting)
        [1]
        [1]   ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
        [1]   │ Cypress:    8.2.0                                                                              │
        [1]   │ Browser:    Electron 89                                                                        │
        [1]   │ Specs:      1 found (functional/login.spec.ts)                                                 │
        [1]   └────────────────────────────────────────────────────────────────────────────────────────────────┘
        [1]
        [1]
        [1] ────────────────────────────────────────────────────────────────────────────────────────────────────
        [1]
        [1]   Running:  functional/login.spec.ts                                                        (1 of 1)
        [0] No type errors found
        [0] Version: typescript 4.2.4
        [0] Time: 14681ms
        [0] Hash: 7f72c1685a3c8c11842f
        [0] Built at: 12/02/2021 8:12:01 AM
        [0] Entrypoint main [big] = runtime.js runtime.js.map vendor.js main.js main.js.map
        [0] Entrypoint polyfills [big] = runtime.js runtime.js.map polyfills.js polyfills.js.map
        [0] Entrypoint styles [big] = runtime.js runtime.js.map styles.js styles.js.map
        [0] chunk {main} main.js, main.js.map (main) 696 KiB ={runtime}= ={vendor}= [initial] [rendered]
        [0] chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 654 KiB ={runtime}= [initial] [rendered]
        [0] chunk {runtime} runtime.js, runtime.js.map (runtime) 0 bytes ={main}= ={polyfills}= ={styles}= ={vendor}= [entry] [rendered]
        [0] chunk {styles} styles.js, styles.js.map (styles) 1.87 MiB ={runtime}= [initial] [rendered]
        [0] chunk {vendor} vendor.js (vendor) 1.42 MiB ={main}= ={runtime}= [initial] [rendered] split chunk (cache group: vendor) (name: vendor)
        [1] Starting type checking service...
        [1] Using 1 worker with 2048MB memory limit
        [1] Starting type checking service...
        [1] Using 1 worker with 2048MB memory limit
        [0] [HPM] Error occurred while trying to proxy request /health from localhost:4200 to http://localhost:3000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
        [0] [HPM] Error occurred while trying to proxy request /health from localhost:4200 to http://localhost:3000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
        [0] [HPM] Error occurred while trying to proxy request /health from localhost:4200 to http://localhost:3000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
        [0] [HPM] Error occurred while trying to proxy request /health from localhost:4200 to http://localhost:3000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
        [0] [HPM] Error occurred while trying to proxy request /login from localhost:4200 to http://localhost:3000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
        [1] Warning: We failed processing this video.
        [1]
        [1] This error will not alter the exit code.
        [1]
        [1] TimeoutError: operation timed out
        [1]     at afterTimeout (C:\Users\AppData\Local\Cypress\Cache\8.2.0\Cypress\resources\app\packages\server\node_modules\bluebird\js\release\timers.js:46:19)
        [1]     at Timeout.timeoutTimeout [as _onTimeout] (C:\Users\AppData\Local\Cypress\Cache\8.2.0\Cypress\resources\app\packages\server\node_modules\bluebird\js\release\timers.js:76:13)     
        [1]     at listOnTimeout (internal/timers.js:554:17)
        [1]     at processTimers (internal/timers.js:497:7)
        [1]
        [1]
        [1]   (Results)
        [1]
        [1]   ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
        [1]   │ Tests:        1                                                                                │
        [1]   │ Passing:      1                                                                                │
        [1]   │ Failing:      0                                                                                │
        [1]   │ Pending:      0                                                                                │
        [1]   │ Skipped:      0                                                                                │
        [1]   │ Screenshots:  0                                                                                │
        [1]   │ Video:        false                                                                            │
        [1]   │ Duration:     2 seconds                                                                        │
        [1]   │ Spec Ran:     functional/login.spec.ts                                                         │
        [1]   └────────────────────────────────────────────────────────────────────────────────────────────────┘
        [1] 
        [1] 
        [1] ====================================================================================================
        [1]
        [1]   (Run Finished)
        [1]
        [1]
        [1]        Spec                                              Tests  Passing  Failing  Pending  Skipped  
        [1]   ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
        [1]   │ √  functional/login.spec.ts                 00:02        1        1        -        -        - │
        [1]   └────────────────────────────────────────────────────────────────────────────────────────────────┘
        [1]     √  All specs passed!                        00:02        1        1        -        -        -  
        [1]
        [1] 
        [1] ———————————————————————————————————————————————
        [1]
        [1] >  NX   SUCCESS  Running target "e2e" succeeded
        [1]
        [1]
        [1] npm run e2e:local exited with code 0
        --> Sending SIGTERM to other processes..
        [0] npm run start exited with code 1
        The terminal process "C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -Command npm run e2e:localhost" terminated with exit code: 1.
        
        Terminal will be reused by tasks, press any key to close it.

From the logs, as "npm run start exited with code 1", running this same npm script within the Azure DevOps CI pipeline, it causes the process to fail. Logs below are from the scripts run on Azure DevOps Pipeline. How do I make "npm run start" exit with a code 0?

Starting: npm haven-e2e:local
==============================================================================
Task         : npm
Description  : Install and publish npm packages, or run an npm command. Supports npmjs.com and authenticated registries like Azure Artifacts.
Version      : 1.187.0
Author       : Microsoft Corporation
Help         : https://docs.microsoft.com/azure/devops/pipelines/tasks/package/npm
==============================================================================
/usr/local/bin/npm --version
8.1.0
/usr/local/bin/npm config list
; "env" config from environment

userconfig = "/home/vsts/work/1/npm/409.npmrc" 

; node bin location = /usr/local/bin/node
; cwd = /home/vsts/work/1/s
; HOME = /home/vsts
; Run `npm config ls -l` to show all defaults.
/usr/local/bin/npm run e2e:localhost

> didit-tech-challenge@0.0.0 e2e:localhost
> concurrently --kill-others "npm run start" "npm run e2e:local"

[1] 
[1] > didit-tech-challenge@0.0.0 e2e:local
[1] > nx run haven-e2e:e2e --baseUrl=http://localhost:4200
[1] 
[0] 
[0] > didit-tech-challenge@0.0.0 start
[0] > nx serve
[0] 
[1] 
[1] > nx run haven-e2e:e2e --baseUrl=http://localhost:4200 
[0] 
[0] > nx run haven:serve 
[1] It looks like this is your first time using Cypress: 8.2.0
[1] 
[1] [STARTED] Task without title.
[0] Starting type checking service...
[0] Using 1 worker with 2048MB memory limit
[0] (node:1989) [DEP0111] DeprecationWarning: Access to process.binding('http_parser') is deprecated.
[0] (Use `node --trace-deprecation ...` to show where the warning was created)
[0] 
[0] >  NX  Web Development Server is listening at http://localhost:4200/
[0] 
[0] (node:1989) [DEP0148] DeprecationWarning: Use of deprecated folder mapping "./" in the "exports" field module resolution of the package at /home/vsts/work/1/s/node_modules/postcss/package.json.
[0] Update this package.json to use a subpath pattern like "./*".
[1] [SUCCESS] Task without title.
[1] 
[1] Opening Cypress...
[0] No type errors found
[0] Version: typescript 4.2.4
[0] Time: 12030ms
[0] Hash: c9337ccd5e2d5b163cd1
[0] Built at: 12/02/2021 10:45:15 AM
[0] Entrypoint main [big] = runtime.js runtime.js.map vendor.js main.js main.js.map
[0] Entrypoint polyfills [big] = runtime.js runtime.js.map polyfills.js polyfills.js.map
[0] Entrypoint styles [big] = runtime.js runtime.js.map styles.js styles.js.map
[0] chunk {main} main.js, main.js.map (main) 695 KiB ={runtime}= ={vendor}= [initial] [rendered]
[0] chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 654 KiB ={runtime}= [initial] [rendered]
[0] chunk {runtime} runtime.js, runtime.js.map (runtime) 0 bytes ={main}= ={polyfills}= ={styles}= ={vendor}= [entry] [rendered]
[0] chunk {styles} styles.js, styles.js.map (styles) 1.87 MiB ={runtime}= [initial] [rendered]
[0] chunk {vendor} vendor.js (vendor) 1.42 MiB ={main}= ={runtime}= [initial] [rendered] split chunk (cache group: vendor) (name: vendor)
[1] 
[1] ================================================================================
[1] 
[1]   (Run Starting)
[1] 
[1] tput: No value for $TERM and no -T specified
[1]   ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
[1]   │ Cypress:    8.2.0                                                                              │
[1]   │ Browser:    Electron 89                                                                        │
[1]   │ Specs:      1 found (functional/login.spec.ts)                                                 │
[1]   └────────────────────────────────────────────────────────────────────────────────────────────────┘
[1] 
[1] 
[1] ────────────────────────────────────────────────────────────────────────────────────────────────────
[1]
[1]   Running:  functional/login.spec.ts                                                        (1 of 1)
[1] Starting type checking service...
[1] Using 1 worker with 2048MB memory limit
[1] Starting type checking service...
[1] Using 1 worker with 2048MB memory limit
[0] [HPM] Error occurred while trying to proxy request /health from localhost:4200 to http://localhost:3000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
[0] [HPM] Error occurred while trying to proxy request /health from localhost:4200 to http://localhost:3000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
[0] [HPM] Error occurred while trying to proxy request /health from localhost:4200 to http://localhost:3000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
[0] [HPM] Error occurred while trying to proxy request /health from localhost:4200 to http://localhost:3000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
[0] [HPM] Error occurred while trying to proxy request /login from localhost:4200 to http://localhost:3000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
[1] 
[1]   (Results)
[1] 
[1]   ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
[1]   │ Tests:        1                                                                                │
[1]   │ Passing:      1                                                                                │
[1]   │ Failing:      0                                                                                │
[1]   │ Pending:      0                                                                                │
[1]   │ Skipped:      0                                                                                │
[1]   │ Screenshots:  0                                                                                │
[1]   │ Video:        true                                                                             │
[1]   │ Duration:     3 seconds                                                                        │
[1]   │ Spec Ran:     functional/login.spec.ts                                                         │
[1]   └────────────────────────────────────────────────────────────────────────────────────────────────┘
[1] 
[1] 
[1]   (Video)
[1] 
[1]   -  Started processing:  Compressing to 32 CRF                                                     
[1]   -  Finished processing: /home/vsts/work/1/s/dist/cypress/apps/haven-e2e/videos/func    (2 seconds)
[1]                           tional/login.spec.ts.mp4                                                  
[1] 
[1] 
[1] ================================================================================
[1] 
[1]   (Run Finished)
[1] 
[1] 
[1] tput: No value for $TERM and no -T specified
[1]        Spec                                              Tests  Passing  Failing  Pending  Skipped  
[1]   ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
[1]   │ ✔  functional/login.spec.ts                 00:03        1        1        -        -        - │
[1]   └────────────────────────────────────────────────────────────────────────────────────────────────┘
[1]     ✔  All specs passed!                        00:03        1        1        -        -        -  
[1] 
[1] 
[1] ———————————————————————————————————————————————
[1] 
[1] >  NX   SUCCESS  Running target "e2e" succeeded
[1] 
[1] 
[1] npm run e2e:local exited with code 0
--> Sending SIGTERM to other processes..
[0] 
[0] ———————————————————————————————————————————————
[0] 
[0] >  NX   ERROR  Running target "haven:serve" failed
[0] 
[0]   Failed tasks:
[0]   
[0]   - haven:serve
[0] 
[0] npm run start exited with code SIGTERM
##[warning]Couldn't find a debug log in the cache or working directory
##[error]Error: Npm failed with return code: 1
Finishing: npm haven-e2e:local
1 Answers

I was able to fix this script using "--success = first". This returns an exit code 0 or exit code 1 based on the success or failure of the "first" child to terminate (npm run e2e:local).

"e2e:localhost": "concurrently --kill-others --success= first \"npm run start\" \"npm run e2e:local\"

Thanks to @Lawrence Cherone for the suggestion.

Related