'How to get environment variables defined in serverless.yml in tests

I am using the serverless framework for running lambda functions on AWS.

In my serverless.yml there are environment variables that are fetched from SSM.

When I write integration tests for the code, I need the code to have the environment variables and I can't find a good way to do this.

I don't want to duplicate all the variables definitions just for the tests, they are already defined in the serverless.yml. Also, some are secrets and I can't commit them to source conrol, so I would have to also repeat them in the ci environment.

Tried using the serverless-jest-plugin but it is not working and not well maintained.

Ideas I had for solutions:

  1. Make the tests exec sls invoke - this will work but would mean that the code cannot be debugged, I won't know the test coverage, and it will be slow.
  2. Parse the serverless.yml myself and export the env variables - possible but rewriting the logic of pulling the SSM variables just for tests seems wrong.

Any ideas?



Solution 1:[1]

The solution we ended up using is a serverless plugin called serverless-export-env.

After adding this plugin you can run serverless export-env to export all the resolved environment variables to an .env file. This resolves ssm parameters correctly and made integration testing much simpler for us.

BTW, to get the environment variables set from the .env file use the the dotenv npm package.

Credit to grishezz for finding the solution

Solution 2:[2]

You can run node with --require option to inject .env file to a serverless command.

  1. Create .env at the project root with package.json, and list variables in .env.
  2. Install serverless and dotenv in the project by yarn add -D serverless dotenv.
  3. Run a command like node -r dotenv/config ./node_modules/.bin/sls invoke.

Then, you can get environment variables in the handler process.env.XXX.

Solution 3:[3]

Are you looking to do mocked unit tests, or something more like integration tests?

In the first case, you don't need real values for the environment variables. Mock your database, or whatever requires environment variables set. This is actually the preferable way because the tests will run super quickly with proper mocks.

If you are actually looking to go with end-to-end/integration kind of approach, then you would do something like sls invoke, but from jest using javascript. So, like regular network calls to your deployed api.

Also, I would recommend not to store keys in serverless.yml. Try the secret: ${env:MY_SECRET} syntax instead (https://serverless.com/framework/docs/providers/aws/guide/variables#referencing-environment-variables), and use environment variables instead. If you have a ci/cd build server, you can store your secrets there.

Solution 4:[4]

After searching I did my custom solution

import * as data from './secrets.[stage].json'

if( process.env.NODE_ENV === 'test'){
  process.env = Object.assign( data, process.env );
}
//'data' is the object that has the Serverless environment variables 

The SLS environment variables in my case at the file secrets.[stage].json

Serverless.yml has

custom:
 secrets: ${file(secrets.[stage].json)}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 brafdlog
Solution 2 Sangwon Kim
Solution 3 Herman Starikov
Solution 4 Amr