From e2adcc30acd65217c8ed24621edc09a8970d5e3d Mon Sep 17 00:00:00 2001 From: Vinit khandal Date: Thu, 19 Feb 2026 10:50:15 +0530 Subject: [PATCH 1/3] Merge pull request #2576 from RealDevSquad/2569-refactor-test-for-group-idle fix: test expectations for idle user --- models/discordactions.js | 1 + test/unit/models/discordactions.test.js | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/models/discordactions.js b/models/discordactions.js index 54d91aa84..0937b8869 100644 --- a/models/discordactions.js +++ b/models/discordactions.js @@ -404,6 +404,7 @@ const updateIdleUsersOnDiscord = async (dev) => { let allUsersHavingGroupIdle = []; let groupIdleRole; let groupIdleRoleId; + const allMavens = []; try { groupIdleRole = await getGroupRole("group-idle"); diff --git a/test/unit/models/discordactions.test.js b/test/unit/models/discordactions.test.js index bd6084b66..6f4d20836 100644 --- a/test/unit/models/discordactions.test.js +++ b/test/unit/models/discordactions.test.js @@ -1037,7 +1037,7 @@ describe("discordactions", function () { getDiscordMembers[3] = { ...getDiscordMembers[3], - roles: ["1212121212"], + roles: ["3434343434"], }; await addUser(userData[0]); @@ -1079,11 +1079,11 @@ describe("discordactions", function () { await cleanDb(); }); - it("should return totalIdleUsers as 1,totalArchivedUsers as 0, totalRoleToBeAdded as 1", async function () { + it("should return totalIdleUsers as 2,totalArchivedUsers as 0, totalRoleToBeAdded as 2", async function () { const dev = "true"; const res = await updateIdleUsersOnDiscord(dev); - expect(res.totalIdleUsers).to.be.equal(1); - expect(res.totalUserRoleToBeAdded).to.be.equal(1); + expect(res.totalIdleUsers).to.be.equal(2); + expect(res.totalUserRoleToBeAdded).to.be.equal(2); expect(res.totalUserRoleToBeRemoved).to.be.equal(1); expect(res.totalArchivedUsers).to.be.equal(0); }); From 86c6796038604c5b5b2a4615f0779134ca655a4f Mon Sep 17 00:00:00 2001 From: Anuj Chhikara <107175639+AnujChhikara@users.noreply.github.com> Date: Fri, 20 Feb 2026 00:16:50 +0530 Subject: [PATCH 2/3] feat: enhance application scoring and update validation (#2573) * feat: enhance application scoring and update validation - Added score handling in nudgeApplication logic to increment score on nudging. - Updated application creation to set an initial score of 50. - Enhanced application update validation to include optional fields: firstName, lastName, college, skills, city, state, country, and role. - Improved integration tests to verify score updates and application modifications. - Adjusted unit tests to reflect changes in application scoring logic. * feat: introduce application scoring system and update application queries * test: refactor application update test for invalid role handling * refactor: remove firstName and lastName from application update validation and tests * refactor: rename 'college' to 'institution' in application validation, service, and tests --- constants/application.ts | 8 +- controllers/applications.ts | 1 + middlewares/validators/application.ts | 11 ++- models/applications.ts | 11 ++- services/applicationService.ts | 5 +- test/fixtures/applications/applications.ts | 19 +++-- test/integration/application.test.ts | 75 +++++++++++++++---- test/unit/services/applicationService.test.ts | 4 +- test/unit/utils/application.test.ts | 4 +- types/application.d.ts | 8 +- utils/application.ts | 8 +- 11 files changed, 119 insertions(+), 35 deletions(-) diff --git a/constants/application.ts b/constants/application.ts index 60f5d0a15..e82836904 100644 --- a/constants/application.ts +++ b/constants/application.ts @@ -48,6 +48,11 @@ const APPLICATION_STATUS = { * Business requirement: Applications created after this date are considered reviewed * and cannot be resubmitted. This date marks the start of the new application review cycle. */ +const APPLICATION_SCORE = { + INITIAL_SCORE: 50, + NUDGE_BONUS: 10, +}; + const APPLICATION_REVIEW_CYCLE_START_DATE = new Date("2026-01-01T00:00:00.000Z"); module.exports = { @@ -57,5 +62,6 @@ module.exports = { APPLICATION_ERROR_MESSAGES, APPLICATION_LOG_MESSAGES, APPLICATION_REVIEW_CYCLE_START_DATE, - APPLICATION_STATUS + APPLICATION_STATUS, + APPLICATION_SCORE }; diff --git a/controllers/applications.ts b/controllers/applications.ts index 0809348fa..ba344d643 100644 --- a/controllers/applications.ts +++ b/controllers/applications.ts @@ -202,6 +202,7 @@ const nudgeApplication = async (req: CustomRequest, res: CustomResponse) => { message: API_RESPONSE_MESSAGES.NUDGE_SUCCESS, nudgeCount: result.nudgeCount, lastNudgeAt: result.lastNudgeAt, + score: result.score, }); default: return res.boom.badImplementation(INTERNAL_SERVER_ERROR); diff --git a/middlewares/validators/application.ts b/middlewares/validators/application.ts index 6f4293ff3..7fbde2c7f 100644 --- a/middlewares/validators/application.ts +++ b/middlewares/validators/application.ts @@ -31,7 +31,7 @@ const validateApplicationData = async (req: CustomRequest, res: CustomResponse, userId: joi.string().optional(), firstName: joi.string().min(1).required(), lastName: joi.string().min(1).required(), - college: joi.string().min(1).required(), + institution: joi.string().min(1).required(), skills: joi.string().min(5).required(), city: joi.string().min(1).required(), state: joi.string().min(1).required(), @@ -130,6 +130,15 @@ const validateApplicationUpdateData = async (req: CustomRequest, res: CustomResp .strict() .min(1) .keys({ + institution: joi.string().min(1).optional(), + skills: joi.string().min(5).optional(), + city: joi.string().min(1).optional(), + state: joi.string().min(1).optional(), + country: joi.string().min(1).optional(), + role: joi + .string() + .valid(...Object.values(APPLICATION_ROLES)) + .optional(), imageUrl: joi.string().uri().optional(), foundFrom: joi.string().min(1).optional(), introduction: joi.string().min(1).optional(), diff --git a/models/applications.ts b/models/applications.ts index 9f59b84f3..08e1edc62 100644 --- a/models/applications.ts +++ b/models/applications.ts @@ -4,7 +4,7 @@ const { logType } = require("../constants/logs"); const firestore = require("../utils/firestore"); const logger = require("../utils/logger"); const ApplicationsModel = firestore.collection("applicants"); -const { APPLICATION_STATUS_TYPES, APPLICATION_STATUS } = require("../constants/application"); +const { APPLICATION_STATUS_TYPES, APPLICATION_STATUS, APPLICATION_SCORE } = require("../constants/application"); const { convertDaysToMilliseconds } = require("../utils/time"); const getAllApplications = async (limit: number, lastDocId?: string) => { @@ -16,7 +16,7 @@ const getAllApplications = async (limit: number, lastDocId?: string) => { lastDoc = await ApplicationsModel.doc(lastDocId).get(); } - let dbQuery = ApplicationsModel.orderBy("createdAt", "desc"); + let dbQuery = ApplicationsModel.where("isNew", "==", true).orderBy("createdAt", "desc"); if (lastDoc) { dbQuery = dbQuery.startAfter(lastDoc); @@ -59,7 +59,7 @@ const getApplicationsBasedOnStatus = async (status: string, limit: number, lastD try { let lastDoc = null; const applications = []; - let dbQuery = ApplicationsModel.where("status", "==", status); + let dbQuery = ApplicationsModel.where("isNew", "==", true).where("status", "==", status); if (userId) { dbQuery = dbQuery.where("userId", "==", userId); @@ -86,7 +86,7 @@ const getApplicationsBasedOnStatus = async (status: string, limit: number, lastD }); }); - let countQuery = ApplicationsModel.where("status", "==", status); + let countQuery = ApplicationsModel.where("isNew", "==", true).where("status", "==", status); const totalApplications = await countQuery.get(); const totalCount = totalApplications.size; @@ -219,16 +219,19 @@ const nudgeApplication = async ({ applicationId, userId }: { applicationId: stri const currentNudgeCount = application.nudgeCount || 0; const updatedNudgeCount = currentNudgeCount + 1; const newLastNudgeAt = new Date(currentTime).toISOString(); + const updatedScore = (application.score || 0) + APPLICATION_SCORE.NUDGE_BONUS; transaction.update(applicationRef, { nudgeCount: updatedNudgeCount, lastNudgeAt: newLastNudgeAt, + score: updatedScore, }); return { status: APPLICATION_STATUS.success, nudgeCount: updatedNudgeCount, lastNudgeAt: newLastNudgeAt, + score: updatedScore, }; }); diff --git a/services/applicationService.ts b/services/applicationService.ts index b1e81a4a1..664480257 100644 --- a/services/applicationService.ts +++ b/services/applicationService.ts @@ -5,6 +5,7 @@ const { APPLICATION_STATUS_TYPES, APPLICATION_ERROR_MESSAGES, APPLICATION_REVIEW_CYCLE_START_DATE, + APPLICATION_SCORE, } = require("../constants/application"); const logger = require("../utils/logger"); @@ -31,7 +32,7 @@ const transformPayloadToApplication = (payload: applicationPayload, userId: stri country: payload.country, }, professional: { - institution: payload.college, + institution: payload.institution, skills: payload.skills, }, intro: { @@ -86,7 +87,7 @@ export const createApplicationService = async ( const applicationData: application = { ...transformPayloadToApplication(payload, userId), - score: 0, + score: APPLICATION_SCORE.INITIAL_SCORE, status: APPLICATION_STATUS_TYPES.PENDING, createdAt, isNew: true, diff --git a/test/fixtures/applications/applications.ts b/test/fixtures/applications/applications.ts index ea50ab3fc..4e2f0c314 100644 --- a/test/fixtures/applications/applications.ts +++ b/test/fixtures/applications/applications.ts @@ -3,7 +3,7 @@ module.exports = () => { { firstName: "vinayak", lastName: "triveid", - college: "Christ Church college", + institution: "Christ Church institution", skills: "React, Ember, Node js", city: "Kanpur", state: "Uttar Pradesh", @@ -21,12 +21,13 @@ module.exports = () => { }, createdAt: null, role: "developer", + isNew: true, }, { userId: "xyajkdfsfsd", firstName: "Ritik", lastName: "Jaiwal", - college: "Tata Consultancy services", + institution: "Tata Consultancy services", skills: "React, Ember, Node js", city: "Bangalore", state: "Karnataka", @@ -44,9 +45,10 @@ module.exports = () => { }, createdAt: null, role: "developer", + isNew: true, }, { - college: "Groww", + institution: "Groww", state: "Karnataka", firstName: "Vaibhav", lastName: "Desai", @@ -68,9 +70,10 @@ module.exports = () => { status: "rejected", createdAt: null, role: "developer", + isNew: true, }, { - college: "Groww", + institution: "Groww", state: "Karnataka", firstName: "Vaibhav", lastName: "Desai", @@ -92,9 +95,10 @@ module.exports = () => { status: "rejected", createdAt: null, role: "developer", + isNew: true, }, { - college: "Groww", + institution: "Groww", state: "Karnataka", firstName: "Vaibhav", lastName: "Desai", @@ -116,9 +120,10 @@ module.exports = () => { status: "rejected", createdAt: null, role: "developer", + isNew: true, }, { - college: "Groww", + institution: "Groww", state: "Karnataka", firstName: "Vaibhav", lastName: "Desai", @@ -145,7 +150,7 @@ module.exports = () => { city: "Kanpur", state: "UP", country: "India", - college: "Christ Church College", + institution: "Christ Church College", skills: "React, NodeJs, Ember", introduction: "mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at", diff --git a/test/integration/application.test.ts b/test/integration/application.test.ts index 8b48dcd78..8773ed9ea 100644 --- a/test/integration/application.test.ts +++ b/test/integration/application.test.ts @@ -12,7 +12,7 @@ const applicationModel = require("../../models/applications"); const applicationsData = require("../fixtures/applications/applications")(); const cookieName = config.get("userToken.cookieName"); -const { APPLICATION_ERROR_MESSAGES, API_RESPONSE_MESSAGES } = require("../../constants/application"); +const { APPLICATION_ERROR_MESSAGES, API_RESPONSE_MESSAGES, APPLICATION_SCORE } = require("../../constants/application"); const appOwner = userData[3]; const superUser = userData[4]; @@ -334,25 +334,27 @@ describe("Application", function () { }); describe("POST /applications", function () { - it("should create a application and return 201 if the user has not yet submitted the application", function (done) { - chai + it("should create a application and return 201 if the user has not yet submitted the application", async function () { + const res = await chai .request(app) .post(`/applications`) .set("cookie", `${cookieName}=${secondUserJwt}`) .send({ ...applicationsData[5], imageUrl: "https://example.com/image.jpg", - }) - .end((err, res) => { - if (err) { - return done(err); - } - - expect(res).to.have.status(201); - expect(res.body.message).to.be.equal("Application created successfully"); - expect(res.body).to.have.property("applicationId"); - return done(); }); + + expect(res).to.have.status(201); + expect(res.body.message).to.be.equal("Application created successfully"); + expect(res.body).to.have.property("applicationId"); + + const getRes = await chai + .request(app) + .get(`/applications/${res.body.applicationId}`) + .set("cookie", `${cookieName}=${superUserJwt}`); + + expect(getRes).to.have.status(200); + expect(getRes.body.application.score).to.be.equal(50); }); }); @@ -501,6 +503,48 @@ describe("Application", function () { expect(secondRes.body.error).to.be.equal("Conflict"); expect(secondRes.body.message).to.be.equal(APPLICATION_ERROR_MESSAGES.EDIT_TOO_SOON); }); + + it("should return 200 when updating city, state, and country", async function () { + const applicationData = { ...applicationsData[0], userId }; + const testApplicationId = await applicationModel.addApplication(applicationData); + + const res = await chai + .request(app) + .patch(`/applications/${testApplicationId}`) + .set("cookie", `${cookieName}=${jwt}`) + .send({ city: "New Delhi", state: "Delhi", country: "India" }); + + expect(res).to.have.status(200); + expect(res.body.message).to.be.equal("Application updated successfully"); + }); + + it("should return 200 when updating role with a valid role", async function () { + const applicationData = { ...applicationsData[0], userId }; + const testApplicationId = await applicationModel.addApplication(applicationData); + + const res = await chai + .request(app) + .patch(`/applications/${testApplicationId}`) + .set("cookie", `${cookieName}=${jwt}`) + .send({ role: "designer" }); + + expect(res).to.have.status(200); + expect(res.body.message).to.be.equal("Application updated successfully"); + }); + + it("should return 400 when updating role with an invalid role", async function () { + const applicationData = { ...applicationsData[0], userId }; + const testApplicationId = await applicationModel.addApplication(applicationData); + + const res = await chai + .request(app) + .patch(`/applications/${testApplicationId}`) + .set("cookie", `${cookieName}=${jwt}`) + .send({ role: "invalid_role" }); + + expect(res).to.have.status(400); + expect(res.body.error).to.be.equal("Bad Request"); + }); }); describe("PATCH /applications/:applicationId/feedback", function () { @@ -800,7 +844,7 @@ describe("Application", function () { let nudgeApplicationId: string; beforeEach(async function () { - const applicationData = { ...applicationsData[0], userId }; + const applicationData = { ...applicationsData[0], userId, score: APPLICATION_SCORE.INITIAL_SCORE }; nudgeApplicationId = await applicationModel.addApplication(applicationData); }); @@ -820,6 +864,7 @@ describe("Application", function () { expect(res.body.message).to.be.equal(API_RESPONSE_MESSAGES.NUDGE_SUCCESS); expect(res.body.nudgeCount).to.be.equal(1); expect(res.body.lastNudgeAt).to.be.a("string"); + expect(res.body.score).to.be.equal(APPLICATION_SCORE.INITIAL_SCORE + APPLICATION_SCORE.NUDGE_BONUS); done(); }); }); @@ -834,6 +879,7 @@ describe("Application", function () { expect(res).to.have.status(200); expect(res.body.nudgeCount).to.be.equal(1); + expect(res.body.score).to.be.equal(APPLICATION_SCORE.INITIAL_SCORE + APPLICATION_SCORE.NUDGE_BONUS); const twentyFiveHoursAgo = new Date(Date.now() - 25 * 60 * 60 * 1000).toISOString(); applicationModel @@ -856,6 +902,7 @@ describe("Application", function () { expect(res.body.message).to.be.equal(API_RESPONSE_MESSAGES.NUDGE_SUCCESS); expect(res.body.nudgeCount).to.be.equal(2); expect(res.body.lastNudgeAt).to.be.a("string"); + expect(res.body.score).to.be.equal(APPLICATION_SCORE.INITIAL_SCORE + 2 * APPLICATION_SCORE.NUDGE_BONUS); done(); }); }) diff --git a/test/unit/services/applicationService.test.ts b/test/unit/services/applicationService.test.ts index 8f4f4bc12..2e6639d11 100644 --- a/test/unit/services/applicationService.test.ts +++ b/test/unit/services/applicationService.test.ts @@ -140,7 +140,7 @@ describe("createApplicationService", () => { const applicationData = addApplicationStub.getCall(0).args[0]; expect(applicationData.isNew).to.equal(true); - expect(applicationData.score).to.equal(0); + expect(applicationData.score).to.equal(50); expect(applicationData.status).to.equal(APPLICATION_STATUS_TYPES.PENDING); expect(applicationData.nudgeCount).to.equal(0); }); @@ -186,7 +186,7 @@ describe("createApplicationService", () => { expect(applicationData.location.city).to.equal(mockPayload.city); expect(applicationData.location.state).to.equal(mockPayload.state); expect(applicationData.location.country).to.equal(mockPayload.country); - expect(applicationData.professional.institution).to.equal(mockPayload.college); + expect(applicationData.professional.institution).to.equal(mockPayload.institution); expect(applicationData.professional.skills).to.equal(mockPayload.skills); expect(applicationData.intro.introduction).to.equal(mockPayload.introduction); expect(applicationData.intro.funFact).to.equal(mockPayload.funFact); diff --git a/test/unit/utils/application.test.ts b/test/unit/utils/application.test.ts index 63af7921d..4bcdf8745 100644 --- a/test/unit/utils/application.test.ts +++ b/test/unit/utils/application.test.ts @@ -10,7 +10,7 @@ describe("getUserApplicationObject", async function () { city: "Kanpur", state: "UP", country: "India", - college: "Christ Church College", + institution: "Christ Church College", skills: "React, NodeJs, Ember", introduction: "not needed", funFact: "kdfkasdjfkdk", @@ -33,7 +33,7 @@ describe("getUserApplicationObject", async function () { country: rawData.country, }, professional: { - institution: rawData.college, + institution: rawData.institution, skills: rawData.skills, }, intro: { diff --git a/types/application.d.ts b/types/application.d.ts index b2b0f54db..ebff3f1bc 100644 --- a/types/application.d.ts +++ b/types/application.d.ts @@ -60,7 +60,7 @@ export type applicationPayload = { city: string; state: string; country: string; - college: string; + institution: string; skills: string; introduction: string; funFact: string; @@ -74,6 +74,12 @@ export type applicationPayload = { }; export type applicationUpdatePayload = { + city?: string; + state?: string; + country?: string; + institution?: string; + skills?: string; + role?: ApplicationRole; imageUrl?: string; foundFrom?: string; introduction?: string; diff --git a/utils/application.ts b/utils/application.ts index b1a999612..a7055609d 100644 --- a/utils/application.ts +++ b/utils/application.ts @@ -13,7 +13,7 @@ const getUserApplicationObject = (rawData: applicationPayload, userId: string, c country: rawData.country, }, professional: { - institution: rawData.college, + institution: rawData.institution, skills: rawData.skills, }, intro: { @@ -31,6 +31,12 @@ const getUserApplicationObject = (rawData: applicationPayload, userId: string, c }; const FLAT_FIELD_MAP: Record, string> = { + city: "location.city", + state: "location.state", + country: "location.country", + institution: "professional.institution", + skills: "professional.skills", + role: "role", imageUrl: "imageUrl", foundFrom: "foundFrom", introduction: "intro.introduction", From 696cf34db328dccd8fe55d9d01b5637356eda7c7 Mon Sep 17 00:00:00 2001 From: Anuj Chhikara <107175639+AnujChhikara@users.noreply.github.com> Date: Sat, 21 Feb 2026 13:09:46 +0530 Subject: [PATCH 3/3] feat: implement user picture upload handling for application type (#2564) --- controllers/users.js | 25 ++++++++++++++++ middlewares/pictureRouteMiddleware.js | 8 +++++ routes/users.js | 9 +++++- test/integration/application.test.ts | 42 +++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 middlewares/pictureRouteMiddleware.js diff --git a/controllers/users.js b/controllers/users.js index 2ae4cd123..f1dfd0db9 100644 --- a/controllers/users.js +++ b/controllers/users.js @@ -561,6 +561,30 @@ const updateSelf = async (req, res, next) => { } }; +const handleUserPictureUpload = async (req, res) => { + if (req.body.type === "application") { + return postApplicationUserPicture(req, res); + } + return postUserPicture(req, res); +}; + +const postApplicationUserPicture = async (req, res) => { + const { file } = req; + const { id: userId } = req.userData; + const { coordinates } = req.body; + try { + const coordinatesObject = coordinates && JSON.parse(coordinates); + const imageData = await imageService.uploadProfilePicture({ file, userId, coordinates: coordinatesObject }); + return res.status(201).json({ + message: "Application picture uploaded successfully!", + image: imageData, + }); + } catch (error) { + logger.error(`Error while uploading application picture: ${error}`); + return res.boom.badImplementation(INTERNAL_SERVER_ERROR); + } +}; + /** * Post user profile picture * @@ -1186,4 +1210,5 @@ module.exports = { getIdentityStats, updateUsernames, updateProfile, + handleUserPictureUpload, }; diff --git a/middlewares/pictureRouteMiddleware.js b/middlewares/pictureRouteMiddleware.js new file mode 100644 index 000000000..11f8e84de --- /dev/null +++ b/middlewares/pictureRouteMiddleware.js @@ -0,0 +1,8 @@ +const skipWhenApplicationType = (middleware) => { + return (req, res, next) => { + if (req.body.type === "application") return next(); + return middleware(req, res, next); + }; +}; + +module.exports = skipWhenApplicationType; diff --git a/routes/users.js b/routes/users.js index ebf1e4ca2..e151273b4 100644 --- a/routes/users.js +++ b/routes/users.js @@ -15,6 +15,7 @@ const authenticateProfile = require("../middlewares/authenticateProfile"); const { devFlagMiddleware } = require("../middlewares/devFlag"); const { userAuthorization } = require("../middlewares/userAuthorization"); const conditionalMiddleware = require("../middlewares/conditionalMiddleware"); +const skipWhenApplicationType = require("../middlewares/pictureRouteMiddleware"); router.post("/", authorizeAndAuthenticate([ROLES.SUPERUSER], [Services.CRON_JOB_HANDLER]), users.markUnverified); router.post("/update-in-discord", authenticate, authorizeRoles([SUPERUSER]), users.setInDiscordScript); @@ -65,7 +66,13 @@ router.patch( ); // upload.single('profile') -> multer inmemory storage of file for type multipart/form-data -router.post("/picture", authenticate, checkIsVerifiedDiscord, upload.single("profile"), users.postUserPicture); +router.post( + "/picture", + authenticate, + upload.single("profile"), + skipWhenApplicationType(checkIsVerifiedDiscord), + users.handleUserPictureUpload +); router.patch( "/picture/verify/:id", authenticate, diff --git a/test/integration/application.test.ts b/test/integration/application.test.ts index 8773ed9ea..9bb9d38bb 100644 --- a/test/integration/application.test.ts +++ b/test/integration/application.test.ts @@ -13,6 +13,8 @@ const applicationModel = require("../../models/applications"); const applicationsData = require("../fixtures/applications/applications")(); const cookieName = config.get("userToken.cookieName"); const { APPLICATION_ERROR_MESSAGES, API_RESPONSE_MESSAGES, APPLICATION_SCORE } = require("../../constants/application"); +const imageService = require("../../services/imageService"); +const { Buffer } = require("node:buffer"); const appOwner = userData[3]; const superUser = userData[4]; @@ -996,4 +998,44 @@ describe("Application", function () { }); }); }); + + describe("POST /users/picture (application type)", function () { + it("should return 201 when uploading with type=application and valid file", function (done) { + const mockImageResponse = { publicId: "profile/test-id/image", url: "https://res.cloudinary.com/example/image.png" }; + const uploadStub = sinon.stub(imageService, "uploadProfilePicture").resolves(mockImageResponse); + chai + .request(app) + .post("/users/picture") + .type("form") + .set("cookie", `${cookieName}=${jwt}`) + .attach("profile", Buffer.from("fake-image-data", "utf-8"), "image.png") + .field("type", "application") + .end((err, res) => { + uploadStub.restore(); + if (err) return done(err); + expect(res).to.have.status(201); + expect(res.body.message).to.equal("Application picture uploaded successfully!"); + expect(res.body.image).to.deep.equal(mockImageResponse); + return done(); + }); + }); + + it("should return 500 when upload fails", function (done) { + const uploadStub = sinon.stub(imageService, "uploadProfilePicture").rejects(new Error("Upload failed")); + chai + .request(app) + .post("/users/picture") + .type("form") + .set("cookie", `${cookieName}=${jwt}`) + .attach("profile", Buffer.from("fake-image-data", "utf-8"), "image.png") + .field("type", "application") + .end((err, res) => { + uploadStub.restore(); + if (err) return done(err); + expect(res).to.have.status(500); + expect(res.body.error).to.equal("Internal Server Error"); + return done(); + }); + }); + }); });