Sitemap

Strapi, typescript and tests with jest and supertest

5 min readJun 18, 2024

I felt the need to document this because Strapi’s documentation on using Jest and Supertest with TypeScript is somewhat scarce. Therefore, this is for my future reference as well as for anyone else looking to use Jest and Supertest to write tests in TypeScript as part of a TypeScript Strapi project. Of course, this might change with the forthcoming Version 5 of Strapi, but for now, this should work.

Pre-requisites:

  • You are familiar with Strapi and TypeScript, and you have a project configured with Strapi 4.24.5.
  • You have experience with Jest and SuperTest. These tools are fairly standard for writing tests in JavaScript and TypeScript.

So here is the plan

  1. Install Jest and SuperTest, and add configurations in package.json for Jest.
  2. Configure and use a different .env file (.env.test) for tests, so that we have our own configuration for the test environment.
  3. Configure Jest to use TypeScript.
  4. Configure dotenv to load environment variables from your .env.test file.
  5. Use a SQLite database for tests; set it up when our tests start and clean it up when they end.
  6. Load and run a separate instance of Strapi which points to this database.
  7. Ensure all our tests execute with that test environment, and the Strapi instance is shut down when the tests end.
  8. Lastly, write the actual tests, run everything, and conclude.

Let us start by installing jest, supertest and sqlite (we use better-sqlite3 flavor)

npm install jest supertest better-sqlite3 --save-dev 

This installs and configures jest, supertest and better-sqlite3 in package.json of your Strapi project. We need additional configurations for jest in package.json which we will see in a moment.

For now, we create a new file in the root of the project called .env.test , this file is our config file that tells our test environment about our database to be used.

The contents of the file are something like this

NODE_ENV=test
HOST=0.0.0.0
PORT=1338
APP_KEYS=<Your keys here>
API_TOKEN_SALT=<Token salt>
ADMIN_JWT_SECRET=<JWT secret>
TRANSFER_TOKEN_SALT=<Transfer token salt>
# Database
DATABASE_CLIENT=sqlite
DATABASE_HOST=127.0.0.1
DATABASE_FILENAME=.tmp/test.db
JWT_SECRET=<JWT secret>

The contents are self-explanatory, we are basically specifying the environment (test), the database details and keys that are required by Strapi backend while serving the requests.
Salts and keys can be generated by using the below command, I did this on mac terminal, the command generates you may have to find the equivalents in other Operating systems, by default Strapi generates 16 byte, so we might as well go with that. By the way, you can use the env.example provided by Strapi by default, to configure .env.test file.

openssl rand -base64 16

We move on to the step 3, configuring Jest to use Typescript for tests. We will use Babel, as Jest supports typescript via Babel

npm install --save-dev babel-jest @babel/core @babel/preset-env @babel/preset-typescript

we need the babel.config.js file for babel, this will be in the root of your project. It has following contents, we are specifying babel to target the current node version and adding the typescript preset, that allows you to compile TypeScript code using Babel

module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-typescript',
],
};

We do need types in jest also, so lets install them

npm install --save-dev @types/jest

OK, now we are ready for the next step, i.e. Configuring dotenv to load environment variables from your .env.test file.

We will install dotenv by executing

npm install --save-dev dotenv

Now that we have it, we will complete the configuration of jest in package.json and use dotenv to pick up our .env.test file for test env variables.

We will first add the following line within the scripts block in package.json

 "test": "DOTENV_CONFIG_PATH=./.env.test jest --setupFiles dotenv/config --coverage  --forceExit"

so it looks like this

Press enter or click to view image in full size

We are effectively loading the .env.test file via dotenv when starting tests with jest. Note, we added — coverage to get some test related stats. They don’t hurt :)

Next we add the following in package.json, (at the very end of it)

  "jest": {
"testPathIgnorePatterns": [
"/node_modules/",
".tmp",
".cache"
],
"testEnvironment": "node"
}

So our package.json looks something like this

Press enter or click to view image in full size

Next we write code for loading Strapi and write basic test to verify that it is up. (Step # 6)

So here is how we will fire-up and clean-up strapi, you can create strapi.ts file in “test” directory (which should reside in root)

import Strapi from "@strapi/strapi";
import * as fs from "fs";

let instance ;

async function setupStrapi() {
if (!instance) {
await Strapi({distDir : "./dist"}).load(); // very important, this tells
// where to find the transpiled code from typescript
instance = strapi;
await instance.server.mount();
}
return instance;
}

async function cleanupStrapi() {
const dbSettings = strapi.config.get("database.connection") as any ;
console.log(dbSettings) // confirm that we are pointing to sqlite
// with the tmp file residing in /myprojectname/.tmp/test.db'
//close server to release the db-file
await strapi.server.httpServer.close();
await strapi.db.connection.destroy();

//delete test database after all tests have completed

if (dbSettings && dbSettings.connection && dbSettings.connection.filename) {
const tmpDbFile = dbSettings.connection.filename;
if (fs.existsSync(tmpDbFile)) {
fs.unlinkSync(tmpDbFile);
}
}
}
export { setupStrapi, cleanupStrapi };

these two functions will be used in our main test file (called bunchOfTests.test.ts which is as follows)


import { cleanupStrapi, setupStrapi } from "./strapi";

beforeAll(async () => {
await setupStrapi();
});

afterAll(async () => {
await cleanupStrapi();
});

it("strapi is defined", () => {
expect(strapi).toBeDefined();
});

if you run it now, you should see successful execution of 1 test (“strapi is defined”). Let us try to create a user and test it is created successfully. Let us make a new file called user.ts and add the following code into it

import request from "supertest";

const mockUserData = {
username: "tester1",
email: "tester1@strapi.com",
provider: "local",
password: "1234abc",
confirmed: false,
blocked: null,
};

it("should create user with email and return token", async () => {
await strapi.plugins["users-permissions"].services.user.add({
...mockUserData,
});

await request(strapi.server.httpServer)
.post("/api/auth/local")
.set("accept", "application/json")
.set("Content-Type", "application/json")
.send({
identifier: mockUserData.email,
password: mockUserData.password,
})
.expect("Content-Type", /json/)
.expect(200)
.then((data) => {
expect(data.body.jwt).toBeDefined();
});
});

Now we include this user.ts in our bunchOfTests.test.ts file as follows (the last line)

import request from "supertest";
import { cleanupStrapi, setupStrapi } from "./strapi";

beforeAll(async () => {
await setupStrapi();
});

afterAll(async () => {
await cleanupStrapi();
});

it("strapi is defined", () => {
expect(strapi).toBeDefined();
});

import './user' ;

and we run with npm test, we should see the following

Press enter or click to view image in full size
Tests output

Happy testing

--

--

Responses (3)