Added test suites (#9)

This commit is contained in:
Ceferino Patino 2022-03-30 09:46:43 -05:00 committed by GitHub
commit 48899da2d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 36177 additions and 37327 deletions

View file

@ -1,7 +1,7 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
name: Build release assets
on:
push:
@ -16,19 +16,14 @@ jobs:
- uses: actions/checkout@v2
- name: Write .env to build
env:
BUILD_PATH: '${{ secrets.BUILD_PATH }}'
COURIER_AUTH_TOKEN: '${{ secrets.COURIER_AUTH_TOKEN }}'
NODE_ENV: '${{ secrets.NODE_ENV }}'
PORT: '${{ secrets.PORT }}'
REACT_APP_API_ROOT: '${{ secrets.REACT_APP_API_ROOT }}'
REACT_APP_DOMAIN_ROOT: '${{ secrets.REACT_APP_DOMAIN_ROOT }}'
DOTENV: '${{ secrets.DOTENV }}'
run: echo "$DOTENV" >> .env
- name: Write config.json to config
env:
CONFIG_JSON: '${{ secrets.CONFIG_JSON }}'
run: |
echo $BUILD_PATH > .env
echo $COURIER_AUTH_TOKEN >> .env
echo $NODE_ENV >> .env
echo $PORT >> .env
echo $REACT_APP_API_ROOT >> .env
echo $REACT_APP_DOMAIN_ROOT >> .env
mkdir ./server/config
echo "$CONFIG_JSON" >> ./server/config/config.json
- name: Use Node.js 16.x
uses: actions/setup-node@v2
with:

38
.github/workflows/test-build.yml vendored Normal file
View file

@ -0,0 +1,38 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Test build
on:
push:
branches: [development, main]
pull_request:
workflow_dispatch:
jobs:
test:
environment: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Write .env to build
env:
DOTENV: '${{ secrets.DOTENV }}'
run: echo "$DOTENV" >> .env
- name: Write config.json to config
env:
CONFIG_JSON: '${{ secrets.CONFIG_JSON }}'
run: |
mkdir ./server/config
echo "$CONFIG_JSON" >> ./server/config/config.json
- name: Use Node.js 16.x
uses: actions/setup-node@v2
with:
node-version: 16.x
- name: Install dependencies
run: npm ci
- name: Distribute environment file
run: npm run env
- name: Test build
run: npm run test

28651
client/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,7 @@
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.3",
"@testing-library/user-event": "^13.5.0",
"axios": "^0.26.0",
"axios": "^0.26.1",
"mic-recorder-to-mp3": "^2.2.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
@ -23,7 +23,8 @@
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"env": "cp ../.env .env"
},
"eslintConfig": {
"extends": [

View file

@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
import axios from 'axios';
@ -9,6 +9,7 @@ import Form from '../utils/Form';
function Register() {
const navigate = useNavigate();
const [params] = useSearchParams();
const [form, setForm] = useState({
firstName: '',
@ -34,10 +35,10 @@ function Register() {
const { confirmPassword, ...filteredForm } = form;
await axios
.post(
`${process.env.REACT_APP_API_ROOT}/auth/register`,
filteredForm
)
.post(`${process.env.REACT_APP_API_ROOT}/auth/register`, {
...filteredForm,
orgID: params.orgID,
})
.then(() => {
navigate('/login');
})

View file

@ -99,6 +99,12 @@ function OrgDashboard() {
navigator.clipboard.writeText(orgID);
}
function copyJoinLink() {
navigator.clipboard.writeText(
`${process.env.REACT_APP_DOMAIN_ROOT}/regsiter?orgID=${orgID}`
);
}
async function removeSelected() {
const doomedUserIDs = selection.map((row) => row.id);
@ -209,6 +215,12 @@ function OrgDashboard() {
>
Copy Org ID
</Button>
<Button
color='success'
onClick={copyJoinLink}
>
Copy Org Join Link
</Button>
<Button
color='error'
onClick={removeSelected}

33320
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,20 +1,26 @@
{
"name": "test-site",
"name": "know-it-all",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"client": "npm start --prefix client",
"server": "npm start --prefix server",
"build": "npm run env && npm run build --prefix client",
"test": "npm run build && npm run server",
"install-all": "npm ci && npm ci --prefix client && npm ci --prefix server",
"env": "cp .env ./server/.env && cp .env ./client/.env",
"client": "npm start -w client",
"server": "npm start -w server",
"build": "npm run build -w client",
"dev": "npm run server",
"dist": "npm run package",
"test": "npm run test -w server",
"env": "npm run env --ws && touch test_db.sqlite3",
"package": "tar -czf ./dist.tar.gz ./.github ./.vscode ./client ./node_modules ./server .env .gitignore LICENSE package-lock.json package.json README.md",
"dist": "npm run install-all && npm run build && npm run package"
"predev": "npm run build",
"predist": "npm ci && npm run build",
"prebuild": "npm run env"
},
"author": "C4 Patino",
"license": "ISC",
"workspaces": [
"*"
],
"dependencies": {
"create-react-app": "^5.0.0",
"dotenv": "^16.0.0",

View file

@ -15,7 +15,9 @@ var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
if (process.env.LOGGER == 'true') {
app.use(logger('dev'));
}
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

View file

@ -6,7 +6,7 @@
var app = require('../app');
var debug = require('debug')('server:server');
var http = require('http');
require('dotenv').config({ path: `../.env.${process.env.NODE_ENV}` });
require('dotenv').config();
var { sequelize } = require('../models/index');

View file

@ -25,7 +25,7 @@ async function GetOrg(req, res, next) {
if (!result.orgOwner && result.orgMember.length == 0) {
return res
.status(500)
.status(403)
.send('You do not know any organizations with this id.');
}

View file

@ -8,13 +8,12 @@ async function checkKnownUser(req, res, next) {
return next();
}
const result = await User.findOne({
where: { userID: user.userID },
const result = await User.findByPk(userID, {
include: [
{
association: 'ownedOrg',
include: {
association: 'orgMembers',
association: 'orgMember',
where: { userID: user.userID },
},
},
@ -22,7 +21,7 @@ async function checkKnownUser(req, res, next) {
association: 'memberOrgs',
include: [
{
association: 'orgMembers',
association: 'orgMember',
where: { userID: user.userID },
required: false,
},

7024
server/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,9 @@
"version": "0.0.0",
"private": true,
"scripts": {
"start": "nodemon ./bin/www"
"start": "nodemon ./bin/www",
"test": "jest -i --verbose --detectOpenHandles",
"env": "cp ../.env .env"
},
"dependencies": {
"@trycourier/courier": "^3.5.0",
@ -15,13 +17,17 @@
"formidable": "^2.0.1",
"http-errors": "~1.6.3",
"jade": "^0.29.0",
"morgan": "~1.9.1",
"morgan": "^1.10.0",
"mysql2": "^2.3.3",
"node-forge": "^1.2.1",
"nodemon": "^2.0.15",
"sequelize": "^6.17.0",
"sequelize-cli": "^6.4.1",
"sqlite3": "^5.0.2",
"uuid": "^8.3.2"
},
"devDependencies": {
"jest": "^27.5.1",
"nodemon": "^2.0.15",
"supertest": "^6.2.2"
}
}

View file

@ -1,5 +1,5 @@
const forge = require('node-forge');
const { User } = require('../../models/index');
const { User, Organization } = require('../../models/index');
async function CreateUser(req, res, next) {
const body = req.body;
@ -18,19 +18,51 @@ async function CreateUser(req, res, next) {
return res.status(500).send('A user with that email already exists.');
}
try {
const passwordHash = forge.md.sha512
.create()
.update(body.password)
.digest()
.toHex();
const result = await User.create({ ...body, password: passwordHash });
const passwordHash = forge.md.sha512
.create()
.update(body.password)
.digest()
.toHex();
return res.send(result);
} catch (e) {
console.log(e);
if (body.orgID) {
try {
const org = await Organization.findByPk(body.orgID);
return res.status(500).send('Whoops, something went wrong!');
if (!org) {
const result = await User.create({
...body,
password: passwordHash,
});
return res.send(result);
}
const { orgID, ...filteredBody } = body;
const result = await org.createOrgMember({
...filteredBody,
password: passwordHash,
});
return res.send({ user: result, orgID });
} catch (e) {
console.log(e);
return res.status(500).send('Whoops, something went wrong!');
}
} else {
try {
const result = await User.create({
...body,
password: passwordHash,
});
return res.send(result);
} catch (e) {
console.log(e);
return res.status(500).send('Whoops, something went wrong!');
}
}
}

View file

@ -7,14 +7,16 @@ async function RequestReset(req, res, next) {
try {
const email = req.query.email;
if (!email) {
return res.status(500).send('Request missing required fields');
return res.status(400).send('Request missing required fields');
}
const result = await User.findOne({ where: { email: email } });
if (!result) {
return res.status(400).send('Whoops something went wrong');
return res.status(500).send('Whoops something went wrong');
}
console.log(process.env.COURIER_AUTH_TOKEN);
const courier = CourierClient({
authorizationToken: process.env.COURIER_AUTH_TOKEN,
});
@ -34,8 +36,6 @@ async function RequestReset(req, res, next) {
},
});
console.log(`${resetRequest.reqID}`);
return res.send(
'Password reset request sent. If a user exists with this email, an email will be sent with the required information.'
);

View file

@ -13,7 +13,7 @@ async function ResetPassword(req, res, next) {
if (!result) {
return res
.status(404)
.status(500)
.send('A reset request with this ID does not exist');
}

View file

@ -16,7 +16,7 @@ async function UpdateUserDetails(req, res, next) {
if (result) {
return res
.status(400)
.status(500)
.send('A user with that email already exists.');
}
}

View file

@ -7,7 +7,7 @@ async function AddOrgMember(req, res, next) {
const result = await Organization.findByPk(orgID);
if (!result) {
return res.status(500).send('No organization exists with that id.');
return res.status(404).send('No organization exists with that id.');
}
await result.addOrgMember(user.userID);

View file

@ -12,9 +12,7 @@ async function CreateOrg(req, res, next) {
if (existing > 0) {
return res
.status(500)
.send(
'This user already has an organization with this name, please pick another.'
);
.send('This user already has an organization with this name.');
}
const org = await user.createOwnedOrg({

View file

@ -1,9 +1,16 @@
const { Organization } = require('../../models/index');
async function DeleteOrg(req, res, next) {
const user = req.user;
const orgID = req.query.orgID;
await Organization.destroy({ where: { orgID: orgID } });
if (!orgID) {
return res.status(400).send('Form missing required fields');
}
await Organization.destroy({
where: { orgID: orgID, ownerID: user.userID },
});
return res.send('Organization deleted');
}

View file

@ -1,4 +1,4 @@
const { User, Organization } = require('../../models/index');
const { Organization } = require('../../models/index');
async function GetOrg(req, res, next) {
const user = req.user;

View file

@ -17,9 +17,11 @@ async function RemoveOrgMember(req, res, next) {
await result.removeOrgMember(user.userID);
} else {
if (user.userID == result.orgOwner.userID) {
await result.removeOrgMembers(doomedUserIDs);
await result.removeOrgMember(doomedUserIDs);
} else {
res.status(403).send('You do not have permission to do that.');
return res
.status(403)
.send('You do not have permission to do that.');
}
}

View file

@ -10,12 +10,14 @@ async function UpdateOrgDetails(req, res, next) {
const result = await user.getOwnedOrg({ where: { orgID: orgID } });
if (result.length < 1) {
return res.status(400).send('No organzation with that ID exists.');
return res
.status(500)
.send('You do not own an organization with that id.');
}
result[0].update({ orgName: orgName });
return res.send(result);
return res.send(result[0]);
}
module.exports = UpdateOrgDetails;

View file

@ -0,0 +1,129 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize, Organization } = require('../../models/index');
const app = require('../../app');
const { createTestUser, createTestOrg } = require('../utils');
describe('CreateUser', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] User successfully created', async () => {
const user = {
firstName: 'Test',
lastName: 'User',
email: 'test.user@test.com',
pronouns: 'they/them',
};
const password = 'password';
await supertest(app)
.post('/api/auth/register')
.send({ ...user, password })
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then((response) => {
expect(response.body).toEqual(expect.objectContaining(user));
});
});
test('[500] Request missing fields', async () => {
await supertest(app)
.post('/api/auth/register')
.send()
.expect(400, 'The request is missing required fields.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[500] User already exists', async () => {
await createTestUser('Test', 'User', 'password');
const userInfo = {
firstName: 'Test',
lastName: 'User',
email: 'test.user@test.com',
pronouns: 'they/them',
password: 'password',
};
await supertest(app)
.post('/api/auth/register')
.send(userInfo)
.expect(500, 'A user with that email already exists.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[200] Created with organization', async () => {
const orgOwner = {
firstName: 'Org',
lastName: 'Owner',
password: 'password',
};
const org = await createTestOrg('Test Org', orgOwner);
const user = {
firstName: 'Test',
lastName: 'User',
email: 'test.user@test.com',
pronouns: 'they/them',
};
const password = 'password';
await supertest(app)
.post(`/api/auth/register`)
.send({ ...user, password, orgID: org.orgID })
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then(async (response) => {
const org = await Organization.findByPk(response.body.orgID, {
include: {
association: 'orgMember',
},
});
expect(response.body.user).toEqual(
expect.objectContaining(user)
);
expect(org.orgMember).toEqual(
expect.arrayContaining([expect.objectContaining(user)])
);
});
});
test('[200] Attemped to create with organization', async () => {
const orgOwner = {
firstName: 'Org',
lastName: 'Owner',
password: 'password',
};
await createTestOrg('Test Org', orgOwner);
const user = {
firstName: 'Test',
lastName: 'User',
email: 'test.user@test.com',
pronouns: 'they/them',
};
const password = 'password';
await supertest(app)
.post(`/api/auth/register`)
.send({ ...user, password, orgID: 'randomString' })
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then(async (response) => {
expect(response.body).toEqual(expect.objectContaining(user));
});
});
});

View file

@ -0,0 +1,66 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize } = require('../../models/index');
const app = require('../../app');
const { createTestOrg, createTestUser } = require('../utils');
describe('GetOwnedOrgs', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Retrieved joined orgs', async () => {
var org = await createTestOrg('Test Org', {
firstName: 'Test',
lastName: 'User',
password: 'password',
});
const user = await createTestUser('New', 'User', 'password');
const token = await user.createToken({ expires: true });
await user.addMemberOrg(org.orgID);
await supertest(app)
.get('/api/auth/orgs')
.query({ token: token.tokenID })
.send()
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then((response) => {
const data = {
orgID: org.orgID,
ownerID: org.ownerID,
orgName: org.orgName,
};
expect(response.body).toEqual(
expect.arrayContaining([expect.objectContaining(data)])
);
});
});
test('[403] Missing token', async () => {
await supertest(app)
.get('/api/auth/orgs')
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
await supertest(app)
.get('/api/auth/orgs')
.query({ token: 'randomString' })
.send()
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,61 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize, Token } = require('../../models/index');
const app = require('../../app');
const { createTestUser } = require('../utils');
describe('GetOwnedOrgs', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Retrieved owned orgs', async () => {
const user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken({ expires: true });
var org = await user.createOwnedOrg({ orgName: 'Org' });
await supertest(app)
.get('/api/auth')
.query({ token: token.tokenID })
.send()
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then((response) => {
const data = {
orgID: org.orgID,
ownerID: org.ownerID,
orgName: org.orgName,
};
expect(response.body).toEqual(
expect.arrayContaining([expect.objectContaining(data)])
);
});
});
test('[403] Missing token', async () => {
await supertest(app)
.get('/api/auth')
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
await supertest(app)
.get('/api/auth')
.query({ token: 'randomString' })
.send()
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,109 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize, Token } = require('../../models/index');
const app = require('../../app');
const { createTestToken, createTestUser } = require('../utils');
describe('GetUserDetails', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Successfully recieved user details', async () => {
const token = await createTestToken({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.get(`/api/auth/${token.userID}`)
.query({
token: token.tokenID,
})
.send()
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then((response) => {
expect(response.body).toEqual(
expect.objectContaining({
firstName: 'Test',
lastName: 'User',
email: 'test.user@test.com',
})
);
});
});
test('[500] User ID does not exist', async () => {
const token = await createTestToken({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.get(`/api/auth/randomString`)
.query({ token: token.tokenID })
.send()
.expect(500, 'No user with that ID exists.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] No contact with that user', async () => {
const token = await createTestToken({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
const user = await createTestUser('New', 'User', 'password');
await supertest(app)
.get(`/api/auth/${user.userID}`)
.query({ token: token.tokenID })
.send()
.expect(403, 'You do not have contact with this user.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] Missing token', async () => {
const token = await createTestToken({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.get(`/api/auth/${token.userID}`)
.query()
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
const token = await createTestToken({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.get(`/api/auth/${token.userID}`)
.query({ token: 'randomString' })
.send()
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,56 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize, Token } = require('../../models/index');
const app = require('../../app');
const { createTestUser } = require('../utils');
describe('Login', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Successful login', async () => {
const password = 'password';
const user = await createTestUser('Test', 'User', password);
await supertest(app)
.post('/api/auth/login')
.send({ email: user.email, password })
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then(async (response) => {
const token = await Token.findByPk(response.body.token);
expect(response.body.token).toEqual(token.tokenID);
expect(response.body.userID).toEqual(token.userID);
});
});
test('[400] Request missing fields', async () => {
await supertest(app)
.post('/api/auth/login')
.send()
.expect(400, 'Request lacking information')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[400] Invalid password', async () => {
const password = 'password';
const user = await createTestUser('Test', 'User', password);
await supertest(app)
.post('/api/auth/login')
.send({ email: user.email, password: 'randomString' })
.expect(400, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,50 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize, Token } = require('../../models/index');
const app = require('../../app');
const { createTestToken } = require('../utils');
describe('Logout', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Successful logout', async () => {
const token = await createTestToken({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.post('/api/auth/logout')
.send({ token: token.tokenID })
.expect(200, 'User logged out')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] Missing token', async () => {
await supertest(app)
.post('/api/auth/logout')
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
await supertest(app)
.post('/api/auth/logout')
.send({ token: 'randomString' })
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,53 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize } = require('../../models/index');
const app = require('../../app');
const { createTestUser } = require('../utils');
describe('Logout', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Successful reset request', async () => {
const user = await createTestUser('Test', 'User', 'password');
await supertest(app)
.get('/api/auth/reset-password')
.query({ email: user.email })
.send()
.expect(
200,
'Password reset request sent. If a user exists with this email, an email will be sent with the required information.'
)
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[400] Request missing email', async () => {
await supertest(app)
.get('/api/auth/reset-password')
.send()
.expect(400, 'Request missing required fields')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[500] No user with email', async () => {
await createTestUser('Test', 'User', 'password');
await supertest(app)
.get('/api/auth/reset-password')
.query({ email: 'randomString' })
.send()
.expect(500, 'Whoops something went wrong')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,60 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize } = require('../../models/index');
const app = require('../../app');
const { createTestResetRequest } = require('../utils');
describe('ResetPassword', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Successful reset password', async () => {
const resetRequest = await createTestResetRequest({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.patch(`/api/auth/reset-password/${resetRequest.reqID}`)
.send({
password: 'newPassword',
})
.expect(200, 'Your password has been changed')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[400] Missing password', async () => {
const resetRequest = await createTestResetRequest({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.patch(`/api/auth/reset-password/${resetRequest.reqID}`)
.send()
.expect(400, 'Form missing required information.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[500] Reset request does not exist', async () => {
await supertest(app)
.patch(`/api/auth/reset-password/randomString`)
.send({
password: 'newPassword',
})
.expect(500, 'A reset request with this ID does not exist')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,34 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize } = require('../../models/index');
const app = require('../../app');
describe('SetAudio', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[403] Missing token', async () => {
await supertest(app)
.post('/api/auth/logout')
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
await supertest(app)
.post('/api/auth/logout')
.send({ token: 'randomString' })
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,82 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize } = require('../../models/index');
const app = require('../../app');
const { createTestToken, createTestUser } = require('../utils');
describe('UpdateUserDetails', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Successfully changed user details', async () => {
const token = await createTestToken({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.patch('/api/auth/update')
.send({
firstName: 'New',
lastName: 'User',
email: 'new.user@test.com',
token: token.tokenID,
})
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then(async (response) => {
expect(response.body).toEqual(
expect.objectContaining({
firstName: 'New',
lastName: 'User',
email: 'new.user@test.com',
})
);
});
});
test('[500] Pre-existing user with email', async () => {
const token = await createTestToken({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await createTestUser('New', 'User', 'password');
await supertest(app)
.patch('/api/auth/update')
.send({
email: 'new.user@test.com',
token: token.tokenID,
})
.expect(500, 'A user with that email already exists.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] Missing token', async () => {
await supertest(app)
.patch('/api/auth/update')
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
await supertest(app)
.patch('/api/auth/update')
.send({ token: 'randomString' })
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,76 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize } = require('../../models/index');
const app = require('../../app');
const { createTestOrg, createTestUser, createTestToken } = require('../utils');
describe('AddOrgMember', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] User added to organization', async () => {
var org = await createTestOrg('Org', {
firstName: 'New',
lastName: 'User',
password: 'password',
});
var user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
await supertest(app)
.post(`/api/org/${org.orgID}/add`)
.send({ token: token.tokenID })
.expect(200, 'User added to organization.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/)
.then(async () => {
const members = await org.getOrgMember();
expect(members).toEqual(
expect.arrayContaining([
expect.objectContaining(user.dataValues),
])
);
});
});
test('[404] Organization not found', async () => {
const token = await createTestToken({
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.post(`/api/org/randomString/add`)
.send({ token: token.tokenID })
.expect(404, 'No organization exists with that id.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] Missing token', async () => {
await supertest(app)
.post('/api/auth/logout')
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
await supertest(app)
.post('/api/auth/logout')
.send({ token: 'randomString' })
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,87 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize, Token } = require('../../models/index');
const app = require('../../app');
const { createTestUser } = require('../utils');
describe('GetOwnedOrgs', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Organization created', async () => {
var user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
await supertest(app)
.post('/api/org/create')
.send({ token: token.tokenID, orgName: 'Org' })
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then((response) => {
expect(response.body).toEqual(
expect.objectContaining({
ownerID: user.userID,
orgName: 'Org',
})
);
});
});
test('[400] Form missing orgName', async () => {
var user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
await supertest(app)
.post('/api/org/create')
.send({ token: token.tokenID })
.expect(400, 'Form missing necessary fields')
.set('Accept', 'text/html')
.expect('Content-Type', /html/);
});
test('[500] Pre-existing organization with that name', async () => {
var user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
await user.createOwnedOrg({
orgName: 'Org',
});
await supertest(app)
.post('/api/org/create')
.send({ token: token.tokenID, orgName: 'Org' })
.expect(
500,
'This user already has an organization with this name.'
)
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] Missing token', async () => {
await supertest(app)
.post('/api/org/create')
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
await supertest(app)
.post('/api/org/create')
.send({
token: 'randomString',
})
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,124 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize, Organization } = require('../../models/index');
const app = require('../../app');
const { createTestUser, createTestOrg } = require('../utils');
describe('GetOwnedOrgs', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Organization deleted', async () => {
const user = await createTestUser('Test', 'User', 'password');
var org = await user.createOwnedOrg({
orgName: 'Org',
});
const token = await user.createToken();
await supertest(app)
.delete('/api/org/delete')
.query({
token: token.tokenID,
orgID: org.orgID,
})
.send()
.expect(200, 'Organization deleted')
.set('Accept', 'text/html')
.expect('Content-Type', /text/)
.then(async () => {
const data = await Organization.findByPk(org.orgID);
expect(data).toEqual(null);
});
});
test('[200] No organization deleted with that ID', async () => {
const user = await createTestUser('Test', 'User', 'password');
var org = await user.createOwnedOrg({
orgName: 'Org',
});
const token = await user.createToken();
await supertest(app)
.delete('/api/org/delete')
.query({
token: token.tokenID,
orgID: 'randomString',
})
.send()
.expect(200, 'Organization deleted')
.set('Accept', 'text/html')
.expect('Content-Type', /text/)
.then(async () => {
const data = await Organization.findByPk(org.orgID);
expect(data.dataValues).toEqual(org.dataValues);
});
});
test('[200] Organization not owned by that user', async () => {
const user = await createTestUser('Test', 'User', 'password');
const newUser = await createTestUser('New', 'User', 'password');
var org = await user.createOwnedOrg({
orgName: 'Org',
});
const token = await newUser.createToken();
await supertest(app)
.delete('/api/org/delete')
.query({
token: token.tokenID,
orgID: 'randomString',
})
.send()
.expect(200, 'Organization deleted')
.set('Accept', 'text/html')
.expect('Content-Type', /text/)
.then(async () => {
const data = await Organization.findByPk(org.orgID);
expect(data.dataValues).toEqual(org.dataValues);
});
});
test('[400] No orgID provided', async () => {
const user = await createTestUser('Test', 'User', 'password');
const newUser = await createTestUser('New', 'User', 'password');
const token = await newUser.createToken();
await supertest(app)
.delete('/api/org/delete')
.query({
token: token.tokenID,
})
.send()
.expect(400, 'Form missing required fields')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] Missing token', async () => {
await supertest(app)
.delete('/api/org/delete')
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
await supertest(app)
.delete('/api/org/delete')
.query({
token: 'randomString',
})
.send()
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,118 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize, Organization } = require('../../models/index');
const app = require('../../app');
const { createTestUser, createTestOrg } = require('../utils');
describe('GetOwnedOrgs', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Organization retrieved', async () => {
const user = await createTestUser('Test', 'User', 'password');
const org = await user.createOwnedOrg({
orgName: 'Org',
});
const token = await user.createToken();
await supertest(app)
.get(`/api/org/${org.orgID}`)
.query({ token: token.tokenID })
.send()
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then((response) => {
const orgData = {
orgName: org.orgName,
orgID: org.orgID,
ownerID: org.ownerID,
};
const userData = {
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
};
expect(response.body).toEqual(
expect.objectContaining({
org: expect.objectContaining(orgData),
status: true,
})
);
expect(response.body.org.orgOwner).toEqual(
expect.objectContaining(userData)
);
});
});
test('[500] No organization with that id', async () => {
const user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
await supertest(app)
.get(`/api/org/randomString`)
.query({ token: token.tokenID })
.send()
.expect(500, 'There is no organization with this id.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[500] Unknown organization queried', async () => {
const org = await createTestOrg('Org', {
firstName: 'New',
lastName: 'User',
password: 'password',
});
const user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
await supertest(app)
.get(`/api/org/${org.orgID}`)
.query({ token: token.tokenID })
.send()
.expect(403, 'You do not know any organizations with this id.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] Missing token', async () => {
const user = await createTestUser('Test', 'User', 'password');
const org = await user.createOwnedOrg({
orgName: 'Org',
});
await supertest(app)
.get(`/api/org/${org.orgID}`)
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
const user = await createTestUser('Test', 'User', 'password');
const org = await user.createOwnedOrg({
orgName: 'Org',
});
await supertest(app)
.get(`/api/org/${org.orgID}`)
.query({
token: 'randomString',
})
.send()
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,122 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize } = require('../../models/index');
const app = require('../../app');
const { createTestUser, createTestOrg } = require('../utils');
describe('GetOwnedOrgs', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] User removed from organization', async () => {
const user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
const org = await user.createOwnedOrg({
orgName: 'Org',
});
const newUser = await createTestUser('New', 'User', 'password');
await org.addOrgMember(newUser.userID);
await supertest(app)
.post(`/api/org/${org.orgID}/delete`)
.send({
token: token.tokenID,
doomedUsers: [newUser.userID],
})
.expect(200, 'User(s) removed from organization.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/)
.then(async () => {
const data = await org.getOrgMember();
expect(data).toEqual(
expect.not.arrayContaining([
expect.objectContaining(user.dataValues),
])
);
});
});
test('[500] Organization does not exist', async () => {
const user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
const org = await user.createOwnedOrg({
orgName: 'Org',
});
const newUser = await createTestUser('New', 'User', 'password');
await org.addOrgMember(newUser.userID);
await supertest(app)
.post(`/api/org/randomString/delete`)
.send({
token: token.tokenID,
doomedUsers: [newUser.userID],
})
.expect(500, 'No organization exists with that id.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] Insufficient permissions', async () => {
const org = await createTestOrg('Org', {
firstName: 'Test',
lastName: 'User',
password: 'password',
});
const user = await createTestUser('New', 'User', 'password');
const token = await user.createToken();
await org.addOrgMember(user.userID);
await supertest(app)
.post(`/api/org/${org.orgID}/delete`)
.send({
token: token.tokenID,
doomedUsers: [user.userID],
})
.expect(403, 'You do not have permission to do that.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] Missing token', async () => {
const org = await createTestOrg('Org', {
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.post(`/api/org/${org.orgID}/delete`)
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
const org = await createTestOrg('Org', {
firstName: 'Test',
lastName: 'User',
password: 'password',
});
await supertest(app)
.post(`/api/org/${org.orgID}/delete`)
.send({
token: 'randomString',
})
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

View file

@ -0,0 +1,101 @@
require('dotenv').config();
const supertest = require('supertest');
var { sequelize, Organization } = require('../../models/index');
const app = require('../../app');
const { createTestUser, createTestOrg, createTestToken } = require('../utils');
describe('GetOwnedOrgs', function () {
beforeEach(async () => {
try {
await sequelize.authenticate();
await sequelize.sync({ force: 'true' });
} catch (error) {
console.log('[ERROR]: Database connection failed');
}
});
test('[200] Successfully changed org name', async () => {
const user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
const org = await user.createOwnedOrg({
orgName: 'Org',
});
await supertest(app)
.patch('/api/org/update')
.send({
token: token.tokenID,
orgID: org.orgID,
orgName: 'New Name',
})
.expect(200)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.then((response) => {
const data = {
orgName: 'New Name',
orgID: org.orgID,
ownerID: org.ownerID,
};
expect(response.body).toEqual(expect.objectContaining(data));
});
});
test('[400] Form missing information', async () => {
const user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
const org = await user.createOwnedOrg({
orgName: 'Org',
});
await supertest(app)
.patch('/api/org/update')
.send({
token: token.tokenID,
})
.expect(400, 'Form missing required information.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[500] No organization exists with that id', async () => {
const user = await createTestUser('Test', 'User', 'password');
const token = await user.createToken();
const org = await user.createOwnedOrg({
orgName: 'Org',
});
await supertest(app)
.patch('/api/org/update')
.send({
token: token.tokenID,
orgID: 'randomString',
orgName: 'New Name',
})
.expect(500, 'You do not own an organization with that id.')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[403] Missing token', async () => {
await supertest(app)
.patch('/api/org/update')
.send()
.expect(403, 'Unauthorized user')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
test('[511] Token was not found', async () => {
await supertest(app)
.patch('/api/org/update')
.send({
token: 'randomString',
})
.expect(511, 'Session expired')
.set('Accept', 'text/html')
.expect('Content-Type', /text/);
});
});

68
server/tests/utils.js Normal file
View file

@ -0,0 +1,68 @@
const forge = require('node-forge');
const { User, Organization } = require('../models/index');
async function createTestUser(firstName, lastName, password) {
const hashedPassword = forge.md.sha512
.create()
.update(password)
.digest()
.toHex();
const userInfo = {
firstName: firstName,
lastName: lastName,
email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@test.com`,
pronouns: 'they/them',
password: hashedPassword,
};
return await User.create(userInfo);
}
async function createTestOrg(orgName, owner) {
const hashedPassword = forge.md.sha512
.create()
.update(owner.password)
.digest()
.toHex();
const userInfo = {
...owner,
email: `${owner.firstName.toLowerCase()}.${owner.lastName.toLowerCase()}@test.com`,
pronouns: 'they/them',
password: hashedPassword,
};
const user = await User.create(userInfo);
const org = await user.createOwnedOrg({ orgName });
return org;
}
async function createTestToken(owner) {
const user = await createTestUser(
owner.firstName,
owner.lastName,
owner.password
);
return await user.createToken({
userID: user.userID,
expires: true,
});
}
async function createTestResetRequest(owner) {
const user = await createTestUser(
owner.firstName,
owner.lastName,
owner.password
);
return await user.createResetRequest({
userID: user.userID,
});
}
module.exports = {
createTestUser,
createTestOrg,
createTestToken,
createTestResetRequest,
};