ProjectCollabratecDetails.test.mjs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. import { vi, expect } from 'vitest'
  2. import mongodb from 'mongodb-legacy'
  3. import sinon from 'sinon'
  4. const { ObjectId } = mongodb
  5. const MODULE_PATH =
  6. '../../../../app/src/Features/Project/ProjectCollabratecDetailsHandler.mjs'
  7. describe('ProjectCollabratecDetailsHandler', function () {
  8. beforeEach(async function (ctx) {
  9. ctx.projectId = new ObjectId('5bea8747c7bba6012fcaceb3')
  10. ctx.userId = new ObjectId('5be316a9c7f6aa03802ea8fb')
  11. ctx.userId2 = new ObjectId('5c1794b3f0e89b1d1c577eca')
  12. ctx.ProjectModel = {}
  13. vi.doMock('mongodb-legacy', () => ({
  14. default: { ObjectId },
  15. }))
  16. vi.doMock('../../../../app/src/models/Project.mjs', () => ({
  17. Project: ctx.ProjectModel,
  18. }))
  19. ctx.ProjectCollabratecDetailsHandler = (await import(MODULE_PATH)).default
  20. })
  21. describe('initializeCollabratecProject', function () {
  22. describe('when update succeeds', function () {
  23. beforeEach(async function (ctx) {
  24. ctx.ProjectModel.updateOne = sinon
  25. .stub()
  26. .returns({ exec: sinon.stub().resolves() })
  27. await ctx.ProjectCollabratecDetailsHandler.promises.initializeCollabratecProject(
  28. ctx.projectId,
  29. ctx.userId,
  30. 'collabratec-document-id',
  31. 'collabratec-private-group-id'
  32. )
  33. })
  34. it('should update project model', function (ctx) {
  35. const update = {
  36. $set: {
  37. collabratecUsers: [
  38. {
  39. user_id: ctx.userId,
  40. collabratec_document_id: 'collabratec-document-id',
  41. collabratec_privategroup_id: 'collabratec-private-group-id',
  42. },
  43. ],
  44. },
  45. }
  46. expect(ctx.ProjectModel.updateOne).to.have.been.calledWith(
  47. { _id: ctx.projectId },
  48. update
  49. )
  50. })
  51. })
  52. describe('when update has error', function () {
  53. beforeEach(function (ctx) {
  54. ctx.ProjectModel.updateOne = sinon
  55. .stub()
  56. .returns({ exec: sinon.stub().rejects() })
  57. })
  58. it('should be rejected', async function (ctx) {
  59. await expect(
  60. ctx.ProjectCollabratecDetailsHandler.promises.initializeCollabratecProject(
  61. ctx.projectId,
  62. ctx.userId,
  63. 'collabratec-document-id',
  64. 'collabratec-private-group-id'
  65. )
  66. ).to.be.rejected
  67. })
  68. })
  69. describe('with invalid args', function () {
  70. beforeEach(function (ctx) {
  71. ctx.ProjectModel.updateOne = sinon
  72. .stub()
  73. .returns({ exec: sinon.stub().resolves() })
  74. ctx.resultPromise =
  75. ctx.ProjectCollabratecDetailsHandler.promises.initializeCollabratecProject(
  76. 'bad-project-id',
  77. 'bad-user-id',
  78. 'collabratec-document-id',
  79. 'collabratec-private-group-id'
  80. )
  81. })
  82. it('should be rejected without updating', async function (ctx) {
  83. await expect(ctx.resultPromise).to.be.rejected
  84. expect(ctx.ProjectModel.updateOne).not.to.have.been.called
  85. })
  86. })
  87. })
  88. describe('isLinkedCollabratecUserProject', function () {
  89. beforeEach(function (ctx) {
  90. ctx.ProjectModel.findOne = sinon.stub().resolves()
  91. })
  92. describe('when find succeeds', function () {
  93. describe('when user project found', function () {
  94. beforeEach(async function (ctx) {
  95. ctx.ProjectModel.findOne = sinon
  96. .stub()
  97. .returns({ exec: sinon.stub().resolves('project') })
  98. ctx.result =
  99. await ctx.ProjectCollabratecDetailsHandler.promises.isLinkedCollabratecUserProject(
  100. ctx.projectId,
  101. ctx.userId
  102. )
  103. })
  104. it('should call find with project and user id', function (ctx) {
  105. expect(ctx.ProjectModel.findOne).to.have.been.calledWithMatch({
  106. _id: new ObjectId(ctx.projectId),
  107. collabratecUsers: {
  108. $elemMatch: {
  109. user_id: new ObjectId(ctx.userId),
  110. },
  111. },
  112. })
  113. })
  114. it('should return true', function (ctx) {
  115. expect(ctx.result).to.equal(true)
  116. })
  117. })
  118. describe('when user project is not found', function () {
  119. beforeEach(async function (ctx) {
  120. ctx.ProjectModel.findOne = sinon
  121. .stub()
  122. .returns({ exec: sinon.stub().resolves(null) })
  123. ctx.result =
  124. await ctx.ProjectCollabratecDetailsHandler.promises.isLinkedCollabratecUserProject(
  125. ctx.projectId,
  126. ctx.userId
  127. )
  128. })
  129. it('should return false', function (ctx) {
  130. expect(ctx.result).to.equal(false)
  131. })
  132. })
  133. })
  134. describe('when find has error', function () {
  135. beforeEach(function (ctx) {
  136. ctx.ProjectModel.findOne = sinon
  137. .stub()
  138. .returns({ exec: sinon.stub().rejects() })
  139. })
  140. it('should be rejected', async function (ctx) {
  141. await expect(
  142. ctx.ProjectCollabratecDetailsHandler.promises.isLinkedCollabratecUserProject(
  143. ctx.projectId,
  144. ctx.userId
  145. )
  146. ).to.be.rejected
  147. })
  148. })
  149. describe('with invalid args', function () {
  150. beforeEach(function (ctx) {
  151. ctx.ProjectModel.findOne = sinon
  152. .stub()
  153. .returns({ exec: sinon.stub().resolves() })
  154. ctx.resultPromise =
  155. ctx.ProjectCollabratecDetailsHandler.promises.isLinkedCollabratecUserProject(
  156. 'bad-project-id',
  157. 'bad-user-id'
  158. )
  159. })
  160. it('should be rejected without updating', async function (ctx) {
  161. await expect(ctx.resultPromise).to.be.rejected
  162. expect(ctx.ProjectModel.findOne).not.to.have.been.called
  163. })
  164. })
  165. })
  166. describe('linkCollabratecUserProject', function () {
  167. describe('when update succeeds', function () {
  168. beforeEach(async function (ctx) {
  169. ctx.ProjectModel.updateOne = sinon
  170. .stub()
  171. .returns({ exec: sinon.stub().resolves() })
  172. await ctx.ProjectCollabratecDetailsHandler.promises.linkCollabratecUserProject(
  173. ctx.projectId,
  174. ctx.userId,
  175. 'collabratec-document-id'
  176. )
  177. })
  178. it('should update project model', function (ctx) {
  179. const query = {
  180. _id: ctx.projectId,
  181. collabratecUsers: {
  182. $not: {
  183. $elemMatch: {
  184. collabratec_document_id: 'collabratec-document-id',
  185. user_id: ctx.userId,
  186. },
  187. },
  188. },
  189. }
  190. const update = {
  191. $push: {
  192. collabratecUsers: {
  193. collabratec_document_id: 'collabratec-document-id',
  194. user_id: ctx.userId,
  195. },
  196. },
  197. }
  198. expect(ctx.ProjectModel.updateOne).to.have.been.calledWith(
  199. query,
  200. update
  201. )
  202. })
  203. })
  204. describe('when update has error', function () {
  205. beforeEach(function (ctx) {
  206. ctx.ProjectModel.updateOne = sinon
  207. .stub()
  208. .returns({ exec: sinon.stub().rejects() })
  209. })
  210. it('should be rejected', async function (ctx) {
  211. await expect(
  212. ctx.ProjectCollabratecDetailsHandler.promises.linkCollabratecUserProject(
  213. ctx.projectId,
  214. ctx.userId,
  215. 'collabratec-document-id'
  216. )
  217. ).to.be.rejected
  218. })
  219. })
  220. describe('with invalid args', function () {
  221. beforeEach(function (ctx) {
  222. ctx.ProjectModel.updateOne = sinon
  223. .stub()
  224. .returns({ exec: sinon.stub().resolves() })
  225. ctx.resultPromise =
  226. ctx.ProjectCollabratecDetailsHandler.promises.linkCollabratecUserProject(
  227. 'bad-project-id',
  228. 'bad-user-id',
  229. 'collabratec-document-id'
  230. )
  231. })
  232. it('should be rejected without updating', async function (ctx) {
  233. await expect(ctx.resultPromise).to.be.rejected
  234. expect(ctx.ProjectModel.updateOne).not.to.have.been.called
  235. })
  236. })
  237. })
  238. describe('setCollabratecUsers', function () {
  239. beforeEach(function (ctx) {
  240. ctx.collabratecUsers = [
  241. {
  242. user_id: ctx.userId,
  243. collabratec_document_id: 'collabratec-document-id-1',
  244. collabratec_privategroup_id: 'collabratec-private-group-id-1',
  245. },
  246. {
  247. user_id: ctx.userId2,
  248. collabratec_document_id: 'collabratec-document-id-2',
  249. collabratec_privategroup_id: 'collabratec-private-group-id-2',
  250. },
  251. ]
  252. })
  253. describe('when update succeeds', function () {
  254. beforeEach(async function (ctx) {
  255. ctx.ProjectModel.updateOne = sinon
  256. .stub()
  257. .returns({ exec: sinon.stub().resolves() })
  258. await ctx.ProjectCollabratecDetailsHandler.promises.setCollabratecUsers(
  259. ctx.projectId,
  260. ctx.collabratecUsers
  261. )
  262. })
  263. it('should update project model', function (ctx) {
  264. const update = {
  265. $set: {
  266. collabratecUsers: ctx.collabratecUsers,
  267. },
  268. }
  269. expect(ctx.ProjectModel.updateOne).to.have.been.calledWith(
  270. { _id: ctx.projectId },
  271. update
  272. )
  273. })
  274. })
  275. describe('when update has error', function () {
  276. beforeEach(function (ctx) {
  277. ctx.ProjectModel.updateOne = sinon
  278. .stub()
  279. .returns({ exec: sinon.stub().rejects() })
  280. })
  281. it('should be rejected', async function (ctx) {
  282. await expect(
  283. ctx.ProjectCollabratecDetailsHandler.promises.setCollabratecUsers(
  284. ctx.projectId,
  285. ctx.collabratecUsers
  286. )
  287. ).to.be.rejected
  288. })
  289. })
  290. describe('with invalid project_id', function () {
  291. beforeEach(function (ctx) {
  292. ctx.ProjectModel.updateOne = sinon
  293. .stub()
  294. .returns({ exec: sinon.stub().resolves() })
  295. ctx.resultPromise =
  296. ctx.ProjectCollabratecDetailsHandler.promises.setCollabratecUsers(
  297. 'bad-project-id',
  298. ctx.collabratecUsers
  299. )
  300. })
  301. it('should be rejected without updating', async function (ctx) {
  302. await expect(ctx.resultPromise).to.be.rejected
  303. expect(ctx.ProjectModel.updateOne).not.to.have.been.called
  304. })
  305. })
  306. describe('with invalid user_id', function () {
  307. beforeEach(function (ctx) {
  308. ctx.collabratecUsers[1].user_id = 'bad-user-id'
  309. ctx.ProjectModel.updateOne = sinon
  310. .stub()
  311. .returns({ exec: sinon.stub().resolves() })
  312. ctx.resultPromise =
  313. ctx.ProjectCollabratecDetailsHandler.promises.setCollabratecUsers(
  314. ctx.projectId,
  315. ctx.collabratecUsers
  316. )
  317. })
  318. it('should be rejected without updating', async function (ctx) {
  319. await expect(ctx.resultPromise).to.be.rejected
  320. expect(ctx.ProjectModel.updateOne).not.to.have.been.called
  321. })
  322. })
  323. })
  324. describe('unlinkCollabratecUserProject', function () {
  325. describe('when update succeeds', function () {
  326. beforeEach(async function (ctx) {
  327. ctx.ProjectModel.updateOne = sinon
  328. .stub()
  329. .returns({ exec: sinon.stub().resolves() })
  330. await ctx.ProjectCollabratecDetailsHandler.promises.unlinkCollabratecUserProject(
  331. ctx.projectId,
  332. ctx.userId
  333. )
  334. })
  335. it('should update project model', function (ctx) {
  336. const query = { _id: ctx.projectId }
  337. const update = {
  338. $pull: {
  339. collabratecUsers: {
  340. user_id: ctx.userId,
  341. },
  342. },
  343. }
  344. expect(ctx.ProjectModel.updateOne).to.have.been.calledWith(
  345. query,
  346. update
  347. )
  348. })
  349. })
  350. describe('when update has error', function () {
  351. beforeEach(function (ctx) {
  352. ctx.ProjectModel.updateOne = sinon
  353. .stub()
  354. .returns({ exec: sinon.stub().rejects() })
  355. })
  356. it('should be rejected', async function (ctx) {
  357. await expect(
  358. ctx.ProjectCollabratecDetailsHandler.promises.unlinkCollabratecUserProject(
  359. ctx.projectId,
  360. ctx.userId
  361. )
  362. ).to.be.rejected
  363. })
  364. })
  365. describe('with invalid args', function () {
  366. beforeEach(function (ctx) {
  367. ctx.ProjectModel.updateOne = sinon
  368. .stub()
  369. .returns({ exec: sinon.stub().resolves() })
  370. ctx.resultPromise =
  371. ctx.ProjectCollabratecDetailsHandler.promises.unlinkCollabratecUserProject(
  372. 'bad-project-id',
  373. 'bad-user-id'
  374. )
  375. })
  376. it('should be rejected without updating', async function (ctx) {
  377. await expect(ctx.resultPromise).to.be.rejected
  378. expect(ctx.ProjectModel.updateOne).not.to.have.been.called
  379. })
  380. })
  381. })
  382. })