DocumentControllerTests.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  4. no-unused-vars,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  12. */
  13. const sinon = require('sinon')
  14. const chai = require('chai')
  15. const should = chai.should()
  16. const { expect } = chai
  17. const modulePath =
  18. '../../../../app/src/Features/Documents/DocumentController.js'
  19. const SandboxedModule = require('sandboxed-module')
  20. const events = require('events')
  21. const MockRequest = require('../helpers/MockRequest')
  22. const MockResponse = require('../helpers/MockResponse')
  23. const Errors = require('../../../../app/src/Features/Errors/Errors')
  24. describe('DocumentController', function() {
  25. beforeEach(function() {
  26. this.DocumentController = SandboxedModule.require(modulePath, {
  27. requires: {
  28. 'logger-sharelatex': {
  29. log() {},
  30. err() {}
  31. },
  32. '../Project/ProjectGetter': (this.ProjectGetter = {}),
  33. '../Project/ProjectLocator': (this.ProjectLocator = {}),
  34. '../Project/ProjectEntityHandler': (this.ProjectEntityHandler = {}),
  35. '../Project/ProjectEntityUpdateHandler': (this.ProjectEntityUpdateHandler = {})
  36. }
  37. })
  38. this.res = new MockResponse()
  39. this.req = new MockRequest()
  40. this.next = sinon.stub()
  41. this.project_id = 'project-id-123'
  42. this.doc_id = 'doc-id-123'
  43. this.doc_lines = ['one', 'two', 'three']
  44. this.version = 42
  45. this.ranges = { mock: 'ranges' }
  46. this.pathname = '/a/b/c/file.tex'
  47. this.lastUpdatedAt = new Date().getTime()
  48. this.lastUpdatedBy = 'fake-last-updater-id'
  49. return (this.rev = 5)
  50. })
  51. describe('getDocument', function() {
  52. beforeEach(function() {
  53. return (this.req.params = {
  54. Project_id: this.project_id,
  55. doc_id: this.doc_id
  56. })
  57. })
  58. describe('when the project exists without project history enabled', function() {
  59. beforeEach(function() {
  60. this.project = { _id: this.project_id }
  61. return (this.ProjectGetter.getProject = sinon
  62. .stub()
  63. .callsArgWith(2, null, this.project))
  64. })
  65. describe('when the document exists', function() {
  66. beforeEach(function() {
  67. this.doc = { _id: this.doc_id }
  68. this.ProjectLocator.findElement = sinon
  69. .stub()
  70. .callsArgWith(1, null, this.doc, { fileSystem: this.pathname })
  71. this.ProjectEntityHandler.getDoc = sinon
  72. .stub()
  73. .callsArgWith(
  74. 2,
  75. null,
  76. this.doc_lines,
  77. this.rev,
  78. this.version,
  79. this.ranges
  80. )
  81. return this.DocumentController.getDocument(
  82. this.req,
  83. this.res,
  84. this.next
  85. )
  86. })
  87. it('should get the project', function() {
  88. return this.ProjectGetter.getProject
  89. .calledWith(this.project_id, { rootFolder: true, overleaf: true })
  90. .should.equal(true)
  91. })
  92. it('should get the pathname of the document', function() {
  93. return this.ProjectLocator.findElement
  94. .calledWith({
  95. project: this.project,
  96. element_id: this.doc_id,
  97. type: 'doc'
  98. })
  99. .should.equal(true)
  100. })
  101. it('should get the document content', function() {
  102. return this.ProjectEntityHandler.getDoc
  103. .calledWith(this.project_id, this.doc_id)
  104. .should.equal(true)
  105. })
  106. it('should return the document data to the client as JSON', function() {
  107. this.res.type.should.equal('application/json')
  108. return this.res.body.should.equal(
  109. JSON.stringify({
  110. lines: this.doc_lines,
  111. version: this.version,
  112. ranges: this.ranges,
  113. pathname: this.pathname
  114. })
  115. )
  116. })
  117. })
  118. describe("when the document doesn't exist", function() {
  119. beforeEach(function() {
  120. this.ProjectLocator.findElement = sinon
  121. .stub()
  122. .callsArgWith(1, new Errors.NotFoundError('not found'))
  123. return this.DocumentController.getDocument(
  124. this.req,
  125. this.res,
  126. this.next
  127. )
  128. })
  129. it('should call next with the NotFoundError', function() {
  130. return this.next
  131. .calledWith(new Errors.NotFoundError('not found'))
  132. .should.equal(true)
  133. })
  134. })
  135. })
  136. describe('when project exists with project history enabled', function() {
  137. beforeEach(function() {
  138. this.doc = { _id: this.doc_id }
  139. this.projectHistoryId = 1234
  140. this.project = {
  141. _id: this.project_id,
  142. overleaf: { history: { id: this.projectHistoryId } }
  143. }
  144. this.ProjectGetter.getProject = sinon
  145. .stub()
  146. .callsArgWith(2, null, this.project)
  147. this.ProjectLocator.findElement = sinon
  148. .stub()
  149. .callsArgWith(1, null, this.doc, { fileSystem: this.pathname })
  150. this.ProjectEntityHandler.getDoc = sinon
  151. .stub()
  152. .callsArgWith(
  153. 2,
  154. null,
  155. this.doc_lines,
  156. this.rev,
  157. this.version,
  158. this.ranges
  159. )
  160. return this.DocumentController.getDocument(
  161. this.req,
  162. this.res,
  163. this.next
  164. )
  165. })
  166. it('should return the history id to the client as JSON', function() {
  167. this.res.type.should.equal('application/json')
  168. return this.res.body.should.equal(
  169. JSON.stringify({
  170. lines: this.doc_lines,
  171. version: this.version,
  172. ranges: this.ranges,
  173. pathname: this.pathname,
  174. projectHistoryId: this.projectHistoryId
  175. })
  176. )
  177. })
  178. })
  179. describe('when the project does not exist', function() {
  180. beforeEach(function() {
  181. this.ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, null)
  182. return this.DocumentController.getDocument(
  183. this.req,
  184. this.res,
  185. this.next
  186. )
  187. })
  188. it('returns a 404', function() {
  189. return this.res.statusCode.should.equal(404)
  190. })
  191. })
  192. })
  193. describe('setDocument', function() {
  194. beforeEach(function() {
  195. return (this.req.params = {
  196. Project_id: this.project_id,
  197. doc_id: this.doc_id
  198. })
  199. })
  200. describe('when the document exists', function() {
  201. beforeEach(function() {
  202. this.ProjectEntityUpdateHandler.updateDocLines = sinon.stub().yields()
  203. this.req.body = {
  204. lines: this.doc_lines,
  205. version: this.version,
  206. ranges: this.ranges,
  207. lastUpdatedAt: this.lastUpdatedAt,
  208. lastUpdatedBy: this.lastUpdatedBy
  209. }
  210. return this.DocumentController.setDocument(
  211. this.req,
  212. this.res,
  213. this.next
  214. )
  215. })
  216. it('should update the document in Mongo', function() {
  217. return sinon.assert.calledWith(
  218. this.ProjectEntityUpdateHandler.updateDocLines,
  219. this.project_id,
  220. this.doc_id,
  221. this.doc_lines,
  222. this.version,
  223. this.ranges,
  224. this.lastUpdatedAt,
  225. this.lastUpdatedBy
  226. )
  227. })
  228. it('should return a successful response', function() {
  229. return this.res.success.should.equal(true)
  230. })
  231. })
  232. describe("when the document doesn't exist", function() {
  233. beforeEach(function() {
  234. this.ProjectEntityUpdateHandler.updateDocLines = sinon
  235. .stub()
  236. .yields(new Errors.NotFoundError('document does not exist'))
  237. this.req.body = { lines: this.doc_lines }
  238. return this.DocumentController.setDocument(
  239. this.req,
  240. this.res,
  241. this.next
  242. )
  243. })
  244. it('should call next with the NotFoundError', function() {
  245. return this.next
  246. .calledWith(new Errors.NotFoundError('not found'))
  247. .should.equal(true)
  248. })
  249. })
  250. })
  251. })