/jest-dynamodb

Jest preset for DynamoDB local server

Primary LanguageJavaScriptMIT LicenseMIT

jest-dynamodb CircleCI npm (scoped)

Jest preset to run DynamoDB Local

Usage

0. Install

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

Make sure aws-sdk is installed as a peer dependency.

1. Create jest.config.js

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

2. Create jest-dynamodb-config.js

See Create Table API.

You can set up tables as an object:

module.exports = {
  tables: [
    {
      TableName: `files`,
      KeySchema: [{AttributeName: 'id', KeyType: 'HASH'}],
      AttributeDefinitions: [{AttributeName: 'id', AttributeType: 'S'}],
      ProvisionedThroughput: {ReadCapacityUnits: 1, WriteCapacityUnits: 1}
    }
    // etc
  ],
  port: 8000
};

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

module.exports = async () => {
  const serverless = new (require('serverless'))();

  await serverless.init();
  const service = await serverless.variables.populateService();
  const resources = service.resources.Resources;

  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.safeLoad(
    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 x.TableName === "object") {
        table.TableName = table.TableName.data.replace('${env}','test');
      }
      delete table.TimeToLiveSpecification; //errors on dynamo-local
      return table;
    });
  
  return {
    tables,
    port: 8000
  };
};

3. Configure DynamoDB client

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'})
};

const ddb = new DocumentClient(config);

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'
  });
});

Troubleshooting

UnknownError: Not Found

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

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

License

MIT © Shelf