OutputController.test.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { vi, describe, beforeEach, it } from 'vitest'
  2. import sinon from 'sinon'
  3. import path from 'node:path'
  4. const MODULE_PATH = path.join(
  5. import.meta.dirname,
  6. '../../../app/js/OutputController'
  7. )
  8. describe('OutputController', () => {
  9. describe('createOutputZip', () => {
  10. beforeEach(async ctx => {
  11. ctx.archive = {}
  12. ctx.pipeline = sinon.stub().resolves()
  13. ctx.archiveFilesForBuild = sinon.stub().resolves(ctx.archive)
  14. vi.doMock('../../../app/js/OutputFileArchiveManager', () => ({
  15. default: {
  16. archiveFilesForBuild: ctx.archiveFilesForBuild,
  17. },
  18. }))
  19. vi.doMock('node:stream/promises', () => ({
  20. pipeline: ctx.pipeline,
  21. }))
  22. ctx.OutputController = (await import(MODULE_PATH)).default
  23. })
  24. describe('when OutputFileArchiveManager creates an archive', () => {
  25. beforeEach(async ctx => {
  26. await new Promise((resolve, reject) => {
  27. ctx.res = {
  28. attachment: sinon.stub(),
  29. setHeader: sinon.stub(),
  30. }
  31. ctx.req = {
  32. params: {
  33. project_id: 'project-id-123',
  34. user_id: 'user-id-123',
  35. build_id: 'build-id-123',
  36. },
  37. query: {
  38. files: ['output.tex'],
  39. },
  40. }
  41. ctx.pipeline.callsFake(() => {
  42. resolve()
  43. return Promise.resolve()
  44. })
  45. ctx.OutputController.createOutputZip(ctx.req, ctx.res)
  46. })
  47. })
  48. it('creates a pipeline from the archive to the response', ctx => {
  49. sinon.assert.calledWith(ctx.pipeline, ctx.archive, ctx.res)
  50. })
  51. it('calls the express convenience method to set attachment headers', ctx => {
  52. sinon.assert.calledWith(ctx.res.attachment, 'output.zip')
  53. })
  54. it('sets the X-Content-Type-Options header to nosniff', ctx => {
  55. sinon.assert.calledWith(
  56. ctx.res.setHeader,
  57. 'X-Content-Type-Options',
  58. 'nosniff'
  59. )
  60. })
  61. })
  62. describe('when OutputFileArchiveManager throws an error', () => {
  63. let error
  64. beforeEach(async ctx => {
  65. await new Promise((resolve, reject) => {
  66. error = new Error('error message')
  67. ctx.archiveFilesForBuild.rejects(error)
  68. ctx.res = {
  69. status: sinon.stub().returnsThis(),
  70. send: sinon.stub(),
  71. }
  72. ctx.req = {
  73. params: {
  74. project_id: 'project-id-123',
  75. user_id: 'user-id-123',
  76. build_id: 'build-id-123',
  77. },
  78. query: {
  79. files: ['output.tex'],
  80. },
  81. }
  82. ctx.OutputController.createOutputZip(
  83. ctx.req,
  84. ctx.res,
  85. (ctx.next = sinon.stub().callsFake(() => {
  86. resolve()
  87. }))
  88. )
  89. })
  90. })
  91. it('calls next with the error', ctx => {
  92. sinon.assert.calledWith(ctx.next, error)
  93. })
  94. })
  95. })
  96. })