ProjectOptionsHandler.test.mjs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import { vi, expect } from 'vitest'
  2. import sinon from 'sinon'
  3. import mongodb from 'mongodb-legacy'
  4. const modulePath =
  5. '../../../../app/src/Features/Project/ProjectOptionsHandler.mjs'
  6. const { ObjectId } = mongodb
  7. describe('ProjectOptionsHandler', function () {
  8. const projectId = '4eecaffcbffa66588e000008'
  9. beforeEach(async function (ctx) {
  10. ctx.projectModel = class Project {}
  11. ctx.projectModel.updateOne = sinon.stub().resolves()
  12. ctx.db = {
  13. projects: {
  14. updateOne: sinon.stub().resolves(),
  15. },
  16. }
  17. vi.doMock('../../../../app/src/models/Project', () => ({
  18. Project: ctx.projectModel,
  19. }))
  20. vi.doMock('@overleaf/settings', () => ({
  21. default: {
  22. languages: [
  23. { name: 'English', code: 'en' },
  24. { name: 'French', code: 'fr' },
  25. ],
  26. imageRoot: 'docker-repo/subdir',
  27. allowedImageNames: [
  28. { imageName: 'texlive-0000.0', imageDesc: 'test image 0' },
  29. { imageName: 'texlive-1234.5', imageDesc: 'test image 1' },
  30. ],
  31. },
  32. }))
  33. vi.doMock('../../../../app/src/infrastructure/mongodb', () => ({
  34. db: ctx.db,
  35. ObjectId,
  36. }))
  37. ctx.handler = (await import(modulePath)).default
  38. })
  39. describe('Setting the compiler', function () {
  40. it('should perform and update on mongo', async function (ctx) {
  41. await ctx.handler.promises.setCompiler(projectId, 'xeLaTeX')
  42. const args = ctx.projectModel.updateOne.args[0]
  43. args[0]._id.should.equal(projectId)
  44. args[1].compiler.should.equal('xelatex')
  45. })
  46. it('should not perform and update on mongo if it is not a recognised compiler', async function (ctx) {
  47. await expect(
  48. ctx.handler.promises.setCompiler(projectId, 'something')
  49. ).to.be.rejectedWith('invalid compiler')
  50. ctx.projectModel.updateOne.called.should.equal(false)
  51. })
  52. describe('when called without arg', function () {
  53. it('should callback with null', async function (ctx) {
  54. await ctx.handler.promises.setCompiler(projectId, null)
  55. ctx.projectModel.updateOne.callCount.should.equal(0)
  56. })
  57. })
  58. describe('when mongo update error occurs', function () {
  59. beforeEach(function (ctx) {
  60. ctx.projectModel.updateOne = sinon.stub().yields('error')
  61. })
  62. it('should be rejected', async function (ctx) {
  63. await expect(ctx.handler.promises.setCompiler(projectId, 'xeLaTeX')).to
  64. .be.rejected
  65. })
  66. })
  67. })
  68. describe('Setting the imageName', function () {
  69. it('should perform and update on mongo', async function (ctx) {
  70. await ctx.handler.promises.setImageName(projectId, 'texlive-1234.5')
  71. const args = ctx.projectModel.updateOne.args[0]
  72. args[0]._id.should.equal(projectId)
  73. args[1].imageName.should.equal('docker-repo/subdir/texlive-1234.5')
  74. })
  75. it('should not perform and update on mongo if it is not a reconised image name', async function (ctx) {
  76. const fakeImageName = 'something'
  77. await expect(
  78. ctx.handler.promises.setImageName(projectId, fakeImageName)
  79. ).to.be.rejectedWith('invalid imageName')
  80. ctx.projectModel.updateOne.called.should.equal(false)
  81. })
  82. describe('when called without arg', function () {
  83. it('should callback with null', async function (ctx) {
  84. await ctx.handler.promises.setImageName(projectId, null)
  85. ctx.projectModel.updateOne.callCount.should.equal(0)
  86. })
  87. })
  88. describe('when mongo update error occurs', function () {
  89. beforeEach(function (ctx) {
  90. ctx.projectModel.updateOne = sinon.stub().yields('error')
  91. })
  92. it('should be rejected', async function (ctx) {
  93. await expect(
  94. ctx.handler.promises.setImageName(projectId, 'texlive-1234.5')
  95. ).to.be.rejected
  96. })
  97. })
  98. })
  99. describe('setting the spellCheckLanguage', function () {
  100. it('should perform and update on mongo', async function (ctx) {
  101. await ctx.handler.promises.setSpellCheckLanguage(projectId, 'fr')
  102. const args = ctx.projectModel.updateOne.args[0]
  103. args[0]._id.should.equal(projectId)
  104. args[1].spellCheckLanguage.should.equal('fr')
  105. })
  106. it('should not perform and update on mongo if it is not a reconised langauge', async function (ctx) {
  107. const fakeLanguageCode = 'not a lang'
  108. await expect(
  109. ctx.handler.promises.setSpellCheckLanguage(projectId, fakeLanguageCode)
  110. ).to.be.rejectedWith('invalid languageCode')
  111. ctx.projectModel.updateOne.called.should.equal(false)
  112. })
  113. it('should perform and update on mongo if the language is blank (means turn it off)', async function (ctx) {
  114. await ctx.handler.promises.setSpellCheckLanguage(projectId, '')
  115. ctx.projectModel.updateOne.called.should.equal(true)
  116. })
  117. describe('when mongo update error occurs', function () {
  118. beforeEach(function (ctx) {
  119. ctx.projectModel.updateOne = sinon.stub().yields('error')
  120. })
  121. it('should be rejected', async function (ctx) {
  122. await expect(ctx.handler.promises.setSpellCheckLanguage(projectId)).to
  123. .be.rejected
  124. })
  125. })
  126. })
  127. describe('setting the brandVariationId', function () {
  128. it('should perform and update on mongo', async function (ctx) {
  129. await ctx.handler.promises.setBrandVariationId(projectId, '123')
  130. const args = ctx.projectModel.updateOne.args[0]
  131. args[0]._id.should.equal(projectId)
  132. args[1].brandVariationId.should.equal('123')
  133. })
  134. it('should not perform and update on mongo if there is no brand variation', async function (ctx) {
  135. await ctx.handler.promises.setBrandVariationId(projectId, null)
  136. ctx.projectModel.updateOne.called.should.equal(false)
  137. })
  138. it('should not perform and update on mongo if brand variation is an empty string', async function (ctx) {
  139. await ctx.handler.promises.setBrandVariationId(projectId, '')
  140. ctx.projectModel.updateOne.called.should.equal(false)
  141. })
  142. describe('when mongo update error occurs', function () {
  143. beforeEach(function (ctx) {
  144. ctx.projectModel.updateOne = sinon.stub().yields('error')
  145. })
  146. it('should be rejected', async function (ctx) {
  147. await expect(ctx.handler.promises.setBrandVariationId(projectId, '123'))
  148. .to.be.rejected
  149. })
  150. })
  151. })
  152. describe('setting the rangesSupportEnabled', function () {
  153. it('should perform and update on mongo', async function (ctx) {
  154. await ctx.handler.promises.setHistoryRangesSupport(projectId, true)
  155. sinon.assert.calledWith(
  156. ctx.db.projects.updateOne,
  157. { _id: new ObjectId(projectId) },
  158. { $set: { 'overleaf.history.rangesSupportEnabled': true } }
  159. )
  160. })
  161. describe('when mongo update error occurs', function () {
  162. beforeEach(function (ctx) {
  163. ctx.db.projects.updateOne = sinon.stub().yields('error')
  164. })
  165. it('should be rejected', async function (ctx) {
  166. await expect(
  167. ctx.handler.promises.setHistoryRangesSupport(projectId, true)
  168. ).to.be.rejected
  169. })
  170. })
  171. })
  172. describe('unsetting the brandVariationId', function () {
  173. it('should perform and update on mongo', async function (ctx) {
  174. await ctx.handler.promises.unsetBrandVariationId(projectId)
  175. const args = ctx.projectModel.updateOne.args[0]
  176. args[0]._id.should.equal(projectId)
  177. expect(args[1]).to.deep.equal({ $unset: { brandVariationId: 1 } })
  178. })
  179. describe('when mongo update error occurs', function () {
  180. beforeEach(function (ctx) {
  181. ctx.projectModel.updateOne = sinon.stub().yields('error')
  182. })
  183. it('should be rejected', async function (ctx) {
  184. expect(ctx.handler.promises.unsetBrandVariationId(projectId)).to.be
  185. .rejected
  186. })
  187. })
  188. })
  189. })