overleaf/services/web/test/unit/src/Uploads/ProjectUploadManagerTests.js

267 lines
8.2 KiB
JavaScript
Raw Normal View History

const sinon = require('sinon')
const { expect } = require('chai')
const timekeeper = require('timekeeper')
const SandboxedModule = require('sandboxed-module')
const MODULE_PATH =
'../../../../app/src/Features/Uploads/ProjectUploadManager.js'
describe('ProjectUploadManager', function() {
beforeEach(function() {
this.now = Date.now()
timekeeper.freeze(this.now)
this.project_id = 'project-id-123'
this.folder_id = 'folder-id-123'
this.owner_id = 'owner-id-123'
this.source = '/path/to/zip/file-name.zip'
this.destination = `/path/to/zip/file-name-${this.now}`
this.root_folder_id = this.folder_id
this.owner_id = 'owner-id-123'
this.name = 'Project name'
this.othername = 'Other name'
this.project = {
_id: this.project_id,
rootFolder: [{ _id: this.root_folder_id }]
}
this.topLevelDestination = '/path/to/zip/file-extracted/nested'
this.fs = {
remove: sinon.stub().resolves()
}
this.ArchiveManager = {
promises: {
extractZipArchive: sinon.stub().resolves(),
findTopLevelDirectory: sinon.stub().resolves(this.topLevelDestination)
}
}
this.FileSystemImportManager = {
promises: {
addFolderContents: sinon.stub().resolves()
}
}
this.ProjectCreationHandler = {
promises: {
createBlankProject: sinon.stub().resolves(this.project)
}
}
this.ProjectRootDocManager = {
promises: {
setRootDocAutomatically: sinon.stub().resolves(),
findRootDocFileFromDirectory: sinon
.stub()
.resolves({ path: 'main.tex', content: this.othername }),
setRootDocFromName: sinon.stub().resolves()
}
}
this.ProjectDetailsHandler = {
fixProjectName: sinon.stub().returnsArg(0),
promises: {
generateUniqueName: sinon.stub().resolves(this.othername)
}
}
this.ProjectDeleter = {
promises: {
deleteProject: sinon.stub().resolves()
}
}
this.DocumentHelper = {
getTitleFromTexContent: sinon.stub().returns(this.othername)
}
this.ProjectUploadManager = SandboxedModule.require(MODULE_PATH, {
globals: {
console: console
},
requires: {
'fs-extra': this.fs,
'./FileSystemImportManager': this.FileSystemImportManager,
'./ArchiveManager': this.ArchiveManager,
'../Project/ProjectCreationHandler': this.ProjectCreationHandler,
'../Project/ProjectRootDocManager': this.ProjectRootDocManager,
'../Project/ProjectDetailsHandler': this.ProjectDetailsHandler,
'../Project/ProjectDeleter': this.ProjectDeleter,
'../Documents/DocumentHelper': this.DocumentHelper
}
})
})
afterEach(function() {
timekeeper.reset()
})
describe('createProjectFromZipArchive', function() {
describe('when the title can be read from the root document', function() {
beforeEach(async function() {
await this.ProjectUploadManager.promises.createProjectFromZipArchive(
this.owner_id,
this.name,
this.source
)
})
it('should extract the archive', function() {
this.ArchiveManager.promises.extractZipArchive.should.have.been.calledWith(
this.source,
this.destination
)
})
it('should find the top level directory', function() {
this.ArchiveManager.promises.findTopLevelDirectory.should.have.been.calledWith(
this.destination
)
})
it('should insert the extracted archive into the folder', function() {
this.FileSystemImportManager.promises.addFolderContents.should.have.been.calledWith(
this.owner_id,
this.project_id,
this.folder_id,
this.topLevelDestination,
false
)
})
it('should create a project owned by the owner_id', function() {
this.ProjectCreationHandler.promises.createBlankProject.should.have.been.calledWith(
this.owner_id
)
})
it('should create a project with the correct name', function() {
this.ProjectCreationHandler.promises.createBlankProject.should.have.been.calledWith(
sinon.match.any,
this.othername
)
})
it('should read the title from the tex contents', function() {
this.DocumentHelper.getTitleFromTexContent.should.have.been.called
})
it('should set the root document', function() {
this.ProjectRootDocManager.promises.setRootDocFromName.should.have.been.calledWith(
this.project_id,
'main.tex'
)
})
it('should ensure the name is valid', function() {
this.ProjectDetailsHandler.fixProjectName.should.have.been.called
})
})
describe("when the root document can't be determined", function() {
beforeEach(async function() {
this.ProjectRootDocManager.promises.findRootDocFileFromDirectory.resolves(
{}
)
await this.ProjectUploadManager.promises.createProjectFromZipArchive(
this.owner_id,
this.name,
this.source
)
})
it('should not try to set the root doc', function() {
this.ProjectRootDocManager.promises.setRootDocFromName.should.not.have
.been.called
})
})
})
describe('createProjectFromZipArchiveWithName', function() {
beforeEach(async function() {
await this.ProjectUploadManager.promises.createProjectFromZipArchiveWithName(
this.owner_id,
this.name,
this.source
)
})
it('should create a project owned by the owner_id', function() {
this.ProjectCreationHandler.promises.createBlankProject.should.have.been.calledWith(
this.owner_id
)
})
it('should create a project with the correct name', function() {
this.ProjectCreationHandler.promises.createBlankProject.should.have.been.calledWith(
sinon.match.any,
this.othername
)
})
it('should automatically set the root doc', function() {
this.ProjectRootDocManager.promises.setRootDocAutomatically.should.have.been.calledWith(
this.project_id
)
})
it('should extract the archive', function() {
this.ArchiveManager.promises.extractZipArchive.should.have.been.calledWith(
this.source,
this.destination
)
})
it('should find the top level directory', function() {
this.ArchiveManager.promises.findTopLevelDirectory.should.have.been.calledWith(
this.destination
)
})
it('should insert the extracted archive into the folder', function() {
this.FileSystemImportManager.promises.addFolderContents.should.have.been.calledWith(
this.owner_id,
this.project_id,
this.folder_id,
this.topLevelDestination,
false
)
})
it('should remove the destination directory afterwards', function() {
this.fs.remove.should.have.been.calledWith(this.destination)
})
describe('when inserting the zip file contents into the root folder fails', function() {
beforeEach(async function() {
this.FileSystemImportManager.promises.addFolderContents.rejects()
await expect(
this.ProjectUploadManager.promises.createProjectFromZipArchiveWithName(
this.owner_id,
this.name,
this.source
)
).to.be.rejected
})
it('should cleanup the blank project created', async function() {
this.ProjectDeleter.promises.deleteProject.should.have.been.calledWith(
this.project_id
)
})
})
describe('when setting automatically the root doc fails', function() {
beforeEach(async function() {
this.ProjectRootDocManager.promises.setRootDocAutomatically.rejects()
await expect(
this.ProjectUploadManager.promises.createProjectFromZipArchiveWithName(
this.owner_id,
this.name,
this.source
)
).to.be.rejected
})
it('should cleanup the blank project created', function() {
this.ProjectDeleter.promises.deleteProject.should.have.been.calledWith(
this.project_id
)
})
})
})
})