| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- import { expect } from 'chai'
- import mongodb from 'mongodb-legacy'
- import Path from 'node:path'
- import fs from 'node:fs'
- import { Project } from '../../../app/src/models/Project.js'
- import ProjectGetter from '../../../app/src/Features/Project/ProjectGetter.js'
- import UserHelper from './helpers/User.mjs'
- import MockDocStoreApiClass from './mocks/MockDocstoreApi.mjs'
- import MockDocUpdaterApiClass from './mocks/MockDocUpdaterApi.mjs'
- import { fileURLToPath } from 'node:url'
- const User = UserHelper.promises
- const ObjectId = mongodb.ObjectId
- const __dirname = fileURLToPath(new URL('.', import.meta.url))
- let MockDocStoreApi, MockDocUpdaterApi
- before(function () {
- MockDocUpdaterApi = MockDocUpdaterApiClass.instance()
- MockDocStoreApi = MockDocStoreApiClass.instance()
- })
- describe('ProjectStructureChanges', function () {
- let owner
- beforeEach(async function () {
- owner = new User()
- await owner.login()
- })
- async function createExampleProject(owner) {
- const projectId = await owner.createProject('example-project', {
- template: 'example',
- })
- const project = await ProjectGetter.promises.getProject(projectId)
- const rootFolderId = project.rootFolder[0]._id.toString()
- return { projectId, rootFolderId }
- }
- async function createExampleDoc(owner, projectId) {
- const project = await ProjectGetter.promises.getProject(projectId)
- const { response, body } = await owner.doRequest('POST', {
- uri: `project/${projectId}/doc`,
- json: {
- name: 'new.tex',
- parent_folder_id: project.rootFolder[0]._id,
- },
- })
- if (response.statusCode < 200 || response.statusCode >= 300) {
- throw new Error(`failed to add doc ${response.statusCode}`)
- }
- return body._id
- }
- async function createExampleFolder(owner, projectId) {
- const { response, body } = await owner.doRequest('POST', {
- uri: `project/${projectId}/folder`,
- json: {
- name: 'foo',
- },
- })
- if (response.statusCode < 200 || response.statusCode >= 300) {
- throw new Error(`failed to add doc ${response.statusCode}`)
- }
- return body._id
- }
- async function uploadExampleProject(owner, zipFilename, options = {}) {
- const zipFile = fs.createReadStream(
- Path.resolve(Path.join(__dirname, '..', 'files', zipFilename))
- )
- const { response, body } = await owner.doRequest('POST', {
- uri: 'project/new/upload',
- formData: {
- name: zipFilename,
- qqfile: zipFile,
- },
- })
- if (
- !options.allowBadStatus &&
- (response.statusCode < 200 || response.statusCode >= 300)
- ) {
- throw new Error(`failed to upload project ${response.statusCode}`)
- }
- return { projectId: JSON.parse(body).project_id, response }
- }
- async function deleteItem(owner, projectId, type, itemId) {
- return await owner.deleteItemInProject(projectId, type, itemId)
- }
- describe('uploading a project with a name', function () {
- let exampleProjectId
- const testProjectName = 'wombat'
- beforeEach(async function () {
- const { projectId } = await uploadExampleProject(
- owner,
- 'test_project_with_name.zip'
- )
- exampleProjectId = projectId
- })
- it('should set the project name from the zip contents', async function () {
- const project = await ProjectGetter.promises.getProject(exampleProjectId)
- expect(project.name).to.equal(testProjectName)
- })
- })
- describe('uploading a project with an invalid name', function () {
- let exampleProjectId
- const testProjectMatch = /^bad[^\\]+name$/
- beforeEach(async function () {
- const { projectId } = await uploadExampleProject(
- owner,
- 'test_project_with_invalid_name.zip'
- )
- exampleProjectId = projectId
- })
- it('should set the project name from the zip contents', async function () {
- const project = await ProjectGetter.promises.getProject(exampleProjectId)
- expect(project.name).to.match(testProjectMatch)
- })
- })
- describe('uploading an empty zipfile', function () {
- let res
- beforeEach(async function () {
- const { response } = await uploadExampleProject(
- owner,
- 'test_project_empty.zip',
- { allowBadStatus: true }
- )
- res = response
- })
- it('should fail with 422 error', function () {
- expect(res.statusCode).to.equal(422)
- })
- })
- describe('uploading a zipfile containing only empty directories', function () {
- let res
- beforeEach(async function () {
- const { response } = await uploadExampleProject(
- owner,
- 'test_project_with_empty_folder.zip',
- { allowBadStatus: true }
- )
- res = response
- })
- it('should fail with 422 error', function () {
- expect(res.statusCode).to.equal(422)
- })
- })
- describe('uploading a project with a shared top-level folder', function () {
- let exampleProjectId
- beforeEach(async function () {
- const { projectId } = await uploadExampleProject(
- owner,
- 'test_project_with_shared_top_level_folder.zip'
- )
- exampleProjectId = projectId
- })
- it('should not create the top-level folder', async function () {
- const project = await ProjectGetter.promises.getProject(exampleProjectId)
- expect(project.rootFolder[0].folders.length).to.equal(0)
- expect(project.rootFolder[0].docs.length).to.equal(2)
- })
- })
- describe('uploading a project with backslashes in the path names', function () {
- let exampleProjectId
- beforeEach(async function () {
- const { projectId } = await uploadExampleProject(
- owner,
- 'test_project_with_backslash_in_filename.zip'
- )
- exampleProjectId = projectId
- })
- it('should treat the backslash as a directory separator', async function () {
- const project = await ProjectGetter.promises.getProject(exampleProjectId)
- expect(project.rootFolder[0].folders[0].name).to.equal('styles')
- expect(project.rootFolder[0].folders[0].docs[0].name).to.equal('ao.sty')
- })
- })
- describe('deleting docs', function () {
- beforeEach(async function () {
- const { projectId } = await createExampleProject(owner)
- this.exampleProjectId = projectId
- const folderId = await createExampleFolder(owner, projectId)
- this.exampleFolderId = folderId
- const docId = await createExampleDoc(owner, projectId)
- this.exampleDocId = docId
- MockDocUpdaterApi.reset()
- const project = await ProjectGetter.promises.getProject(
- this.exampleProjectId
- )
- this.project0 = project
- })
- it('should pass the doc name to docstore', async function () {
- await deleteItem(owner, this.exampleProjectId, 'doc', this.exampleDocId)
- expect(
- MockDocStoreApi.getDeletedDocs(this.exampleProjectId)
- ).to.deep.equal([{ _id: this.exampleDocId, name: 'new.tex' }])
- })
- describe('when rootDoc_id matches doc being deleted', function () {
- beforeEach(async function () {
- await Project.updateOne(
- { _id: this.exampleProjectId },
- { $set: { rootDoc_id: this.exampleDocId } }
- ).exec()
- })
- it('should clear rootDoc_id', async function () {
- await deleteItem(owner, this.exampleProjectId, 'doc', this.exampleDocId)
- const project = ProjectGetter.promises.getProject(this.exampleProjectId)
- expect(project.rootDoc_id).to.be.undefined
- })
- })
- describe('when rootDoc_id does not match doc being deleted', function () {
- beforeEach(async function () {
- this.exampleRootDocId = new ObjectId()
- await Project.updateOne(
- { _id: this.exampleProjectId },
- { $set: { rootDoc_id: this.exampleRootDocId } }
- ).exec()
- })
- it('should not clear rootDoc_id', async function () {
- await deleteItem(owner, this.exampleProjectId, 'doc', this.exampleDocId)
- const project = await ProjectGetter.promises.getProject(
- this.exampleProjectId
- )
- expect(project.rootDoc_id.toString()).to.equal(
- this.exampleRootDocId.toString()
- )
- })
- })
- })
- })
|