Skip to content

Commit

Permalink
Merge pull request #75 from FYP-2024-IQMA/SCRUM-129-Implement-routing…
Browse files Browse the repository at this point in the history
…-across-screens

Scrum 129 implement routing across screens
  • Loading branch information
mohammadfadhli authored Sep 18, 2024
2 parents 3efb81f + 2267eb0 commit 6afa580
Show file tree
Hide file tree
Showing 22 changed files with 493 additions and 198 deletions.
43 changes: 18 additions & 25 deletions backend/__tests__/controllers/resultController.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,44 +69,37 @@ describe("POST /createresult", () => {

/* READ */

describe("GET /getresultbyid/:userid", () => {

describe("GET /checkifcompletedquiz/:userid/:quizid", () => {
const userID = "USR0001";
const quizID = 2;

it("should return 200 and the results of a user", async () => {

const mockData = [
{
"quizID": 1,
"dateCreated": "2024-09-01T05:26:54.096997+00:00"
},
{
"quizID": 2,
"dateCreated": "2024-09-01T05:27:01.340253+00:00"
}
]
it("should return 200 and a boolean result to show if a user has completed the quiz", async () => {
const mockData = true;

resultService.getResultByUserId.mockResolvedValue(mockData);
resultService.checkIfCompletedQuiz.mockResolvedValue(mockData);

const response = await request(app).get(`/result/getresultbyid/${userID}`);
const response = await request(app).get(
`/result/getifcompletedquiz/${userID}/${quizID}`
);

expect(response.status).toBe(200);
expect(response.body).toEqual(mockData);
expect(resultService.getResultByUserId).toHaveBeenCalledTimes(1);
expect(resultService.checkIfCompletedQuiz).toHaveBeenCalledTimes(1);
});

it("should return 500 and an error message on failure", async () => {
const errMessage = "Database error";
const mockError = new Error("Database error");

resultService.getResultByUserId.mockRejectedValue(mockError);
resultService.checkIfCompletedQuiz.mockRejectedValue(mockError);

const response = await request(app).get(`/result/getresultbyid/${userID}`);
const response = await request(app).get(
`/result/checkifcompletedquiz/${userID}/${quizID}`
);

expect(response.status).toBe(500);
expect(response.body).toEqual({
error: "Failed to retrieve Result",
});
expect(resultService.getResultByUserId).toHaveBeenCalledTimes(1);
expect(response.body.details).toEqual(errMessage);
expect(resultService.checkIfCompletedQuiz).toHaveBeenCalledTimes(1);
});
});

Expand Down Expand Up @@ -232,7 +225,7 @@ describe("GET /getnoofcompletedlessons/:userid/:sectionid/:unitid", () => {
const sectionID = "SEC0001";
const unitID = "UNIT0001";

it.only("should return 200 and the unit progress of a user", async () => {
it("should return 200 and the unit progress of a user", async () => {
resultService.getNoOfCompletedLesson.mockResolvedValue(2);

const response = await request(app).get(
Expand All @@ -244,7 +237,7 @@ describe("GET /getnoofcompletedlessons/:userid/:sectionid/:unitid", () => {
expect(resultService.getNoOfCompletedLesson).toHaveBeenCalledTimes(1);
});

it.only("should return 500 and an error message on failure", async () => {
it("should return 500 and an error message on failure", async () => {
const mockError = new Error("Database error");

resultService.getNoOfCompletedLesson.mockRejectedValue(mockError);
Expand Down
55 changes: 32 additions & 23 deletions backend/__tests__/services/resultService.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,43 +55,52 @@ describe("createResult", () => {

/* READ */

describe("getResultByUserId", () => {
const mockData = [
{
quizID: 1,
dateCreated: "2024-09-01T05:26:54.096997+00:00",
},
{
quizID: 2,
dateCreated: "2024-09-01T05:27:01.340253+00:00",
},
];

describe("checkIfCompletedQuiz", () => {
const userID = "USR0001";
const quizID = 2;

it("should return true when user completed the quiz", async () => {
const mockCount = 1;
const mockEq2 = jest
.fn()
.mockResolvedValue({ count: mockCount, error: null });
const mockEq1 = jest.fn().mockReturnValue({ eq: mockEq2 });
const mockSelect = jest.fn().mockReturnValue({ eq: mockEq1 });
supabase.from.mockReturnValue({ select: mockSelect });

it("should return an array of quizID & dateCreated", async () => {
const mockEq = jest
const result = await resultService.checkIfCompletedQuiz(userID, quizID);

expect(result).toEqual(true);
});

it("should return false when user did not complete the quiz", async () => {
const mockCount = 0;
const mockEq2 = jest
.fn()
.mockResolvedValue({ data: mockData, error: null });
const mockSelect = jest.fn().mockReturnValue({ eq: mockEq });
.mockResolvedValue({ count: mockCount, error: null });
const mockEq1 = jest.fn().mockReturnValue({ eq: mockEq2 });
const mockSelect = jest.fn().mockReturnValue({ eq: mockEq1 });
supabase.from.mockReturnValue({ select: mockSelect });

const result = await resultService.getResultByUserId(userID);
const result = await resultService.checkIfCompletedQuiz(userID, quizID);

expect(result).toEqual(mockData);
expect(result).toEqual(false);
});

it("should throw an error and log the error when there is an error from the database", async () => {
const errorMessage = "Failed to fetch user results";

const mockEq = jest
const mockEq2 = jest
.fn()
.mockResolvedValue({ data: null, error: new Error(errorMessage) });
const mockSelect = jest.fn().mockReturnValue({ eq: mockEq });
.mockResolvedValue({ count: null, error: new Error(errorMessage) });
const mockEq1 = jest.fn().mockReturnValue({ eq: mockEq2 });
const mockSelect = jest.fn().mockReturnValue({ eq: mockEq1 });
supabase.from.mockReturnValue({ select: mockSelect });

await expect(resultService.getResultByUserId(userID)).rejects.toThrow(errorMessage);

await expect(
resultService.checkIfCompletedQuiz(userID, quizID)
).rejects.toThrow(errorMessage);

expect(console.error).toHaveBeenCalledWith(new Error(errorMessage));
});
});
Expand Down
8 changes: 4 additions & 4 deletions backend/dist/controllers/resultController.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getNoOfCompletedLesson = exports.getCircularProgress = exports.getUserProgress = exports.getResultByUserId = exports.getAllResults = exports.createResult = void 0;
exports.getNoOfCompletedLesson = exports.getCircularProgress = exports.getUserProgress = exports.checkIfCompletedQuiz = exports.getAllResults = exports.createResult = void 0;
const resultService = __importStar(require("../services/resultService"));
const lessonService = __importStar(require("../services/lessonService"));
const errorHandling_1 = __importDefault(require("../errors/errorHandling"));
Expand Down Expand Up @@ -72,9 +72,9 @@ const getAllResults = (req, res) => __awaiter(void 0, void 0, void 0, function*
}
});
exports.getAllResults = getAllResults;
const getResultByUserId = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
const checkIfCompletedQuiz = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
try {
const result = yield resultService.getResultByUserId(req.params.userid);
const result = yield resultService.checkIfCompletedQuiz(req.params.userid, req.params.quizid);
res.status(200).json(result);
}
catch (error) {
Expand All @@ -84,7 +84,7 @@ const getResultByUserId = (req, res) => __awaiter(void 0, void 0, void 0, functi
}
}
});
exports.getResultByUserId = getResultByUserId;
exports.checkIfCompletedQuiz = checkIfCompletedQuiz;
const getUserProgress = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
try {
const userProgress = yield resultService.getUserProgress(req.params.userid, req.params.sectionid);
Expand Down
2 changes: 1 addition & 1 deletion backend/dist/routes/resultRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const router = (0, express_1.Router)();
router.post("/createresult", authMiddleware_1.default, resultController.createResult);
/* READ */
router.get("/getallresults", authMiddleware_1.default, resultController.getAllResults);
router.get("/getresultbyid/:userid", authMiddleware_1.default, resultController.getResultByUserId);
router.get("/checkifcompletedquiz/:userid/:quizid", authMiddleware_1.default, resultController.checkIfCompletedQuiz);
router.get("/getuserprogress/:userid/:sectionid?", authMiddleware_1.default, resultController.getUserProgress);
router.get("/getcircularprogress/:userid/:sectionid/:unitid", authMiddleware_1.default, resultController.getCircularProgress);
router.get("/getnoofcompletedlessons/:userid/:sectionid/:unitid", authMiddleware_1.default, resultController.getNoOfCompletedLesson);
Expand Down
13 changes: 7 additions & 6 deletions backend/dist/services/resultService.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.createResult = createResult;
exports.getAllResults = getAllResults;
exports.getResultByUserId = getResultByUserId;
exports.checkIfCompletedQuiz = checkIfCompletedQuiz;
exports.getUserProgress = getUserProgress;
exports.getNoOfCompletedLesson = getNoOfCompletedLesson;
const supabaseConfig_1 = __importDefault(require("../config/supabaseConfig"));
Expand Down Expand Up @@ -52,18 +52,19 @@ function getAllResults() {
}
});
}
function getResultByUserId(userID) {
function checkIfCompletedQuiz(userID, quizID) {
return __awaiter(this, void 0, void 0, function* () {
const { data, error } = yield supabaseConfig_1.default
const { count, error } = yield supabaseConfig_1.default
.from("result")
.select("quizID, dateCreated")
.eq("userID", userID);
.select("*", { count: "exact" })
.eq("userID", userID)
.eq("quizID", quizID);
if (error) {
console.error(error);
throw error;
}
else {
return data;
return count > 0;
}
});
}
Expand Down
9 changes: 6 additions & 3 deletions backend/src/controllers/resultController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ export const getAllResults = async (req: Request, res: Response) => {
}
};

export const getResultByUserId = async (req: Request, res: Response) => {
export const checkIfCompletedQuiz = async (req: Request, res: Response) => {
try {
const result = await resultService.getResultByUserId(req.params.userid);
const result = await resultService.checkIfCompletedQuiz(
req.params.userid,
req.params.quizid
);
res.status(200).json(result);
} catch (error: any) {
const errorResponse = handleError(error);
if(errorResponse){
if (errorResponse) {
res.status(errorResponse.status).json(errorResponse);
}
}
Expand Down
6 changes: 3 additions & 3 deletions backend/src/routes/resultRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ router.post("/createresult", verifyToken, resultController.createResult);
/* READ */
router.get("/getallresults", verifyToken, resultController.getAllResults);
router.get(
"/getresultbyid/:userid",
verifyToken,
resultController.getResultByUserId
"/checkifcompletedquiz/:userid/:quizid",
verifyToken,
resultController.checkIfCompletedQuiz
);
router.get(
"/getuserprogress/:userid/:sectionid?",
Expand Down
11 changes: 6 additions & 5 deletions backend/src/services/resultService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,18 @@ export async function getAllResults() {
}


export async function getResultByUserId(userID: string) {
const { data, error } = await supabase
export async function checkIfCompletedQuiz(userID: string, quizID: string): Promise<boolean> {
const { count, error } = await supabase
.from("result")
.select("quizID, dateCreated")
.eq("userID", userID);
.select("*", { count: "exact" })
.eq("userID", userID)
.eq("quizID", quizID);

if (error) {
console.error(error);
throw error;
} else {
return data;
return count! > 0;
}
}

Expand Down
Loading

0 comments on commit 6afa580

Please sign in to comment.