How can I populate a Test DB with sample data?

System Information
  • Strapi Version: 4.1.7
  • Operating System: Mac OS Monterey
  • Database: SQLite
  • Node Version: 16.14.0
  • NPM Version: 8.3.1
  • Jest Version: ^27.5.1
  • Jest-junit Version: ^13.0.0,
  • Junit Version: ^1.4.9,
  • Yarn Version:

I’m using Strapi to manage the backend of a blog. It currently allows for actions such as post creation (creation of a blog post) which is achievable using the admin panel. I’m trying to write tests for the application, and the goal of one of the test cases is to retrieve posts, i.e. I’m making a GET request to api/posts to retrieve all the posts. The problem is that I can’t successfully pre-populate the Test Database with sample posts so that there is actual data in the response when the test runs.

In short, I’d like to add some data to the DB before running the tests. Below are snippets of my program. If you need more details to assist with this, please don’t hesitate to ask. Thank you.

The controller for the post resource; src/api/post/controllers/post.js

'use strict';

/**
 *  post controller
 */

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::post.post');

The test entry point, /tests/app.test.js

const { fs } = require('fs');
const jestConfig = require('../jest.config');
const { setUpStrapi, cleanUpStrapi } = require('./helpers/strapi');

jest.setTimeout(15000);

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

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

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

// require("./user")
require("./post")

The strapi.js helper, /tests/helpers/strapi.js

const fs = require('fs');
const Strapi = require('@strapi/strapi');
const _ = require("lodash");

let instance;
/**
 * Sets up strapi for further testing
 */
async function setUpStrapi() {
    if (!instance) {
        await Strapi().load();
        instance = strapi;
        await instance.server.mount();
    }
    return instance;
}

/**
 * Cleans up strapi after testing
 */

async function cleanUpStrapi() {
    const dbSettings = strapi.config.get('database.connection');
    const tmpDbFile = dbSettings.connection.filename;

    await strapi.server.httpServer.close();

    if (dbSettings && tmpDbFile) {
        if (fs.existsSync(tmpDbFile)) {
            fs.unlinkSync(tmpDbFile);
        }
    }
    await strapi.db.connection.destroy();
}

/**
 * Returns valid JWT token for authenticated user
 * @param {String | number } idOrEmail, either user_id or email
 */
const jwt = (idOrEmail) => {
    return strapi.plugins["user-permissions"].services.jwt.issue({
        [Number.isInteger(idOrEmail) ? "id" : "emmail"]: idOrEmail,
    })
}

/**
 * Grants database `permissions` table that role can access an endpoint/controllers
 *
 * @param {int} roleID, 1 Autentihected, 2 Public, etc
 * @param {string} value, in form or dot string eg `"permissions.users-permissions.controllers.auth.changepassword"`
 * @param {boolean} enabled, default true
 * @param {string} policy, default ''
 */
 const grantPrivilege = async (
    roleID = 1,
    path,
    enabled = true,
    policy = ""
  ) => {
    const service = strapi.plugin("users-permissions").service("role");
  
    const role = await service.getRole(roleID);
  
    _.set(role.permissions, path, { enabled, policy });
    // console.log("*********", role.permissions["api::post"]["controllers"]["post"])
    return service.updateRole(roleID, role);
  };
  

  /** Updates database `permissions` that role can access an endpoint
   * @see grantPrivilege
   */
  
  const grantPrivileges = async (roleID = 1, values = []) => {
    await Promise.all(values.map((val) => grantPrivilege(roleID, val)));
  };

module.exports = { setUpStrapi, cleanUpStrapi, jwt, grantPrivilege, grantPrivileges};

The factory methods for post.js, /tests/post/factory.js

const fs = require("fs")


/**
 * 
 * @returns a newly created file file
 */
const imageFileURL = () => {

    fs.appendFile('testFile.txt', 'A new file!', function (err) {
        if (err) throw err;
      });

    var file = 'testFile.txt'
    return file
}

/**
 * Returns data for post creation
 */
const defaultPostData = {
    title: "Test Post",
    description: "A test post",
    content: "This is a test post",
    featuredImage: imageFileURL(),
}


/**
 * Delete the created file
 */

const deleteTestFile = async () => {
    fs.unlink("testFile.txt", function(err) {
        if(err && err.code == 'ENOENT') {
            // file doens't exist
            console.info("File doesn't exist, won't remove it.");
        }
    })
}

/**
 * Should return created post
 */
const createPost = async () => {
    const post =  await strapi.service("api::post.post").create({
            data :{
            ...defaultPostData
            }
        })
    return post
}


module.exports = {
    defaultPostData,
    deleteTestFile,
    createPost
}

The tests for the post resource, /tests/posts/index.js

const { describe, beforeAll, afterAll, it, expect } = require("@jest/globals")
const request = require("supertest")
const {
    setUpStrapi,
    cleanUpStrapi,
    grantPrivilege,
} = require("../helpers/strapi")
const { createUser } = require("../user/factory")
const { createPost, deleteTestFile, defaultPostData } = require("./factory")

beforeAll(async () => {
    await setUpStrapi()
    //calls the createPost method and create a post, but it causes the tests to fail
    post = await createPost() 
})

afterAll(async () => {
    await cleanUpStrapi()
    await deleteTestFile()
    await new Promise(resolve => setTimeout(() => resolve(), 10000));
})

describe("Test Post Methods", () => {
    let user

    beforeAll(async () => {
        await grantPrivilege(1, "api::post.controllers.post.find")
        await grantPrivilege(2, "api::post.controllers.post.find")
        user = await createUser()
    })

    it("Should return all posts for user", async () => {
        const jwt = strapi.plugins["users-permissions"].services.jwt.issue({
            id: user.id,
        })

        await request(strapi.server.httpServer)
            .get("/api/posts")
            .set({"Accept": "*/*", "Content-Type": "application/json"})
            .expect("Content-Type", /json/)
            .expect(200)
            .then((data) => {
                expect(data.body).toBeDefined()
                // expect(data.body.data[0].attributes.title).toBe("Test Post")
            })

    })

})

I expect that the post would be created, but it doesn’t get created and instead the tests fail with this error;

❯ npm run test

> project@0.1.0 test
> jest --forceExit --detectOpenHandles

 FAIL  tests/app.test.js (22.741 s)
  ✕ strapi is defined
  Test Post Methods
    ✕ Should return all posts for user

  ● strapi is defined
  ● Test Post Methods › Should return all posts for user

Test Suites: 1 failed, 1 total
Tests:       2 failed, 2 total
Snapshots:   0 total
Time:        22.864 s, estimated 25 s
Ran all test suites

If I choose not to create a post, however, the tests run successfully. I’d appreciate any help I can get. Thank you.

2 Likes

Hey, I was wondering if you managed to solve this.

Also, have you considered using the config-sync plugin, to populate the DB with data before tests. In theory this could be used to create the posts as well as users and permissions. .) I don’t have any concrete advice on how to do this. Theoretically, it should be possible.