diff --git a/src/Pages/AuditLog/AuditLog.js b/src/Pages/AuditLog/AuditLog.js
index b115998ee..339a36b9f 100644
--- a/src/Pages/AuditLog/AuditLog.js
+++ b/src/Pages/AuditLog/AuditLog.js
@@ -1,4 +1,4 @@
-import { useState, useEffect } from 'react';
+import React, { useState, useEffect } from 'react';
import { getAllLogs, createAuditLogEventSource } from '../../APIFunctions/AuditLog';
import Pagination from './Components/Pagination';
import { useSCE } from '../../Components/context/SceContext';
diff --git a/test/api/AuditLog.js b/test/api/AuditLog.js
new file mode 100644
index 000000000..fa914041b
--- /dev/null
+++ b/test/api/AuditLog.js
@@ -0,0 +1,158 @@
+process.env.NODE_ENV = 'test';
+
+const User = require('../../api/main_endpoints/models/User.js');
+const AuditLog = require('../../api/main_endpoints/models/AuditLog.js');
+
+const chai = require('chai');
+
+const chaiHttp = require('chai-http');
+const {
+ UNAUTHORIZED,
+} = require('../../api/util/constants.js').STATUS_CODES;
+const SceApiTester = require('../util/tools/SceApiTester.js');
+
+let app = null;
+let test = null;
+const expect = chai.expect;
+const tools = require('../util/tools/tools.js');
+const {
+ setTokenStatus,
+ resetTokenMock,
+ restoreTokenMock,
+ initializeTokenMock
+} = require('../util/mocks/TokenValidFunctions.js');
+const {
+ setDiscordAPIStatus,
+ resetDiscordAPIMock,
+ restoreDiscordAPIMock,
+ initializeDiscordAPIMock
+} = require('../util/mocks/DiscordApiFunction.js');
+const { MEMBERSHIP_STATE } = require('../../api/util/constants.js');
+const AuditLogActions = require('../../api/main_endpoints/util/auditLogActions.js');
+
+chai.should();
+chai.use(chaiHttp);
+
+describe('AuditLog', () => {
+ before(done => {
+ initializeTokenMock();
+ initializeDiscordAPIMock();
+ app = tools.initializeServer([
+ __dirname + '/../../api/main_endpoints/routes/AuditLog.js'
+ ]);
+ test = new SceApiTester(app);
+
+ tools.emptySchema(User);
+ tools.emptySchema(AuditLog);
+ const testUser = new User({
+ email: 'audit@b.c',
+ password: 'Passw0rd',
+ firstName: 'firstName',
+ lastName: 'lastName',
+ major: 'Software Engineering',
+ });
+ testUser.save();
+ const testLog = new AuditLog({
+ userId: testUser._id,
+ action: AuditLogActions.LOG_IN,
+ documentId: testUser._id,
+ details: {email: testUser.email },
+ });
+ testLog.save();
+ done();
+ });
+
+ after(done => {
+ resetTokenMock();
+ restoreDiscordAPIMock();
+ tools.terminateServer(done);
+ });
+
+ beforeEach(() => {
+ setTokenStatus(false);
+ setDiscordAPIStatus(false);
+ });
+
+ afterEach(async () => {
+ restoreTokenMock();
+ resetTokenMock();
+ restoreDiscordAPIMock();
+ resetDiscordAPIMock();
+ });
+
+ const token = '';
+
+ describe('GET /getAuditLogs', () => {
+ const url = '/api/AuditLog/getAuditLogs/';
+
+ it('Should return status code 401 if no token is passed through', async () => {
+ setTokenStatus(false);
+ const result = await test.sendGetRequest(url);
+ expect(result).to.have.status(UNAUTHORIZED);
+ });
+
+ it('Should return status code 401 if access level is invalid', async () => {
+ setTokenStatus(false, { accessLevel: MEMBERSHIP_STATE.MEMBER });
+ const result = await test.sendGetRequestWithToken(token, url);
+ expect(result).to.have.status(UNAUTHORIZED);
+ });
+
+ it('Should return at most 50 records when query is an empty string and access level is valid', async () => {
+ setTokenStatus(true, { accessLevel: MEMBERSHIP_STATE.OFFICER});
+
+ before(async () => {
+ const newUser = new User({
+ email: 'auditLog@b.c',
+ password: 'Passw0rd',
+ firstName: 'first name',
+ lastName: 'last name',
+ major: 'Software Engineering',
+ });
+ newUser.save();
+
+ for (let i = 0; i < 3; i++) {
+ await AuditLog.create({
+ userId: newUser._id,
+ action: AuditLogActions.RESET_PW,
+ documentId: newUser._id,
+ details: {email: newUser.email },
+ });
+ }
+
+ for (let i = 0; i < 60; i++) {
+ await AuditLog.create({
+ userId: newUser._id,
+ action: AuditLogActions.EMAIL_SENT,
+ documentId: newUser._id,
+ details: {email: newUser.email },
+ });
+ }
+ });
+ const result = await test.sendGetRequestWithToken(token, url);
+ expect(result.body.items).that.is.an('array');
+ expect(result.body.items.length).at.most(50);
+ });
+
+ it('Should return the testUser when query is "audit@b.c" and access level is OFFICER', async () => {
+ setTokenStatus(true, { accessLevel: MEMBERSHIP_STATE.OFFICER});
+ const search = 'audit@b.c';
+ const fullUrl = `/api/AuditLog/getAuditLogs?search=${encodeURIComponent(search)}`;
+ const result = await test.sendGetRequestWithToken(token, fullUrl);
+ expect(result.body.items).that.is.an('array').to.have.lengthOf(1);
+ expect(result.body.items[0].userId.email).to.eql('audit@b.c');
+ });
+
+ it('Should return an empty array when the query matches no record: "randome@e.f" and access level is ADMIN', async () => {
+ setTokenStatus(true, { accessLevel: MEMBERSHIP_STATE.ADMIN});
+ const search = 'randome@e.f';
+ const fullUrl = `/api/AuditLog/getAuditLogs?search=${encodeURIComponent(search)}`;
+ const result = await test.sendGetRequestWithToken(token, fullUrl);
+ expect(result.body.items).that.is.an('array').that.is.empty;
+ });
+
+ after(async () => {
+ await User.deleteMany({});
+ await AuditLog.deleteMany({});
+ });
+ });
+});
diff --git a/test/frontend/Routing.test.js b/test/frontend/Routing.test.js
index 12e1e7ebe..7268bbf2a 100644
--- a/test/frontend/Routing.test.js
+++ b/test/frontend/Routing.test.js
@@ -15,6 +15,7 @@ import EditUserInfo from '../../src/Pages/UserManager/EditUserInfo';
import URLShortenerPage from '../../src/Pages/URLShortener/URLShortener';
import sendUnsubscribeEmail from '../../src/Pages/Profile/admin/SendUnsubscribeEmail';
import NotFoundPage from '../../src/Pages/NotFoundPage/NotFoundPage';
+import AuditLogPage from '../../src/Pages/AuditLog/AuditLog';
import { membershipState } from '../../src/Enums';
import { MemoryRouter } from 'react-router-dom';
@@ -59,6 +60,17 @@ function getComponentFromRoute(route, props = adminAppProps, user = mockUser) {
describe(' with ', () => {
describe('Renders correct components for Admin user', () => {
+ // Prevent ReferenceError: EventSource is not defined
+ if (typeof global.EventSource === 'undefined') {
+ global.EventSource = class {
+ constructor() {}
+ close() {}
+ addEventListener() {}
+ removeEventListener() {}
+ onmessage() {}
+ onerror() {}
+ };
+ }
it('Should render a component with the / endpoint', () => {
const wrapper = getComponentFromRoute('/');
expect(wrapper.find(Home)).to.have.lengthOf(1);
@@ -150,5 +162,13 @@ describe(' with ', () => {
expect(wrapper.find(NotFoundPage)).to.have.lengthOf(1);
}
);
+ it(
+ 'Should render a component with with the /audit-logs ' +
+ 'endpoint',
+ () => {
+ const wrapper = getComponentFromRoute('/audit-logs');
+ expect(wrapper.find(AuditLogPage)).to.have.lengthOf(1);
+ }
+ );
});
});