If you're using Jest to write integration tests (that hit the database) for your Node application, you'll quickly notice that it's tricky to isolate your tests if you're using only one test database.
While Jest runs all tests in a single testsuite sequentially, it runs your testsuites in parallel (by default). This makes for faster execution times, but it also means that changes to your database in one testsuite could interfere with another test that's currently running in a different testsuite.
An easy solution to this is to configure a new SQLite in-memory database for each of your testsuites or test-files. This way, a testsuite only makes changes to its own database without affecting the database being used by other running testsuites.
In this tutorial, I'll walk through a simple setup for using in-memory databases in your Jest testsuites and running your database migrations on them before each test using Knex. The code for this tutorial is available here: https://github.com/rukykf/jest-sqlite-tutorial
In your knexfile create a new connection for your test file like so:
// knexfile.js
const path = require("path")
module.exports = {
...
test: {
client: "sqlite3",
connection: ":memory:",
useNullAsDefault: true,
migrations: {
directory: path.join(__dirname, "migrations")
},
seeds: {
directory: path.join(__dirname, "seeds")
}
},
}
When instantiating Knex, specify that you want to use the test
config we just created in our knexfile
For instance, in a file db-config.js
we could do this
// db-config.js
const knex = require("knex")
const config = require("./knexfile")
let db = null
if (process.env.NODE_ENV === "test") {
db = knex(config.test)
} else {
db = knex(config.development)
}
module.exports = db
By default, Jest will set NODE_ENV
to test
when you are running your tests.
Then in your integration testsuites, you need to run your migrations on the in-memory database before executing any tests.
// users.test.js and db-config.js are in the same directory
const db = require("./db-config")
beforeAll(async () => {
// run the migrations and do any other setup here
await db.migrate.latest()
})
test("select users", async () => {
let users = await db.from("users").select("name")
expect(users.length).toEqual(0)
})
That's it. Now each of your testsuites will use a separate SQLite database. You still have to keep in mind that all the tests in a given testsuite will use one database.
Top comments (3)
thank you soo much for this!,
i was having issues trying to get my test database to connect, but it kept connecting to the development database
and many examples are overly complicated
this solution is very nice and fixed my issue
Yesssss! Thank you so much. I was chasing my tail for many days until I found this tutorial. Really helped me breeze through the setup. ^.^
There are so many complicated articles floating around about this topic - but you helped me solve my problem in less than 5 min! I was having a problem running tests with jest and supertest and my knex wasn't creating a test database to test them in. The way you laid it out fixed my issue. Thank you!