Files
overleaf-cep/services/filestore/test/unit/js/LocalFileWriter.test.js
Andrew Rumble 90cf4b6a0a Merge pull request #29841 from overleaf/ar-convert-filestore-to-esm
[filestore] convert to ES modules

GitOrigin-RevId: 404905973548bb6e437fff66b368e87be8249b73
2025-12-05 09:05:35 +00:00

116 lines
3.4 KiB
JavaScript

import sinon from 'sinon'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { Errors } from '@overleaf/object-persistor'
const modulePath = '../../../app/js/LocalFileWriter.js'
describe('LocalFileWriter', function () {
const writeStream = 'writeStream'
const readStream = 'readStream'
const settings = { path: { uploadFolder: '/uploads' } }
const fsPath = '/uploads/wombat'
const filename = 'wombat'
let stream, fs, LocalFileWriter
beforeEach(async function () {
fs = {
createWriteStream: sinon.stub().returns(writeStream),
promises: {
unlink: sinon.stub().resolves(),
},
}
stream = {
pipeline: sinon.stub().yields(),
}
const ObjectPersistor = { Errors }
vi.doMock('fs', () => ({
default: fs,
}))
vi.doMock('stream', () => ({
default: stream,
}))
vi.doMock('@overleaf/settings', () => ({
default: settings,
}))
vi.doMock('@overleaf/metrics', () => ({
default: {
inc: sinon.stub(),
Timer: sinon.stub().returns({ done: sinon.stub() }),
},
}))
vi.doMock('@overleaf/object-persistor', () => ObjectPersistor)
LocalFileWriter = (await import(modulePath)).default
})
describe('writeStream', function () {
it('writes the stream to the upload folder', async function () {
await new Promise(resolve => {
LocalFileWriter.writeStream(readStream, filename, (err, path) => {
expect(err).not.to.exist
expect(fs.createWriteStream).to.have.been.calledWith(fsPath)
expect(stream.pipeline).to.have.been.calledWith(
readStream,
writeStream
)
expect(path).to.equal(fsPath)
resolve()
})
})
})
describe('when there is an error', function () {
const error = new Error('not enough ketchup')
beforeEach(function () {
stream.pipeline.yields(error)
})
it('should wrap the error', async function () {
await expect(
LocalFileWriter.promises.writeStream(readStream, filename)
).to.be.rejected.and.eventually.have.property('cause', error)
})
it('should delete the temporary file', async function () {
await expect(LocalFileWriter.promises.writeStream(readStream, filename))
.to.be.rejected
expect(fs.promises.unlink).to.have.been.calledWith(fsPath)
})
})
})
describe('deleteFile', function () {
it('should unlink the file', async function () {
await LocalFileWriter.promises.deleteFile(fsPath)
expect(fs.promises.unlink).to.have.been.calledWith(fsPath)
})
it('should not call unlink with an empty path', async function () {
await LocalFileWriter.promises.deleteFile('')
expect(fs.promises.unlink).not.to.have.been.called
})
it('should not throw a error if the file does not exist', async function () {
const error = new Error('file not found')
error.code = 'ENOENT'
fs.promises.unlink = sinon.stub().rejects(error)
await LocalFileWriter.promises.deleteFile(fsPath)
})
it('should wrap the error', async function () {
const error = new Error('failed to reticulate splines')
fs.promises.unlink = sinon.stub().rejects(error)
await expect(
LocalFileWriter.promises.deleteFile(fsPath)
).to.be.rejectedWith(Errors.WriteError)
})
})
})