2

In the package's package.json, I have two scripts. One starts the server for testing, and one starts the tests:

"scripts": {
  "start": "webpack-dev-server --config ./webpack.config.js --no-inline",
  "test": "jest"
}

Note that start is a background script that starts a server then stays running in the terminal until it is manually interrupted (Ctrl + C). So the npm run test script must be executed in a separate terminal.

However, the server can also be started from another server package (using lerna in the context of a monorepo), as offered by that package's package.json:

"scripts": {
  "debug": "DEBUG=* ts-node src/"
}

Likewise, this is also background script that starts a server then stays running in the terminal until it is manually interrupted (Ctrl + C).

I want my test files to know how the server was started when the script npm run test is executed. This could be done by setting or altering an env variable in the start script, that is later inspected in the test files. If that env variable is set then the test will know that its server was started by a user running npm run start in that package before hand. If not, then the tests will know that the server was started by a user doing npm run debug in the other package. It would then be able to run some conditional code, such as:

if (process.env.server_from_start) {
  ...
} else {
  ...
}

I have gotten as far as sharing an env variable from within a script, by doing:

"scripts": {
  "script1": "export FOO=bar && bash script_that_echos_FOO.sh",
  "script2": "bash script_that_echos_FOO.sh"
}

FOO is echoed correctly when I run npm run script1, but nothing is echoed when I run npm run script2.

zr0gravity7
  • 2,917
  • 1
  • 12
  • 33
  • Conventionally `process.env.NODE_ENV === 'test'` when a script is executed by test runner. This includes Jest. It doesn't need to be set manually. Is this what you wanted? – Estus Flask May 21 '20 at 17:09
  • Not quite. I want to set an environment variable in one script, and then retrieve it in another script (where both scripts are defined in the same package). Editted OP to show current progress. – zr0gravity7 May 21 '20 at 18:13
  • I'm not sure if I understood your case correctly but it seems it's not possible to do what you're trying to do. See https://stackoverflow.com/questions/12351702/how-to-write-a-bash-script-to-set-global-environment-variable , and may not be desirable for environment variables to persist. If you want totally unrelated scripts to communicate with each other, you likely need some other way rather than shell environment. – Estus Flask May 21 '20 at 18:40
  • I think in the end it is possible to persist an env file across scripts, but not in any clean way that is natively supported by npm. Something like writing the env variable to a `.env` file, then retrieving it from that `.env` file in the second script (or via some js file that the second script calls using the [dotenv](https://www.npmjs.com/package/dotenv) package). This does seem to be an anti-pattern. – zr0gravity7 May 22 '20 at 04:11
  • 1
    Yes, this is what I meant. A file is the most simple way to exchange information between processes. The problem happens when it's not cleaned up on exit and affects future launches. – Estus Flask May 22 '20 at 05:13

1 Answers1

2

I found a solution from this article in the paragraph titled Accessing variables in multiple scripts.

The idea is that the runner script is responsible for setting the cross-script environment variable and running a subsequent script. When runner spawns a child process running the subsequent script script1/script2, the child process will have access to the defined environment variable from runner. I believe that is why when you ran your original script2 there was no output, because the original script1 and script2 were run in independent processes.

Updated scripts:

"scripts": {
    "runner": "FOO=bar npm run",
    "script1": "bash script_that_echos_FOO.sh",
    "script2": "bash another_script_that_echos_FOO.sh",
    "multiScript": "npm-run-all script1 script2" 
}

The runner script would be invoked with the following. The parameter after -- is appended to end of the runner script and tells which script to run after setting the FOO environment variable.

In addition, I've added how you could run multiple scripts using npm-run-all so that all the scripts spawned from runner have access to the FOO environment variable.

npm run runner -- script1 // script1 runs and has access to FOO
npm run runner -- script2 // script2 runs and has access to FOO
npm run runner -- multiScript // script1 and script2 run (sequentially) with both having access to FOO

I want to add that this method is really beneficial when you have a dynamic environment variable that needs to be set. For my purpose it was to retrieve and set a token needed prior to executing some tests. The following example sets the environment variable to the result of a script.

"scripts": {
    "runner": "FOO=$(node ./retrieveDynamicToken.js) npm run",
    ...
}
rdrw
  • 763
  • 1
  • 8
  • 17