[PnP migration] Remove mock-fs dependency (#33835)
GitOrigin-RevId: ff8df32d85b2ecd2837c9eee6d6d2b3b95285239
This commit is contained in:
committed by
Copybot
parent
3fcd133198
commit
97247b8ea5
@@ -38,7 +38,6 @@
|
|||||||
"mocha": "^11.1.0",
|
"mocha": "^11.1.0",
|
||||||
"mocha-junit-reporter": "^2.2.1",
|
"mocha-junit-reporter": "^2.2.1",
|
||||||
"mocha-multi-reporters": "^1.5.1",
|
"mocha-multi-reporters": "^1.5.1",
|
||||||
"mock-fs": "^5.2.0",
|
|
||||||
"mongodb": "6.12.0",
|
"mongodb": "6.12.0",
|
||||||
"sandboxed-module": "^2.0.4",
|
"sandboxed-module": "^2.0.4",
|
||||||
"sinon": "^9.2.4",
|
"sinon": "^9.2.4",
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ const fs = require('node:fs')
|
|||||||
const fsPromises = require('node:fs/promises')
|
const fsPromises = require('node:fs/promises')
|
||||||
const { glob } = require('glob')
|
const { glob } = require('glob')
|
||||||
const Path = require('node:path')
|
const Path = require('node:path')
|
||||||
|
const { promisify } = require('node:util')
|
||||||
const { PassThrough } = require('node:stream')
|
const { PassThrough } = require('node:stream')
|
||||||
const { pipeline } = require('node:stream/promises')
|
const { pipeline } = require('node:stream/promises')
|
||||||
|
|
||||||
|
const openCb = promisify(fs.open)
|
||||||
|
|
||||||
const AbstractPersistor = require('./AbstractPersistor')
|
const AbstractPersistor = require('./AbstractPersistor')
|
||||||
const { ReadError, WriteError, NotImplementedError } = require('./Errors')
|
const { ReadError, WriteError, NotImplementedError } = require('./Errors')
|
||||||
const PersistorHelper = require('./PersistorHelper')
|
const PersistorHelper = require('./PersistorHelper')
|
||||||
@@ -85,8 +88,9 @@ module.exports = class FSPersistor extends AbstractPersistor {
|
|||||||
})
|
})
|
||||||
const fsPath = this._getFsPath(location, name, opts.useSubdirectories)
|
const fsPath = this._getFsPath(location, name, opts.useSubdirectories)
|
||||||
|
|
||||||
|
let fd
|
||||||
try {
|
try {
|
||||||
opts.fd = await fsPromises.open(fsPath, 'r')
|
fd = await openCb(fsPath, 'r')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw PersistorHelper.wrapError(
|
throw PersistorHelper.wrapError(
|
||||||
err,
|
err,
|
||||||
@@ -96,7 +100,7 @@ module.exports = class FSPersistor extends AbstractPersistor {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const stream = fs.createReadStream(null, opts)
|
const stream = fs.createReadStream(null, { ...opts, fd })
|
||||||
// Return a PassThrough stream with a minimal interface. It will buffer until the caller starts reading. It will emit errors from the source stream (Stream.pipeline passes errors along).
|
// Return a PassThrough stream with a minimal interface. It will buffer until the caller starts reading. It will emit errors from the source stream (Stream.pipeline passes errors along).
|
||||||
const pass = new PassThrough()
|
const pass = new PassThrough()
|
||||||
pipeline(stream, observer, pass).catch(() => {})
|
pipeline(stream, observer, pass).catch(() => {})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const crypto = require('node:crypto')
|
const crypto = require('node:crypto')
|
||||||
|
const os = require('node:os')
|
||||||
const { expect } = require('chai')
|
const { expect } = require('chai')
|
||||||
const mockFs = require('mock-fs')
|
|
||||||
const fs = require('node:fs')
|
const fs = require('node:fs')
|
||||||
const fsPromises = require('node:fs/promises')
|
const fsPromises = require('node:fs/promises')
|
||||||
const Path = require('node:path')
|
const Path = require('node:path')
|
||||||
@@ -10,22 +10,59 @@ const Errors = require('../../src/Errors')
|
|||||||
|
|
||||||
const MODULE_PATH = '../../src/FSPersistor.js'
|
const MODULE_PATH = '../../src/FSPersistor.js'
|
||||||
|
|
||||||
|
function createTree(base, tree) {
|
||||||
|
fs.mkdirSync(base, { recursive: true })
|
||||||
|
for (const [name, content] of Object.entries(tree)) {
|
||||||
|
const fullPath = Path.join(base, name)
|
||||||
|
if (Buffer.isBuffer(content) || typeof content === 'string') {
|
||||||
|
fs.writeFileSync(fullPath, content)
|
||||||
|
} else if (content && typeof content.symlink === 'string') {
|
||||||
|
fs.symlinkSync(content.symlink, fullPath)
|
||||||
|
} else {
|
||||||
|
createTree(fullPath, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe('FSPersistorTests', function () {
|
describe('FSPersistorTests', function () {
|
||||||
const localFiles = {
|
const fileContents = {
|
||||||
'/uploads/info.txt': Buffer.from('This information is critical', {
|
'info.txt': Buffer.from('This information is critical', {
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
}),
|
}),
|
||||||
'/uploads/other.txt': Buffer.from('Some other content', {
|
'other.txt': Buffer.from('Some other content', {
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
const location = '/bucket'
|
let tmpDir
|
||||||
|
let location
|
||||||
|
let notADirPath
|
||||||
const files = {
|
const files = {
|
||||||
wombat: 'animals/wombat.tex',
|
wombat: 'animals/wombat.tex',
|
||||||
giraffe: 'animals/giraffe.tex',
|
giraffe: 'animals/giraffe.tex',
|
||||||
potato: 'vegetables/potato.tex',
|
potato: 'vegetables/potato.tex',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
tmpDir = fs.mkdtempSync(Path.join(os.tmpdir(), 'fs-persistor-test-'))
|
||||||
|
createTree(tmpDir, {
|
||||||
|
uploads: {
|
||||||
|
'info.txt': fileContents['info.txt'],
|
||||||
|
'other.txt': fileContents['other.txt'],
|
||||||
|
},
|
||||||
|
'not-a-dir':
|
||||||
|
'This regular file is meant to prevent using this path as a directory',
|
||||||
|
directory: {
|
||||||
|
subdirectory: {},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
notADirPath = Path.join(tmpDir, 'not-a-dir')
|
||||||
|
location = Path.join(tmpDir, 'bucket')
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
fs.rmSync(tmpDir, { recursive: true })
|
||||||
|
})
|
||||||
|
|
||||||
const scenarios = [
|
const scenarios = [
|
||||||
{
|
{
|
||||||
description: 'default settings',
|
description: 'default settings',
|
||||||
@@ -54,31 +91,26 @@ describe('FSPersistorTests', function () {
|
|||||||
persistor = new FSPersistor(scenario.settings)
|
persistor = new FSPersistor(scenario.settings)
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockFs({
|
|
||||||
...localFiles,
|
|
||||||
'/not-a-dir':
|
|
||||||
'This regular file is meant to prevent using this path as a directory',
|
|
||||||
'/directory/subdirectory': {},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
mockFs.restore()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('sendFile', function () {
|
describe('sendFile', function () {
|
||||||
it('should copy the file', async function () {
|
it('should copy the file', async function () {
|
||||||
await persistor.sendFile(location, files.wombat, '/uploads/info.txt')
|
await persistor.sendFile(
|
||||||
|
location,
|
||||||
|
files.wombat,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
const contents = await fsPromises.readFile(
|
const contents = await fsPromises.readFile(
|
||||||
scenario.fsPath(files.wombat)
|
scenario.fsPath(files.wombat)
|
||||||
)
|
)
|
||||||
expect(contents.equals(localFiles['/uploads/info.txt'])).to.be.true
|
expect(contents.equals(fileContents['info.txt'])).to.be.true
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return an error if the file cannot be stored', async function () {
|
it('should return an error if the file cannot be stored', async function () {
|
||||||
await expect(
|
await expect(
|
||||||
persistor.sendFile('/not-a-dir', files.wombat, '/uploads/info.txt')
|
persistor.sendFile(
|
||||||
|
notADirPath,
|
||||||
|
files.wombat,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
).to.be.rejectedWith(Errors.WriteError)
|
).to.be.rejectedWith(Errors.WriteError)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -88,7 +120,9 @@ describe('FSPersistorTests', function () {
|
|||||||
|
|
||||||
describe("when the file doesn't exist", function () {
|
describe("when the file doesn't exist", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
stream = fs.createReadStream('/uploads/info.txt')
|
stream = fs.createReadStream(
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should write the stream to disk', async function () {
|
it('should write the stream to disk', async function () {
|
||||||
@@ -96,7 +130,7 @@ describe('FSPersistorTests', function () {
|
|||||||
const contents = await fsPromises.readFile(
|
const contents = await fsPromises.readFile(
|
||||||
scenario.fsPath(files.wombat)
|
scenario.fsPath(files.wombat)
|
||||||
)
|
)
|
||||||
expect(contents.equals(localFiles['/uploads/info.txt'])).to.be.true
|
expect(contents.equals(fileContents['info.txt'])).to.be.true
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should delete the temporary file', async function () {
|
it('should delete the temporary file', async function () {
|
||||||
@@ -109,7 +143,7 @@ describe('FSPersistorTests', function () {
|
|||||||
describe('on error', function () {
|
describe('on error', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
await expect(
|
await expect(
|
||||||
persistor.sendStream('/not-a-dir', files.wombat, stream)
|
persistor.sendStream(notADirPath, files.wombat, stream)
|
||||||
).to.be.rejectedWith(Errors.WriteError)
|
).to.be.rejectedWith(Errors.WriteError)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -129,13 +163,12 @@ describe('FSPersistorTests', function () {
|
|||||||
describe('when the md5 hash matches', function () {
|
describe('when the md5 hash matches', function () {
|
||||||
it('should write the stream to disk', async function () {
|
it('should write the stream to disk', async function () {
|
||||||
await persistor.sendStream(location, files.wombat, stream, {
|
await persistor.sendStream(location, files.wombat, stream, {
|
||||||
sourceMd5: md5(localFiles['/uploads/info.txt']),
|
sourceMd5: md5(fileContents['info.txt']),
|
||||||
})
|
})
|
||||||
const contents = await fsPromises.readFile(
|
const contents = await fsPromises.readFile(
|
||||||
scenario.fsPath(files.wombat)
|
scenario.fsPath(files.wombat)
|
||||||
)
|
)
|
||||||
expect(contents.equals(localFiles['/uploads/info.txt'])).to.be
|
expect(contents.equals(fileContents['info.txt'])).to.be.true
|
||||||
.true
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -169,9 +202,11 @@ describe('FSPersistorTests', function () {
|
|||||||
await persistor.sendFile(
|
await persistor.sendFile(
|
||||||
location,
|
location,
|
||||||
files.wombat,
|
files.wombat,
|
||||||
'/uploads/info.txt'
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
|
stream = fs.createReadStream(
|
||||||
|
Path.join(tmpDir, 'uploads', 'other.txt')
|
||||||
)
|
)
|
||||||
stream = fs.createReadStream('/uploads/other.txt')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should write the stream to disk', async function () {
|
it('should write the stream to disk', async function () {
|
||||||
@@ -179,7 +214,7 @@ describe('FSPersistorTests', function () {
|
|||||||
const contents = await fsPromises.readFile(
|
const contents = await fsPromises.readFile(
|
||||||
scenario.fsPath(files.wombat)
|
scenario.fsPath(files.wombat)
|
||||||
)
|
)
|
||||||
expect(contents.equals(localFiles['/uploads/other.txt'])).to.be.true
|
expect(contents.equals(fileContents['other.txt'])).to.be.true
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should delete the temporary file', async function () {
|
it('should delete the temporary file', async function () {
|
||||||
@@ -192,7 +227,7 @@ describe('FSPersistorTests', function () {
|
|||||||
describe('on error', function () {
|
describe('on error', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
await expect(
|
await expect(
|
||||||
persistor.sendStream('/not-a-dir', files.wombat, stream)
|
persistor.sendStream(notADirPath, files.wombat, stream)
|
||||||
).to.be.rejectedWith(Errors.WriteError)
|
).to.be.rejectedWith(Errors.WriteError)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -200,8 +235,7 @@ describe('FSPersistorTests', function () {
|
|||||||
const contents = await fsPromises.readFile(
|
const contents = await fsPromises.readFile(
|
||||||
scenario.fsPath(files.wombat)
|
scenario.fsPath(files.wombat)
|
||||||
)
|
)
|
||||||
expect(contents.equals(localFiles['/uploads/info.txt'])).to.be
|
expect(contents.equals(fileContents['info.txt'])).to.be.true
|
||||||
.true
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should delete the temporary file', async function () {
|
it('should delete the temporary file', async function () {
|
||||||
@@ -215,13 +249,12 @@ describe('FSPersistorTests', function () {
|
|||||||
describe('when the md5 hash matches', function () {
|
describe('when the md5 hash matches', function () {
|
||||||
it('should write the stream to disk', async function () {
|
it('should write the stream to disk', async function () {
|
||||||
await persistor.sendStream(location, files.wombat, stream, {
|
await persistor.sendStream(location, files.wombat, stream, {
|
||||||
sourceMd5: md5(localFiles['/uploads/other.txt']),
|
sourceMd5: md5(fileContents['other.txt']),
|
||||||
})
|
})
|
||||||
const contents = await fsPromises.readFile(
|
const contents = await fsPromises.readFile(
|
||||||
scenario.fsPath(files.wombat)
|
scenario.fsPath(files.wombat)
|
||||||
)
|
)
|
||||||
expect(contents.equals(localFiles['/uploads/other.txt'])).to.be
|
expect(contents.equals(fileContents['other.txt'])).to.be.true
|
||||||
.true
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -238,8 +271,7 @@ describe('FSPersistorTests', function () {
|
|||||||
const contents = await fsPromises.readFile(
|
const contents = await fsPromises.readFile(
|
||||||
scenario.fsPath(files.wombat)
|
scenario.fsPath(files.wombat)
|
||||||
)
|
)
|
||||||
expect(contents.equals(localFiles['/uploads/info.txt'])).to.be
|
expect(contents.equals(fileContents['info.txt'])).to.be.true
|
||||||
.true
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should delete the temporary file', async function () {
|
it('should delete the temporary file', async function () {
|
||||||
@@ -254,13 +286,17 @@ describe('FSPersistorTests', function () {
|
|||||||
|
|
||||||
describe('getObjectStream', function () {
|
describe('getObjectStream', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
await persistor.sendFile(location, files.wombat, '/uploads/info.txt')
|
await persistor.sendFile(
|
||||||
|
location,
|
||||||
|
files.wombat,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return a string with the object contents', async function () {
|
it('should return a string with the object contents', async function () {
|
||||||
const stream = await persistor.getObjectStream(location, files.wombat)
|
const stream = await persistor.getObjectStream(location, files.wombat)
|
||||||
const contents = await streamToBuffer(stream)
|
const contents = await streamToBuffer(stream)
|
||||||
expect(contents.equals(localFiles['/uploads/info.txt'])).to.be.true
|
expect(contents.equals(fileContents['info.txt'])).to.be.true
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should support ranges', async function () {
|
it('should support ranges', async function () {
|
||||||
@@ -274,8 +310,8 @@ describe('FSPersistorTests', function () {
|
|||||||
)
|
)
|
||||||
const contents = await streamToBuffer(stream)
|
const contents = await streamToBuffer(stream)
|
||||||
// end is inclusive in ranges, but exclusive in slice()
|
// end is inclusive in ranges, but exclusive in slice()
|
||||||
expect(contents.equals(localFiles['/uploads/info.txt'].slice(5, 17)))
|
expect(contents.equals(fileContents['info.txt'].slice(5, 17))).to.be
|
||||||
.to.be.true
|
.true
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should give a NotFoundError if the file does not exist', async function () {
|
it('should give a NotFoundError if the file does not exist', async function () {
|
||||||
@@ -287,13 +323,17 @@ describe('FSPersistorTests', function () {
|
|||||||
|
|
||||||
describe('getObjectSize', function () {
|
describe('getObjectSize', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
await persistor.sendFile(location, files.wombat, '/uploads/info.txt')
|
await persistor.sendFile(
|
||||||
|
location,
|
||||||
|
files.wombat,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return the file size', async function () {
|
it('should return the file size', async function () {
|
||||||
expect(
|
expect(
|
||||||
await persistor.getObjectSize(location, files.wombat)
|
await persistor.getObjectSize(location, files.wombat)
|
||||||
).to.equal(localFiles['/uploads/info.txt'].length)
|
).to.equal(fileContents['info.txt'].length)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw a NotFoundError if the file does not exist', async function () {
|
it('should throw a NotFoundError if the file does not exist', async function () {
|
||||||
@@ -305,7 +345,11 @@ describe('FSPersistorTests', function () {
|
|||||||
|
|
||||||
describe('copyObject', function () {
|
describe('copyObject', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
await persistor.sendFile(location, files.wombat, '/uploads/info.txt')
|
await persistor.sendFile(
|
||||||
|
location,
|
||||||
|
files.wombat,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should copy the file to the new location', async function () {
|
it('Should copy the file to the new location', async function () {
|
||||||
@@ -313,13 +357,17 @@ describe('FSPersistorTests', function () {
|
|||||||
const contents = await fsPromises.readFile(
|
const contents = await fsPromises.readFile(
|
||||||
scenario.fsPath(files.potato)
|
scenario.fsPath(files.potato)
|
||||||
)
|
)
|
||||||
expect(contents.equals(localFiles['/uploads/info.txt'])).to.be.true
|
expect(contents.equals(fileContents['info.txt'])).to.be.true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('deleteObject', function () {
|
describe('deleteObject', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
await persistor.sendFile(location, files.wombat, '/uploads/info.txt')
|
await persistor.sendFile(
|
||||||
|
location,
|
||||||
|
files.wombat,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
await fsPromises.access(scenario.fsPath(files.wombat))
|
await fsPromises.access(scenario.fsPath(files.wombat))
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -337,7 +385,11 @@ describe('FSPersistorTests', function () {
|
|||||||
describe('deleteDirectory', function () {
|
describe('deleteDirectory', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
for (const file of Object.values(files)) {
|
for (const file of Object.values(files)) {
|
||||||
await persistor.sendFile(location, file, '/uploads/info.txt')
|
await persistor.sendFile(
|
||||||
|
location,
|
||||||
|
file,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
await fsPromises.access(scenario.fsPath(file))
|
await fsPromises.access(scenario.fsPath(file))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -365,7 +417,11 @@ describe('FSPersistorTests', function () {
|
|||||||
|
|
||||||
describe('checkIfObjectExists', function () {
|
describe('checkIfObjectExists', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
await persistor.sendFile(location, files.wombat, '/uploads/info.txt')
|
await persistor.sendFile(
|
||||||
|
location,
|
||||||
|
files.wombat,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return true for existing files', async function () {
|
it('should return true for existing files', async function () {
|
||||||
@@ -384,13 +440,17 @@ describe('FSPersistorTests', function () {
|
|||||||
describe('directorySize', function () {
|
describe('directorySize', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
for (const file of Object.values(files)) {
|
for (const file of Object.values(files)) {
|
||||||
await persistor.sendFile(location, file, '/uploads/info.txt')
|
await persistor.sendFile(
|
||||||
|
location,
|
||||||
|
file,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should sum directory files size', async function () {
|
it('should sum directory files size', async function () {
|
||||||
expect(await persistor.directorySize(location, 'animals')).to.equal(
|
expect(await persistor.directorySize(location, 'animals')).to.equal(
|
||||||
2 * localFiles['/uploads/info.txt'].length
|
2 * fileContents['info.txt'].length
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -404,7 +464,11 @@ describe('FSPersistorTests', function () {
|
|||||||
describe('listDirectoryKeys', function () {
|
describe('listDirectoryKeys', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
for (const file of Object.values(files)) {
|
for (const file of Object.values(files)) {
|
||||||
await persistor.sendFile(location, file, '/uploads/info.txt')
|
await persistor.sendFile(
|
||||||
|
location,
|
||||||
|
file,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -427,7 +491,11 @@ describe('FSPersistorTests', function () {
|
|||||||
describe('listDirectoryStats', function () {
|
describe('listDirectoryStats', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
for (const file of Object.values(files)) {
|
for (const file of Object.values(files)) {
|
||||||
await persistor.sendFile(location, file, '/uploads/info.txt')
|
await persistor.sendFile(
|
||||||
|
location,
|
||||||
|
file,
|
||||||
|
Path.join(tmpDir, 'uploads', 'info.txt')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -438,7 +506,7 @@ describe('FSPersistorTests', function () {
|
|||||||
expect(keys).to.include(scenario.fsPath(files.wombat))
|
expect(keys).to.include(scenario.fsPath(files.wombat))
|
||||||
expect(keys).to.include(scenario.fsPath(files.giraffe))
|
expect(keys).to.include(scenario.fsPath(files.giraffe))
|
||||||
for (const stat of stats) {
|
for (const stat of stats) {
|
||||||
expect(stat.size).to.equal(localFiles['/uploads/info.txt'].length)
|
expect(stat.size).to.equal(fileContents['info.txt'].length)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,6 @@
|
|||||||
"knip": "5.64.1",
|
"knip": "5.64.1",
|
||||||
"eslint-plugin-testing-library": "7.5.3",
|
"eslint-plugin-testing-library": "7.5.3",
|
||||||
"chart.js": "4.0.1",
|
"chart.js": "4.0.1",
|
||||||
"mock-fs": "5.2.0",
|
|
||||||
"@customerio/cdp-analytics-node": "0.3.9",
|
"@customerio/cdp-analytics-node": "0.3.9",
|
||||||
"@google-cloud/bigquery": "8.1.1",
|
"@google-cloud/bigquery": "8.1.1",
|
||||||
"moment": "2.29.4",
|
"moment": "2.29.4",
|
||||||
|
|||||||
@@ -46,7 +46,6 @@
|
|||||||
"mocha": "^11.1.0",
|
"mocha": "^11.1.0",
|
||||||
"mocha-junit-reporter": "^2.2.1",
|
"mocha-junit-reporter": "^2.2.1",
|
||||||
"mocha-multi-reporters": "^1.5.1",
|
"mocha-multi-reporters": "^1.5.1",
|
||||||
"mock-fs": "^5.1.2",
|
|
||||||
"node-fetch": "^2.7.0",
|
"node-fetch": "^2.7.0",
|
||||||
"nyc": "^17.1.0",
|
"nyc": "^17.1.0",
|
||||||
"sinon": "~9.0.1",
|
"sinon": "~9.0.1",
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { vi, expect, describe, beforeEach, afterEach, it } from 'vitest'
|
import { vi, expect, describe, beforeEach, afterEach, it } from 'vitest'
|
||||||
import Path from 'node:path'
|
import Path from 'node:path'
|
||||||
|
import fs from 'node:fs'
|
||||||
import fsPromises from 'node:fs/promises'
|
import fsPromises from 'node:fs/promises'
|
||||||
import mockFs from 'mock-fs'
|
import os from 'node:os'
|
||||||
|
|
||||||
const MODULE_PATH = Path.join(
|
const MODULE_PATH = Path.join(
|
||||||
import.meta.dirname,
|
import.meta.dirname,
|
||||||
@@ -15,20 +16,19 @@ describe('DraftModeManager', () => {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
ctx.DraftModeManager = (await import(MODULE_PATH)).default
|
ctx.DraftModeManager = (await import(MODULE_PATH)).default
|
||||||
ctx.filename = '/mock/filename.tex'
|
ctx.tmpDir = fs.mkdtempSync(Path.join(os.tmpdir(), 'draft-mode-test-'))
|
||||||
|
ctx.filename = Path.join(ctx.tmpDir, 'filename.tex')
|
||||||
ctx.contents = `\
|
ctx.contents = `\
|
||||||
\\documentclass{article}
|
\\documentclass{article}
|
||||||
\\begin{document}
|
\\begin{document}
|
||||||
Hello world
|
Hello world
|
||||||
\\end{document}\
|
\\end{document}\
|
||||||
`
|
`
|
||||||
mockFs({
|
fs.writeFileSync(ctx.filename, ctx.contents)
|
||||||
[ctx.filename]: ctx.contents,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(ctx => {
|
||||||
mockFs.restore()
|
fs.rmSync(ctx.tmpDir, { recursive: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('injectDraftMode', () => {
|
describe('injectDraftMode', () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import sinon from 'sinon'
|
|
||||||
import { expect, describe, beforeEach, afterEach, it } from 'vitest'
|
import { expect, describe, beforeEach, afterEach, it } from 'vitest'
|
||||||
import mockFs from 'mock-fs'
|
import fs from 'node:fs'
|
||||||
|
import os from 'node:os'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
|
||||||
const modulePath = path.join(
|
const modulePath = path.join(
|
||||||
@@ -8,30 +8,40 @@ const modulePath = path.join(
|
|||||||
'../../../app/js/OutputFileFinder'
|
'../../../app/js/OutputFileFinder'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
function createTree(base, tree) {
|
||||||
|
fs.mkdirSync(base, { recursive: true })
|
||||||
|
for (const [name, content] of Object.entries(tree)) {
|
||||||
|
const fullPath = path.join(base, name)
|
||||||
|
if (Buffer.isBuffer(content) || typeof content === 'string') {
|
||||||
|
fs.writeFileSync(fullPath, content)
|
||||||
|
} else if (content && content.symlink) {
|
||||||
|
fs.symlinkSync(content.symlink, fullPath)
|
||||||
|
} else {
|
||||||
|
createTree(fullPath, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe('OutputFileFinder', function () {
|
describe('OutputFileFinder', function () {
|
||||||
beforeEach(async function (ctx) {
|
beforeEach(async function (ctx) {
|
||||||
ctx.OutputFileFinder = (await import(modulePath)).default
|
ctx.OutputFileFinder = (await import(modulePath)).default
|
||||||
ctx.directory = '/test/dir'
|
ctx.directory = fs.mkdtempSync(
|
||||||
ctx.callback = sinon.stub()
|
path.join(os.tmpdir(), 'output-finder-test-')
|
||||||
|
)
|
||||||
mockFs({
|
createTree(ctx.directory, {
|
||||||
[ctx.directory]: {
|
resource: {
|
||||||
resource: {
|
'path.tex': 'a source file',
|
||||||
'path.tex': 'a source file',
|
|
||||||
},
|
|
||||||
'output.pdf': 'a generated pdf file',
|
|
||||||
extra: {
|
|
||||||
'file.tex': 'a generated tex file',
|
|
||||||
},
|
|
||||||
'sneaky-file': mockFs.symlink({
|
|
||||||
path: '../foo',
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
|
'output.pdf': 'a generated pdf file',
|
||||||
|
extra: {
|
||||||
|
'file.tex': 'a generated tex file',
|
||||||
|
},
|
||||||
|
'sneaky-file': { symlink: '../foo' },
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function (ctx) {
|
||||||
mockFs.restore()
|
fs.rmSync(ctx.directory, { recursive: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('findOutputFiles', function () {
|
describe('findOutputFiles', function () {
|
||||||
|
|||||||
@@ -370,7 +370,6 @@
|
|||||||
"mocha-each": "^2.0.1",
|
"mocha-each": "^2.0.1",
|
||||||
"mocha-junit-reporter": "^2.2.1",
|
"mocha-junit-reporter": "^2.2.1",
|
||||||
"mocha-multi-reporters": "^1.5.1",
|
"mocha-multi-reporters": "^1.5.1",
|
||||||
"mock-fs": "^5.1.2",
|
|
||||||
"nock": "^13.5.6",
|
"nock": "^13.5.6",
|
||||||
"nvd3": "^1.8.6",
|
"nvd3": "^1.8.6",
|
||||||
"nyc": "^17.1.0",
|
"nyc": "^17.1.0",
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { vi, expect } from 'vitest'
|
import { vi, expect } from 'vitest'
|
||||||
import sinon from 'sinon'
|
import sinon from 'sinon'
|
||||||
import mockFs from 'mock-fs'
|
import fs from 'node:fs'
|
||||||
|
import os from 'node:os'
|
||||||
|
import path from 'node:path'
|
||||||
import mongodb from 'mongodb-legacy'
|
import mongodb from 'mongodb-legacy'
|
||||||
import Settings from '@overleaf/settings'
|
import Settings from '@overleaf/settings'
|
||||||
|
|
||||||
@@ -9,6 +11,20 @@ const { ObjectId } = mongodb
|
|||||||
const MODULE_PATH =
|
const MODULE_PATH =
|
||||||
'../../../../app/src/Features/Uploads/FileSystemImportManager.mjs'
|
'../../../../app/src/Features/Uploads/FileSystemImportManager.mjs'
|
||||||
|
|
||||||
|
function createTree(base, tree) {
|
||||||
|
fs.mkdirSync(base, { recursive: true })
|
||||||
|
for (const [name, content] of Object.entries(tree)) {
|
||||||
|
const fullPath = path.join(base, name)
|
||||||
|
if (Buffer.isBuffer(content) || typeof content === 'string') {
|
||||||
|
fs.writeFileSync(fullPath, content)
|
||||||
|
} else if (content && typeof content.symlink === 'string') {
|
||||||
|
fs.symlinkSync(content.symlink, fullPath)
|
||||||
|
} else {
|
||||||
|
createTree(fullPath, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe('FileSystemImportManager', function () {
|
describe('FileSystemImportManager', function () {
|
||||||
beforeEach(async function (ctx) {
|
beforeEach(async function (ctx) {
|
||||||
ctx.projectId = new ObjectId()
|
ctx.projectId = new ObjectId()
|
||||||
@@ -48,14 +64,16 @@ describe('FileSystemImportManager', function () {
|
|||||||
|
|
||||||
describe('importDir', function () {
|
describe('importDir', function () {
|
||||||
beforeEach(async function (ctx) {
|
beforeEach(async function (ctx) {
|
||||||
mockFs({
|
ctx.tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'import-test-'))
|
||||||
|
ctx.importPath = path.join(ctx.tmpDir, 'import-test')
|
||||||
|
createTree(ctx.tmpDir, {
|
||||||
'import-test': {
|
'import-test': {
|
||||||
'main.tex': 'My thesis',
|
'main.tex': 'My thesis',
|
||||||
'link-to-main.tex': mockFs.symlink({ path: 'import-test/main.tex' }),
|
'link-to-main.tex': {
|
||||||
'.DS_Store': 'Should be ignored',
|
symlink: path.join(ctx.tmpDir, 'import-test', 'main.tex'),
|
||||||
images: {
|
|
||||||
'cat.jpg': Buffer.from([1, 2, 3, 4]),
|
|
||||||
},
|
},
|
||||||
|
'.DS_Store': 'Should be ignored',
|
||||||
|
images: { 'cat.jpg': Buffer.from([1, 2, 3, 4]) },
|
||||||
'line-endings': {
|
'line-endings': {
|
||||||
'unix.txt': 'one\ntwo\nthree',
|
'unix.txt': 'one\ntwo\nthree',
|
||||||
'mac.txt': 'uno\rdos\rtres',
|
'mac.txt': 'uno\rdos\rtres',
|
||||||
@@ -67,15 +85,16 @@ describe('FileSystemImportManager', function () {
|
|||||||
'latin1.txt': Buffer.from('tétanisant!', 'latin1'),
|
'latin1.txt': Buffer.from('tétanisant!', 'latin1'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
symlink: mockFs.symlink({ path: 'import-test' }),
|
symlink: { symlink: path.join(ctx.tmpDir, 'import-test') },
|
||||||
})
|
})
|
||||||
ctx.entries =
|
ctx.entries = await ctx.FileSystemImportManager.promises.importDir(
|
||||||
await ctx.FileSystemImportManager.promises.importDir('import-test')
|
ctx.importPath
|
||||||
|
)
|
||||||
ctx.projectPaths = ctx.entries.map(x => x.projectPath)
|
ctx.projectPaths = ctx.entries.map(x => x.projectPath)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function (ctx) {
|
||||||
mockFs.restore()
|
fs.rmSync(ctx.tmpDir, { recursive: true, force: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should import regular docs', function (ctx) {
|
it('should import regular docs', function (ctx) {
|
||||||
@@ -98,7 +117,7 @@ describe('FileSystemImportManager', function () {
|
|||||||
expect(ctx.entries).to.deep.include({
|
expect(ctx.entries).to.deep.include({
|
||||||
type: 'file',
|
type: 'file',
|
||||||
projectPath: '/images/cat.jpg',
|
projectPath: '/images/cat.jpg',
|
||||||
fsPath: 'import-test/images/cat.jpg',
|
fsPath: path.join(ctx.importPath, 'images', 'cat.jpg'),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -142,15 +161,20 @@ describe('FileSystemImportManager', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should error when the root folder is a symlink', async function (ctx) {
|
it('should error when the root folder is a symlink', async function (ctx) {
|
||||||
await expect(ctx.FileSystemImportManager.promises.importDir('symlink')).to
|
await expect(
|
||||||
.be.rejected
|
ctx.FileSystemImportManager.promises.importDir(
|
||||||
|
path.join(ctx.tmpDir, 'symlink')
|
||||||
|
)
|
||||||
|
).to.be.rejected
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('addEntity', function () {
|
describe('addEntity', function () {
|
||||||
describe('with directory', function () {
|
describe('with directory', function () {
|
||||||
beforeEach(async function (ctx) {
|
beforeEach(async function (ctx) {
|
||||||
mockFs({
|
ctx.tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'addentity-dir-'))
|
||||||
|
ctx.fsPath = path.join(ctx.tmpDir, 'path', 'to', 'folder')
|
||||||
|
createTree(ctx.tmpDir, {
|
||||||
path: {
|
path: {
|
||||||
to: {
|
to: {
|
||||||
folder: {
|
folder: {
|
||||||
@@ -160,19 +184,18 @@ describe('FileSystemImportManager', function () {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
await ctx.FileSystemImportManager.promises.addEntity(
|
await ctx.FileSystemImportManager.promises.addEntity(
|
||||||
ctx.userId,
|
ctx.userId,
|
||||||
ctx.projectId,
|
ctx.projectId,
|
||||||
ctx.folderId,
|
ctx.folderId,
|
||||||
'folder',
|
'folder',
|
||||||
'path/to/folder',
|
ctx.fsPath,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function (ctx) {
|
||||||
mockFs.restore()
|
fs.rmSync(ctx.tmpDir, { recursive: true, force: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should add a folder to the project', function (ctx) {
|
it('should add a folder to the project', function (ctx) {
|
||||||
@@ -197,7 +220,7 @@ describe('FileSystemImportManager', function () {
|
|||||||
ctx.projectId,
|
ctx.projectId,
|
||||||
ctx.newFolderId,
|
ctx.newFolderId,
|
||||||
'image.jpg',
|
'image.jpg',
|
||||||
'path/to/folder/image.jpg',
|
path.join(ctx.fsPath, 'image.jpg'),
|
||||||
null,
|
null,
|
||||||
'upload',
|
'upload',
|
||||||
ctx.userId
|
ctx.userId
|
||||||
@@ -206,12 +229,16 @@ describe('FileSystemImportManager', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('with binary file', function () {
|
describe('with binary file', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function (ctx) {
|
||||||
mockFs({ 'uploaded-file': Buffer.from([1, 2, 3, 4]) })
|
ctx.tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'addentity-bin-'))
|
||||||
|
ctx.fsPath = path.join(ctx.tmpDir, 'uploaded-file')
|
||||||
|
createTree(ctx.tmpDir, {
|
||||||
|
'uploaded-file': Buffer.from([1, 2, 3, 4]),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function (ctx) {
|
||||||
mockFs.restore()
|
fs.rmSync(ctx.tmpDir, { recursive: true, force: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with replace set to false', function () {
|
describe('with replace set to false', function () {
|
||||||
@@ -221,7 +248,7 @@ describe('FileSystemImportManager', function () {
|
|||||||
ctx.projectId,
|
ctx.projectId,
|
||||||
ctx.folderId,
|
ctx.folderId,
|
||||||
'image.jpg',
|
'image.jpg',
|
||||||
'uploaded-file',
|
ctx.fsPath,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -231,7 +258,7 @@ describe('FileSystemImportManager', function () {
|
|||||||
ctx.projectId,
|
ctx.projectId,
|
||||||
ctx.folderId,
|
ctx.folderId,
|
||||||
'image.jpg',
|
'image.jpg',
|
||||||
'uploaded-file',
|
ctx.fsPath,
|
||||||
null,
|
null,
|
||||||
'upload',
|
'upload',
|
||||||
ctx.userId
|
ctx.userId
|
||||||
@@ -246,7 +273,7 @@ describe('FileSystemImportManager', function () {
|
|||||||
ctx.projectId,
|
ctx.projectId,
|
||||||
ctx.folderId,
|
ctx.folderId,
|
||||||
'image.jpg',
|
'image.jpg',
|
||||||
'uploaded-file',
|
ctx.fsPath,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -256,7 +283,7 @@ describe('FileSystemImportManager', function () {
|
|||||||
ctx.projectId,
|
ctx.projectId,
|
||||||
ctx.folderId,
|
ctx.folderId,
|
||||||
'image.jpg',
|
'image.jpg',
|
||||||
'uploaded-file',
|
ctx.fsPath,
|
||||||
null,
|
null,
|
||||||
'upload',
|
'upload',
|
||||||
ctx.userId
|
ctx.userId
|
||||||
@@ -271,16 +298,20 @@ describe('FileSystemImportManager', function () {
|
|||||||
['Windows', '\r\n'],
|
['Windows', '\r\n'],
|
||||||
]) {
|
]) {
|
||||||
describe(`with text file (${lineEndingDescription} line endings)`, function () {
|
describe(`with text file (${lineEndingDescription} line endings)`, function () {
|
||||||
beforeEach(function () {
|
beforeEach(function (ctx) {
|
||||||
mockFs({
|
ctx.tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'addentity-txt-'))
|
||||||
|
ctx.fsPath = path.join(ctx.tmpDir, 'path', 'to', 'uploaded-file')
|
||||||
|
createTree(ctx.tmpDir, {
|
||||||
path: {
|
path: {
|
||||||
to: { 'uploaded-file': `one${lineEnding}two${lineEnding}three` },
|
to: {
|
||||||
|
'uploaded-file': `one${lineEnding}two${lineEnding}three`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function (ctx) {
|
||||||
mockFs.restore()
|
fs.rmSync(ctx.tmpDir, { recursive: true, force: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with replace set to false', function () {
|
describe('with replace set to false', function () {
|
||||||
@@ -290,7 +321,7 @@ describe('FileSystemImportManager', function () {
|
|||||||
ctx.projectId,
|
ctx.projectId,
|
||||||
ctx.folderId,
|
ctx.folderId,
|
||||||
'doc.tex',
|
'doc.tex',
|
||||||
'path/to/uploaded-file',
|
ctx.fsPath,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -314,7 +345,7 @@ describe('FileSystemImportManager', function () {
|
|||||||
ctx.projectId,
|
ctx.projectId,
|
||||||
ctx.folderId,
|
ctx.folderId,
|
||||||
'doc.tex',
|
'doc.tex',
|
||||||
'path/to/uploaded-file',
|
ctx.fsPath,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -334,14 +365,20 @@ describe('FileSystemImportManager', function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('with symlink', function () {
|
describe('with symlink', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function (ctx) {
|
||||||
mockFs({
|
ctx.tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'addentity-sym-'))
|
||||||
path: { to: { symlink: mockFs.symlink({ path: '/etc/passwd' }) } },
|
ctx.fsPath = path.join(ctx.tmpDir, 'path', 'to', 'symlink')
|
||||||
|
createTree(ctx.tmpDir, {
|
||||||
|
path: {
|
||||||
|
to: {
|
||||||
|
symlink: { symlink: '/etc/passwd' },
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function (ctx) {
|
||||||
mockFs.restore()
|
fs.rmSync(ctx.tmpDir, { recursive: true, force: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should stop with an error', async function (ctx) {
|
it('should stop with an error', async function (ctx) {
|
||||||
@@ -351,7 +388,7 @@ describe('FileSystemImportManager', function () {
|
|||||||
ctx.projectId,
|
ctx.projectId,
|
||||||
ctx.folderId,
|
ctx.folderId,
|
||||||
'main.tex',
|
'main.tex',
|
||||||
'path/to/symlink',
|
ctx.fsPath,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
).to.be.rejectedWith('path is symlink')
|
).to.be.rejectedWith('path is symlink')
|
||||||
|
|||||||
@@ -6498,7 +6498,6 @@ __metadata:
|
|||||||
mocha: "npm:^11.1.0"
|
mocha: "npm:^11.1.0"
|
||||||
mocha-junit-reporter: "npm:^2.2.1"
|
mocha-junit-reporter: "npm:^2.2.1"
|
||||||
mocha-multi-reporters: "npm:^1.5.1"
|
mocha-multi-reporters: "npm:^1.5.1"
|
||||||
mock-fs: "npm:^5.1.2"
|
|
||||||
multer: "npm:2.1.1"
|
multer: "npm:2.1.1"
|
||||||
node-fetch: "npm:^2.7.0"
|
node-fetch: "npm:^2.7.0"
|
||||||
nyc: "npm:^17.1.0"
|
nyc: "npm:^17.1.0"
|
||||||
@@ -6878,7 +6877,6 @@ __metadata:
|
|||||||
mocha: "npm:^11.1.0"
|
mocha: "npm:^11.1.0"
|
||||||
mocha-junit-reporter: "npm:^2.2.1"
|
mocha-junit-reporter: "npm:^2.2.1"
|
||||||
mocha-multi-reporters: "npm:^1.5.1"
|
mocha-multi-reporters: "npm:^1.5.1"
|
||||||
mock-fs: "npm:^5.2.0"
|
|
||||||
mongodb: "npm:6.12.0"
|
mongodb: "npm:6.12.0"
|
||||||
range-parser: "npm:^1.2.1"
|
range-parser: "npm:^1.2.1"
|
||||||
sandboxed-module: "npm:^2.0.4"
|
sandboxed-module: "npm:^2.0.4"
|
||||||
@@ -7475,7 +7473,6 @@ __metadata:
|
|||||||
mocha-each: "npm:^2.0.1"
|
mocha-each: "npm:^2.0.1"
|
||||||
mocha-junit-reporter: "npm:^2.2.1"
|
mocha-junit-reporter: "npm:^2.2.1"
|
||||||
mocha-multi-reporters: "npm:^1.5.1"
|
mocha-multi-reporters: "npm:^1.5.1"
|
||||||
mock-fs: "npm:^5.1.2"
|
|
||||||
moment: "npm:^2.29.4"
|
moment: "npm:^2.29.4"
|
||||||
mongodb-legacy: "npm:6.1.3"
|
mongodb-legacy: "npm:6.1.3"
|
||||||
mongoose: "npm:8.22.1"
|
mongoose: "npm:8.22.1"
|
||||||
@@ -24737,13 +24734,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"mock-fs@npm:5.2.0":
|
|
||||||
version: 5.2.0
|
|
||||||
resolution: "mock-fs@npm:5.2.0"
|
|
||||||
checksum: 10c0/e917e71295ee9d805c7d9ab0214a66658db0212f35731ba0c75dc1ccbb9964e6787a6d725561f05fcf569c64cf4a1176f5ce438f98b009227520f646f8abf174
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"module-details-from-path@npm:^1.0.3, module-details-from-path@npm:^1.0.4":
|
"module-details-from-path@npm:^1.0.3, module-details-from-path@npm:^1.0.4":
|
||||||
version: 1.0.4
|
version: 1.0.4
|
||||||
resolution: "module-details-from-path@npm:1.0.4"
|
resolution: "module-details-from-path@npm:1.0.4"
|
||||||
|
|||||||
Reference in New Issue
Block a user