From 60f2b345671887046c163b80fcfa558b2a4be859 Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Tue, 2 Nov 2021 20:44:16 +0500 Subject: [PATCH] test(user): added specs for admin action to create user --- .github/workflows/build.yml | 3 + src/routes/api/auth.ts | 2 +- src/routes/api/spec/auth.spec.ts | 17 +--- src/routes/api/spec/drive.spec.ts | 9 ++ src/routes/api/spec/user.spec.ts | 154 ++++++++++++++++++++++++++++++ src/routes/api/user.ts | 4 +- 6 files changed, 172 insertions(+), 17 deletions(-) create mode 100644 src/routes/api/spec/user.spec.ts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1471e29..a73b8e3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,3 +28,6 @@ jobs: run: npm run package:lib env: CI: true + ACCESS_TOKEN_SECRET: ${{secrets.ACCESS_TOKEN_SECRET}} + REFRESH_TOKEN_SECRET: ${{secrets.REFRESH_TOKEN_SECRET}} + AUTH_CODE_SECRET: ${{secrets.AUTH_CODE_SECRET}} diff --git a/src/routes/api/auth.ts b/src/routes/api/auth.ts index c2a738c..10070b1 100644 --- a/src/routes/api/auth.ts +++ b/src/routes/api/auth.ts @@ -120,7 +120,7 @@ authRouter.delete('/logout', (req, res) => { res.sendStatus(204) }) -const generateAccessToken = (data: InfoJWT) => +export const generateAccessToken = (data: InfoJWT) => jwt.sign(data, process.env.ACCESS_TOKEN_SECRET as string, { expiresIn: '1day' }) diff --git a/src/routes/api/spec/auth.spec.ts b/src/routes/api/spec/auth.spec.ts index f86f063..6fe80ce 100644 --- a/src/routes/api/spec/auth.spec.ts +++ b/src/routes/api/spec/auth.spec.ts @@ -11,13 +11,6 @@ const client = { clientid: 'someclientID', clientsecret: 'someclientSecret' } -// const adminUser = { -// displayname: 'Test Admin', -// username: 'testAdminUsername', -// password: '12345678', -// isadmin: true, -// isactive: true -// } const user = { displayname: 'Test User', username: 'testUsername', @@ -38,13 +31,9 @@ describe('auth', () => { }) afterAll(async () => { - if (con) { - await con.connection.dropDatabase() - await con.connection.close() - } - if (mongoServer) { - await mongoServer.stop() - } + await con.connection.dropDatabase() + await con.connection.close() + await mongoServer.stop() }) describe('authorize', () => { diff --git a/src/routes/api/spec/drive.spec.ts b/src/routes/api/spec/drive.spec.ts index 191db5b..78f723e 100644 --- a/src/routes/api/spec/drive.spec.ts +++ b/src/routes/api/spec/drive.spec.ts @@ -4,12 +4,20 @@ import { getTreeExample } from '../../../controllers/deploy' import { getTmpFilesFolderPath } from '../../../utils/file' import { folderExists, fileExists, readFile, deleteFolder } from '@sasjs/utils' import path from 'path' +import { generateAccessToken } from '../auth' describe('files', () => { + const accessToken = generateAccessToken({ + client_id: 'someClientID', + username: 'username', + isadmin: false, + isactive: true + }) describe('deploy', () => { const shouldFailAssertion = async (payload: any) => { const res = await request(app) .post('/SASjsApi/drive/deploy') + .auth(accessToken, { type: 'bearer' }) .send(payload) expect(res.statusCode).toEqual(400) @@ -79,6 +87,7 @@ describe('files', () => { it('should respond with payload example if valid payload was not provided', async () => { const res = await request(app) .post('/SASjsApi/drive/deploy') + .auth(accessToken, { type: 'bearer' }) .send({ fileTree: getTreeExample() }) expect(res.statusCode).toEqual(200) diff --git a/src/routes/api/spec/user.spec.ts b/src/routes/api/spec/user.spec.ts new file mode 100644 index 0000000..d0e6d1c --- /dev/null +++ b/src/routes/api/spec/user.spec.ts @@ -0,0 +1,154 @@ +import mongoose, { Mongoose } from 'mongoose' +import { MongoMemoryServer } from 'mongodb-memory-server' +import request from 'supertest' +import app from '../../../app' +import { createUser } from '../../../controllers/createUser' +import { createClient } from '../../../controllers/createClient' +import { generateAccessToken, populateClients } from '../auth' +import { InfoJWT } from '../../../types' + +const client = { + clientid: 'someclientID', + clientsecret: 'someclientSecret' +} +const adminUser = { + displayname: 'Test Admin', + username: 'testAdminUsername', + password: '12345678', + isadmin: true, + isactive: true +} +const user = { + displayname: 'Test User', + username: 'testUsername', + password: '87654321', + isadmin: false, + isactive: true +} + +describe('user', () => { + let con: Mongoose + let mongoServer: MongoMemoryServer + + beforeAll(async () => { + mongoServer = await MongoMemoryServer.create() + con = await mongoose.connect(mongoServer.getUri()) + }) + + afterAll(async () => { + await con.connection.dropDatabase() + await con.connection.close() + await mongoServer.stop() + }) + + describe('create', () => { + const adminAccessToken = generateAccessToken({ + client_id: client.clientid, + username: adminUser.username, + isadmin: adminUser.isadmin, + isactive: adminUser.isactive + }) + + afterEach(async () => { + const collections = mongoose.connection.collections + const collection = collections['users'] + await collection.deleteMany({}) + }) + + it('should respond with new user', async () => { + const res = await request(app) + .post('/SASjsApi/user') + .auth(adminAccessToken, { type: 'bearer' }) + .send(user) + .expect(200) + + expect(res.body.username).toEqual(user.username) + expect(res.body.displayname).toEqual(user.displayname) + expect(res.body.isadmin).toEqual(user.isadmin) + expect(res.body.isactive).toEqual(user.isactive) + }) + + it('should respond with Unauthorized if access token is not present', async () => { + const res = await request(app) + .post('/SASjsApi/user') + .send(user) + .expect(401) + + expect(res.text).toEqual('Unauthorized') + expect(res.body).toEqual({}) + }) + + it('should respond with Forbideen if access token is not of an admin account', async () => { + const accessToken = generateAccessToken({ + client_id: client.clientid, + username: user.username, + isadmin: user.isadmin, + isactive: user.isactive + }) + + const res = await request(app) + .post('/SASjsApi/user') + .auth(accessToken, { type: 'bearer' }) + .send(user) + .expect(403) + + expect(res.text).toEqual('Admin account required') + expect(res.body).toEqual({}) + }) + + it('should respond with Forbidden if username is already present', async () => { + await createUser(user) + + const res = await request(app) + .post('/SASjsApi/user') + .auth(adminAccessToken, { type: 'bearer' }) + .send(user) + .expect(403) + + expect(res.text).toEqual('Error: Username already exists.') + expect(res.body).toEqual({}) + }) + + it('should respond with Bad Request if username is missing', async () => { + const res = await request(app) + .post('/SASjsApi/user') + .auth(adminAccessToken, { type: 'bearer' }) + .send({ + ...user, + username: undefined + }) + .expect(400) + + expect(res.text).toEqual(`"username" is required`) + expect(res.body).toEqual({}) + }) + + it('should respond with Bad Request if password is missing', async () => { + const res = await request(app) + .post('/SASjsApi/user') + .auth(adminAccessToken, { type: 'bearer' }) + .send({ + ...user, + password: undefined + }) + .expect(400) + + expect(res.text).toEqual(`"password" is required`) + expect(res.body).toEqual({}) + }) + + it('should respond with Bad Request if displayname is missing', async () => { + const res = await request(app) + .post('/SASjsApi/user') + .auth(adminAccessToken, { type: 'bearer' }) + .send({ + ...user, + displayname: undefined + }) + .expect(400) + + expect(res.text).toEqual(`"displayname" is required`) + expect(res.body).toEqual({}) + }) + }) +}) diff --git a/src/routes/api/user.ts b/src/routes/api/user.ts index 78bcb56..0e33dec 100644 --- a/src/routes/api/user.ts +++ b/src/routes/api/user.ts @@ -16,8 +16,8 @@ userRouter.post('/', async (req, res) => { isadmin: savedUser.isadmin, isactive: savedUser.isactive }) - } catch (err) { - res.status(400).send(err) + } catch (err: any) { + res.status(403).send(err.toString()) } })