Skip to content

Commit

Permalink
Merge pull request #157 from CS3219-AY2324S1/add-jest-testing
Browse files Browse the repository at this point in the history
Add integration testing module
  • Loading branch information
gowribhat authored Nov 15, 2023
2 parents e799988 + 94125e5 commit db96213
Show file tree
Hide file tree
Showing 15 changed files with 2,773 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Run tests on PeerPrepTest

on:
workflow_dispatch: {}

jobs:
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: tests
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: master

- name: Install dependencies
run: yarn install --frozen-lockfile --production=false

- name: Run all tests
run: yarn test
1 change: 1 addition & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules
21 changes: 21 additions & 0 deletions tests/credentials.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const { v4: uuid } = require("uuid");

const getUser = (isMaintainer) => {
if (isMaintainer) return MAINTAINER_USER;
const userId = uuid();
return {
name: userId,
email: `${userId}@example.com`,
password: userId
}
}

const MAINTAINER_USER = {
name: "Maintainer",
email: "[email protected]",
password: "maintainer",
}

module.exports = {
getUser
}
3 changes: 3 additions & 0 deletions tests/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
UNEXPECTED_SUCCESS_MSG: "Expected an error but the request succeeded."
};
7 changes: 7 additions & 0 deletions tests/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type { import('jest').Config} */
const config = {
setupFiles: ["<rootDir>/setEnvVars.js"],
transform: {}
}

export default config;
14 changes: 14 additions & 0 deletions tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"type": "module",
"dependencies": {
"axios": "^1.6.0",
"jest": "^29.7.0",
"socket.io-client": "^4.7.2",
"uuid": "^9.0.1"
},
"scripts": {
"test": "jest",
"test:watch": "yarn test --watch",
"test:dev": "NODE_ENV=dev yarn test"
}
}
145 changes: 145 additions & 0 deletions tests/questions-service/question.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
const axios = require('axios');
const { UNEXPECTED_SUCCESS_MSG } = require("../errors.js");
const { signUpAndLogin, loginAsMaintainer, deleteUserWithToken } = require("../utils.js")
const questionsUrl = `${process.env.REACT_APP_QUESTIONS_SERVICE_HOST}/questions`

let normalToken;
let maintainerToken;
beforeAll(async () => {
await signUpAndLogin().then((x) => normalToken = x.token);
await loginAsMaintainer().then((x) => maintainerToken = x.token)
});
afterAll(async () => {
deleteUserWithToken(normalToken);
});

describe('Non-maintainer actions', () => {
test('Get one questions', async () => {
const response = await axios.get(`${questionsUrl}/1`, { headers: { Authorization: normalToken }});
expect(response.status).toBe(200);
expect(response.data).not.toBeNull();
});

test('Add a new question without maintainer permission', async () => {
try {
const header = {
headers: { Authorization: normalToken },
};
const params = {
title: "New Question",
complexity: "easy",
categories: [],
description: "testing question",
};
await axios.post(questionsUrl, params, header);
throw new Error(UNEXPECTED_SUCCESS_MSG);
} catch (error) {
expect(error.response.status).toBe(401);
expect(error.response.data).toBe("not a maintainer!")
}
});

test('Edit existing question without maintainer permission', async () => {
try {
const header = {
headers: { Authorization: normalToken },
};
const params = {
title: "Edited Question",
complexity: "easy",
categories: [],
description: "Editing question description",
};
await axios.put(`${questionsUrl}/1`, params, header);
throw new Error(UNEXPECTED_SUCCESS_MSG);
} catch (error) {
expect(error.response.status).toBe(401);
expect(error.response.data).toBe("not a maintainer!")
}
});

test('Delete existing question without maintainer permission', async () => {
try {
const header = {
headers: { Authorization: normalToken },
};
await axios.delete(`${questionsUrl}/1`, header);
throw new Error(UNEXPECTED_SUCCESS_MSG);
} catch (error) {
expect(error.response.status).toBe(401);
expect(error.response.data).toBe("not a maintainer!")
}
});
});

describe('Maintainer actions', () => {
let questionId;
let questionTitle;
let questionComplexity;
let questionCategories;
let questionDescription;
test('Get one questions', async () => {
const response = await axios.get(`${questionsUrl}/1`, { headers: { Authorization: maintainerToken }});
expect(response.status).toBe(200);
expect(response.data).not.toBeNull();
});

test('Add a new question', async () => {
const header = {
headers: { Authorization: maintainerToken },
};
questionTitle = "Question Added";
questionComplexity = "easy";
questionCategories = [];
questionDescription = "Test description"
const params = {
title: questionTitle,
complexity: questionComplexity,
categories: questionCategories,
description: questionDescription,
};
const response = await axios.post(questionsUrl, params, header);
expect(response.status).toBe(200);
expect(response.data.title).toBe(questionTitle);
expect(response.data.complexity).toBe(questionComplexity);
expect(response.data.categories).toStrictEqual(questionCategories);
expect(response.data.description).toBe(questionDescription);
expect(response.data.question_id).not.toBeNull();
questionId = response.data.question_id;
});

test('Edit existing question', async () => {
const header = {
headers: { Authorization: maintainerToken },
};
questionTitle = "Question Edited";
questionComplexity = "hard";
questionDescription = "Test description edited"
const params = {
title: questionTitle,
complexity: questionComplexity,
categories: questionCategories,
description: questionDescription,
};
response = await axios.put(`${questionsUrl}/${questionId}`, params, header);
expect(response.status).toBe(200);
expect(response.data.title).toBe(questionTitle);
expect(response.data.complexity).toBe(questionComplexity);
expect(response.data.categories).toStrictEqual(questionCategories);
expect(response.data.description).toBe(questionDescription);
expect(response.data.question_id).not.toBeNull();
});

test('Delete existing question', async () => {
const header = {
headers: { Authorization: maintainerToken },
};
const response = await axios.delete(`${questionsUrl}/${questionId}`, header);
expect(response.status).toBe(200);
expect(response.data.title).toBe(questionTitle);
expect(response.data.complexity).toBe(questionComplexity);
expect(response.data.categories).toStrictEqual(questionCategories);
expect(response.data.description).toBe(questionDescription);
expect(response.data.question_id).not.toBeNull();
});
});
12 changes: 12 additions & 0 deletions tests/questions-service/questions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const axios = require("axios");
const { signUpAndLogin, deleteUserWithToken } = require("../utils.js");
const questionsUrl = `${process.env.REACT_APP_QUESTIONS_SERVICE_HOST}/questions`;

let token;
beforeAll(() => signUpAndLogin().then((x) => { token = x.token }));
afterAll(() => deleteUserWithToken(token));

test('Get all questions', async () => {
const response = await axios.get( questionsUrl, { headers: { Authorization: token }});
expect(response.status).toBe(200);
});
11 changes: 11 additions & 0 deletions tests/setEnvVars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
if (process.env.NODE_ENV === 'dev') {
process.env.REACT_APP_QUESTIONS_SERVICE_HOST = "http://localhost:3001";
process.env.REACT_APP_USERS_SERVICE_HOST = "http://localhost:3002";
process.env.REACT_APP_MATCHMAKING_SERVICE_HOST = "http://localhost:3003";
process.env.REACT_APP_COLLABORATION_SERVICE_HOST = "http://localhost:3004";
} else {
process.env.REACT_APP_QUESTIONS_SERVICE_HOST = "https://peerpreptest.bryanlohxz.com/api/questions-service";
process.env.REACT_APP_USERS_SERVICE_HOST = "https://peerpreptest.bryanlohxz.com/api/users-service";
process.env.REACT_APP_MATCHMAKING_SERVICE_HOST = "https://peerpreptest.bryanlohxz.com/api/matchmaking-service";
process.env.REACT_APP_COLLABORATION_SERVICE_HOST = "https://peerpreptest.bryanlohxz.com/api/collaboration-service";
}
24 changes: 24 additions & 0 deletions tests/users-service/delete.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const axios = require('axios');

const { INVALID_JWT_ERROR_MSG } = require("./errors.js");
const { signUpAndLogin } = require("../utils.js");
const profileUrl = `${process.env.REACT_APP_USERS_SERVICE_HOST}/profile`;

let token;
beforeAll(() => signUpAndLogin().then((x) => token = x.token));

test('Delete user profile with unauthorized token', async () => {
try {
const unauthorizedToken = 'invalid-token';
await axios.delete(profileUrl, { headers: { Authorization: unauthorizedToken }});
throw new Error(UNEXPECTED_SUCCESS_MSG);
} catch (error) {
expect(error.response.status).toBe(401);
expect(error.response.data).toBe(INVALID_JWT_ERROR_MSG);
}
});

test('Delete user profile with a valid token', async () => {
const response = await axios.delete(profileUrl, { headers: { Authorization: token }});
expect(response.status).toBe(200);
});
8 changes: 8 additions & 0 deletions tests/users-service/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
INCORRECT_PASSWORD_MSG: "The password entered is incorrect.",
INVALID_JWT_ERROR_MSG: "JWT is either missing, invalid or has expired.",
INVALID_REQUEST_BODY_ERROR_MESSAGE: "Please check your request body.",
SERVER_ERROR_MSG: "Sorry, something went wrong with the server.",
USER_NOT_FOUND_MSG: "Sorry, the user cannot be found.",
USER_WITH_SAME_EMAIL_FOUND_MSG: "Another user with this email already exists.",
};
Loading

0 comments on commit db96213

Please sign in to comment.