Unit Tests in Serverless

Hey! Got the error:

FAIL tests/billing.test.js
● Test suite failed to run

Plugin/Preset files are not allowed to export objects, only functions. In D:\simply\noteit\noteit-api\node_modules\babel-preset-stage-3\lib\index.js

  at createDescriptor (node_modules/@babel/core/lib/config/config-descriptors.js:178:11)
  at items.map (node_modules/@babel/core/lib/config/config-descriptors.js:109:50)
      at Array.map (<anonymous>)
  at createDescriptors (node_modules/@babel/core/lib/config/config-descriptors.js:109:29)
  at createPresetDescriptors (node_modules/@babel/core/lib/config/config-descriptors.js:101:10)
  at presets (node_modules/@babel/core/lib/config/config-descriptors.js:47:19)
  at mergeChainOpts (node_modules/@babel/core/lib/config/config-chain.js:320:26)
  at node_modules/@babel/core/lib/config/config-chain.js:283:7
  at buildRootChain (node_modules/@babel/core/lib/config/config-chain.js:120:22)
  at loadPrivatePartialConfig (node_modules/@babel/core/lib/config/partial.js:85:55)

Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 1.818s
Ran all test suites.
npm ERR! Test failed. See above for more details.

When running npm test. My package.json (different because trying to solve issue):

Thanks

EDIT: copied exact package.json you guys have on GitHub, and only changed Jest to isolate. It seems Jest 24.5.0 has some problems with Babel.
Also, this makes builds fail when using Seed’s auto-deploy (with unit testing enabled)!
EDIT2: the problem arises from Jest 24.0.1 and up, 23.6.0 is fine. The should be a way to make Jest and Babel work fine together right?

So I think I figured this out. Turns out I couldn’t find a way to make the plugins work (transform-runtime and source-map-support) but it seems to work fine without them. So with Jest and Babel updated, this is what my package.json (in part) and .babelrc look like:

package.json

“devDependencies”: {
@babel/cli”: “^7.2.3”,
@babel/core”: “^7.4.0”,
@babel/node”: “^7.2.2”,
@babel/plugin-transform-runtime”: “^7.4.0”,
@babel/preset-env”: “^7.4.2”,
“aws-sdk”: “^2.224.1”,
“babel-jest”: “^24.5.0”,
“babel-loader”: “^8.0.5”,
“babel-plugin-transform-runtime”: “^6.23.0”,
“jest”: “^24.5.0”,
“serverless-offline”: “^3.18.0”,
“serverless-webpack”: “^5.1.0”,
“webpack”: “^4.2.0”,
“webpack-node-externals”: “^1.6.0”
},
“dependencies”: {
“aws-sdk”: “^2.422.0”,
“babel-runtime”: “^6.26.0”,
“semver”: “^6.0.0”,
“serverless”: “^1.39.1”,
“source-map-support”: “^0.4.18”,
“stripe”: “^6.28.0”,
“uuid”: “^3.3.2”
},
“jest”: {
“testEnvironment”: “node”
}

.babelrc

{
“presets”: [
“jest”,
[
@babel/preset-env”,
{
“debug”: false,
“modules”: “commonjs”,
“targets”: {
“node”: “current”
},
“useBuiltIns”: false
}
]
]
}

And now it passes Jest tests!

3 Likes

Thank you so much, adding the .babelrc fixed my issue! For others encountering the same problem, you don’t need the extra dependences.

Thanks so much. Creating the .babelrc fixed the problem for me as well, didn’t have to change anything else. Here it is with proper formatting:

{
    "presets": [
        "jest", [
            "@babel/preset-env", {
                "debug": false,
                "modules": "commonjs",
                "targets": {
                    "node": "current"
                },
                "useBuiltIns": false
            }
        ]
    ]
}

@jayair: You should probably add this to the repo, or at least mention it in the text.

Are you using the serverless-bundle plugin? Cos we recently updated things to get rid of all the Webpack and Babel configs.

let’s use es2015

module.exports = function calculateCost(storage) {
  const rate = storage <= 10 ? 4 : storage <= 100 ? 2 : 1;

  return rate * storage * 100;
};
const calculateCost = require("../libs/billing-lib");
1 Like
D:\Shadow\Desktop\serverless-stack-2-api>npm test

> serverless-nodejs-starter@1.1.0 test D:\Shadow\Desktop\serverless-stack-2-api
> jest

 FAIL  tests/billing.test.js
  ● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    D:\Shadow\Desktop\serverless-stack-2-api\tests\billing.test.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import { calculateCost } from "../libs/billing-lib";
                                                                                                    ^

    SyntaxError: Unexpected token {

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/node_modules/@jest/transform/build/ScriptTransformer.js:537:17)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        4.374s
Ran all test suites.
npm ERR! Test failed.  See above for more details.

I have no idea why it seems to be causing an issue with the first line

Hmm I think you might be using an older version of the starter project? Can you compare your package.json to the one in the demo repo?

I seem to be having some trouble running the unit tests. When running npm test I get the following error.

  SyntaxError: Cannot use import statement outside a module

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)

This is running node 12.11.1 on Windows 10. Package.json is as follows:

{
  "name": "notes-app-api",
  "version": "1.1.0",
  "description": "A Node.js starter for the Serverless Framework with async/await and unit test support",
  "main": "handler.js",
  "scripts": {
"test": "jest"
  },
  "author": "",
  "license": "MIT",
  "repository": {
"type": "git",
"url": "https://github.com/AnomalyInnovations/serverless-nodejs-starter.git"
  },
  "devDependencies": {
"aws-sdk": "^2.545.0",
"jest": "^24.9.0",
"serverless-bundle": "^1.2.5",
"serverless-dotenv-plugin": "^2.1.1",
"serverless-offline": "^5.3.3"
  },
  "dependencies": {
"stripe": "^7.10.0",
"uuid": "^3.3.3"
  }
}

Any ideas?

I’m also hitting problems when I try to deploy using Seed. Logged error is

```
    /tmp/seed/source/tests/billing.test.js:1
```

```
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import { calculateCost } from "../libs/billing-lib";
```

```
                                                                                                    ^
```

```

```

```
    SyntaxError: Unexpected token {
```

```

```

```
      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:537:17)
```

```
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:579:25)
```

and

```
ERROR: FAIL tests/billing.test.js
```

```
ERROR:   ● Test suite failed to run
```

```
ERROR: 
```

```
ERROR:     Jest encountered an unexpected token
```

```
ERROR: 
```

```
ERROR:     This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
```

```
ERROR: 
```

```
ERROR:     By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
```

```
ERROR: 
```

```
ERROR:     Here's what you can do:
```

```
ERROR:      • To have some of your "node_modules"
```

Hmm you might be using an older version of the tutorial. The test command should be using serverless-bundle test instead.

That seems to have done the trick. I was halfway through the tutorial when you released the node 8 > 10 update. Started again from scratch but it must have cached something somewhere.

Thanks for the help and thank you for creating such a great tutorial series.

1 Like

Glad you figured it out!

This worked for me, great idea!

1 Like

Hmm that page doesn’t have the line you are talking about?

I know this is an old thread, but you’ve been super helpful in the past and I can’t seem to find any information on what I’m trying to do with unit testing. My question is, “How do I unit test a serverless lambda function with DB calls when there’s no connection to the DB before it’s been deployed?”. Example:

export async function getResources(){
    const resources = await db('resources')
    .select('resources.firstname, 'resources.lastname');

    //do something with the object returned

return resources;
}

In this case, I’d like to test what I’m doing with the returned object(which would be where the comment is), but need to somehow get the test to skip the db call and replace it with mock data we’ve created and check the result. Any tips would be greatly appreciated. Thanks!

I’ve only used Python for this stuff before so I’m new to the Javscript AWS world. But a little bit of looking around and maybe this article can help: it mocks out the AWS SDK for JavaScript

I still had problems with that error today. I dug around and learnt a little about ECMAScript modules. If you create another package.json inside test/ and say it’s a module, it works for me:

tests/package.json

{
  "type": "module"
}

Output:

(serverless-stack) bash-3.2$ npm test

> notes-app-api@1.1.0 test /Users/julian/learn/serverless-stack/notes-app-api
> serverless-bundle test

 PASS  tests/billing.test.js
  ✓ Lowest tier (3ms)
  ✓ Middle tier
  ✓ Highest tier (1ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        1.636s, estimated 2s
Ran all test suites.
1 Like

Great tutorial, thank you!

Any idea how I could use jest or any other testing library to test one API Gateway endpoint protected by Cognito?

As an extra level of security, I’m using CognIto Identity Id as param to post data in DynamoDB and so to prevent a malicious user with access in the same pool to post data on behalf of an other user, but I could not really figure out how to test it.

Here an example of DynamoDb param I’m using to update user data:

const params = {
    TableName: "products",
    Key: {
      userId: event.requestContext.identity.cognitoIdentityId,
      productId: event.pathParameters.productId
    },

Typically we end up testing the Lambda function directly as unit tests. But maybe you are looking for integration testing?