ProjectDownloadsControllerTests.mjs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // TODO: This file was created by bulk-decaffeinate.
  2. // Fix any style issues and re-enable lint.
  3. /*
  4. * decaffeinate suggestions:
  5. * DS102: Remove unnecessary code created because of implicit returns
  6. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  7. */
  8. import sinon from 'sinon'
  9. import esmock from 'esmock'
  10. import MockRequest from '../helpers/MockRequest.js'
  11. import MockResponse from '../helpers/MockResponse.js'
  12. const modulePath =
  13. '../../../../app/src/Features/Downloads/ProjectDownloadsController.mjs'
  14. describe('ProjectDownloadsController', function () {
  15. beforeEach(async function () {
  16. this.project_id = 'project-id-123'
  17. this.req = new MockRequest()
  18. this.res = new MockResponse()
  19. this.next = sinon.stub()
  20. this.DocumentUpdaterHandler = sinon.stub()
  21. return (this.ProjectDownloadsController = await esmock.strict(modulePath, {
  22. '../../../../app/src/Features/Downloads/ProjectZipStreamManager.mjs':
  23. (this.ProjectZipStreamManager = {}),
  24. '../../../../app/src/Features/Project/ProjectGetter.js':
  25. (this.ProjectGetter = {}),
  26. '@overleaf/metrics': (this.metrics = {}),
  27. '../../../../app/src/Features/DocumentUpdater/DocumentUpdaterHandler.js':
  28. this.DocumentUpdaterHandler,
  29. }))
  30. })
  31. describe('downloadProject', function () {
  32. beforeEach(function () {
  33. this.stream = { pipe: sinon.stub() }
  34. this.ProjectZipStreamManager.createZipStreamForProject = sinon
  35. .stub()
  36. .callsArgWith(1, null, this.stream)
  37. this.req.params = { Project_id: this.project_id }
  38. this.project_name = 'project name with accênts'
  39. this.ProjectGetter.getProject = sinon
  40. .stub()
  41. .callsArgWith(2, null, { name: this.project_name })
  42. this.DocumentUpdaterHandler.flushProjectToMongo = sinon
  43. .stub()
  44. .callsArgWith(1)
  45. this.metrics.inc = sinon.stub()
  46. return this.ProjectDownloadsController.downloadProject(
  47. this.req,
  48. this.res,
  49. this.next
  50. )
  51. })
  52. it('should create a zip from the project', function () {
  53. return this.ProjectZipStreamManager.createZipStreamForProject
  54. .calledWith(this.project_id)
  55. .should.equal(true)
  56. })
  57. it('should stream the zip to the request', function () {
  58. return this.stream.pipe.calledWith(this.res).should.equal(true)
  59. })
  60. it('should set the correct content type on the request', function () {
  61. return this.res.contentType
  62. .calledWith('application/zip')
  63. .should.equal(true)
  64. })
  65. it('should flush the project to mongo', function () {
  66. return this.DocumentUpdaterHandler.flushProjectToMongo
  67. .calledWith(this.project_id)
  68. .should.equal(true)
  69. })
  70. it("should look up the project's name", function () {
  71. return this.ProjectGetter.getProject
  72. .calledWith(this.project_id, { name: true })
  73. .should.equal(true)
  74. })
  75. it('should name the downloaded file after the project', function () {
  76. this.res.headers.should.deep.equal({
  77. 'Content-Disposition': `attachment; filename="${this.project_name}.zip"`,
  78. 'Content-Type': 'application/zip',
  79. 'X-Content-Type-Options': 'nosniff',
  80. })
  81. })
  82. it('should record the action via Metrics', function () {
  83. return this.metrics.inc.calledWith('zip-downloads').should.equal(true)
  84. })
  85. })
  86. describe('downloadMultipleProjects', function () {
  87. beforeEach(function () {
  88. this.stream = { pipe: sinon.stub() }
  89. this.ProjectZipStreamManager.createZipStreamForMultipleProjects = sinon
  90. .stub()
  91. .callsArgWith(1, null, this.stream)
  92. this.project_ids = ['project-1', 'project-2']
  93. this.req.query = { project_ids: this.project_ids.join(',') }
  94. this.DocumentUpdaterHandler.flushMultipleProjectsToMongo = sinon
  95. .stub()
  96. .callsArgWith(1)
  97. this.metrics.inc = sinon.stub()
  98. return this.ProjectDownloadsController.downloadMultipleProjects(
  99. this.req,
  100. this.res,
  101. this.next
  102. )
  103. })
  104. it('should create a zip from the project', function () {
  105. return this.ProjectZipStreamManager.createZipStreamForMultipleProjects
  106. .calledWith(this.project_ids)
  107. .should.equal(true)
  108. })
  109. it('should stream the zip to the request', function () {
  110. return this.stream.pipe.calledWith(this.res).should.equal(true)
  111. })
  112. it('should set the correct content type on the request', function () {
  113. return this.res.contentType
  114. .calledWith('application/zip')
  115. .should.equal(true)
  116. })
  117. it('should flush the projects to mongo', function () {
  118. return this.DocumentUpdaterHandler.flushMultipleProjectsToMongo
  119. .calledWith(this.project_ids)
  120. .should.equal(true)
  121. })
  122. it('should name the downloaded file after the project', function () {
  123. this.res.headers.should.deep.equal({
  124. 'Content-Disposition':
  125. 'attachment; filename="Overleaf Projects (2 items).zip"',
  126. 'Content-Type': 'application/zip',
  127. 'X-Content-Type-Options': 'nosniff',
  128. })
  129. })
  130. it('should record the action via Metrics', function () {
  131. return this.metrics.inc
  132. .calledWith('zip-downloads-multiple')
  133. .should.equal(true)
  134. })
  135. })
  136. })