mirror of
https://github.com/Discreetly/server.git
synced 2026-01-07 19:53:55 -05:00
feature(jest) writing tests for express endpoints
This commit is contained in:
9
jest.config.cjs
Normal file
9
jest.config.cjs
Normal file
@@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
"transform": {
|
||||
"^.+\\.jsx?$": "babel-jest",
|
||||
"^.+\\.tsx?$": ["ts-jest", { tsconfig: "./tsconfig.tests.json" }]
|
||||
},
|
||||
}
|
||||
5767
package-lock.json
generated
5767
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -11,7 +11,8 @@
|
||||
"start": "node dist/server.cjs",
|
||||
"watch": "rollup --config rollup.config.mjs --watch",
|
||||
"serve": "nodemon -q dist/server.jcs",
|
||||
"dev": "concurrently \"npm run watch\" \"npm run serve\""
|
||||
"dev": "concurrently \"npm run watch\" \"npm run serve\"",
|
||||
"test": "jest --watch --verbose"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18.x.x"
|
||||
@@ -41,23 +42,36 @@
|
||||
"socket.io": "^4.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.22.9",
|
||||
"@babel/preset-env": "^7.22.9",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@jest/globals": "^29.6.2",
|
||||
"@rollup/plugin-commonjs": "^25.0.2",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.1.0",
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.5.3",
|
||||
"@types/node": "^20.4.5",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^6.2.0",
|
||||
"@typescript-eslint/parser": "^6.2.0",
|
||||
"babel-jest": "^29.6.2",
|
||||
"concurrently": "^8.2.0",
|
||||
"eslint": "^8.45.0",
|
||||
"jest": "^29.6.2",
|
||||
"jest-mock-extended": "^3.0.4",
|
||||
"nodemon": "^3.0.1",
|
||||
"prisma": "^5.0.0",
|
||||
"rollup": "^3.26.2",
|
||||
"rollup-plugin-cleaner": "^1.0.0",
|
||||
"rollup-plugin-include-sourcemaps": "^0.7.0",
|
||||
"rollup-plugin-typescript2": "^0.35.0",
|
||||
"supertest": "^6.3.3",
|
||||
"ts-jest": "^29.1.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.6"
|
||||
"typescript": "^5.1.6",
|
||||
"vitest": "^0.34.1",
|
||||
"vitest-mock-extended": "^1.1.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { MessageI, RoomI } from 'discreetly-interfaces';
|
||||
import { str2BigInt } from 'discreetly-interfaces';
|
||||
import { RLNVerifier } from 'rlnjs';
|
||||
import vkey from './verification_key.js';
|
||||
import vkey from './verification_key'
|
||||
import { Group } from '@semaphore-protocol/group';
|
||||
|
||||
const v = new RLNVerifier(vkey);
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { RoomI, genId } from 'discreetly-interfaces';
|
||||
import { serverConfig } from '../config/serverConfig';
|
||||
import { randn_bm } from '../utils';
|
||||
import { generateClaimCodes } from 'discreetly-claimcodes';
|
||||
import type { ClaimCodeT } from 'discreetly-claimcodes';
|
||||
import { genMockUsers, genClaimCodeArray } from '../utils';
|
||||
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
@@ -19,7 +18,7 @@ interface ClaimCode {
|
||||
roomIds: string[];
|
||||
}
|
||||
|
||||
export function getRoomByID(id: string): Promise<RoomI> {
|
||||
export function getRoomByID(id: string): Promise<RoomI | null> | null {
|
||||
return prisma.rooms
|
||||
.findUnique({
|
||||
where: {
|
||||
@@ -73,40 +72,15 @@ export function getRoomsByIdentity(identity: string): RoomI[] {
|
||||
* @param {number} [numClaimCodes=0] - The number of claim codes to generate for the room.
|
||||
* @param {number} [approxNumMockUsers=20] - The approximate number of mock users to generate for the room.
|
||||
*/
|
||||
export function createRoom(
|
||||
export async function createRoom(
|
||||
name: string,
|
||||
rateLimit: number = 1000,
|
||||
userMessageLimit: number = 1,
|
||||
numClaimCodes: number = 0,
|
||||
approxNumMockUsers: number = 20
|
||||
): boolean {
|
||||
function genMockUsers(numMockUsers: number): string[] {
|
||||
// Generates random number of mock users between 0.5 x numMockusers and 2 x numMockUsers
|
||||
const newNumMockUsers = randn_bm(numMockUsers / 2, numMockUsers * 2);
|
||||
const mockUsers: string[] = [];
|
||||
for (let i = 0; i < newNumMockUsers; i++) {
|
||||
mockUsers.push(
|
||||
genId(
|
||||
serverConfig.id,
|
||||
// Generates a random string of length 10
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 2 + 10) + i
|
||||
).toString()
|
||||
);
|
||||
}
|
||||
return mockUsers;
|
||||
}
|
||||
|
||||
function genClaimCodeArray(numClaimCodes: number): { claimcode: string }[] {
|
||||
const claimCodes = generateClaimCodes(numClaimCodes);
|
||||
const codeArr: { claimcode: string }[] = claimCodes.map((code: ClaimCodeT) => ({
|
||||
claimcode: code.code
|
||||
}));
|
||||
return codeArr;
|
||||
}
|
||||
|
||||
approxNumMockUsers: number = 20,
|
||||
): Promise<boolean> {
|
||||
const claimCodes: { claimcode: string }[] = genClaimCodeArray(numClaimCodes);
|
||||
console.log(claimCodes);
|
||||
const mockUsers: string[] = genMockUsers(approxNumMockUsers);
|
||||
const roomData = {
|
||||
where: {
|
||||
@@ -125,7 +99,7 @@ export function createRoom(
|
||||
}
|
||||
};
|
||||
|
||||
prisma.rooms
|
||||
await prisma.rooms
|
||||
.upsert(roomData)
|
||||
.then(() => {
|
||||
return true;
|
||||
@@ -134,7 +108,7 @@ export function createRoom(
|
||||
return false;
|
||||
}
|
||||
|
||||
export function findClaimCode(code: string): Promise<CodeStatus> {
|
||||
export function findClaimCode(code: string): Promise<CodeStatus | null> {
|
||||
return prisma.claimCodes.findUnique({
|
||||
where: { claimcode: code }
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { Express, RequestHandler } from 'express';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { serverConfig } from '../config/serverConfig';
|
||||
import { pp } from '../utils.js';
|
||||
import { pp } from '../utils';
|
||||
import {
|
||||
getRoomByID,
|
||||
getRoomsByIdentity,
|
||||
@@ -14,12 +14,12 @@ import {
|
||||
} from '../data/db';
|
||||
import { RoomI } from 'discreetly-interfaces';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
export function initEndpoints(app: Express, adminAuth: RequestHandler) {
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
app.get(['/', '/api'], (req, res) => {
|
||||
pp('Express: fetching server info');
|
||||
res.json(serverConfig);
|
||||
res.status(200).json(serverConfig);
|
||||
});
|
||||
|
||||
app.get('/api/room/:id', (req, res) => {
|
||||
@@ -76,13 +76,16 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) {
|
||||
userMessageLimit: number;
|
||||
numClaimCodes?: number;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
const roomMetadata = req.body.data as RoomData;
|
||||
const roomMetadata = req.body as RoomData;
|
||||
console.log(roomMetadata)
|
||||
const roomName = roomMetadata.roomName;
|
||||
const rateLimit = roomMetadata.rateLimit;
|
||||
const userMessageLimit = roomMetadata.userMessageLimit;
|
||||
const numClaimCodes = roomMetadata.numClaimCodes || 0;
|
||||
const result = createRoom(roomName, rateLimit, userMessageLimit, numClaimCodes);
|
||||
console.log(result);
|
||||
if (result) {
|
||||
// TODO should return roomID and claim codes if they are generated
|
||||
res.status(200).json({ message: 'Room created successfully' });
|
||||
@@ -116,4 +119,5 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) {
|
||||
res.status(500).json({ error: 'Internal Server Error' });
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -55,22 +55,27 @@ function initAppListeners() {
|
||||
socket_server.listen(socketServerPort, () => {
|
||||
pp(`SocketIO Server is running at port ${socketServerPort}`);
|
||||
});
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main entry point for the server
|
||||
*/
|
||||
let _app
|
||||
if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
|
||||
console.log('~~~~DEVELOPMENT MODE~~~~');
|
||||
initWebsockets(io);
|
||||
initEndpoints(app, adminAuth);
|
||||
listEndpoints(app);
|
||||
initAppListeners();
|
||||
_app = initAppListeners();
|
||||
mock(io);
|
||||
// TODO! This is dangerous and only for development
|
||||
console.log('Admin password: ' + admin_password);
|
||||
} else {
|
||||
initWebsockets(io);
|
||||
initEndpoints(app, adminAuth);
|
||||
initAppListeners();
|
||||
_app = initAppListeners();
|
||||
}
|
||||
|
||||
|
||||
export default _app;
|
||||
|
||||
29
src/utils.ts
29
src/utils.ts
@@ -1,3 +1,7 @@
|
||||
import { genId } from 'discreetly-interfaces'
|
||||
import { serverConfig } from './config/serverConfig'
|
||||
import { generateClaimCodes } from 'discreetly-claimcodes';
|
||||
import type { ClaimCodeT } from 'discreetly-claimcodes';
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
@@ -9,6 +13,31 @@ export function shim() {
|
||||
};
|
||||
}
|
||||
|
||||
export function genMockUsers(numMockUsers: number): string[] {
|
||||
// Generates random number of mock users between 0.5 x numMockusers and 2 x numMockUsers
|
||||
const newNumMockUsers = randn_bm(numMockUsers / 2, numMockUsers * 2);
|
||||
const mockUsers: string[] = [];
|
||||
for (let i = 0; i < newNumMockUsers; i++) {
|
||||
mockUsers.push(
|
||||
genId(
|
||||
serverConfig.id,
|
||||
// Generates a random string of length 10
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 2 + 10) + i
|
||||
).toString()
|
||||
);
|
||||
}
|
||||
return mockUsers;
|
||||
}
|
||||
|
||||
export function genClaimCodeArray(numClaimCodes: number): { claimcode: string }[] {
|
||||
const claimCodes = generateClaimCodes(numClaimCodes);
|
||||
const codeArr: { claimcode: string }[] = claimCodes.map((code: ClaimCodeT) => ({
|
||||
claimcode: code.code
|
||||
}));
|
||||
return codeArr;
|
||||
}
|
||||
/**
|
||||
* Logs the provided string to the console with the specified log level.
|
||||
* @param {any} str - The string to log.
|
||||
|
||||
79
tests/express.test.ts
Normal file
79
tests/express.test.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
const request = require('supertest');
|
||||
import { assert } from 'console';
|
||||
import _app from '../src/server'
|
||||
import { genId } from 'discreetly-interfaces';
|
||||
import { serverConfig } from '../src/config/serverConfig';
|
||||
import { describe } from 'node:test';
|
||||
|
||||
process.env.DATABASE_URL = process.env.DATABASE_URL_TEST
|
||||
|
||||
|
||||
|
||||
const room = {
|
||||
roomName: 'Test-room',
|
||||
rateLimit: 1000,
|
||||
userMessageLimit: 1,
|
||||
numClaimCodes: 5,
|
||||
approxNumMockUsers: 20,
|
||||
}
|
||||
|
||||
const roomByIdTest = genId(serverConfig.id, room.roomName).toString();
|
||||
|
||||
describe('GET /', () => {
|
||||
test('It should respond with server info', () => {
|
||||
request(_app).get('/').expect('Content-Type', 'application/json; charset=utf-8').then(res => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /room/add", () => {
|
||||
test("It should add a new room to the database", async () => {
|
||||
const username = 'admin';
|
||||
const password = process.env.PASSWORD;
|
||||
const base64Credentials = Buffer.from(`${username}:${password}`).toString('base64');
|
||||
|
||||
await request(_app)
|
||||
.post("/room/add")
|
||||
.set('Authorization', `Basic ${base64Credentials}`)
|
||||
.send(room)
|
||||
.then(res => {
|
||||
expect(res.json === '{message :"Room created successfully"}')
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe("GET /api/room/:id", () => {
|
||||
test("It should return the room with the given id", async () => {
|
||||
await request(_app)
|
||||
.get(`/api/room/${roomByIdTest}`)
|
||||
.then(res => {
|
||||
console.log(res.body);
|
||||
expect(res.body.roomName === room.roomName)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("GET /api/rooms", () => {
|
||||
test("It should return all rooms", async () => {
|
||||
await request(_app)
|
||||
.get("/api/rooms")
|
||||
.then(res => {
|
||||
expect(res.body.length > 0)
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
describe("GET /logclaimcodes", () => {
|
||||
test("It should return all claim codes", async () => {
|
||||
const username = 'admin';
|
||||
const password = process.env.PASSWORD;
|
||||
const base64Credentials = Buffer.from(`${username}:${password}`).toString('base64');
|
||||
await request(_app)
|
||||
.get("/logclaimcodes")
|
||||
.set('Authorization', `Basic ${base64Credentials}`)
|
||||
.then(res => {
|
||||
expect(res.body.length > 0)
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -19,4 +19,4 @@
|
||||
"./src/**/*",
|
||||
"./src/types/index.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
5
tsconfig.tests.json
Normal file
5
tsconfig.tests.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"strictNullChecks": true,
|
||||
"skipLibCheck": true
|
||||
}
|
||||
Reference in New Issue
Block a user