Przeglądaj źródła

Merge pull request #23209 from overleaf/jdt-async-await-prj-entity-handler

Async/await the ProjectEntityHandler

GitOrigin-RevId: 873106c4ea56e13d864407b338a1924370ba6709
Jimmy Domagala-Tang 1 rok temu
rodzic
commit
98b5bf2694

+ 178 - 227
services/web/app/src/Features/Project/ProjectEntityHandler.js

@@ -2,260 +2,211 @@ const path = require('path')
 const DocstoreManager = require('../Docstore/DocstoreManager')
 const Errors = require('../Errors/Errors')
 const ProjectGetter = require('./ProjectGetter')
-const { promisifyAll } = require('@overleaf/promise-utils')
+const { callbackifyAll } = require('@overleaf/promise-utils')
 const OError = require('@overleaf/o-error')
 const { iterablePaths } = require('./IterablePath')
 
-const ProjectEntityHandler = {
-  getAllDocs(projectId, callback) {
-    // We get the path and name info from the project, and the lines and
-    // version info from the doc store.
-    DocstoreManager.getAllDocs(projectId, (error, docContentsArray) => {
-      if (error != null) {
-        return callback(error)
-      }
-
-      // Turn array from docstore into a dictionary based on doc id
-      const docContents = {}
-      for (const docContent of docContentsArray) {
-        docContents[docContent._id] = docContent
-      }
-
-      ProjectEntityHandler._getAllFolders(projectId, (error, folders) => {
-        if (error != null) {
-          return callback(error)
-        }
-        const docs = {}
-        for (const { path: folderPath, folder } of folders) {
-          for (const doc of iterablePaths(folder, 'docs')) {
-            const content = docContents[doc._id.toString()]
-            if (content != null) {
-              try {
-                docs[path.join(folderPath, doc.name)] = {
-                  _id: doc._id,
-                  name: doc.name,
-                  lines: content.lines,
-                  rev: content.rev,
-                  folder,
-                }
-              } catch (err) {
-                return callback(err)
-              }
-            }
-          }
+async function getAllDocs(projectId) {
+  // We get the path and name info from the project, and the lines and
+  // version info from the doc store.
+  const docContentsArray = await DocstoreManager.promises.getAllDocs(projectId)
+
+  // Turn array from docstore into a dictionary based on doc id
+  const docContents = {}
+  for (const docContent of docContentsArray) {
+    docContents[docContent._id] = docContent
+  }
+
+  const folders = await _getAllFolders(projectId)
+  const docs = {}
+  for (const { path: folderPath, folder } of folders) {
+    for (const doc of iterablePaths(folder, 'docs')) {
+      const content = docContents[doc._id.toString()]
+      if (content != null) {
+        docs[path.join(folderPath, doc.name)] = {
+          _id: doc._id,
+          name: doc.name,
+          lines: content.lines,
+          rev: content.rev,
+          folder,
         }
+      }
+    }
+  }
 
-        callback(null, docs)
-      })
-    })
-  },
+  return docs
+}
 
-  getAllFiles(projectId, callback) {
-    ProjectEntityHandler._getAllFolders(projectId, (err, folders) => {
-      if (err != null) {
-        return callback(err)
+async function getAllFiles(projectId) {
+  const folders = await _getAllFolders(projectId)
+  const files = {}
+  for (const { path: folderPath, folder } of folders) {
+    for (const file of iterablePaths(folder, 'fileRefs')) {
+      if (file != null) {
+        files[path.join(folderPath, file.name)] = { ...file, folder }
       }
-      const files = {}
-      for (const { path: folderPath, folder } of folders) {
-        for (const file of iterablePaths(folder, 'fileRefs')) {
-          if (file != null) {
-            try {
-              files[path.join(folderPath, file.name)] = { ...file, folder }
-            } catch (err) {
-              return callback(err)
-            }
-          }
-        }
-      }
-      callback(null, files)
-    })
-  },
+    }
+  }
+  return files
+}
 
-  getAllEntities(projectId, callback) {
-    ProjectGetter.getProject(projectId, (err, project) => {
-      if (err != null) {
-        return callback(err)
-      }
-      if (project == null) {
-        return callback(new Errors.NotFoundError('project not found'))
-      }
-      try {
-        const entities = ProjectEntityHandler.getAllEntitiesFromProject(project)
-        callback(null, entities)
-      } catch (err) {
-        callback(err)
-      }
-    })
-  },
+async function getAllEntities(projectId) {
+  const project = await ProjectGetter.promises.getProject(projectId)
+  if (project == null) {
+    throw new Errors.NotFoundError('project not found')
+  }
+  const entities = getAllEntitiesFromProject(project)
+  return entities
+}
 
-  getAllEntitiesFromProject(project) {
-    const folders = ProjectEntityHandler._getAllFoldersFromProject(project)
-    const docs = []
-    const files = []
-    for (const { path: folderPath, folder } of folders) {
-      for (const doc of iterablePaths(folder, 'docs')) {
-        if (doc != null) {
-          docs.push({ path: path.join(folderPath, doc.name), doc })
-        }
+function getAllEntitiesFromProject(project) {
+  const folders = _getAllFoldersFromProject(project)
+  const docs = []
+  const files = []
+  for (const { path: folderPath, folder } of folders) {
+    for (const doc of iterablePaths(folder, 'docs')) {
+      if (doc != null) {
+        docs.push({ path: path.join(folderPath, doc.name), doc })
       }
-      for (const file of iterablePaths(folder, 'fileRefs')) {
-        if (file != null) {
-          files.push({ path: path.join(folderPath, file.name), file })
-        }
+    }
+    for (const file of iterablePaths(folder, 'fileRefs')) {
+      if (file != null) {
+        files.push({ path: path.join(folderPath, file.name), file })
       }
     }
-    return { docs, files, folders }
-  },
+  }
+  return { docs, files, folders }
+}
 
-  getAllDocPathsFromProjectById(projectId, callback) {
-    ProjectGetter.getProjectWithoutDocLines(projectId, (err, project) => {
-      if (err != null) {
-        return callback(err)
-      }
-      if (project == null) {
-        return callback(Errors.NotFoundError('no project'))
-      }
-      try {
-        const docPaths = ProjectEntityHandler.getAllDocPathsFromProject(project)
-        callback(null, docPaths)
-      } catch (err) {
-        callback(err)
-      }
-    })
-  },
+async function getAllDocPathsFromProjectById(projectId) {
+  const project =
+    await ProjectGetter.promises.getProjectWithoutDocLines(projectId)
+  if (project == null) {
+    throw new Errors.NotFoundError('no project')
+  }
+  const docPaths = getAllDocPathsFromProject(project)
+  return docPaths
+}
 
-  getAllDocPathsFromProject(project) {
-    const folders = ProjectEntityHandler._getAllFoldersFromProject(project)
-    const docPath = {}
-    for (const { path: folderPath, folder } of folders) {
-      for (const doc of iterablePaths(folder, 'docs')) {
-        docPath[doc._id] = path.join(folderPath, doc.name)
-      }
+function getAllDocPathsFromProject(project) {
+  const folders = _getAllFoldersFromProject(project)
+  const docPath = {}
+  for (const { path: folderPath, folder } of folders) {
+    for (const doc of iterablePaths(folder, 'docs')) {
+      docPath[doc._id] = path.join(folderPath, doc.name)
     }
-    return docPath
-  },
+  }
+  return docPath
+}
 
-  getDoc(projectId, docId, options, callback) {
-    if (options == null) {
-      options = {}
-    }
-    if (typeof options === 'function') {
-      callback = options
-      options = {}
-    }
+async function getDoc(projectId, docId) {
+  const { lines, rev, version, ranges } = await DocstoreManager.promises.getDoc(
+    projectId,
+    docId
+  )
+  return { lines, rev, version, ranges }
+}
 
-    DocstoreManager.getDoc(projectId, docId, options, callback)
-  },
+/**
+ * @param {ObjectId | string} projectId
+ * @param {ObjectId | string} docId
+ */
+async function getDocPathByProjectIdAndDocId(projectId, docId) {
+  const project =
+    await ProjectGetter.promises.getProjectWithoutDocLines(projectId)
+  if (project == null) {
+    throw new Errors.NotFoundError('no project')
+  }
+  const docPath = await getDocPathFromProjectByDocId(project, docId)
+  if (docPath == null) {
+    throw new Errors.NotFoundError('no doc')
+  }
+  return docPath
+}
 
-  /**
-   * @param {ObjectId | string} projectId
-   * @param {ObjectId | string} docId
-   * @param {Function} callback
-   */
-  getDocPathByProjectIdAndDocId(projectId, docId, callback) {
-    ProjectGetter.getProjectWithoutDocLines(projectId, (err, project) => {
-      if (err != null) {
-        return callback(err)
-      }
-      if (project == null) {
-        return callback(new Errors.NotFoundError('no project'))
-      }
-      ProjectEntityHandler.getDocPathFromProjectByDocId(
-        project,
+function _recursivelyFindDocInFolder(basePath, docId, folder) {
+  const docInCurrentFolder = (folder.docs || []).find(
+    currentDoc => currentDoc._id.toString() === docId.toString()
+  )
+  if (docInCurrentFolder != null) {
+    return path.join(basePath, docInCurrentFolder.name)
+  } else {
+    let docPath, childFolder
+    for (childFolder of iterablePaths(folder, 'folders')) {
+      docPath = _recursivelyFindDocInFolder(
+        path.join(basePath, childFolder.name),
         docId,
-        (err, docPath) => {
-          if (err) return callback(Errors.OError.tag(err))
-          if (docPath == null) {
-            return callback(new Errors.NotFoundError('no doc'))
-          }
-          callback(null, docPath)
-        }
-      )
-    })
-  },
-
-  /**
-   * @param {Project} project
-   * @param {ObjectId | string} docId
-   * @param {Function} callback
-   */
-  getDocPathFromProjectByDocId(project, docId, callback) {
-    function recursivelyFindDocInFolder(basePath, docId, folder) {
-      const docInCurrentFolder = (folder.docs || []).find(
-        currentDoc => currentDoc._id.toString() === docId.toString()
+        childFolder
       )
-      if (docInCurrentFolder != null) {
-        return path.join(basePath, docInCurrentFolder.name)
-      } else {
-        let docPath, childFolder
-        for (childFolder of iterablePaths(folder, 'folders')) {
-          docPath = recursivelyFindDocInFolder(
-            path.join(basePath, childFolder.name),
-            docId,
-            childFolder
-          )
-          if (docPath != null) {
-            return docPath
-          }
-        }
-        return null
+      if (docPath != null) {
+        return docPath
       }
     }
-    try {
-      const docPath = recursivelyFindDocInFolder(
-        '/',
-        docId,
-        project.rootFolder[0]
-      )
-      callback(null, docPath)
-    } catch (err) {
-      callback(err)
-    }
-  },
+    return null
+  }
+}
 
-  _getAllFolders(projectId, callback) {
-    ProjectGetter.getProjectWithoutDocLines(projectId, (err, project) => {
-      if (err != null) {
-        return callback(err)
-      }
-      if (project == null) {
-        return callback(new Errors.NotFoundError('no project'))
-      }
-      try {
-        const folders = ProjectEntityHandler._getAllFoldersFromProject(project)
-        callback(null, folders)
-      } catch (err) {
-        callback(err)
-      }
-    })
-  },
+/**
+ * @param {Project} project
+ * @param {ObjectId | string} docId
+ * @param {Function} callback
+ */
+async function getDocPathFromProjectByDocId(project, docId) {
+  const docPath = _recursivelyFindDocInFolder('/', docId, project.rootFolder[0])
+  return docPath
+}
 
-  _getAllFoldersFromProject(project) {
-    const folders = []
-    try {
-      const processFolder = (basePath, folder) => {
-        folders.push({ path: basePath, folder })
-        if (folder.folders) {
-          for (const childFolder of iterablePaths(folder, 'folders')) {
-            if (childFolder.name != null) {
-              const childPath = path.join(basePath, childFolder.name)
-              processFolder(childPath, childFolder)
-            }
+async function _getAllFolders(projectId) {
+  const project =
+    await ProjectGetter.promises.getProjectWithoutDocLines(projectId)
+
+  if (project == null) {
+    throw new Errors.NotFoundError('no project')
+  }
+  const folders = _getAllFoldersFromProject(project)
+  return folders
+}
+
+function _getAllFoldersFromProject(project) {
+  const folders = []
+  try {
+    const processFolder = (basePath, folder) => {
+      folders.push({ path: basePath, folder })
+      if (folder.folders) {
+        for (const childFolder of iterablePaths(folder, 'folders')) {
+          if (childFolder.name != null) {
+            const childPath = path.join(basePath, childFolder.name)
+            processFolder(childPath, childFolder)
           }
         }
       }
-      processFolder('/', project.rootFolder[0])
-      return folders
-    } catch (err) {
-      throw OError.tag(err, 'Error getting folders', { projectId: project._id })
     }
-  },
+    processFolder('/', project.rootFolder[0])
+    return folders
+  } catch (err) {
+    throw OError.tag(err, 'Error getting folders', { projectId: project._id })
+  }
 }
 
-module.exports = ProjectEntityHandler
-module.exports.promises = promisifyAll(ProjectEntityHandler, {
-  without: ['getAllEntitiesFromProject'],
-  multiResult: {
-    getDoc: ['lines', 'rev', 'version', 'ranges'],
-  },
-})
+const ProjectEntityHandler = {
+  getAllDocs,
+  getAllFiles,
+  getAllEntities,
+  getAllDocPathsFromProjectById,
+  getDoc,
+  getDocPathByProjectIdAndDocId,
+  getDocPathFromProjectByDocId,
+  _getAllFolders,
+}
+
+module.exports = {
+  ...callbackifyAll(ProjectEntityHandler, {
+    multiResult: {
+      getDoc: ['lines', 'rev', 'version', 'ranges'],
+    },
+  }),
+  promises: ProjectEntityHandler,
+  getAllEntitiesFromProject,
+  getAllDocPathsFromProject,
+  _getAllFoldersFromProject,
+}

+ 146 - 176
services/web/test/unit/src/Project/ProjectEntityHandlerTests.js

@@ -31,14 +31,16 @@ describe('ProjectEntityHandler', function () {
 
     this.ProjectEntityHandler = SandboxedModule.require(modulePath, {
       requires: {
-        '../Docstore/DocstoreManager': (this.DocstoreManager = {}),
+        '../Docstore/DocstoreManager': (this.DocstoreManager = {
+          promises: {},
+        }),
         '../../Features/DocumentUpdater/DocumentUpdaterHandler':
           this.DocumentUpdaterHandler,
         '../../models/Project': {
           Project: this.ProjectModel,
         },
         './ProjectLocator': this.ProjectLocator,
-        './ProjectGetter': (this.ProjectGetter = {}),
+        './ProjectGetter': (this.ProjectGetter = { promises: {} }),
         '../ThirdPartyDataStore/TpdsUpdateSender': this.TpdsUpdateSender,
       },
     })
@@ -82,13 +84,14 @@ describe('ProjectEntityHandler', function () {
           ],
         },
       ]
-      this.ProjectGetter.getProjectWithoutDocLines = sinon
+      this.ProjectGetter.promises.getProjectWithoutDocLines = sinon
         .stub()
-        .yields(null, this.project)
+        .resolves(this.project)
     })
 
     describe('getAllDocs', function () {
-      beforeEach(function () {
+      let fetchedDocs
+      beforeEach(async function () {
         this.docs = [
           {
             _id: this.doc1._id,
@@ -101,18 +104,21 @@ describe('ProjectEntityHandler', function () {
             rev: (this.rev2 = 2),
           },
         ]
-        this.DocstoreManager.getAllDocs = sinon
+        this.DocstoreManager.promises.getAllDocs = sinon
           .stub()
-          .callsArgWith(1, null, this.docs)
-        this.ProjectEntityHandler.getAllDocs(projectId, this.callback)
+          .resolves(this.docs)
+        fetchedDocs =
+          await this.ProjectEntityHandler.promises.getAllDocs(projectId)
       })
 
       it('should get the doc lines and rev from the docstore', function () {
-        this.DocstoreManager.getAllDocs.calledWith(projectId).should.equal(true)
+        this.DocstoreManager.promises.getAllDocs
+          .calledWith(projectId)
+          .should.equal(true)
       })
 
       it('should call the callback with the docs with the lines and rev included', function () {
-        this.callback.should.have.been.calledWith(null, {
+        expect(fetchedDocs).to.deep.equal({
           '/doc1': {
             _id: this.doc1._id,
             lines: this.lines1,
@@ -132,13 +138,17 @@ describe('ProjectEntityHandler', function () {
     })
 
     describe('getAllFiles', function () {
-      beforeEach(function () {
+      let allFiles
+      beforeEach(async function () {
         this.callback = sinon.stub()
-        this.ProjectEntityHandler.getAllFiles(projectId, this.callback)
+        allFiles = await this.ProjectEntityHandler.promises.getAllFiles(
+          projectId,
+          this.callback
+        )
       })
 
       it('should call the callback with the files', function () {
-        this.callback.should.have.been.calledWith(null, {
+        expect(allFiles).to.deep.equal({
           '/file1': { ...this.file1, folder: this.project.rootFolder[0] },
           '/folder1/file2': { ...this.file2, folder: this.folder1 },
         })
@@ -176,83 +186,66 @@ describe('ProjectEntityHandler', function () {
     })
 
     describe('getDocPathByProjectIdAndDocId', function () {
-      beforeEach(function () {
-        this.callback = sinon.stub()
-      })
-      it('should call the callback with the path for an existing doc id at the root level', function () {
-        this.ProjectEntityHandler.getDocPathByProjectIdAndDocId(
-          projectId,
-          this.doc1._id,
-          this.callback
-        )
-        this.callback.calledWith(null, `/${this.doc1.name}`).should.equal(true)
+      it('should call the callback with the path for an existing doc id at the root level', async function () {
+        const path =
+          await this.ProjectEntityHandler.promises.getDocPathByProjectIdAndDocId(
+            projectId,
+            this.doc1._id
+          )
+        expect(path).to.deep.equal(`/${this.doc1.name}`)
       })
 
-      it('should call the callback with the path for an existing doc id nested within a folder', function () {
-        this.ProjectEntityHandler.getDocPathByProjectIdAndDocId(
-          projectId,
-          this.doc2._id,
-          this.callback
-        )
-        this.callback
-          .calledWith(null, `/folder1/${this.doc2.name}`)
-          .should.equal(true)
+      it('should call the callback with the path for an existing doc id nested within a folder', async function () {
+        const path =
+          await this.ProjectEntityHandler.promises.getDocPathByProjectIdAndDocId(
+            projectId,
+            this.doc2._id
+          )
+        expect(path).to.deep.equal(`/folder1/${this.doc2.name}`)
       })
 
-      it('should call the callback with a NotFoundError for a non-existing doc', function () {
-        this.ProjectEntityHandler.getDocPathByProjectIdAndDocId(
-          projectId,
-          'non-existing-id',
-          this.callback
-        )
-        expect(this.callback.firstCall.args[0]).to.be.an.instanceof(
-          Errors.NotFoundError
-        )
+      it('should call the callback with a NotFoundError for a non-existing doc', async function () {
+        await expect(
+          this.ProjectEntityHandler.promises.getDocPathByProjectIdAndDocId(
+            projectId,
+            'non-existing-id'
+          )
+        ).to.be.rejectedWith(Errors.NotFoundError)
       })
 
-      it('should call the callback with a NotFoundError for an existing file', function () {
-        this.ProjectEntityHandler.getDocPathByProjectIdAndDocId(
-          projectId,
-          this.file1._id,
-          this.callback
-        )
-        expect(this.callback.firstCall.args[0]).to.be.an.instanceof(
-          Errors.NotFoundError
-        )
+      it('should call the callback with a NotFoundError for an existing file', async function () {
+        await expect(
+          this.ProjectEntityHandler.promises.getDocPathByProjectIdAndDocId(
+            projectId,
+            this.file1._id
+          )
+        ).to.be.rejectedWith(Errors.NotFoundError)
       })
     })
 
-    describe('_getAllFolders', function () {
-      beforeEach(function () {
+    describe('_getAllFolders', async function () {
+      let folders
+      beforeEach(async function () {
         this.callback = sinon.stub()
-        this.ProjectEntityHandler._getAllFolders(projectId, this.callback)
+        folders =
+          await this.ProjectEntityHandler.promises._getAllFolders(projectId)
       })
 
       it('should get the project without the docs lines', function () {
-        this.ProjectGetter.getProjectWithoutDocLines
+        this.ProjectGetter.promises.getProjectWithoutDocLines
           .calledWith(projectId)
           .should.equal(true)
       })
 
       it('should call the callback with the folders', function () {
-        this.callback
-          .calledWith(null, [
-            { path: '/', folder: this.project.rootFolder[0] },
-            { path: '/folder1', folder: this.folder1 },
-          ])
-          .should.equal(true)
+        expect(folders).to.deep.equal([
+          { path: '/', folder: this.project.rootFolder[0] },
+          { path: '/folder1', folder: this.folder1 },
+        ])
       })
     })
 
     describe('_getAllFoldersFromProject', function () {
-      beforeEach(function () {
-        this.callback = sinon.stub()
-        this.ProjectEntityHandler._getAllFoldersFromProject(
-          this.project,
-          this.callback
-        )
-      })
-
       it('should return the folders', function () {
         expect(
           this.ProjectEntityHandler._getAllFoldersFromProject(this.project)
@@ -303,13 +296,13 @@ describe('ProjectEntityHandler', function () {
           ],
         },
       ]
-      this.ProjectGetter.getProjectWithoutDocLines = sinon
+      this.ProjectGetter.promises.getProjectWithoutDocLines = sinon
         .stub()
-        .yields(null, this.project)
+        .resolves(this.project)
     })
 
     describe('getAllDocs', function () {
-      beforeEach(function () {
+      beforeEach(async function () {
         this.docs = [
           {
             _id: this.doc1._id,
@@ -322,128 +315,102 @@ describe('ProjectEntityHandler', function () {
             rev: (this.rev2 = 2),
           },
         ]
-        this.DocstoreManager.getAllDocs = sinon
+        this.DocstoreManager.promises.getAllDocs = sinon
           .stub()
-          .callsArgWith(1, null, this.docs)
-        this.ProjectEntityHandler.getAllDocs(projectId, this.callback)
-      })
-
-      it('should get the doc lines and rev from the docstore', function () {
-        this.DocstoreManager.getAllDocs.calledWith(projectId).should.equal(true)
+          .resolves(this.docs)
       })
 
-      it('should call the callback with an error', function () {
-        this.callback.should.have.been.calledWith(sinon.match.defined)
+      it('should call the callback with an error', async function () {
+        await expect(this.ProjectEntityHandler.promises.getAllDocs(projectId))
+          .to.be.rejected
       })
     })
 
     describe('getAllFiles', function () {
-      beforeEach(function () {
-        this.callback = sinon.stub()
-        this.ProjectEntityHandler.getAllFiles(projectId, this.callback)
-      })
-
-      it('should call the callback with and error', function () {
-        this.callback.should.have.been.calledWith(sinon.match.defined)
+      it('should call the callback with and error', async function () {
+        await expect(this.ProjectEntityHandler.promises.getAllFiles(projectId))
+          .to.be.rejected
       })
     })
 
     describe('getDocPathByProjectIdAndDocId', function () {
-      beforeEach(function () {
-        this.callback = sinon.stub()
-      })
-      it('should call the callback with an error for an existing doc id at the root level', function () {
-        this.ProjectEntityHandler.getDocPathByProjectIdAndDocId(
-          projectId,
-          this.doc1._id,
-          this.callback
-        )
-        this.callback.should.have.been.calledWith(sinon.match.instanceOf(Error))
+      it('should call the callback with an error for an existing doc id at the root level', async function () {
+        await expect(
+          this.ProjectEntityHandler.promises.getDocPathByProjectIdAndDocId(
+            projectId,
+            this.doc1._id
+          )
+        ).to.be.rejectedWith(Error)
       })
 
-      it('should call the callback with an error for an existing doc id nested within a folder', function () {
-        this.ProjectEntityHandler.getDocPathByProjectIdAndDocId(
-          projectId,
-          this.doc2._id,
-          this.callback
-        )
-        this.callback.should.have.been.calledWith(sinon.match.instanceOf(Error))
+      it('should call the callback with an error for an existing doc id nested within a folder', async function () {
+        await expect(
+          this.ProjectEntityHandler.promises.getDocPathByProjectIdAndDocId(
+            projectId,
+            this.doc2._id
+          )
+        ).to.be.rejectedWith(Error)
       })
 
-      it('should call the callback with an error for a non-existing doc', function () {
-        this.ProjectEntityHandler.getDocPathByProjectIdAndDocId(
-          projectId,
-          'non-existing-id',
-          this.callback
-        )
-        this.callback.should.have.been.calledWith(sinon.match.instanceOf(Error))
+      it('should call the callback with an error for a non-existing doc', async function () {
+        await expect(
+          this.ProjectEntityHandler.promises.getDocPathByProjectIdAndDocId(
+            projectId,
+            'non-existing-id'
+          )
+        ).to.be.rejectedWith(Error)
       })
 
-      it('should call the callback with an error for an existing file', function () {
-        this.ProjectEntityHandler.getDocPathByProjectIdAndDocId(
-          projectId,
-          this.file1._id,
-          this.callback
-        )
-        this.callback.should.have.been.calledWith(sinon.match.instanceOf(Error))
+      it('should call the callback with an error for an existing file', async function () {
+        await expect(
+          this.ProjectEntityHandler.promises.getDocPathByProjectIdAndDocId(
+            projectId,
+            this.file1._id
+          )
+        ).to.be.rejectedWith(Error)
       })
     })
 
     describe('_getAllFolders', function () {
-      beforeEach(function () {
-        this.callback = sinon.stub()
-        this.ProjectEntityHandler._getAllFolders(projectId, this.callback)
-      })
-
-      it('should get the project without the docs lines', function () {
-        this.ProjectGetter.getProjectWithoutDocLines
-          .calledWith(projectId)
-          .should.equal(true)
-      })
-
-      it('should call the callback with an error', function () {
-        this.callback.should.have.been.calledWith(sinon.match.defined)
+      it('should call the callback with an error', async function () {
+        await expect(
+          this.ProjectEntityHandler.promises._getAllFolders(projectId)
+        ).to.be.rejected
       })
     })
 
     describe('getAllEntities', function () {
       beforeEach(function () {
-        this.ProjectGetter.getProject = sinon.stub().yields(null, this.project)
-        this.callback = sinon.stub()
-        this.ProjectEntityHandler.getAllEntities(projectId, this.callback)
+        this.ProjectGetter.promises.getProject = sinon
+          .stub()
+          .resolves(this.project)
       })
 
-      it('should call the callback with an error', function () {
-        this.callback.should.have.been.calledWith(sinon.match.defined)
+      it('should call the callback with an error', async function () {
+        await expect(
+          this.ProjectEntityHandler.promises.getAllEntities(projectId)
+        ).to.be.rejected
       })
     })
 
     describe('getAllDocPathsFromProjectById', function () {
-      beforeEach(function () {
-        this.callback = sinon.stub()
-        this.ProjectEntityHandler.getAllDocPathsFromProjectById(
-          projectId,
-          this.callback
-        )
-      })
-
-      it('should call the callback with an error', function () {
-        this.callback.should.have.been.calledWith(sinon.match.defined)
+      it('should call the callback with an error', async function () {
+        await expect(
+          this.ProjectEntityHandler.promises.getAllDocPathsFromProjectById(
+            projectId
+          )
+        ).to.be.rejected
       })
     })
 
     describe('getDocPathFromProjectByDocId', function () {
-      beforeEach(function () {
-        this.callback = sinon.stub()
-        this.ProjectEntityHandler.getDocPathFromProjectByDocId(
-          projectId,
-          this.doc1._id,
-          this.callback
-        )
-      })
-
-      it('should call the callback with an error', function () {
-        this.callback.should.have.been.calledWith(sinon.match.defined)
+      it('should call the callback with an error', async function () {
+        await expect(
+          this.ProjectEntityHandler.promises.getDocPathFromProjectByDocId(
+            projectId,
+            this.doc1._id
+          )
+        ).to.be.rejected
       })
     })
   })
@@ -454,23 +421,23 @@ describe('ProjectEntityHandler', function () {
       this.rev = 5
       this.version = 42
       this.ranges = { mock: 'ranges' }
-
-      this.DocstoreManager.getDoc = sinon
-        .stub()
-        .callsArgWith(3, null, this.lines, this.rev, this.version, this.ranges)
-      this.ProjectEntityHandler.getDoc(projectId, docId, this.callback)
-    })
-
-    it('should call the docstore', function () {
-      this.DocstoreManager.getDoc
-        .calledWith(projectId, docId)
-        .should.equal(true)
+      this.callback = sinon.stub()
+      this.DocstoreManager.promises.getDoc = sinon.stub().resolves({
+        lines: this.lines,
+        rev: this.rev,
+        version: this.version,
+        ranges: this.ranges,
+      })
     })
 
-    it('should call the callback with the lines, version and rev', function () {
-      this.callback
-        .calledWith(null, this.lines, this.rev, this.version, this.ranges)
-        .should.equal(true)
+    it('should call the callback with the lines, version and rev', function (done) {
+      this.ProjectEntityHandler.getDoc(projectId, docId, doc => {
+        this.DocstoreManager.promises.getDoc
+          .calledWith(projectId, docId)
+          .should.equal(true)
+        expect(doc).to.exist
+        done()
+      })
     })
   })
 
@@ -483,14 +450,17 @@ describe('ProjectEntityHandler', function () {
       this.version = 42
       this.ranges = { mock: 'ranges' }
 
-      this.DocstoreManager.getDoc = sinon
-        .stub()
-        .callsArgWith(3, null, this.lines, this.rev, this.version, this.ranges)
+      this.DocstoreManager.promises.getDoc = sinon.stub().resolves({
+        lines: this.lines,
+        rev: this.rev,
+        version: this.version,
+        ranges: this.ranges,
+      })
       result = await this.ProjectEntityHandler.promises.getDoc(projectId, docId)
     })
 
     it('should call the docstore', function () {
-      this.DocstoreManager.getDoc
+      this.DocstoreManager.promises.getDoc
         .calledWith(projectId, docId)
         .should.equal(true)
     })