diff --git a/test/08-sbvrApi.test.ts b/test/08-sbvrApi.test.ts new file mode 100644 index 000000000..d87e9523d --- /dev/null +++ b/test/08-sbvrApi.test.ts @@ -0,0 +1,108 @@ +import supertest from 'supertest'; +import { expect } from 'chai'; +const configPath = __dirname + '/fixtures/08-sbvrApi/config.js'; +import { testInit, testDeInit, testLocalServer } from './lib/test-init'; +import { PineTest } from 'pinejs-client-supertest'; +import type { AnyObject } from 'pinejs-client-core'; + +describe('08 sbvrApi', function () { + let pineServer: Awaited>; + let pineTest: PineTest; + before(async () => { + pineServer = await testInit({ + configPath, + deleteDb: true, + exposeAuthEndpoints: true, + }); + pineTest = new PineTest({}, { app: testLocalServer }); + }); + + after(async () => { + testDeInit(pineServer); + }); + + describe('permissions.getUserPermissionsForRole', () => { + let guestId: number; + const testPermissions = ['test.permission1', 'test.permission2']; + before(async () => { + guestId = await getUserId('guest'); + const permissionIds = await createPermissions(testPermissions); + const roleId = await createRole('test', permissionIds); + await grantRoleToUser(roleId, guestId); + }); + + it(`should be able to get a specific user permissions`, async () => { + // pine API only exists on the process it is currently running. + // We use custom endpoints to expose the specific funcionality being tested + const response = await supertest(testLocalServer) + .get('/auth-test/getUserPermissionsForRole') + .send({ userId: guestId }); + expect(response.body).to.deep.equal([...testPermissions, 'resource.all']); + }); + + it(`should be an empty array if user does not exist`, async () => { + const response = await supertest(testLocalServer) + .get('/auth-test/getUserPermissions') + .send({ userId: 4242 }); + expect(response.body).to.deep.equal([]); + }); + }); + + const getUserId = async (username: string): Promise => { + const { + d: [{ id }], + } = await doAuthRequest('GET', 'user', { username }); + return id; + }; + + const createPermissions = async ( + permissionNames: string[], + ): Promise => { + return ( + await Promise.all( + permissionNames.map(async (permissionName) => + doAuthRequest('POST', 'permission', { name: permissionName }), + ), + ) + ).map((response) => response.id); + }; + + const createRole = async ( + roleName: string, + permissionIds: number[], + ): Promise => { + const { id: roleId } = await doAuthRequest('POST', 'role', { + name: roleName, + }); + await Promise.all( + permissionIds.map(async (permissionId) => + doAuthRequest('POST', 'role__has__permission', { + role: roleId, + permission: permissionId, + }), + ), + ); + + return roleId; + }; + + const grantRoleToUser = async (role: number, user: number) => { + await doAuthRequest('POST', 'user__has__role', { role, user }); + }; + + const doAuthRequest = async ( + method: 'GET' | 'POST', + resource: string, + body: AnyObject, + ) => { + return ( + await pineTest.request({ + apiPrefix: 'Auth/', + method, + resource, + body, + options: { returnResource: false }, + }) + ).body; + }; +}); diff --git a/test/fixtures/08-sbvrApi/basic.sbvr b/test/fixtures/08-sbvrApi/basic.sbvr new file mode 100644 index 000000000..be6f0ce6d --- /dev/null +++ b/test/fixtures/08-sbvrApi/basic.sbvr @@ -0,0 +1,4 @@ +Vocabulary: basic + +Term: name + Concept Type: Short Text (Type) diff --git a/test/fixtures/08-sbvrApi/config.ts b/test/fixtures/08-sbvrApi/config.ts new file mode 100644 index 000000000..ca3392003 --- /dev/null +++ b/test/fixtures/08-sbvrApi/config.ts @@ -0,0 +1,22 @@ +import type { ConfigLoader } from '../../../src/server-glue/module'; + +const apiRoot = 'basic'; +const modelName = 'basic'; +const modelFile = __dirname + '/basic.sbvr'; + +export default { + models: [ + { + modelName, + modelFile, + apiRoot, + }, + ], + users: [ + { + username: 'guest', + password: ' ', + permissions: ['resource.all'], + }, + ], +} as ConfigLoader.Config; diff --git a/test/lib/pine-in-process.ts b/test/lib/pine-in-process.ts index 981e5e155..108be9630 100644 --- a/test/lib/pine-in-process.ts +++ b/test/lib/pine-in-process.ts @@ -14,6 +14,7 @@ export async function forkInit() { processArgs.listenPort, processArgs.deleteDb, processArgs.withLoginRoute, + processArgs.exposeAuthEndpoints, ); // load hooks diff --git a/test/lib/pine-init.ts b/test/lib/pine-init.ts index 4c9450997..bd565f4f8 100644 --- a/test/lib/pine-init.ts +++ b/test/lib/pine-init.ts @@ -8,6 +8,7 @@ export type PineTestOptions = { hooksPath?: string; routesPath?: string; withLoginRoute?: boolean; + exposeAuthEndpoints?: boolean; deleteDb: boolean; listenPort: number; }; @@ -17,11 +18,27 @@ export async function init( initPort: number, deleteDb: boolean = false, withLoginRoute: boolean = false, + exposeAuthEndpoints: boolean = false, ) { const app = express(); app.use(express.urlencoded({ extended: true })); app.use(express.json()); + if (exposeAuthEndpoints) { + app.all('/Auth/*', pine.sbvrUtils.handleODataRequest); + + // pine object that can actually call the helper functions we want to test only exist on the server process + // in order to be able to invoke these functions (in a different process) and properly test we create a custom + // endpoint which allows us to execute the api function we are testing + app.get('/auth-test/getUserPermissions', async (req, res) => { + const body = req.body as { userId: number }; + const permissions = await pine.permissions.getUserPermissions( + body.userId, + ); + res.status(200).send(permissions); + }); + } + if (withLoginRoute) { /* eslint-disable @typescript-eslint/no-var-requires */ const expressSession: typeof ExpressSession = require('express-session'); diff --git a/test/lib/test-init.ts b/test/lib/test-init.ts index c4b0aea16..229cd6af1 100644 --- a/test/lib/test-init.ts +++ b/test/lib/test-init.ts @@ -17,6 +17,7 @@ export async function testInit( hooksPath: options.hooksPath, routesPath: options.routesPath, withLoginRoute: options.withLoginRoute, + exposeAuthEndpoints: options.exposeAuthEndpoints, }; const testServer = fork( __dirname + '/pine-in-process.ts',