Jest doesn't load environment variables (even with --setupFiles dotenv/config) - javascript

I'm writing tests for my Express project, but when I run the test script my environment variables are not loaded.
In other threads people suggested using --setupFiles dotenv/config, which I did, but unfortunately it didn't work. I tried both adding it to my test script and to a jest.config.js file, but none worked. Does someone have any hint on how to fix this?
Context
This is how I setup jest on package.json:
"scripts": {
"test": "jest --watchAll --setupFiles dotenv/config"
},
"jest": {
"testEnvironment": "node"
},
At the top of my app.js file, I load my environment variables with
require('dotenv').config();
And this is my folder structure:

Fixed it by moving .env file from the src/ folder to the root folder.

Have a look at this project. It uses both cross-env and dotenv to pass env variables to Express:
cross-env NODE_ENV=production node -r dotenv/config ./build/srv/main.js
Alternatively the sibling project uses cross-env only.
Disclosure: I'm the author of the above 'crisp' projects.

Related

How to setup mocha to run tests in a Gatsby repo

I'm trying to get tests to run in a gatsby repo using Mocha, because we already have a lot of tests using mocha and chai, and we don't want to have 2 different assertion libraries, so we're not using Jest.
The first thing I did, is this:
npm i -D mocha chai #testing-library/react
Which installs mocha v8 and chai v4, Then I add a naive script in my package.json to see what happens:
"scripts": {
"test": "mocha --watch"
}
This gives me an error: unexpected token import for import { expect } from 'chai'; in my bare-bones test file. So next step, following Gatsby's conventions:
"scripts": {
"test": "npx --node-arg '-r esm' mocha --watch"
}
Okay, we're live, but no tests are running, next iteration:
"scripts": {
"test": "npx --node-arg '-r esm' mocha --watch 'src/**'"
}
Alright, now it crashes because of SyntaxError: Invalid or unexpected token for a <div> in a react component file.
At this point, I wonder if I really have to install babel and all of its machinery just to run a simple test, especially since gatsby does not use babel at all?
Does someone know of a really clean, modern setup that makes writing tests with mocha in Gatsby simple? Can esm be taught to read JSX without a pile of hacks?
At this point, I wonder if I really have to install babel and all of its machinery just to run a simple test
Unfortunately, yes.
, especially since gatsby does not use babel at all?
Actually that's not true, it's babel all the way down.
Thankfully, since Gatsby has already done all the tedious work of setting up babel, it's rather easy to set up your tests.
First, install the missing bits:
npm i -D #babel/register jsdom jsdom-global
Then add a fresh .babelrc at the root of the project with the following config:
{
"presets": ["babel-preset-gatsby"]
}
You don't need to install babel-preset-gatsby since it comes with all Gatsby setup.
That should be it. Now replace esm with #babel/register & register jsdom-global. Also make sure you set your NODE_ENV to test:
NODE_ENV=test npx mocha -r #babel/register -r jsdom-global/register ./src/**/*.test.js
And that should work.
When you add the test command to package.json, no needs to use npx:
"scripts": {
"test": "NODE_ENV=test mocha -r #babel/register -r jsdom-global/register ./src/**/*.test.js"
}
If you're testing Gatsby components, here's a few global variables you need to watch out for: __PATH_PREFIX__, __BASE_PATH__, and ___loader.
Mock them however you'd like, but for a quick and dirty test:
globalThis.__PATH_PREFIX__ = '/'
globalThis.__BASE_PATH__ = './'
globalThis.___loader = { enqueue: () => {} }

Where is json.config file found in the root of the project?

I am new in development field.
I have already made an app in create-react-app.
But now I have been asked to submit json.config file..
It is mentioned that -
The file must be called config.json and must be stored in the root level of your project.
Here is the format of the configuration file:
{
"install": "npm install",
"run": "npm start",
"port": 3000
}
I am unable to find it in my project folders and dependency folders and files.
Create-React-App creates this file for you under the hood. So you don't have to setup it. You can open the terminal and write npm install and after npm start. That will open your web app in http://localhost:3000.
More details https://create-react-app.dev/docs/available-scripts
Edit: Dependencies should be inside the package.json in the root directory.

Webpack: -p vs NODE_ENV=production vs process.env.NODE_ENV

I'm having an issue with webpack in production and I'm getting confused with the different ways of running webpack in the production environment (I'm using Windows).
Can someone explain the difference between these:
One: CLI
webpack -p
Two: CLI
SET NODE_ENV=production
webpack
Three: webpack.config.js
new webpack.ProvidePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
})
I'm using React and need to build a production version which is both minified and includes the production version of React.
SET NODE_ENV=production sets NODE_ENV environment variable to "production" on the server. The machine that compiles and bundles your javascript source files. So it can for example select a different webpack config file for production.
But this enviroment variable has no effect when this javascript code actually runs. Because the javascript code will run on a browser in a different machine.
The providePlugin helps to set NODE_ENV variable in the browser. Where your javascript actually runs. Actually what it really does is replacing occurences of process.env.NODE_ENV with "production" rather than setting a variable. But effects are same.
EDIT: It's actually DefinePlugin that should be used for this purpose.
Weback -p advertises to doing the second of above but seems to have some issues.
Based on webpack documentation setting webpack -p performs following
Minification using UglifyJSPlugin
Runs the LoaderOptionsPlugin
Sets the Node environment variable
So instead of doing:
"scripts": {
"dist": "NODE_ENV=production webpack",
"start": "webpack"
}
You can just specify
"scripts": {
"dist": "webpack -p",
"start": "webpack"
}

JS unit testing: run tests on file changes (like nodemon)

I have two question on JS unit testing:
1) Is there some tool that allows to automaticaly run javascript unit tests when certain files are changed (like for example nodemon restarts node.js on js changes).
2) Is this strategy appropriate (efficient) way to run unit tests?
Thanks,
Alex
For those who are committed to using nodemon, nodemon -x "npm test" has worked for me.
A little explanation
nodemon --help says:
-x, --exec app ........... execute script with "app", ie. -x "python -v".
In our case npm test is set to run tests by configuring our package.json
For example:
"scripts": {
"test": "mocha"
},
When using jest, nodemon is not necessary. Simply set the test script command to jest --watchAll in package.json as follows:
"scripts": {
"test": "jest --watchAll"
}
Check out grunt build system and the watch task. You can setup grunt to watch for file changes and then run any tasks you want (test, lint, compile, etc...).
https://github.com/cowboy/grunt
Some of the ideas are covered in this tutorial. http://javascriptplayground.com/blog/2012/04/grunt-js-command-line-tutorial
Here's a snippet of my package.json:
"scripts": {
"develop": "nodemon ./src/server.js --watch src --watch __tests__ -x \"yarn run test\"",
"test": "mocha ./__tests__/**/*.js --timeout 10000" }
The develop script is my command line to run my express server (entry: ./src/server.js), watch the /src directory which has all my server/API code, watch the /__tests__ directory which as all my specs and lastly tells nodemon to execute the enclosed statement before each restart/run with -x \"yarn run test\"
yarn run test is no different than npm run test. I prefer yarn over npm so that part is up to you. What is important is the \" tags inside the JSON value... without it, it will fail since the argument will be tokenized incorrectly.
This setup allows me to trigger changes from either server/API code or writing/fixing specs and trigger full test run BEFORE restarting the server via nodemon.
Cheers!

How to use nodemon with .env files?

I am using an .env file to hold environment variables for the server. This works if I run the server with foreman start. But it doesn't work with nodemon.
I would like to use nodemon instead because it restarts automatically when you modify the server. How can I get nodemon to work with .env files?
Install dotenv npm i dotenv
Create .env file and your variables inside
Add the script to execute
"dev": "nodemon -r dotenv/config ./app/index.js " or
"start": "node -r dotenv/config ./app/index.js "
Run the app using npm run dev or npm run start
I have a production Procfile with:
web: node web.js
So I have created a Procfile_dev file with:
web: nodemon web.js
And when I am at development environment I run:
$ foreman start -f Procfile_dev
It works like a charm and doesn't affect production.
You can get nodemon to directly use the .env with the following command
$: env $(cat .env) nodemon app.js
Be aware that you'll have to restart it if you make changes to .env and it won't like it if there are any spaces in your .env file.
With recent versions of Node (since io.js 1.6), you can pass it the -r flag to require a module on start. This lets you directly load .env by using nodemon's --exec:
nodemon --exec 'node -r dotenv/config'
This requires the npm package dotenv to be installed.
Place your local configuration variables in the .env file and run foreman along with nodemon using the following command
$ foreman run nodemon web.js
This works pretty well for me so far,
nodemon -w . -w .env index.js
How it works:
"-w ." tells nodemon to watch the files in the current directory
"-w .env" tells nodemon to watch the .env file
"index.js" is just the file to run when changes occur (could be anything)
"scripts": {
"start": "node -r dotenv/config src/server.js dotenv_config_path=dev.env dotenv_config_debug=true",
"start:dev": "nodemon --exec \"npm start\""
}
In my case the .env file is used for development and not deployment. So I wanted my code to be decoupled from the .env file. Ideally I didn't want to import 'dotenv/config' anywhere in my code. This is my solution:
My nodemon config:
{
"watch": [
"src",
".env"
],
"ext": ".ts",
"exec": "ts-node -r dotenv/config ./src/index.ts"
}
My NPM script:
"start:dev": "nodemon"
In this solution ts-node requires dotenv, which sets up the environment variables before the main app starts. This means that nowhere in my code do I need a import 'dotenv/config'. dotenv can become a dev dependency, and this also prevents dotenv to be loaded at all once the code is deployed.
Thread necromancy!
Use grunt-env to load environmental variables from your heroku config.
In Three steps
Creating the file on root folder > .env
# .env ======
PORT=5000
WHO_AM_I="Who Knows"
Install the dotenv
Run below command
"dev": "nodemon -r dotenv/config src/app.js"
You can access the your defined variables using > process.env.varible_name
If you want to run Typescript in nodemon and require a particular .env file with dotenv then you can do:
In package.json scripts:
"dev": "nodemon -r dotenv/config src/myApp.ts dotenv_config_path=/path/to/your/env/file",
And a line in nodemon.json to tell nodemon to use ts-node when encountering Typescript extensions:
"execMap": {"ts": "node -r ts-node/register"},
This is useful for using a development .env file say .env.development.local for local dev work and leave the main .env file for live production variables.
Use the -w key to specify nodemon what to watch additionally.
"scripts": {
"dev": "env-cmd nodemon -w app -w *.js -w .env server.js"
}
Don't forget rerun npm run dev
Heroku Procfile
Change: web: node app.js to web: nodemon app.js
To load the dotenv package and any declared .env vars into the environment, you can do the following:
nodemon -r dotenv/config myapp.js
I use cross-env for environments.
npm i cross-env
set package.json.
"start": "cross-env NODE_ENV=production node dist/app.js",
"dev": "cross-env NODE_ENV=dev nodemon --exec ts-node src/app.ts",
npm run start OR npm run dev

Categories