• Stars
    star
    179
  • Rank 213,970 (Top 5 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 5 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Jest preset for DynamoDB local server

jest-dynamodb CircleCI npm (scoped)

Jest preset to run DynamoDB Local

Usage

0. Install

$ yarn add @shelf/jest-dynamodb --dev

Make sure java runtime available for running DynamoDBLocal.jar

1. Create jest.config.js

module.exports = {
  preset: '@shelf/jest-dynamodb',
};

2. Create jest-dynamodb-config.js

2.1 Properties

tables
  • Type: object[]
  • Required: true

Array of createTable params.

port
  • Type: number
  • Required: false

Port number. The default port number is 8000.

hostname
  • Type: string
  • Required: false

Hostname. The default hostname is localhost.

options
  • Type: string[]
  • Required: false

Additional arguments for dynamodb-local. The default value is ['-sharedDb'].

clientConfig
  • Type: object
  • Required: false

Constructor params of DynamoDB client.

installerConfig
  • Type: {installPath?: string, downloadUrl?: string}

  • Required: false

  • installPath defines the location where dynamodb-local is installed or will be installed.

  • downloadUrl defines the url of dynamodb-local package.

The default value is defined at https://github.com/rynop/dynamodb-local/blob/2e6c1cb2edde4de0dc51a71c193c510b939d4352/index.js#L16-L19

2.2 Examples

You can set up tables as an object:

Whole list of config properties can be found here

/**
 * @type {import('@shelf/jest-dynamodb/lib').Config}')}
 */
const config = {
  tables: [
    {
      TableName: `files`,
      KeySchema: [{AttributeName: 'id', KeyType: 'HASH'}],
      AttributeDefinitions: [{AttributeName: 'id', AttributeType: 'S'}],
      ProvisionedThroughput: {ReadCapacityUnits: 1, WriteCapacityUnits: 1},
    },
    // etc
  ],
  port: 8000,
};
module.exports = config;

Or as an async function (particularly useful when resolving DynamoDB setup dynamically from serverless.yml):

module.exports = async () => {
  const serverless = new (require('serverless'))();
  // If using monorepo where DynamoDB serverless.yml is in another directory
  // const serverless = new (require('serverless'))({ servicePath: '../../../core/data' });

  await serverless.init();
  const service = await serverless.variables.populateService();
  const resources = service.resources.filter(r => Object.keys(r).includes('Resources'))[0];

  const tables = Object.keys(resources)
    .map(name => resources[name])
    .filter(r => r.Type === 'AWS::DynamoDB::Table')
    .map(r => r.Properties);

  return {
    tables,
    port: 8000,
  };
};

Or read table definitions from a CloudFormation template (example handles a !Sub on TableName, i.e. TableName: !Sub "${env}-users" ):

const yaml = require('js-yaml');
const fs = require('fs');
const {CLOUDFORMATION_SCHEMA} = require('cloudformation-js-yaml-schema');

module.exports = async () => {
  const cf = yaml.load(fs.readFileSync('../cf-templates/example-stack.yaml', 'utf8'), {
    schema: CLOUDFORMATION_SCHEMA,
  });
  var tables = [];
  Object.keys(cf.Resources).forEach(item => {
    tables.push(cf.Resources[item]);
  });

  tables = tables
    .filter(r => r.Type === 'AWS::DynamoDB::Table')
    .map(r => {
      let table = r.Properties;
      if (typeof r.TableName === 'object') {
        table.TableName = table.TableName.data.replace('${env}', 'test');
      }
      delete table.TimeToLiveSpecification; //errors on dynamo-local
      return table;
    });

  return {
    tables,
    port: 8000,
  };
};

3.1 Configure DynamoDB client (from aws-sdk v2)

const {DocumentClient} = require('aws-sdk/clients/dynamodb');

const isTest = process.env.JEST_WORKER_ID;
const config = {
  convertEmptyValues: true,
  ...(isTest && {
    endpoint: 'localhost:8000',
    sslEnabled: false,
    region: 'local-env',
    credentials: {
      accessKeyId: 'fakeMyKeyId',
      secretAccessKey: 'fakeSecretAccessKey',
    },
  }),
};

const ddb = new DocumentClient(config);

3.2 Configure DynamoDB client (from aws-sdk v3)

const {DynamoDB} = require('@aws-sdk/client-dynamodb');
const {DynamoDBDocument} = require('@aws-sdk/lib-dynamodb');

const isTest = process.env.JEST_WORKER_ID;

const ddb = DynamoDBDocument.from(
  new DynamoDB({
    ...(isTest && {
      endpoint: 'localhost:8000',
      sslEnabled: false,
      region: 'local-env',
      credentials: {
        accessKeyId: 'fakeMyKeyId',
        secretAccessKey: 'fakeSecretAccessKey',
      },
    }),
  }),
  {
    marshallOptions: {
      convertEmptyValues: true,
    },
  }
);

4. PROFIT! Write tests

it('should insert item into table', async () => {
  await ddb.put({TableName: 'files', Item: {id: '1', hello: 'world'}}).promise();

  const {Item} = await ddb.get({TableName: 'files', Key: {id: '1'}}).promise();

  expect(Item).toEqual({
    id: '1',
    hello: 'world',
  });
});

Monorepo Support

By default the jest-dynamodb-config.js is read from cwd directory, but this might not be suitable for monorepos with nested jest projects with nested jest.config.* files nested in subdirectories.

If your jest-dynamodb-config.js file is not located at {cwd}/jest-dynamodb-config.js or you are using nested jest projects, you can define the environment variable JEST_DYNAMODB_CONFIG with the absolute path of the respective jest-dynamodb-config.js file.

Example Using JEST_DYNAMODB_CONFIG in nested project

// src/nested/project/jest.config.js
const path = require('path');

// Define path of project level config - extension not required as file will be imported via `require(process.env.JEST_DYNAMODB_CONFIG)`
process.env.JEST_DYNAMODB_CONFIG = path.resolve(__dirname, './jest-dynamodb-config');

module.exports = {
  preset: '@shelf/jest-dynamodb'
  displayName: 'nested-project',
};

Troubleshooting

UnknownError: Not Found

Perhaps something is using your port specified in jest-dynamodb-config.js.

com.almworks.sqlite4java.Internal log WARNING: [sqlite] cannot open DB[1]:

See https://www.josephso.dev/using-jest-dynamodb-in-apple-silicon-platform-workaround/#community-build

Alternatives

  • jest-dynalite - a much lighter version which spins up an instance for each runner & doesn't depend on Java

Read

Used by

See Also

Publish

$ git checkout master
$ yarn version
$ yarn publish
$ git push origin master --tags

License

MIT © Shelf

More Repositories

1

chrome-aws-lambda-layer

58 MB Google Chrome to fit inside AWS Lambda Layer compressed with Brotli
627
star
2

jest-mongodb

Jest preset for MongoDB in-memory server
TypeScript
588
star
3

aws-lambda-libreoffice

Utility to work with Docker version of LibreOffice in Lambda
TypeScript
221
star
4

libreoffice-lambda-layer

Shell
109
star
5

ghostscript-lambda-layer

Ghostscript AWS Lambda layer
Shell
93
star
6

aws-lambda-tesseract

6 MB Tesseract (with English training data) to fit inside AWS Lambda
Shell
86
star
7

dynamodb-parallel-scan

Scan large DynamoDB tables faster with parallelism
TypeScript
65
star
8

libreoffice-lambda-base-image

26
star
9

fast-chunk-string

Chunk string into equal substrings with unicode support
TypeScript
18
star
10

tika-text-extract

Extract text from a document by Apache Tika
TypeScript
15
star
11

dynamodb-query-optimized

TypeScript
13
star
12

apache-tika-lambda-layer

AWS Lambda layer containing latest version of Apache Tika
Shell
13
star
13

winston-datadog-logs-transport

Winston transport for Datadog Logs (not events)
JavaScript
13
star
14

java-lambda-layer

AWS Lambda layer with Java 8
Shell
12
star
15

jest-postgres

Jest preset for running tests with local Postgres
TypeScript
10
star
16

aws-ddb-with-xray

AWS DynamoDB Document Client initialized with X-Ray
TypeScript
9
star
17

jest-elasticsearch

Jest preset for running tests with local ElasticSearch
TypeScript
9
star
18

aws-lambda-brotli-unpacker

Unpacks large Lambda binaries to /tmp
TypeScript
9
star
19

fast-natural-order-by

Lightweight (< 2.3kB gzipped) and performant natural sorting of arrays and collections by differentiating between unicode characters, numbers, dates, etc.
TypeScript
8
star
20

es-painless-fields

Generate Painless Elasticsearch script to set / unset fields on document from JavaScript Object
TypeScript
7
star
21

serverless-simplify-default-exec-role-plugin

Fixes "IamRoleLambdaExecution - Maximum policy size of 10240 bytes exceeded" error
JavaScript
7
star
22

fast-normalize-spaces

A faster (by 16-70%) implementation of "normalize-space-x" package that uses at least 3x less RAM
TypeScript
6
star
23

elasticsearch-local

Run any version of ElasticSearch locally
TypeScript
6
star
24

eslint-config

JavaScript
6
star
25

array-chunk-by-size

Chunk array of objects by their size in JSON
TypeScript
4
star
26

postgres-local

Run Postgres locally
TypeScript
4
star
27

jest-testrail-reporter

Simple package to submit jest test results to TestRail
TypeScript
3
star
28

aws-ssm-get-param-cli

Get value of SSM parameter
JavaScript
3
star
29

pspdfkit-ssr

Utilities to work with PSPDFKit's server-side rendering
TypeScript
2
star
30

gh-sdk

Convenient wrapper for GitHub API for automation tasks
TypeScript
2
star
31

react-outside-click

React library for handling outside clicks of a specified element
TypeScript
2
star
32

renovate-config-public

1
star
33

is-string-in-quotes

Check if string is inside quotation marks (21 styles)
TypeScript
1
star
34

fast-normalize-spaces-as

TypeScript
1
star
35

trim-around-tag

Trims text to max length around any HTML tag w/o breaking words
TypeScript
1
star
36

evaluate-expressions

Evaluate expressions that consist of multiple rules and joiners.
TypeScript
1
star
37

datetime

Shelf dates library
TypeScript
1
star
38

text-normalizer

Clone of openai Whisperer text normalization done and tested on Typescript!
TypeScript
1
star
39

table-of-contents

Linkify HTML headers and generate a TOC
TypeScript
1
star
40

image-preview-overlay

TypeScript
1
star