Unit testing endpoints 403 FORBIDDEN

System Information
  • Strapi Version: 3.3.4
  • Operating System:
  • Database: mongo
  • Node Version: 12.16.1
  • NPM Version:
  • Yarn Version: 1.19.1

I there,

I’m tying to integrate unit testing to my strapi application. I follow these documentation :

But when i run a test I have a 403 and not a 200

/tests/app.test.js

const fs = require('fs')
const { setupStrapi } = require('./helpers/strapi')

/** this code is called once before any test is called */
jest.setTimeout(15000)
beforeAll(async (done) => {
  await setupStrapi() // singleton so it can be called many times
  done()
})

/** this code is called once before all the tested are finished */
afterAll(async (done) => {
  const dbSettings = strapi.config.get('database.connections.default.settings')

  //delete test database after all tests
  if (dbSettings && dbSettings.filename) {
    const tmpDbFile = `${__dirname}/../${dbSettings.filename}`
    if (fs.existsSync(tmpDbFile)) {
      fs.unlinkSync(tmpDbFile)
    }
  }
  done()
})

it('strapi is defined', () => {
  expect(strapi).toBeDefined()
})
require('./hello')

/test/helpers/strapi.js

const Strapi = require('strapi')
const http = require('http')

let instance

async function setupStrapi() {
  if (!instance) {
    /** the following code in copied from `./node_modules/strapi/lib/Strapi.js` */
    await Strapi().load()
    instance = strapi // strapi is global now
    await instance.app
      .use(instance.router.routes()) // populate KOA routes
      .use(instance.router.allowedMethods()) // populate KOA methods

    instance.server = http.createServer(instance.app.callback())
  }
  return instance
}

module.exports = { setupStrapi }

/tests/hello/index.js

const request = require('supertest')

it('should return hello world', async (done) => {
  await request(strapi.server) // app server is an instance of Class: http.Server
    .get('/hello')
    .expect(200) // Expect response http code 200
    .then((data) => {
      expect(data.text).toBe('Hello World!') // expect the response text
    })
  done()
})

Any idea ?
Thanks in advance

1 Like

Hey,

I am having the same issue, have you found any solution to this?

Hi @Beenyaa, no I don’t unfortunately

That is very unfortunate :confused:, I am still trying to find an answer, if I find something, I’ll let you know!

2 Likes

@Jean1 I got in touch with Mateusz Wojczal and he helped me figure out this authentication issue we were having. The unit testing documentation isn’t clear about this, but we need to give privilege to the testing instance separately, it isn’t done automatically.

If you copy the contents of this example’s strapi-unit-test-example/strapi.js at master · qunabu/strapi-unit-test-example · GitHub strapi.js file and paste it into your /test/helpers/strapi.js file, then all you have to do is to add the following code into your tests/hello/index.js file:

const request = require("supertest")
const { grantPrivilege } = require("./../helpers/strapi");

beforeAll(async () => {
  await grantPrivilege(2, "permissions.application.controllers.hello.index");  // Gives Public access to endpoint
});

it('should return hello world', async (done) => {
    await request(strapi.server) // app server is an instance of Class: http.Server
    .get('/hello')
    .expect(200) // Expect response http code 200
    .then((data) => {
      expect(data.text).toBe('Hello World!') // expect the response text
    })
  done()
})

Now it should work.

1 Like

Ho yes thanks you @Beenyaa ! Maybe it would be nice to add this to the official documentation

1 Like

I agree, not sure how that could be done though. I’ll try find a way, or someone to do it.

Hi @Beenyaa

I tried the same way. I pasted the code from strapi-unit-test-example/strapi.js at master · qunabu/strapi-unit-test-example · GitHub and added it in config /tests/helper/strapi.js but getting this error:

Hi @Beenyaa

I tried the same way. I pasted the code from strapi-unit-test-example/strapi.js at master · qunabu/strapi-unit-test-example · GitHub and added it in config /tests/helper/strapi.js but getting this error:

Hi @Beenyaa

This error too.

Thank you, but I think that using the grantPrivileges function instead of its singular form would be better in case of many routes to test.

Folks, anyone found the solution for entry.notFound error ? I can see the same error.

I have the same issue also. In my case, I can’t make testing POST method with jest, even though I have set the grantPrivileges in beforeAll.

const request = require("supertest");
const { grantPrivilege, grantPrivileges } = require("./../helpers/strapi");

const mockJobData = {
  ad: {
    title: "Coconut Climber",
    description: "Mencari pemanjat pohon kelapa professional",
    media: [8, 9],
    media_thumbnail: 9,
    keywords: "coconut,climber,coconut-climber",
  },
  is_business: true,
  business_name: "PT Coconut Clumber",
  phone: "085156629208",
  sallary_per: "month",
  sallary_amount: 100000,
  is_workday_negotiable: true,
  is_worktime_negotiable: true,
  lat: "-8.7432722",
  lng: "115.17264",
  start_at: "09:00:00",
  end_at: "15:00:00",
  work_days: [
    {
      day_of_week: 2,
      is_working: true,
    },
  ],
};

beforeAll(async () => {
    await grantPrivileges(1, [
      "permissions.application.controllers.job.find",
      "permissions.application.controllers.job.findOne",
      "permissions.application.controllers.job.create",
      "permissions.application.controllers.job.update",
      "permissions.application.controllers.job.delete",
    ]);
  });

  it("POST /jobs", async () => {
    const user = await strapi.plugins["users-permissions"].services.user.add({
      ...mockUserData,
    });

    const jwt = strapi.plugins["users-permissions"].services.jwt.issue({
      id: user.id,
    });

    await request(strapi.server)
      .post("/jobs")
      .set("Authorization", "Bearer " + jwt)
      .send(mockJobData)
      .expect("Content-Type", /json/)
      .expect(200)
      .then((data) => {
        expect(data.body).toBeDefined();
      });
  });

The error :
Screen Shot 2022-04-20 at 10.43.38

Anyone can help me, please?

I had to rewrite grant privileges to get it working:

/**
 * Grants database `permissions` table that role can access an endpoint/controllers
 *
 * @param {int} roleID, 1 Authenticated, 2 Public, etc
 * @param {string} modelUID e.g. api::restaurant.restaurant
 * @param {string} route, route which should be granted access to if enabled is true
 * @param {boolean} enabled, default true
 * @param {string} policy, default ''
 */
const grantPrivilege = async (
  roleID,
  modelUID,
  route,
  enabled = true,
  policy = ""
) => {
  const service = strapi.plugin("users-permissions").service("role");

  const role = await service.findOne(roleID);

  const [modelID, modelName] = modelUID.split(".")

  _.set(role.permissions[modelID].controllers[modelName], route, { enabled, policy })

  return service.updateRole(roleID, role);
};

/** Updates database `permissions` that role can access an endpoint
 * @see grantPrivilege
 */

const grantPrivileges = async (roleID = 1, modelUID, routes = []) => {
  await Promise.all(routes.map((route) => grantPrivilege(roleID, modelUID, route)));
};

/* Usage:

  await grantPrivileges(user.role.id,
    "api::restaurant.restaurant",
    [
      'create'
    ]
  )
*/
1 Like