In this tutorial, you will create a simple Mongoose model and write tests using Jest and the MongoDB memory server.
What Is MongoDB Memory Server?
The last thing you want is to save fake data in your real database which might happen if you connect to it during testing. Instead, you may opt to use a separate local MongoDB instance to store your data. While this works, it is infeasible if your tests run on the cloud. Moreover, connecting and querying a real database during each test can get expensive.
MongoDB memory server, however, spins up a real MongoDB server and allows you to store the test data in memory. This makes it faster than using a local MongoDB database since data is not written on a physical disk.
Creating the Mongoose Model
Mongoose models provide an interface for interfacing with the MongoDB database. To create them, you need to compile them from a Mongoose schema, which defines your MongoDB data model. This tutorial will use a schema for a to-do document. It will contain the title and completed fields.
Run the following command in the terminal to create a new folder and navigate to it.
Initialize npm with the following command:
The -y flag instructs npm to generate a package.json file with default values.
Execute this command to install the mongoose package:
Create a new file called todo.model.js and define the todo schema:
At the end of this file, create and export the todo model:
Planning the Tests
When writing tests, you want to plan what you will be testing beforehand. This ensures you are testing all the functionality of your model.
From the Mongoose model we created, the todo should contain an item of type String and a completed field of type Boolean. Both of these fields are required. This means that, at minimum, our test should be ensuring:
Valid items are successfully saved in the database. Items without required fields are not saved. Items with fields of invalid type are not saved.
We will write these tests in one test block since they are related. In Jest, you define this test block using the describe function. For example:
Setting Up the Database
To set up a MongoDB memory server, you will create a new Mongo memory server instance and connect to Mongoose. You will also create functions that will be responsible for dropping all the collections in the database and disconnecting from the Mongo memory server instance.
Run the following command to install mongodb-memory-server.
Create a new file called setuptestdb.js and import mongoose and mongodb-memory-server.
Next, create a connectDB() function. This function creates a new Mongo memory server instance and connects to Mongoose. You will run it before all the tests to connect to the test database.
Create a dropDB() function by adding the following code. This function drops the database, closes the Mongoose connection, and stops the Mongo memory server instance. You will run this function after all the tests have finished running.
The last function you will create is called dropCollections(). It drops all the created Mongoose collections. You will run it after each test.
Finally, export the conenctDB(), dropDB(), and dropCollections() functions.
Writing the Tests
As mentioned, you will use Jest to write the tests. Run the following command to install jest.
In the package.json file, configure jest. Replace your existing “scripts” block with the following:
Create a new file called todo.model.test.js and import the mongoose library, the todo model, and the conenctDB(), dropDB(), and dropCollections() functions:
You need to run the connectDB() function before all the tests run. With Jest, you can use the beforeAll() method.
You also need to run cleanup functions. After each test, run the dropCollections() function and the dropDB() function after all the tests. You don’t need to do this manually and can use afterEach() and afterAll() methods from Jest.
Add the following code to the todo.model.test.js file to set up and clean up the database.
You are now ready to create the tests.
The first test will check whether the todo item was successfully inserted into the database. It will check whether the object Id is present in the created to and whether the data therein matches the one you sent to the database.
Create a describe block and add the following code.
This creates a new document in the database containing the data in the validTodo variable. The returned object is then validated against the expected values. For this test to pass, the returned value should have an object ID. Also, the values in the item and completed fields should match those in the validTodo object.
Apart from testing the normal use case, you also need to test a failing use case. From the tests we planned, you need to test the mongoose model with a todo object, with a missing required field and one with an incorrect type.
Add a second test to the same describe block, as follows:
The Todo mongoose model expects both the item and completed fields. It should throw an error if you try to save a todo without one of these fields. This test uses the try…catch block to catch the thrown error. The test expects the errors to be a mongoose validation error and stem from the missing completed field.
To test if the model throws an error if you use values of the wrong type, add the following code to the describe block.
Note the value of the completed field is a string instead of a boolean. The test expects a validation error to be thrown as the model expects a boolean value.
MongoMemoryServer and Jest Make a Great Team
The mongo-memory-server npm package provides an easy solution for testing Mongoose models. You can store dummy data in memory without touching your application’s database.
You can use MongoMemoryServer with Jest to write tests for Mongoose models. Note that it does not cover all the possible tests you can write for your models. Those tests will depend on your schema.