From ae8229660e2bd0a12ae99299c8646dbb8fba7b6f Mon Sep 17 00:00:00 2001 From: JamesNg Date: Sat, 3 May 2025 10:29:04 -0400 Subject: [PATCH 1/4] wrote unit tests for questions router --- backend/globalConfig.json | 2 +- backend/routers/questions.router.test.js | 107 +++++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 backend/routers/questions.router.test.js diff --git a/backend/globalConfig.json b/backend/globalConfig.json index ae7585862..72949a2fb 100644 --- a/backend/globalConfig.json +++ b/backend/globalConfig.json @@ -1 +1 @@ -{"mongoUri":"mongodb://127.0.0.1:56074/jest?","mongoDBName":"jest"} \ No newline at end of file +{"mongoUri":"mongodb://127.0.0.1:40417/jest?","mongoDBName":"jest"} \ No newline at end of file diff --git a/backend/routers/questions.router.test.js b/backend/routers/questions.router.test.js new file mode 100644 index 000000000..54319aad2 --- /dev/null +++ b/backend/routers/questions.router.test.js @@ -0,0 +1,107 @@ +// Mock and import Question model +jest.mock('../models/question.model'); +const { Question } = require('../models'); + +// Import question router +const questionsRouter = require('./questions.router'); + +// Create a test app with Express +const express = require('express'); +const supertest = require('supertest'); +const testapp = express(); +// Allow for body parsing in test +testapp.use(express.json()); +testapp.use('/api/questions/', questionsRouter); +const request = supertest(testapp); + +describe('Unit tests for questions router', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('READ', () => { + // Mock question data + const mockQuestions = [ + { + id: 1, + questionText: 'What is your favorite color?', + htmlName: 'favoriteColor', + answers: { + answerOneText: 'Red', + answerTwoText: 'Blue', + answerThreeText: 'Green', + answerFourText: 'Yellow', + }, + }, + { + id: 2, + questionText: 'What is your favorite food?', + htmlName: 'favoriteFood', + answers: { + answerOneText: 'Pizza', + answerTwoText: 'Cheeseburger', + answerThreeText: 'Sushi', + answerFourText: 'Chicken', + }, + }, + ]; + + it('should return all questions with GET /api/questions', async (done) => { + // Mock the Question.find() method + Question.find.mockResolvedValue(mockQuestions); + + // Mock the request to the API + const response = await request.get('/api/questions'); + + // Tests + expect(response.status).toBe(200); + expect(response.body).toEqual(mockQuestions); + + // Marks completion of tests + done(); + }); + + it('should return a specific question with GET /api/questions/:id', async (done) => { + // Mock the Question.findById() method + const questionId = 1; + Question.findById.mockResolvedValue(mockQuestions[0]); + // Mock the request to the API + const response = await request.get(`/api/questions/${questionId}`); + // Tests + expect(response.status).toBe(200); + expect(response.body).toEqual(mockQuestions[0]); + + // Marks completion of tests + done(); + }); + }); + + describe('CREATE', () => { + it('should create a new question with POST /api/questions/', async (done) => { + // Mock the Question.create() method + const newQuestion = { + id: 3, + questionText: 'What is your favorite animal?', + htmlName: 'favoriteAnimal', + answers: { + answerOneText: 'Dog', + answerTwoText: 'Cat', + answerThreeText: 'Bird', + answerFourText: 'Fish', + }, + }; + + Question.create.mockResolvedValue(newQuestion); + + // Mock the request to the API + const response = await request.post('/api/questions/').send(newQuestion); + + // Tests + expect(Question.create).toHaveBeenCalledWith(newQuestion); + expect(response.status).toBe(201); + + // Marks completion of tests + done(); + }); + }); +}); From c3e882a5e0fcb1ce68191382eca0114c95dbb2ab Mon Sep 17 00:00:00 2001 From: JamesNg Date: Tue, 27 May 2025 12:23:16 -0400 Subject: [PATCH 2/4] updated changes to tests --- backend/globalConfig.json | 2 +- backend/package.json | 1 + backend/routers/questions.router.test.js | 20 ++++++++++++++------ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/backend/globalConfig.json b/backend/globalConfig.json index 72949a2fb..1cba1a5b1 100644 --- a/backend/globalConfig.json +++ b/backend/globalConfig.json @@ -1 +1 @@ -{"mongoUri":"mongodb://127.0.0.1:40417/jest?","mongoDBName":"jest"} \ No newline at end of file +{"mongoUri":"mongodb://127.0.0.1:44891/jest?","mongoDBName":"jest"} \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 628339b8e..e2c1aeda8 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,6 +8,7 @@ "format": "prettier --check .", "test": "jest", "test:watch": "jest --watch", + "test:qs": "jest --watch questions.router.test.js", "start": "node server.js", "dev": "nodemon server.js", "client": "npm run start --prefix client", diff --git a/backend/routers/questions.router.test.js b/backend/routers/questions.router.test.js index 54319aad2..e30269fac 100644 --- a/backend/routers/questions.router.test.js +++ b/backend/routers/questions.router.test.js @@ -5,12 +5,14 @@ const { Question } = require('../models'); // Import question router const questionsRouter = require('./questions.router'); -// Create a test app with Express +// Create a test app with Express const express = require('express'); const supertest = require('supertest'); const testapp = express(); -// Allow for body parsing in test +// Allow for body parsing of JSON data testapp.use(express.json()); +// Allow for body parsing of HTML data +testapp.use(express.urlencoded({ extended: false })); testapp.use('/api/questions/', questionsRouter); const request = supertest(testapp); @@ -54,6 +56,7 @@ describe('Unit tests for questions router', () => { const response = await request.get('/api/questions'); // Tests + expect(Question.find).toHaveBeenCalled(); expect(response.status).toBe(200); expect(response.body).toEqual(mockQuestions); @@ -63,13 +66,17 @@ describe('Unit tests for questions router', () => { it('should return a specific question with GET /api/questions/:id', async (done) => { // Mock the Question.findById() method - const questionId = 1; - Question.findById.mockResolvedValue(mockQuestions[0]); + const mockQuestion = mockQuestions[0]; + const { id } = mockQuestion; + Question.findById.mockResolvedValue(mockQuestion); + // Mock the request to the API - const response = await request.get(`/api/questions/${questionId}`); + const response = await request.get(`/api/questions/${id}`); + // Tests + expect(Question.findById).toHaveBeenCalledWith(`${id}`); expect(response.status).toBe(200); - expect(response.body).toEqual(mockQuestions[0]); + expect(response.body).toEqual(mockQuestion); // Marks completion of tests done(); @@ -91,6 +98,7 @@ describe('Unit tests for questions router', () => { }, }; + // Mock Question.create method Question.create.mockResolvedValue(newQuestion); // Mock the request to the API From d9816317d77e73bf9259989a62c076818747b3d6 Mon Sep 17 00:00:00 2001 From: JamesNg Date: Tue, 27 May 2025 12:27:29 -0400 Subject: [PATCH 3/4] removed temporarily added script for testing router --- backend/globalConfig.json | 2 +- backend/package.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/globalConfig.json b/backend/globalConfig.json index 1cba1a5b1..9d972397d 100644 --- a/backend/globalConfig.json +++ b/backend/globalConfig.json @@ -1 +1 @@ -{"mongoUri":"mongodb://127.0.0.1:44891/jest?","mongoDBName":"jest"} \ No newline at end of file +{"mongoUri":"mongodb://127.0.0.1:35691/jest?","mongoDBName":"jest"} \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index e2c1aeda8..628339b8e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,7 +8,6 @@ "format": "prettier --check .", "test": "jest", "test:watch": "jest --watch", - "test:qs": "jest --watch questions.router.test.js", "start": "node server.js", "dev": "nodemon server.js", "client": "npm run start --prefix client", From acd0621c05d06e54bc1fad9b42fc35aa2a0b1cd1 Mon Sep 17 00:00:00 2001 From: JamesNg Date: Tue, 17 Jun 2025 19:03:12 -0400 Subject: [PATCH 4/4] added testing for fail cases --- backend/routers/questions.router.test.js | 74 +++++++++++++++++++++++- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/backend/routers/questions.router.test.js b/backend/routers/questions.router.test.js index e30269fac..50e4cc1da 100644 --- a/backend/routers/questions.router.test.js +++ b/backend/routers/questions.router.test.js @@ -1,8 +1,6 @@ -// Mock and import Question model +// Mock and import Question model, import question router jest.mock('../models/question.model'); const { Question } = require('../models'); - -// Import question router const questionsRouter = require('./questions.router'); // Create a test app with Express @@ -17,6 +15,7 @@ testapp.use('/api/questions/', questionsRouter); const request = supertest(testapp); describe('Unit tests for questions router', () => { + // Clear all mocks after each test afterEach(() => { jest.clearAllMocks(); }); @@ -64,6 +63,28 @@ describe('Unit tests for questions router', () => { done(); }); + it('should return 400 status code when there is an error with GET /api/questions', async (done) => { + // Mock the error thrown when find method is called + const error = new Error('Database error'); + Question.find.mockRejectedValue(error); + + // Mock console log function + const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); + + // Mock the request to the API + const response = await request.get('/api/questions'); + + // Tests + expect(Question.find).toHaveBeenCalled(); + expect(consoleLogSpy).toHaveBeenCalledWith(error); + expect(response.status).toBe(400); + + // Clean up and restores original console log function + consoleLogSpy.mockRestore(); + // Marks completion of tests + done(); + }); + it('should return a specific question with GET /api/questions/:id', async (done) => { // Mock the Question.findById() method const mockQuestion = mockQuestions[0]; @@ -81,6 +102,31 @@ describe('Unit tests for questions router', () => { // Marks completion of tests done(); }); + + it('should return 400 status code when there is an error with GET /api/questions/:id', async (done) => { + // Mock user id + const id = mockQuestions[0].id; + + // Mock the error when findById method is called + const error = new Error('Database error'); + Question.findById.mockRejectedValue(error); + + // Mock console log function + const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); + + // Mock the request to the API + const response = await request.get(`/api/questions/${id}`); + + // Tests + expect(Question.findById).toHaveBeenCalledWith(`${id}`); + expect(consoleLogSpy).toHaveBeenCalledWith(error); + expect(response.status).toBe(400); + + // Clean up and restores original console log function + consoleLogSpy.mockRestore(); + // Marks completion of tests + done(); + }); }); describe('CREATE', () => { @@ -111,5 +157,27 @@ describe('Unit tests for questions router', () => { // Marks completion of tests done(); }); + + it('should return 400 status code when there is an error with POST /api/questions', async (done) => { + // Mock the error thrown when create method is called + const error = new Error('Database error'); + Question.create.mockRejectedValue(error); + + // Mock console log function + const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); + + // Mock the request to the API + const response = await request.post('/api/questions'); + + // Tests + expect(Question.create).toHaveBeenCalled(); + expect(consoleLogSpy).toHaveBeenCalledWith(error); + expect(response.status).toBe(400); + + // Clean up and restores original console log function + consoleLogSpy.mockRestore(); + // Marks completion of tests + done(); + }); }); });