From 89cab7aff1827dc4670404756ccecf39bea9686e Mon Sep 17 00:00:00 2001 From: jjshen Date: Sun, 9 Feb 2025 23:31:56 -0500 Subject: [PATCH 1/6] working branch which allows a user to 'tag' a topic as resolved by typing it in. this will mark the topic as resolved, and will unmark it as resolved if the tag is removed --- public/src/client/topic.js | 4 ++++ src/controllers/topics.js | 16 +++++++++------- src/topics/tags.js | 13 +++++++++++-- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/public/src/client/topic.js b/public/src/client/topic.js index 7e65cbeb..0da5f55c 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -74,6 +74,10 @@ define('forum/topic', [ handleTopicSearch(); + if (ajaxify.data.resolved) { + $('.topic-title').append(' Resolved'); + } + hooks.fire('action:topic.loaded', ajaxify.data); }; diff --git a/src/controllers/topics.js b/src/controllers/topics.js index b4aa48cb..d5a4f488 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -411,25 +411,25 @@ const db = require('../database'); topicsController.setResolved = async function (req, res) { try { const { tid } = req.params; - const { resolved } = req.body; // Expected payload: { "resolved": true } or { "resolved": false } + let { resolved } = req.body; if (typeof resolved !== 'boolean') { return res.status(400).json({ error: "Invalid request. 'resolved' must be a boolean." }); } - // Fetch the topic to ensure it exists - const topic = await topics.getTopicData(tid); - if (!topic) { - return res.status(404).json({ error: 'Topic not found' }); + // Fetch topic tags + const topicTags = await Topics.getTopicTags(tid); + if (topicTags.includes('resolved')) { + resolved = true; // Auto-set resolved if tag is present } - // Ensure the user has permission to edit the topic + // Check user permissions const canEdit = await privileges.topics.canEdit(tid, req.uid); if (!canEdit) { return res.status(403).json({ error: '[[error:no-privileges]]' }); } - // Update the `resolved` field in Redis + // Update the resolved status in the database await db.setObjectField(`topic:${tid}`, 'resolved', resolved.toString()); res.json({ message: 'Topic resolved status updated', tid, resolved }); @@ -437,3 +437,5 @@ topicsController.setResolved = async function (req, res) { res.status(500).json({ error: error.message }); } }; + + diff --git a/src/topics/tags.js b/src/topics/tags.js index daab4e5f..3167268d 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -413,12 +413,21 @@ module.exports = function (Topics) { Topics.updateTopicTags = async function (tid, tags) { await Topics.deleteTopicTags(tid); const cid = await Topics.getTopicField(tid, 'cid'); - + tags = await Topics.filterTags(tags, cid); await Topics.addTags(tags, [tid]); + + // Auto-update resolved status if the "resolved" tag is present + if (tags.includes('resolved')) { + await db.setObjectField(`topic:${tid}`, 'resolved', 'true'); + } + if (!tags.includes('resolved')) { + await db.setObjectField(`topic:${tid}`, 'resolved', 'false'); + } + plugins.hooks.fire('action:topic.updateTags', { tags, tid }); }; - + Topics.deleteTopicTags = async function (tid) { const topicData = await Topics.getTopicFields(tid, ['cid', 'tags']); const { cid } = topicData; From 8893116fb5f5a4afda26276a2a731758d42993ce Mon Sep 17 00:00:00 2001 From: jjshen Date: Sat, 22 Feb 2025 17:03:41 -0500 Subject: [PATCH 2/6] added 2 test cases for testing if topic correctly updates resolved status when flagging --- test/topics.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/topics.js b/test/topics.js index a3346faa..08878721 100644 --- a/test/topics.js +++ b/test/topics.js @@ -2587,6 +2587,24 @@ describe('topicsController.setResolved - Unit Test', () => { assert(res.status.calledWith(400)); assert(res.json.calledWithMatch({ error: "Invalid request. 'resolved' must be a boolean." })); }); + + it('should update the database with the correct resolved status', async () => { + req.body.resolved = true; + await topicsController.setResolved(req, res); + + const resolvedStatus = await topics.getTopicField(req.params.tid, 'resolved'); + assert.strictEqual(resolvedStatus, 'true'); + }); + + it('should not update the resolved status if the topic does not exist', async () => { + req.params.tid = 999999; // Non-existent topic + req.body.resolved = true; + await topicsController.setResolved(req, res); + + assert(res.status.calledWith(404)); + assert(res.json.calledWithMatch({ error: 'Topic not found' })); + }); + }); // Integration Tests Marking Question Resolved/Unresolved From 8496523c1e4195fc4330a43d82e726f1b1facfe7 Mon Sep 17 00:00:00 2001 From: Jorge Urias Date: Thu, 27 Feb 2025 00:14:01 -0500 Subject: [PATCH 3/6] Fixed lint test errors on src/controllers/topics.js, src//topics/tags.js, and test/topics.js --- dump.rdb | Bin 56246 -> 79772 bytes src/controllers/topics.js | 56 +++++++++++++++++++------------------- src/topics/tags.js | 8 +++--- test/topics.js | 21 +++++++------- 4 files changed, 42 insertions(+), 43 deletions(-) diff --git a/dump.rdb b/dump.rdb index 322f6cc8499faff91a1f4274f6bb497eb63c950e..bf3cb98361ca5ebe28961c5ca50465d923e0b77b 100644 GIT binary patch delta 15834 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 { assert.deepStrictEqual(res.data, { error: "Invalid request. 'resolved' must be a boolean." }); }); - it('should return 400 if "resolved" field is not a boolean', () => { - req.body.resolved = 'invalid'; // Invalid type - topicsController.setResolved(req, res); - - assert(res.status.calledWith(400)); - assert(res.json.calledWithMatch({ error: "Invalid request. 'resolved' must be a boolean." })); - }); + it('should return 400 if "resolved" field is not a boolean', () => { + req.body.resolved = 'invalid'; // Invalid type + topicsController.setResolved(req, res); + + assert(res.status.calledWith(400)); + assert(res.json.calledWithMatch({ error: "Invalid request. 'resolved' must be a boolean." })); + }); it('should update the database with the correct resolved status', async () => { req.body.resolved = true; await topicsController.setResolved(req, res); - + const resolvedStatus = await topics.getTopicField(req.params.tid, 'resolved'); assert.strictEqual(resolvedStatus, 'true'); }); - + it('should not update the resolved status if the topic does not exist', async () => { req.params.tid = 999999; // Non-existent topic req.body.resolved = true; await topicsController.setResolved(req, res); - + assert(res.status.calledWith(404)); assert(res.json.calledWithMatch({ error: 'Topic not found' })); }); - }); From 423e5beb00576fbaab934595807d513ce0f179c3 Mon Sep 17 00:00:00 2001 From: Jorge Urias Date: Thu, 27 Feb 2025 00:49:24 -0500 Subject: [PATCH 4/6] Edited test/plugins.js file and the topicsController.setResolved - Unit Test in test/topics.js --- dump.rdb | Bin 79772 -> 55566 bytes test/plugins.js | 3 +- test/topics.js | 295 +++++++++++++++++++++++++++++++++--------------- 3 files changed, 205 insertions(+), 93 deletions(-) diff --git a/dump.rdb b/dump.rdb index bf3cb98361ca5ebe28961c5ca50465d923e0b77b..5b3f4395a5c2e178869397e1db698aeae8995ad0 100644 GIT binary patch delta 3305 zcmaJ@eN4DG6GDIxO!yY5QWRTtTF`!I5lO^Uu>w)B>pn!Zm=r|5 zp6ab_J=1!IR*ORJv|3k-c5dyuDO6X#s(8B7o}*nYZ8>%YTlTv*K-+C+|J-wudw;+8 zeV_Mvp7(v_i_n%pNSnh_Ir8@E;qZ+$o>lfrPvu$V%w*AUxV!o(`$~6>r&sj7Xe56~ zgleA|u8af>YNhN0DMW)kPI!A>Q?sf99>*mTG@C*y8o zHn%aag}{5jiGlUmBpKZn0|pZ%tSgd8*;Wm`th-0ep3;!XxZWdcKd-{w8B(NLw&3(y z8QyN{6#Ezabi695R!U@l#oOx0i;X*>A2;N%T1g+o58kHmx zbzN5UtL+-ZiZwMnoZo^eE6M6OJXF*+HLg0u2MaFa*HVdsu>Dc2_ zp;r@$ruVJT#b%=>G|nV2TB~I$cDl)LUIso9mQt#oSqvR9msC zmxOE-o?iYLQCm^zsi}2WdLy0L>C>GV8O|)HGd+WC2_aMATV*0*|WQp zq!nAY`voM|WvFO|3S4(rVM#2{DLYRSn)_gt9*T4=?kzcoFVbW<-9CiH>vK_jz`)05 z9f>3qGviBTOau>9O)fLO+DRX(c6&*{!lhZHZ z&fpnK%!(1P>TCFfIHNcf@>Ui&A99mj| zy=V3K?n@bXOvjJyDeuG4GmWSV*@kO{55w_IOehgCX*{KQ(FtgCa~3fK%;7BjQRZhI zKO;-{Om$2Yb%G5PSPE}>^~S1NnM@=SiA98n$tc>3jAK#Uc+BYsnU{b%-Cex7P>we( zYN~1}iV9PBo)fK5l0Hf+X3~Ymj*Ecm5f^Vii~VzaSUy9Jn=>Ra=O?ou`)>rW-K-1yJZ*PN^y{Be8<^J z8)2}fpnyIp#;h)!DDdm~Rbr*^8j3~+!^MNB-}Ne%p3dVgJ=H_7hQ#78VjEs=lv955 z2(QKFZFP7xFm}N-ua3gzgpM6KWiO?f2ZLyO+!HQP+oO3O_Bs*oI2#h%&@sAI^akDoeYZDY#dl6$d6jxAoutq213~- z$EKZvVemxP;-Lr6!^~RoeT)>|MH+N9sL`zp>zJa%)dm@~Qy8RqeE9m{da+E)Zq^bt zhF#HUOF4nBnZq7tTo7foS5U6qo~Rt`o6_;@3TP2Pas|BZb+)IL* zi9+j(W<1Aq@@(Ta?F=FK>yuXn>MiV4Q4bvCoq}7J5k}Y}Qexx<9)XJmA7kn6X(XKz z#zN^>E>`jj2esQVPwnpMXZQ0~F!}XF>UU)ipDg__hdvXqSj`TU%vEt;Z7nFMT{zWw-F4L$Gar7kG?_C z?dLFbZ~>cWBPwR%+vhwLt3nAG?YO)N=DEhPxf~A3XE6~M$1emUX_oZ!ztC2igSN*E z>?@N<@*79Bq(m-eG6Y@SI2(rEPm`<@r$&|1)$6KPy4OWV3lqv;<$1QYuwqp>4abb{ zIC4IcL^uQ8+#J+>{?oXo34x4#)K)r+4k2D9$v^5X%H zkGs~x?|JX!Uw-hq;W~v}C3*!t3#KX}*0^hRL&EjOM8f_pgE&baJDNePq@T5B5_{YS zz1u~v-ili8N^w0Yin~SZx0EMc_ATAw_@Rq?mlN8%A5XirW2sgw4yM}mtql>)23|=v z`9!g!41Y$LE(zL+fBzc-?6|Vv|GsA=CVm?Ik5=;n_J@AJV^MT_I&Lur%&N5UUa@$r nFN5Ni;QPF@TZDC^cXr}`uxN8&%A^V6jgJ0GHDqJsS1$WE=+z|^ delta 16123 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 { it('should install a plugin', function (done) { this.timeout(0); - plugins.toggleInstall(pluginName, '1.0.16', (err, pluginData) => { + // Before it was 1.0.16 + plugins.toggleInstall(pluginName, '4.1.0', (err, pluginData) => { assert.ifError(err); latest = pluginData.latest; diff --git a/test/topics.js b/test/topics.js index e44b5634..96768777 100644 --- a/test/topics.js +++ b/test/topics.js @@ -2524,106 +2524,217 @@ describe('Topics\'', async () => { +// // Unit Tests Marking Question Resolved/Unresolved +// const topicsController = require('../src/controllers/topics'); + +// describe('topicsController.setResolved - Unit Test', () => { +// let req; +// let res; +// let testTid; +// let adminUid; +// let adminJar; +// let csrf_token; + +// beforeEach(async () => { +// adminUid = await User.create({ username: 'admin', password: '123456' }); +// await groups.join('administrators', adminUid); +// const adminLogin = await helpers.loginUser('admin', '123456'); +// adminJar = adminLogin.jar; +// csrf_token = adminLogin.csrf_token; +// // Create a test topic in the database using the actual API function +// const categoryObj = await categories.create({ +// name: 'Resolved Topics Test', +// description: 'Category for testing resolved topics', +// }); +// const topic = await topics.post({ +// uid: adminUid, +// title: 'Test Topic', +// content: 'This is a test topic.', +// cid: categoryObj.cid, // Assuming category ID 1 exists in test DB +// }); +// testTid = topic.topicData.tid; // Get the actual created topic ID +// req = { params: { tid: testTid }, body: {}, uid: 1 }; +// res = { +// data: null, +// statusCode: null, +// json: function (data) { this.data = data; return this; }, +// status: function (code) { this.statusCode = code; return this; }, +// }; +// }); + +// afterEach(async () => { +// // Clean up the test topic +// await topics.purge(testTid, 1); +// }); + +// it('should successfully mark a topic as resolved', async () => { +// req.body.resolved = true; +// await topicsController.setResolved(req, res); + +// assert.deepStrictEqual(res.data, { +// message: 'Topic resolved status updated', +// tid: testTid, +// resolved: true, +// }); +// }); + +// it('should successfully unmark a topic as resolved (set unresolved)', async () => { +// req.body.resolved = false; +// await topicsController.setResolved(req, res); + +// assert.deepStrictEqual(res.data, { +// message: 'Topic resolved status updated', +// tid: testTid, +// resolved: false, +// }); +// }); + +// it('should return 400 if "resolved" field is missing', async () => { +// await topicsController.setResolved(req, res); + +// assert.strictEqual(res.statusCode, 400); +// assert.deepStrictEqual(res.data, { error: "Invalid request. 'resolved' must be a boolean." }); +// }); + +// it('should return 400 if "resolved" field is not a boolean', () => { +// req.body.resolved = 'invalid'; // Invalid type +// topicsController.setResolved(req, res); + +// assert(res.status.calledWith(400)); +// assert(res.json.calledWithMatch({ error: "Invalid request. 'resolved' must be a boolean." })); +// }); + +// it('should update the database with the correct resolved status', async () => { +// req.body.resolved = true; +// await topicsController.setResolved(req, res); + +// const resolvedStatus = await topics.getTopicField(req.params.tid, 'resolved'); +// assert.strictEqual(resolvedStatus, 'true'); +// }); + +// it('should not update the resolved status if the topic does not exist', async () => { +// req.params.tid = 999999; // Non-existent topic +// req.body.resolved = true; +// await topicsController.setResolved(req, res); + +// assert(res.status.calledWith(404)); +// assert(res.json.calledWithMatch({ error: 'Topic not found' })); +// }); +// }); + // Unit Tests Marking Question Resolved/Unresolved const topicsController = require('../src/controllers/topics'); describe('topicsController.setResolved - Unit Test', () => { - let req; - let res; - let testTid; - let adminUid; - let adminJar; - let csrf_token; - - beforeEach(async () => { - adminUid = await User.create({ username: 'admin', password: '123456' }); - await groups.join('administrators', adminUid); - const adminLogin = await helpers.loginUser('admin', '123456'); - adminJar = adminLogin.jar; - csrf_token = adminLogin.csrf_token; - // Create a test topic in the database using the actual API function - const categoryObj = await categories.create({ - name: 'Resolved Topics Test', - description: 'Category for testing resolved topics', - }); - const topic = await topics.post({ - uid: adminUid, - title: 'Test Topic', - content: 'This is a test topic.', - cid: categoryObj.cid, // Assuming category ID 1 exists in test DB - }); - testTid = topic.topicData.tid; // Get the actual created topic ID - req = { params: { tid: testTid }, body: {}, uid: 1 }; - res = { - data: null, - statusCode: null, - json: function (data) { this.data = data; return this; }, - status: function (code) { this.statusCode = code; return this; }, - }; - }); - - afterEach(async () => { - // Clean up the test topic - await topics.purge(testTid, 1); - }); - - it('should successfully mark a topic as resolved', async () => { - req.body.resolved = true; - await topicsController.setResolved(req, res); - - assert.deepStrictEqual(res.data, { - message: 'Topic resolved status updated', - tid: testTid, - resolved: true, - }); - }); - - it('should successfully unmark a topic as resolved (set unresolved)', async () => { - req.body.resolved = false; - await topicsController.setResolved(req, res); - - assert.deepStrictEqual(res.data, { - message: 'Topic resolved status updated', - tid: testTid, - resolved: false, - }); - }); - - it('should return 400 if "resolved" field is missing', async () => { - await topicsController.setResolved(req, res); - - assert.strictEqual(res.statusCode, 400); - assert.deepStrictEqual(res.data, { error: "Invalid request. 'resolved' must be a boolean." }); - }); - - it('should return 400 if "resolved" field is not a boolean', () => { - req.body.resolved = 'invalid'; // Invalid type - topicsController.setResolved(req, res); - - assert(res.status.calledWith(400)); - assert(res.json.calledWithMatch({ error: "Invalid request. 'resolved' must be a boolean." })); - }); - - it('should update the database with the correct resolved status', async () => { - req.body.resolved = true; - await topicsController.setResolved(req, res); - - const resolvedStatus = await topics.getTopicField(req.params.tid, 'resolved'); - assert.strictEqual(resolvedStatus, 'true'); - }); - - it('should not update the resolved status if the topic does not exist', async () => { - req.params.tid = 999999; // Non-existent topic - req.body.resolved = true; - await topicsController.setResolved(req, res); - - assert(res.status.calledWith(404)); - assert(res.json.calledWithMatch({ error: 'Topic not found' })); - }); + let req; + let res; + let testTid; + let adminUid; + let adminJar; + let csrf_token; + + beforeEach(async () => { + adminUid = await User.create({ username: 'admin', password: '123456' }); + await groups.join('administrators', adminUid); + const adminLogin = await helpers.loginUser('admin', '123456'); + adminJar = adminLogin.jar; + csrf_token = adminLogin.csrf_token; + + // Create a test topic in the database using the actual API function + const categoryObj = await categories.create({ + name: 'Resolved Topics Test', + description: 'Category for testing resolved topics', + }); + const topic = await topics.post({ + uid: adminUid, + title: 'Test Topic', + content: 'This is a test topic.', + cid: categoryObj.cid, + }); + testTid = topic.topicData.tid; + + req = { params: { tid: testTid }, body: {}, uid: 1 }; + res = { + data: null, + statusCode: null, + statusHistory: [], + jsonHistory: [], + json: function (data) { + this.data = data; + this.jsonHistory.push(data); + return this; + }, + status: function (code) { + this.statusCode = code; + this.statusHistory.push(code); + return this; + }, + }; + }); + + afterEach(async () => { + // Clean up the test topic + await topics.purge(testTid, 1); + }); + + it('should successfully mark a topic as resolved', async () => { + req.body.resolved = true; + await topicsController.setResolved(req, res); + + assert.deepStrictEqual(res.data, { + message: 'Topic resolved status updated', + tid: testTid, + resolved: true, + }); + }); + + it('should successfully unmark a topic as resolved (set unresolved)', async () => { + req.body.resolved = false; + await topicsController.setResolved(req, res); + + assert.deepStrictEqual(res.data, { + message: 'Topic resolved status updated', + tid: testTid, + resolved: false, + }); + }); + + it('should return 400 if "resolved" field is missing', async () => { + await topicsController.setResolved(req, res); + + assert.strictEqual(res.statusHistory[0], 400); + assert.deepStrictEqual(res.jsonHistory[0], { error: "Invalid request. 'resolved' must be a boolean." }); + }); + + it('should return 400 if "resolved" field is not a boolean', async () => { + req.body.resolved = 'invalid'; // Invalid type + await topicsController.setResolved(req, res); + + assert.strictEqual(res.statusHistory[0], 400); + assert.deepStrictEqual(res.jsonHistory[0], { error: "Invalid request. 'resolved' must be a boolean." }); + }); + + it('should update the database with the correct resolved status', async () => { + req.body.resolved = true; + await topicsController.setResolved(req, res); + + const resolvedStatus = await topics.getTopicField(req.params.tid, 'resolved'); + assert.strictEqual(resolvedStatus, 'true'); // Ensure value is stored as string + }); + + it('should not update the resolved status if the topic does not exist', async () => { + req.params.tid = 999999; // Non-existent topic + req.body.resolved = true; + await topicsController.setResolved(req, res); + + assert.strictEqual(res.statusHistory[0], 404); + assert.deepStrictEqual(res.jsonHistory[0], { error: 'Topic not found' }); + }); }); + // Integration Tests Marking Question Resolved/Unresolved describe('Marking Topics as Resolved', () => { let testTid; From c198aa67abf46418416468ea39b380868fda0d39 Mon Sep 17 00:00:00 2001 From: Jorge Urias Date: Thu, 27 Feb 2025 00:52:25 -0500 Subject: [PATCH 5/6] Deleted commented old code in test/topics.js --- test/topics.js | 308 +++++++++++++++++-------------------------------- 1 file changed, 104 insertions(+), 204 deletions(-) diff --git a/test/topics.js b/test/topics.js index 96768777..78176415 100644 --- a/test/topics.js +++ b/test/topics.js @@ -2522,214 +2522,114 @@ describe('Topics\'', async () => { }); - - -// // Unit Tests Marking Question Resolved/Unresolved -// const topicsController = require('../src/controllers/topics'); - -// describe('topicsController.setResolved - Unit Test', () => { -// let req; -// let res; -// let testTid; -// let adminUid; -// let adminJar; -// let csrf_token; - -// beforeEach(async () => { -// adminUid = await User.create({ username: 'admin', password: '123456' }); -// await groups.join('administrators', adminUid); -// const adminLogin = await helpers.loginUser('admin', '123456'); -// adminJar = adminLogin.jar; -// csrf_token = adminLogin.csrf_token; -// // Create a test topic in the database using the actual API function -// const categoryObj = await categories.create({ -// name: 'Resolved Topics Test', -// description: 'Category for testing resolved topics', -// }); -// const topic = await topics.post({ -// uid: adminUid, -// title: 'Test Topic', -// content: 'This is a test topic.', -// cid: categoryObj.cid, // Assuming category ID 1 exists in test DB -// }); -// testTid = topic.topicData.tid; // Get the actual created topic ID -// req = { params: { tid: testTid }, body: {}, uid: 1 }; -// res = { -// data: null, -// statusCode: null, -// json: function (data) { this.data = data; return this; }, -// status: function (code) { this.statusCode = code; return this; }, -// }; -// }); - -// afterEach(async () => { -// // Clean up the test topic -// await topics.purge(testTid, 1); -// }); - -// it('should successfully mark a topic as resolved', async () => { -// req.body.resolved = true; -// await topicsController.setResolved(req, res); - -// assert.deepStrictEqual(res.data, { -// message: 'Topic resolved status updated', -// tid: testTid, -// resolved: true, -// }); -// }); - -// it('should successfully unmark a topic as resolved (set unresolved)', async () => { -// req.body.resolved = false; -// await topicsController.setResolved(req, res); - -// assert.deepStrictEqual(res.data, { -// message: 'Topic resolved status updated', -// tid: testTid, -// resolved: false, -// }); -// }); - -// it('should return 400 if "resolved" field is missing', async () => { -// await topicsController.setResolved(req, res); - -// assert.strictEqual(res.statusCode, 400); -// assert.deepStrictEqual(res.data, { error: "Invalid request. 'resolved' must be a boolean." }); -// }); - -// it('should return 400 if "resolved" field is not a boolean', () => { -// req.body.resolved = 'invalid'; // Invalid type -// topicsController.setResolved(req, res); - -// assert(res.status.calledWith(400)); -// assert(res.json.calledWithMatch({ error: "Invalid request. 'resolved' must be a boolean." })); -// }); - -// it('should update the database with the correct resolved status', async () => { -// req.body.resolved = true; -// await topicsController.setResolved(req, res); - -// const resolvedStatus = await topics.getTopicField(req.params.tid, 'resolved'); -// assert.strictEqual(resolvedStatus, 'true'); -// }); - -// it('should not update the resolved status if the topic does not exist', async () => { -// req.params.tid = 999999; // Non-existent topic -// req.body.resolved = true; -// await topicsController.setResolved(req, res); - -// assert(res.status.calledWith(404)); -// assert(res.json.calledWithMatch({ error: 'Topic not found' })); -// }); -// }); - // Unit Tests Marking Question Resolved/Unresolved const topicsController = require('../src/controllers/topics'); describe('topicsController.setResolved - Unit Test', () => { - let req; - let res; - let testTid; - let adminUid; - let adminJar; - let csrf_token; - - beforeEach(async () => { - adminUid = await User.create({ username: 'admin', password: '123456' }); - await groups.join('administrators', adminUid); - const adminLogin = await helpers.loginUser('admin', '123456'); - adminJar = adminLogin.jar; - csrf_token = adminLogin.csrf_token; - - // Create a test topic in the database using the actual API function - const categoryObj = await categories.create({ - name: 'Resolved Topics Test', - description: 'Category for testing resolved topics', - }); - const topic = await topics.post({ - uid: adminUid, - title: 'Test Topic', - content: 'This is a test topic.', - cid: categoryObj.cid, - }); - testTid = topic.topicData.tid; - - req = { params: { tid: testTid }, body: {}, uid: 1 }; - res = { - data: null, - statusCode: null, - statusHistory: [], - jsonHistory: [], - json: function (data) { - this.data = data; - this.jsonHistory.push(data); - return this; - }, - status: function (code) { - this.statusCode = code; - this.statusHistory.push(code); - return this; - }, - }; - }); - - afterEach(async () => { - // Clean up the test topic - await topics.purge(testTid, 1); - }); - - it('should successfully mark a topic as resolved', async () => { - req.body.resolved = true; - await topicsController.setResolved(req, res); - - assert.deepStrictEqual(res.data, { - message: 'Topic resolved status updated', - tid: testTid, - resolved: true, - }); - }); - - it('should successfully unmark a topic as resolved (set unresolved)', async () => { - req.body.resolved = false; - await topicsController.setResolved(req, res); - - assert.deepStrictEqual(res.data, { - message: 'Topic resolved status updated', - tid: testTid, - resolved: false, - }); - }); - - it('should return 400 if "resolved" field is missing', async () => { - await topicsController.setResolved(req, res); - - assert.strictEqual(res.statusHistory[0], 400); - assert.deepStrictEqual(res.jsonHistory[0], { error: "Invalid request. 'resolved' must be a boolean." }); - }); - - it('should return 400 if "resolved" field is not a boolean', async () => { - req.body.resolved = 'invalid'; // Invalid type - await topicsController.setResolved(req, res); - - assert.strictEqual(res.statusHistory[0], 400); - assert.deepStrictEqual(res.jsonHistory[0], { error: "Invalid request. 'resolved' must be a boolean." }); - }); - - it('should update the database with the correct resolved status', async () => { - req.body.resolved = true; - await topicsController.setResolved(req, res); - - const resolvedStatus = await topics.getTopicField(req.params.tid, 'resolved'); - assert.strictEqual(resolvedStatus, 'true'); // Ensure value is stored as string - }); - - it('should not update the resolved status if the topic does not exist', async () => { - req.params.tid = 999999; // Non-existent topic - req.body.resolved = true; - await topicsController.setResolved(req, res); - - assert.strictEqual(res.statusHistory[0], 404); - assert.deepStrictEqual(res.jsonHistory[0], { error: 'Topic not found' }); - }); + let req; + let res; + let testTid; + let adminUid; + let adminJar; + let csrf_token; + + beforeEach(async () => { + adminUid = await User.create({ username: 'admin', password: '123456' }); + await groups.join('administrators', adminUid); + const adminLogin = await helpers.loginUser('admin', '123456'); + adminJar = adminLogin.jar; + csrf_token = adminLogin.csrf_token; + + // Create a test topic in the database using the actual API function + const categoryObj = await categories.create({ + name: 'Resolved Topics Test', + description: 'Category for testing resolved topics', + }); + const topic = await topics.post({ + uid: adminUid, + title: 'Test Topic', + content: 'This is a test topic.', + cid: categoryObj.cid, + }); + testTid = topic.topicData.tid; + + req = { params: { tid: testTid }, body: {}, uid: 1 }; + res = { + data: null, + statusCode: null, + statusHistory: [], + jsonHistory: [], + json: function (data) { + this.data = data; + this.jsonHistory.push(data); + return this; + }, + status: function (code) { + this.statusCode = code; + this.statusHistory.push(code); + return this; + }, + }; + }); + + afterEach(async () => { + // Clean up the test topic + await topics.purge(testTid, 1); + }); + + it('should successfully mark a topic as resolved', async () => { + req.body.resolved = true; + await topicsController.setResolved(req, res); + + assert.deepStrictEqual(res.data, { + message: 'Topic resolved status updated', + tid: testTid, + resolved: true, + }); + }); + + it('should successfully unmark a topic as resolved (set unresolved)', async () => { + req.body.resolved = false; + await topicsController.setResolved(req, res); + + assert.deepStrictEqual(res.data, { + message: 'Topic resolved status updated', + tid: testTid, + resolved: false, + }); + }); + + it('should return 400 if "resolved" field is missing', async () => { + await topicsController.setResolved(req, res); + + assert.strictEqual(res.statusHistory[0], 400); + assert.deepStrictEqual(res.jsonHistory[0], { error: "Invalid request. 'resolved' must be a boolean." }); + }); + + it('should return 400 if "resolved" field is not a boolean', async () => { + req.body.resolved = 'invalid'; // Invalid type + await topicsController.setResolved(req, res); + + assert.strictEqual(res.statusHistory[0], 400); + assert.deepStrictEqual(res.jsonHistory[0], { error: "Invalid request. 'resolved' must be a boolean." }); + }); + + it('should update the database with the correct resolved status', async () => { + req.body.resolved = true; + await topicsController.setResolved(req, res); + + const resolvedStatus = await topics.getTopicField(req.params.tid, 'resolved'); + assert.strictEqual(resolvedStatus, 'true'); // Ensure value is stored as string + }); + + it('should not update the resolved status if the topic does not exist', async () => { + req.params.tid = 999999; // Non-existent topic + req.body.resolved = true; + await topicsController.setResolved(req, res); + + assert.strictEqual(res.statusHistory[0], 404); + assert.deepStrictEqual(res.jsonHistory[0], { error: 'Topic not found' }); + }); }); From 7a0e466034820e83dd50ce70229abf0c24e29d22 Mon Sep 17 00:00:00 2001 From: Jorge Urias Date: Thu, 27 Feb 2025 01:00:09 -0500 Subject: [PATCH 6/6] Edited topicsController.setResolved - Unit Test in test/topics.js on one of the comparison booleans --- test/topics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/topics.js b/test/topics.js index 78176415..64d8b51a 100644 --- a/test/topics.js +++ b/test/topics.js @@ -2619,7 +2619,7 @@ describe('topicsController.setResolved - Unit Test', () => { await topicsController.setResolved(req, res); const resolvedStatus = await topics.getTopicField(req.params.tid, 'resolved'); - assert.strictEqual(resolvedStatus, 'true'); // Ensure value is stored as string + assert.strictEqual(resolvedStatus, true); // Ensure value is stored as string }); it('should not update the resolved status if the topic does not exist', async () => {