mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-03 14:19:01 +02:00
cb0266035d
11 years ago, the db.projects collection was storing doc lines in the
file-tree/rootFolder. Any operations on the project that did not need
those lines were benefitting from excluding all those entries from the
file-tree. These days, the verbose exclusions are not useful anymore and
merely add load on mongo.
REF: 9805c6a9ff
GitOrigin-RevId: 89f544688934c1ed1ca98877ffbe8baefe66c126
742 lines
22 KiB
JavaScript
742 lines
22 KiB
JavaScript
import { beforeEach, describe, it, vi, expect } from 'vitest'
|
|
import sinon from 'sinon'
|
|
import mongodb from 'mongodb-legacy'
|
|
import Errors from '../../../../app/src/Features/Errors/Errors.js'
|
|
import MockRequest from '../helpers/MockRequest.mjs'
|
|
import MockResponse from '../helpers/MockResponse.mjs'
|
|
|
|
const { ObjectId } = mongodb
|
|
|
|
const MODULE_PATH =
|
|
'../../../../app/src/Features/Editor/EditorHttpController.mjs'
|
|
|
|
describe('EditorHttpController', function () {
|
|
beforeEach(async function (ctx) {
|
|
ctx.ownerId = new ObjectId()
|
|
ctx.project = {
|
|
_id: new ObjectId(),
|
|
owner_ref: ctx.ownerId,
|
|
}
|
|
ctx.user = {
|
|
_id: new ObjectId(),
|
|
projects: {},
|
|
}
|
|
ctx.members = [
|
|
{ user: { _id: 'owner', features: {} }, privilegeLevel: 'owner' },
|
|
{ user: { _id: 'one' }, privilegeLevel: 'readOnly' },
|
|
]
|
|
ctx.ownerMember = ctx.members[0]
|
|
ctx.invites = [{ _id: 'three' }, { _id: 'four' }]
|
|
ctx.projectView = {
|
|
_id: ctx.project._id,
|
|
owner: {
|
|
_id: 'owner',
|
|
email: 'owner@example.com',
|
|
other_property: true,
|
|
},
|
|
members: [
|
|
{ _id: 'owner', privileges: 'owner' },
|
|
{ _id: 'one', privileges: 'readOnly' },
|
|
],
|
|
invites: [{ three: 3 }, { four: 4 }],
|
|
}
|
|
ctx.reducedProjectView = {
|
|
_id: ctx.projectView._id,
|
|
owner: { _id: ctx.projectView.owner._id },
|
|
members: [],
|
|
invites: [],
|
|
}
|
|
ctx.doc = { _id: new ObjectId(), name: 'excellent-original-idea.tex' }
|
|
ctx.file = { _id: new ObjectId() }
|
|
ctx.folder = { _id: new ObjectId() }
|
|
ctx.source = 'editor'
|
|
|
|
ctx.parentFolderId = 'mock-folder-id'
|
|
ctx.req = new MockRequest(vi)
|
|
ctx.res = new MockResponse(vi)
|
|
ctx.next = sinon.stub()
|
|
ctx.token = null
|
|
ctx.docLines = ['hello', 'overleaf']
|
|
|
|
ctx.AuthorizationManager = {
|
|
isRestrictedUser: sinon.stub().returns(false),
|
|
promises: {
|
|
getPrivilegeLevelForProjectWithProjectAccess: sinon
|
|
.stub()
|
|
.resolves('owner'),
|
|
},
|
|
}
|
|
const members = ctx.members
|
|
const ownerMember = ctx.ownerMember
|
|
ctx.CollaboratorsGetter = {
|
|
ProjectAccess: class {
|
|
loadOwnerAndInvitedMembers() {
|
|
return { members, ownerMember }
|
|
}
|
|
|
|
loadOwner() {
|
|
return ownerMember
|
|
}
|
|
|
|
isUserTokenMember() {
|
|
return false
|
|
}
|
|
|
|
isUserInvitedMember() {
|
|
return false
|
|
}
|
|
},
|
|
promises: {
|
|
isUserInvitedMemberOfProject: sinon.stub().resolves(false),
|
|
},
|
|
}
|
|
ctx.CollaboratorsHandler = {
|
|
promises: {
|
|
userIsTokenMember: sinon.stub().resolves(false),
|
|
},
|
|
}
|
|
ctx.invites = [
|
|
{
|
|
_id: 'invite_one',
|
|
email: 'user-one@example.com',
|
|
privileges: 'readOnly',
|
|
projectId: ctx.project._id,
|
|
},
|
|
{
|
|
_id: 'invite_two',
|
|
email: 'user-two@example.com',
|
|
privileges: 'readOnly',
|
|
projectId: ctx.project._id,
|
|
},
|
|
]
|
|
ctx.CollaboratorsInviteGetter = {
|
|
promises: {
|
|
getAllInvites: sinon.stub().resolves(ctx.invites),
|
|
},
|
|
}
|
|
ctx.EditorController = {
|
|
promises: {
|
|
addDoc: sinon.stub().resolves(ctx.doc),
|
|
addFile: sinon.stub().resolves(ctx.file),
|
|
addFolder: sinon.stub().resolves(ctx.folder),
|
|
renameEntity: sinon.stub().resolves(),
|
|
moveEntity: sinon.stub().resolves(),
|
|
deleteEntity: sinon.stub().resolves(),
|
|
},
|
|
}
|
|
ctx.ProjectDeleter = {
|
|
promises: {
|
|
unmarkAsDeletedByExternalSource: sinon.stub().resolves(),
|
|
},
|
|
}
|
|
ctx.ProjectGetter = {
|
|
promises: {
|
|
getProject: sinon.stub().resolves(ctx.project),
|
|
},
|
|
}
|
|
ctx.ProjectEditorHandler = {
|
|
buildProjectModelView: sinon.stub().returns(ctx.projectView),
|
|
}
|
|
ctx.Metrics = { inc: sinon.stub() }
|
|
ctx.TokenAccessHandler = {
|
|
getRequestToken: sinon.stub().returns(ctx.token),
|
|
}
|
|
ctx.SessionManager = {
|
|
getLoggedInUserId: sinon.stub().returns(ctx.user._id),
|
|
}
|
|
ctx.ProjectEntityUpdateHandler = {
|
|
promises: {
|
|
convertDocToFile: sinon.stub().resolves(ctx.file),
|
|
},
|
|
}
|
|
ctx.DocstoreManager = {
|
|
promises: {
|
|
getAllDeletedDocs: sinon.stub().resolves([]),
|
|
},
|
|
}
|
|
ctx.HttpErrorHandler = {
|
|
notFound: sinon.stub(),
|
|
unprocessableEntity: sinon.stub(),
|
|
}
|
|
ctx.SplitTestHandler = {
|
|
promises: {
|
|
getAssignmentForUser: sinon.stub().resolves({ variant: 'default' }),
|
|
},
|
|
}
|
|
ctx.UserGetter = { promises: { getUser: sinon.stub().resolves(null, {}) } }
|
|
|
|
vi.mock('../../../../app/src/Features/Errors/Errors.js', () =>
|
|
vi.importActual('../../../../app/src/Features/Errors/Errors.js')
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Project/ProjectDeleter.mjs',
|
|
() => ({
|
|
default: ctx.ProjectDeleter,
|
|
})
|
|
)
|
|
vi.doMock('../../../../app/src/Features/Project/ProjectGetter.mjs', () => ({
|
|
default: ctx.ProjectGetter,
|
|
}))
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Authorization/AuthorizationManager.mjs',
|
|
() => ({
|
|
default: ctx.AuthorizationManager,
|
|
})
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Project/ProjectEditorHandler.mjs',
|
|
() => ({
|
|
default: ctx.ProjectEditorHandler,
|
|
})
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Editor/EditorController.mjs',
|
|
() => ({
|
|
default: ctx.EditorController,
|
|
})
|
|
)
|
|
vi.doMock('@overleaf/metrics', () => ({
|
|
default: ctx.Metrics,
|
|
}))
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Collaborators/CollaboratorsGetter.mjs',
|
|
() => ({
|
|
default: ctx.CollaboratorsGetter,
|
|
})
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Collaborators/CollaboratorsHandler.mjs',
|
|
() => ({
|
|
default: ctx.CollaboratorsHandler,
|
|
})
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Collaborators/CollaboratorsInviteGetter.mjs',
|
|
() => ({
|
|
default: ctx.CollaboratorsInviteGetter,
|
|
})
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/TokenAccess/TokenAccessHandler.mjs',
|
|
() => ({
|
|
default: ctx.TokenAccessHandler,
|
|
})
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Authentication/SessionManager.mjs',
|
|
() => ({
|
|
default: ctx.SessionManager,
|
|
})
|
|
)
|
|
vi.doMock('../../../../app/src/infrastructure/FileWriter.mjs', () => ({
|
|
default: ctx.FileWriter,
|
|
}))
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Project/ProjectEntityUpdateHandler.mjs',
|
|
() => ({
|
|
default: ctx.ProjectEntityUpdateHandler,
|
|
})
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Docstore/DocstoreManager.mjs',
|
|
() => ({
|
|
default: ctx.DocstoreManager,
|
|
})
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Errors/HttpErrorHandler.mjs',
|
|
() => ({
|
|
default: ctx.HttpErrorHandler,
|
|
})
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/SplitTests/SplitTestHandler.mjs',
|
|
() => ({
|
|
default: ctx.SplitTestHandler,
|
|
})
|
|
)
|
|
vi.doMock(
|
|
'../../../../app/src/Features/Compile/CompileManager.mjs',
|
|
() => ({
|
|
default: {},
|
|
})
|
|
)
|
|
vi.doMock('../../../../app/src/Features/User/UserGetter.mjs', () => ({
|
|
default: ctx.UserGetter,
|
|
}))
|
|
|
|
ctx.EditorHttpController = (await import(MODULE_PATH)).default
|
|
})
|
|
|
|
describe('joinProject', function () {
|
|
beforeEach(function (ctx) {
|
|
ctx.req.params = { Project_id: ctx.project._id.toString() }
|
|
ctx.req.query = { user_id: ctx.user._id }
|
|
ctx.req.body = { userId: ctx.user._id.toString() }
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(async function (ctx) {
|
|
await new Promise(resolve => {
|
|
sinon
|
|
.stub(
|
|
ctx.CollaboratorsGetter.ProjectAccess.prototype,
|
|
'isUserInvitedMember'
|
|
)
|
|
.returns(true)
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.joinProject(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should request a full view', function (ctx) {
|
|
expect(
|
|
ctx.ProjectEditorHandler.buildProjectModelView
|
|
).to.have.been.calledWith(
|
|
ctx.project,
|
|
ctx.ownerMember,
|
|
ctx.members,
|
|
ctx.invites,
|
|
false
|
|
)
|
|
})
|
|
|
|
it('should return the project and privilege level', function (ctx) {
|
|
expect(ctx.res.json).toHaveBeenCalledWith({
|
|
project: ctx.projectView,
|
|
privilegeLevel: 'owner',
|
|
isRestrictedUser: false,
|
|
isTokenMember: false,
|
|
isInvitedMember: true,
|
|
})
|
|
})
|
|
|
|
it('should not try to unmark the project as deleted', function (ctx) {
|
|
expect(ctx.ProjectDeleter.promises.unmarkAsDeletedByExternalSource).not
|
|
.to.have.been.called
|
|
})
|
|
|
|
it('should send an inc metric', function (ctx) {
|
|
expect(ctx.Metrics.inc).to.have.been.calledWith('editor.join-project')
|
|
})
|
|
})
|
|
|
|
describe('when the project is marked as deleted', function () {
|
|
beforeEach(async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.projectView.deletedByExternalDataSource = true
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.joinProject(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should unmark the project as deleted', function (ctx) {
|
|
expect(
|
|
ctx.ProjectDeleter.promises.unmarkAsDeletedByExternalSource
|
|
).to.have.been.calledWith(ctx.project._id.toString())
|
|
})
|
|
})
|
|
|
|
describe('with a restricted user', function () {
|
|
beforeEach(async function (ctx) {
|
|
ctx.ProjectEditorHandler.buildProjectModelView.returns(
|
|
ctx.reducedProjectView
|
|
)
|
|
ctx.AuthorizationManager.isRestrictedUser.returns(true)
|
|
ctx.AuthorizationManager.promises.getPrivilegeLevelForProjectWithProjectAccess.resolves(
|
|
'readOnly'
|
|
)
|
|
await new Promise(resolve => {
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.joinProject(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should request a restricted view', function (ctx) {
|
|
expect(
|
|
ctx.ProjectEditorHandler.buildProjectModelView
|
|
).to.have.been.calledWith(ctx.project, ctx.ownerMember, [], [], true)
|
|
})
|
|
|
|
it('should mark the user as restricted, and hide details of owner', function (ctx) {
|
|
expect(ctx.res.json).toHaveBeenCalledWith({
|
|
project: ctx.reducedProjectView,
|
|
privilegeLevel: 'readOnly',
|
|
isRestrictedUser: true,
|
|
isTokenMember: false,
|
|
isInvitedMember: false,
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('when not authorized', function () {
|
|
beforeEach(async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.AuthorizationManager.promises.getPrivilegeLevelForProjectWithProjectAccess.resolves(
|
|
null
|
|
)
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.joinProject(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should send a 403 response', function (ctx) {
|
|
expect(ctx.res.statusCode).to.equal(403)
|
|
})
|
|
})
|
|
|
|
describe('with an anonymous user', function () {
|
|
beforeEach(async function (ctx) {
|
|
ctx.token = 'token'
|
|
ctx.TokenAccessHandler.getRequestToken.returns(ctx.token)
|
|
ctx.ProjectEditorHandler.buildProjectModelView.returns(
|
|
ctx.reducedProjectView
|
|
)
|
|
ctx.req.body = {
|
|
userId: 'anonymous-user',
|
|
anonymousAccessToken: ctx.token,
|
|
}
|
|
ctx.AuthorizationManager.isRestrictedUser
|
|
.withArgs(null, 'readOnly', false, false)
|
|
.returns(true)
|
|
ctx.AuthorizationManager.promises.getPrivilegeLevelForProjectWithProjectAccess
|
|
.withArgs(null, ctx.project._id.toString(), ctx.token)
|
|
.resolves('readOnly')
|
|
await new Promise(resolve => {
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.joinProject(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should request a restricted view', function (ctx) {
|
|
expect(
|
|
ctx.ProjectEditorHandler.buildProjectModelView
|
|
).to.have.been.calledWith(ctx.project, ctx.ownerMember, [], [], true)
|
|
})
|
|
|
|
it('should mark the user as restricted', function (ctx) {
|
|
expect(ctx.res.json).toHaveBeenCalledWith({
|
|
project: ctx.reducedProjectView,
|
|
privilegeLevel: 'readOnly',
|
|
isRestrictedUser: true,
|
|
isTokenMember: false,
|
|
isInvitedMember: false,
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('with a token access user', function () {
|
|
beforeEach(async function (ctx) {
|
|
await new Promise(resolve => {
|
|
sinon
|
|
.stub(
|
|
ctx.CollaboratorsGetter.ProjectAccess.prototype,
|
|
'isUserInvitedMember'
|
|
)
|
|
.returns(false)
|
|
sinon
|
|
.stub(
|
|
ctx.CollaboratorsGetter.ProjectAccess.prototype,
|
|
'isUserTokenMember'
|
|
)
|
|
.returns(true)
|
|
ctx.AuthorizationManager.promises.getPrivilegeLevelForProjectWithProjectAccess.resolves(
|
|
'readAndWrite'
|
|
)
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.joinProject(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should mark the user as being a token-access member', function (ctx) {
|
|
expect(ctx.res.json).toHaveBeenCalledWith({
|
|
project: ctx.projectView,
|
|
privilegeLevel: 'readAndWrite',
|
|
isRestrictedUser: false,
|
|
isTokenMember: true,
|
|
isInvitedMember: false,
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('when project is not found', function () {
|
|
beforeEach(async function (ctx) {
|
|
ctx.ProjectGetter.promises.getProject.resolves(null)
|
|
await new Promise(resolve => {
|
|
ctx.next.callsFake(() => resolve())
|
|
ctx.EditorHttpController.joinProject(ctx.req, ctx.res, ctx.next)
|
|
})
|
|
})
|
|
|
|
it('should handle return not found error', function (ctx) {
|
|
expect(ctx.next).to.have.been.calledWith(
|
|
sinon.match.instanceOf(Errors.NotFoundError)
|
|
)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('addDoc', function () {
|
|
beforeEach(function (ctx) {
|
|
ctx.req.params = { Project_id: ctx.project._id }
|
|
ctx.req.body = {
|
|
name: (ctx.docName = 'doc-name'),
|
|
parent_folder_id: ctx.parentFolderId,
|
|
}
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.addDoc(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should call EditorController.addDoc', function (ctx) {
|
|
expect(ctx.EditorController.promises.addDoc).to.have.been.calledWith(
|
|
ctx.project._id,
|
|
ctx.parentFolderId,
|
|
ctx.docName,
|
|
[],
|
|
'editor',
|
|
ctx.user._id
|
|
)
|
|
})
|
|
|
|
it('should send the doc back as JSON', function (ctx) {
|
|
expect(ctx.res.json).toHaveBeenCalledWith(ctx.doc)
|
|
})
|
|
})
|
|
|
|
describe('unsuccesfully', function () {
|
|
it('handle name too short', async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.req.body.name = ''
|
|
ctx.res.callback = () => {
|
|
expect(ctx.res.statusCode).to.equal(400)
|
|
resolve()
|
|
}
|
|
ctx.EditorHttpController.addDoc(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('handle too many files', async function (ctx) {
|
|
ctx.EditorController.promises.addDoc.rejects(
|
|
new Error('project_has_too_many_files')
|
|
)
|
|
await new Promise(resolve => {
|
|
ctx.res.callback = () => {
|
|
expect(ctx.res.body).to.equal('"project_has_too_many_files_limit"')
|
|
expect(ctx.res.status).toHaveBeenCalledWith(400)
|
|
resolve()
|
|
}
|
|
ctx.EditorHttpController.addDoc(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('addFolder', function () {
|
|
beforeEach(function (ctx) {
|
|
ctx.folderName = 'folder-name'
|
|
ctx.req.params = { Project_id: ctx.project._id }
|
|
ctx.req.body = {
|
|
name: ctx.folderName,
|
|
parent_folder_id: ctx.parentFolderId,
|
|
}
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.addFolder(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should call EditorController.addFolder', function (ctx) {
|
|
expect(ctx.EditorController.promises.addFolder).to.have.been.calledWith(
|
|
ctx.project._id,
|
|
ctx.parentFolderId,
|
|
ctx.folderName,
|
|
'editor'
|
|
)
|
|
})
|
|
|
|
it('should send the folder back as JSON', function (ctx) {
|
|
expect(ctx.res.json).toHaveBeenCalledWith(ctx.folder)
|
|
})
|
|
})
|
|
|
|
describe('unsuccesfully', function () {
|
|
it('handle name too short', async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.req.body.name = ''
|
|
ctx.res.callback = () => {
|
|
expect(ctx.res.statusCode).to.equal(400)
|
|
resolve()
|
|
}
|
|
ctx.EditorHttpController.addFolder(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('handle too many files', async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.EditorController.promises.addFolder.rejects(
|
|
new Error('project_has_too_many_files')
|
|
)
|
|
ctx.res.callback = () => {
|
|
expect(ctx.res.body).to.equal('"project_has_too_many_files_limit"')
|
|
expect(ctx.res.statusCode).to.equal(400)
|
|
resolve()
|
|
}
|
|
ctx.EditorHttpController.addFolder(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('handle invalid element name', async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.EditorController.promises.addFolder.rejects(
|
|
new Error('invalid element name')
|
|
)
|
|
ctx.res.callback = () => {
|
|
expect(ctx.res.body).to.equal('"invalid_file_name"')
|
|
expect(ctx.res.statusCode).to.equal(400)
|
|
resolve()
|
|
}
|
|
ctx.EditorHttpController.addFolder(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('renameEntity', function () {
|
|
beforeEach(function (ctx) {
|
|
ctx.entityId = 'entity-id-123'
|
|
ctx.entityType = 'entity-type'
|
|
ctx.req.params = {
|
|
Project_id: ctx.project._id,
|
|
entity_id: ctx.entityId,
|
|
entity_type: ctx.entityType,
|
|
}
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.newName = 'new-name'
|
|
ctx.req.body = { name: ctx.newName, source: ctx.source }
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.renameEntity(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should call EditorController.renameEntity', function (ctx) {
|
|
expect(
|
|
ctx.EditorController.promises.renameEntity
|
|
).to.have.been.calledWith(
|
|
ctx.project._id,
|
|
ctx.entityId,
|
|
ctx.entityType,
|
|
ctx.newName,
|
|
ctx.user._id,
|
|
ctx.source
|
|
)
|
|
})
|
|
|
|
it('should send back a success response', function (ctx) {
|
|
expect(ctx.res.sendStatus).toHaveBeenCalledWith(204)
|
|
})
|
|
})
|
|
describe('with long name', function () {
|
|
beforeEach(function (ctx) {
|
|
ctx.newName = 'long'.repeat(100)
|
|
ctx.req.body = { name: ctx.newName, source: ctx.source }
|
|
ctx.EditorHttpController.renameEntity(ctx.req, ctx.res)
|
|
})
|
|
|
|
it('should send back a bad request status code', function (ctx) {
|
|
expect(ctx.res.statusCode).to.equal(400)
|
|
})
|
|
})
|
|
|
|
describe('with 0 length name', function () {
|
|
beforeEach(function (ctx) {
|
|
ctx.newName = ''
|
|
ctx.req.body = { name: ctx.newName, source: ctx.source }
|
|
ctx.EditorHttpController.renameEntity(ctx.req, ctx.res)
|
|
})
|
|
|
|
it('should send back a bad request status code', function (ctx) {
|
|
expect(ctx.res.statusCode).to.equal(400)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('moveEntity', function () {
|
|
beforeEach(async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.entityId = 'entity-id-123'
|
|
ctx.entityType = 'entity-type'
|
|
ctx.folderId = 'folder-id-123'
|
|
ctx.req.params = {
|
|
Project_id: ctx.project._id,
|
|
entity_id: ctx.entityId,
|
|
entity_type: ctx.entityType,
|
|
}
|
|
ctx.req.body = { folder_id: ctx.folderId, source: ctx.source }
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.moveEntity(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should call EditorController.moveEntity', function (ctx) {
|
|
expect(ctx.EditorController.promises.moveEntity).to.have.been.calledWith(
|
|
ctx.project._id,
|
|
ctx.entityId,
|
|
ctx.folderId,
|
|
ctx.entityType,
|
|
ctx.user._id,
|
|
ctx.source
|
|
)
|
|
})
|
|
|
|
it('should send back a success response', function (ctx) {
|
|
expect(ctx.res.statusCode).to.equal(204)
|
|
})
|
|
})
|
|
|
|
describe('deleteEntity', function () {
|
|
beforeEach(async function (ctx) {
|
|
await new Promise(resolve => {
|
|
ctx.entityId = 'entity-id-123'
|
|
ctx.entityType = 'entity-type'
|
|
ctx.req.params = {
|
|
Project_id: ctx.project._id,
|
|
entity_id: ctx.entityId,
|
|
entity_type: ctx.entityType,
|
|
}
|
|
ctx.res.callback = resolve
|
|
ctx.EditorHttpController.deleteEntity(ctx.req, ctx.res)
|
|
})
|
|
})
|
|
|
|
it('should call EditorController.deleteEntity', function (ctx) {
|
|
expect(
|
|
ctx.EditorController.promises.deleteEntity
|
|
).to.have.been.calledWith(
|
|
ctx.project._id,
|
|
ctx.entityId,
|
|
ctx.entityType,
|
|
'editor',
|
|
ctx.user._id
|
|
)
|
|
})
|
|
|
|
it('should send back a success response', function (ctx) {
|
|
expect(ctx.res.statusCode).to.equal(204)
|
|
})
|
|
})
|
|
})
|