@nickglenn/mongo-seeder
TypeScript icon, indicating that this package has built-in type declarations

2.0.1 • Public • Published

NodeJS Mongo Seeders for Testing

This library provides methods for quickly creating utilities for inserting seeded data into MongoDB for testing purposes. It supports several methods for inserting one to many rows, applying "patch" data on top of seed generated data, and clean up for seeded data.

Getting Started

Install the library via npm. It's recommended that you install this as a development dependency.

npm i -D @nickglenn/mongo-seeder

Once installed, you can start integrating it by creating a "seeder map". This requires an object where the key represents a collection in your database, and the value is a factory function that returns the data necessary for a single document. It's recommended that you randomize the data output from each factory function in the map as this will help to create more robust tests.

Note: In the example below, we use the faker library to create some randomized data for our tests.

import { createSeederMap } from "@nickglenn/mongo-seeder";
import * as faker from "faker";

export const setupSeeders = createSeederMap({
  users: () => ({
    email: faker.internet.email(),
    password: faker.internet.password(),
  }),
  posts: () => ({
    title: faker.lorem.words(3),
    content: faker.lorem.sentences(5),
    published: faker.random.boolean(),
  }),
});

Now let's add it to our test suite. The createSeederMap function returned another function that needs us to provide an instance of a Mongo Database class. Once we've done that, we can begin using our seeders in some tests.

Note: The following syntax is what you'd likely see in a Jest or Mocha suite.

import * as mongo from "mongodb";
import { setupSeeders } from "./mySeeders";
import { findUserByEmail } from "./some/path/in/app";

let seeders;

beforeAll(async () => {
  // connect to mongodb
  const conn = await mongo.connect("mongodb://localhost/testing");

  // instantiate our seeders
  seeders = setupSeeders(conn.db());
});

afterEach(async () => {
  // after each test we can destroy all seeded data generated by each test
  await seeders.clean();
});

it("correctly fetches a user based on email", async () => {
  // use any of the seeder methods to insert some test records
  const testUser = await seeders.users.one();

  // run your code
  const fetchedUser = await findUserByEmail(testUser.email);

  // perform assertions
  expect(testUser._id.equals(fetchedUser._id)).toBe(true);
});

Seed Patching

type SeedPatcher<T> = Partial<T> | (generated: T, index: number) => T;

All of the methods for inserting seeds into the database support "seed patching". This allows generated records to be augmented in order to support specific test case scenarios.

Patch via Object

Patching seeds using an object performs a deep merge of the patch value on top of the generated value. This allows you to override the generated data before it's put into the database.

Using the example from above, we could alter our test to use a specific email address.

it("correctly fetches a user based on email", async () => {
  // use any of the seeder methods to insert some test records
  const testUser = await seeders.users.one({ email: "hello@example.com" });

  // run your code
  const fetchedUser = await findUserByEmail("hello@example.com");

  // perform assertions
  expect(testUser._id.equals(fetchedUser._id)).toBe(true);
});

Patch via Function

Sometimes a bit more flexibility is needed for testing scenarios. A patching function is called with the generated seed value (and numeric index) and the returned value is what will be stored in the database before being returned.

it("correctly fetches a user based on email from a larger pool of users", async () => {
  // create 5 user records, but only the second record will have the test email
  const testUsers = await seeders.users.many(5, (user, index) => {
    if (index === 1) {
      return { ...user, email: "hello@example.com" };
    }
    return user;
  });

  // run your code
  const fetchedUser = await findUserByEmail("hello@example.com");

  // perform assertions
  expect(testUsers[0]._id.equals(fetchedUser._id)).toBe(false);
  expect(testUsers[1]._id.equals(fetchedUser._id)).toBe(true);
  expect(testUsers[2]._id.equals(fetchedUser._id)).toBe(false);
  expect(testUsers[3]._id.equals(fetchedUser._id)).toBe(false);
  expect(testUsers[4]._id.equals(fetchedUser._id)).toBe(false);
});

Seeder Methods

one

Seeder<T>.one(patch?: SeedPatcher<T>): Promise<T>;

Creates and inserts a single record into the database, returning the inserted record.

many

Seeder<T>.many(count: number, patch?: SeedPatcher<T>): Promise<T[]>;

Creates and inserts 1-n records into the database, returning the inserted records as an array. The argument count cannot be less than 1 and must be an integer value.

random

Seeder<T>.random(min: number, max: number, patch?: SeedPatcher<T>): Promise<T[]>;

Creates and inserts a random number of records (within the given range) into the database, returning the inserted records as an array. The min argument must be 0 or greater and the max argument must be 1 greater than min.

pick

Seeder<T>.pick(min: number, max: number, patch: SeedPatcher<T>): Promise<[ T, T[] ]>;

An amalgamation of the other seeder records, pick actually requires that a seed patcher be provided. This is because pick will create a random number of records (within the given range) and insert them into the database However, a randomly selected record will be selected as the standout and will be patched, while the other records will not be patched and are stored in a crowds array.

This is useful for testing operations that may have differing results based on the amount of "noise" in the database.

const [standout, crowd] = await seeder.users.pick(min: 2, max: 20, { email: "standout@example.com" });

clean

Seeder<T>.clean(): Promise<void>;

Deletes all inserted records created by the seeder instance.

Package Sidebar

Install

npm i @nickglenn/mongo-seeder

Weekly Downloads

12

Version

2.0.1

License

MIT

Unpacked Size

26.7 kB

Total Files

8

Last publish

Collaborators

  • nickglenn