/* eslint-disable
    node/handle-callback-err,
    max-len,
    no-return-assign,
    no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
 * decaffeinate suggestions:
 * DS102: Remove unnecessary code created because of implicit returns
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 */
const SandboxedModule = require('sandboxed-module')
const sinon = require('sinon')
require('chai').should()
const { expect } = require('chai')

const modulePath = require('path').join(
  __dirname,
  '../../../../app/src/Features/Editor/EditorController'
)
const MockClient = require('../helpers/MockClient')
const assert = require('assert')
const { ObjectId } = require('mongodb')

describe('EditorController', function() {
  beforeEach(function() {
    this.project_id = 'test-project-id'
    this.source = 'dropbox'
    this.user_id = new ObjectId()

    this.doc = { _id: (this.doc_id = 'test-doc-id') }
    this.docName = 'doc.tex'
    this.docLines = ['1234', 'dskl']
    this.file = { _id: (this.file_id = 'dasdkjk') }
    this.fileName = 'file.png'
    this.fsPath = '/folder/file.png'
    this.linkedFileData = { provider: 'url' }

    this.newFile = { _id: 'new-file-id' }

    this.folder_id = '123ksajdn'
    this.folder = { _id: this.folder_id }
    this.folderName = 'folder'

    this.callback = sinon.stub()

    return (this.EditorController = SandboxedModule.require(modulePath, {
      globals: {
        console: console
      },
      requires: {
        '../Project/ProjectEntityUpdateHandler': (this.ProjectEntityUpdateHandler = {}),
        '../Project/ProjectOptionsHandler': (this.ProjectOptionsHandler = {
          setCompiler: sinon.stub().yields(),
          setImageName: sinon.stub().yields(),
          setSpellCheckLanguage: sinon.stub().yields()
        }),
        '../Project/ProjectDetailsHandler': (this.ProjectDetailsHandler = {
          setProjectDescription: sinon.stub().yields(),
          renameProject: sinon.stub().yields(),
          setPublicAccessLevel: sinon.stub().yields()
        }),
        '../Project/ProjectDeleter': (this.ProjectDeleter = {}),
        '../DocumentUpdater/DocumentUpdaterHandler': (this.DocumentUpdaterHandler = {
          flushDocToMongo: sinon.stub().yields(),
          setDocument: sinon.stub().yields()
        }),
        './EditorRealTimeController': (this.EditorRealTimeController = {
          emitToRoom: sinon.stub()
        }),
        '@overleaf/metrics': (this.Metrics = { inc: sinon.stub() }),
        'logger-sharelatex': (this.logger = {
          log: sinon.stub(),
          err: sinon.stub()
        })
      }
    }))
  })

  describe('addDoc', function() {
    beforeEach(function() {
      this.ProjectEntityUpdateHandler.addDocWithRanges = sinon
        .stub()
        .yields(null, this.doc, this.folder_id)
      return this.EditorController.addDoc(
        this.project_id,
        this.folder_id,
        this.docName,
        this.docLines,
        this.source,
        this.user_id,
        this.callback
      )
    })

    it('should add the doc using the project entity handler', function() {
      return this.ProjectEntityUpdateHandler.addDocWithRanges
        .calledWith(
          this.project_id,
          this.folder_id,
          this.docName,
          this.docLines,
          {}
        )
        .should.equal(true)
    })

    it('should send the update out to the users in the project', function() {
      return this.EditorRealTimeController.emitToRoom
        .calledWith(
          this.project_id,
          'reciveNewDoc',
          this.folder_id,
          this.doc,
          this.source,
          this.user_id
        )
        .should.equal(true)
    })

    it('calls the callback', function() {
      return this.callback.calledWith(null, this.doc).should.equal(true)
    })
  })

  describe('addFile', function() {
    beforeEach(function() {
      this.ProjectEntityUpdateHandler.addFile = sinon
        .stub()
        .yields(null, this.file, this.folder_id)
      return this.EditorController.addFile(
        this.project_id,
        this.folder_id,
        this.fileName,
        this.fsPath,
        this.linkedFileData,
        this.source,
        this.user_id,
        this.callback
      )
    })

    it('should add the folder using the project entity handler', function() {
      return this.ProjectEntityUpdateHandler.addFile
        .calledWith(
          this.project_id,
          this.folder_id,
          this.fileName,
          this.fsPath,
          this.linkedFileData,
          this.user_id
        )
        .should.equal(true)
    })

    it('should send the update of a new folder out to the users in the project', function() {
      return this.EditorRealTimeController.emitToRoom
        .calledWith(
          this.project_id,
          'reciveNewFile',
          this.folder_id,
          this.file,
          this.source,
          this.linkedFileData,
          this.user_id
        )
        .should.equal(true)
    })

    it('calls the callback', function() {
      return this.callback.calledWith(null, this.file).should.equal(true)
    })
  })

  describe('upsertDoc', function() {
    beforeEach(function() {
      this.ProjectEntityUpdateHandler.upsertDoc = sinon
        .stub()
        .yields(null, this.doc, false)
      return this.EditorController.upsertDoc(
        this.project_id,
        this.folder_id,
        this.docName,
        this.docLines,
        this.source,
        this.user_id,
        this.callback
      )
    })

    it('upserts the doc using the project entity handler', function() {
      return this.ProjectEntityUpdateHandler.upsertDoc
        .calledWith(
          this.project_id,
          this.folder_id,
          this.docName,
          this.docLines,
          this.source
        )
        .should.equal(true)
    })

    it('returns the doc', function() {
      return this.callback.calledWith(null, this.doc).should.equal(true)
    })

    describe('doc does not exist', function() {
      beforeEach(function() {
        this.ProjectEntityUpdateHandler.upsertDoc = sinon
          .stub()
          .yields(null, this.doc, true)
        return this.EditorController.upsertDoc(
          this.project_id,
          this.folder_id,
          this.docName,
          this.docLines,
          this.source,
          this.user_id,
          this.callback
        )
      })

      it('sends an update out to users in the project', function() {
        return this.EditorRealTimeController.emitToRoom
          .calledWith(
            this.project_id,
            'reciveNewDoc',
            this.folder_id,
            this.doc,
            this.source,
            this.user_id
          )
          .should.equal(true)
      })
    })
  })

  describe('upsertFile', function() {
    beforeEach(function() {
      this.ProjectEntityUpdateHandler.upsertFile = sinon
        .stub()
        .yields(null, this.newFile, false, this.file)
      return this.EditorController.upsertFile(
        this.project_id,
        this.folder_id,
        this.fileName,
        this.fsPath,
        this.linkedFileData,
        this.source,
        this.user_id,
        this.callback
      )
    })

    it('upserts the file using the project entity handler', function() {
      return this.ProjectEntityUpdateHandler.upsertFile
        .calledWith(
          this.project_id,
          this.folder_id,
          this.fileName,
          this.fsPath,
          this.linkedFileData,
          this.user_id
        )
        .should.equal(true)
    })

    it('returns the file', function() {
      return this.callback.calledWith(null, this.newFile).should.equal(true)
    })

    describe('file does not exist', function() {
      beforeEach(function() {
        this.ProjectEntityUpdateHandler.upsertFile = sinon
          .stub()
          .yields(null, this.file, true)
        return this.EditorController.upsertFile(
          this.project_id,
          this.folder_id,
          this.fileName,
          this.fsPath,
          this.linkedFileData,
          this.source,
          this.user_id,
          this.callback
        )
      })

      it('should send the update out to users in the project', function() {
        return this.EditorRealTimeController.emitToRoom
          .calledWith(
            this.project_id,
            'reciveNewFile',
            this.folder_id,
            this.file,
            this.source,
            this.linkedFileData,
            this.user_id
          )
          .should.equal(true)
      })
    })
  })

  describe('upsertDocWithPath', function() {
    beforeEach(function() {
      this.docPath = '/folder/doc'

      this.ProjectEntityUpdateHandler.upsertDocWithPath = sinon
        .stub()
        .yields(null, this.doc, false, [], this.folder)
      return this.EditorController.upsertDocWithPath(
        this.project_id,
        this.docPath,
        this.docLines,
        this.source,
        this.user_id,
        this.callback
      )
    })

    it('upserts the doc using the project entity handler', function() {
      return this.ProjectEntityUpdateHandler.upsertDocWithPath
        .calledWith(this.project_id, this.docPath, this.docLines, this.source)
        .should.equal(true)
    })

    describe('doc does not exist', function() {
      beforeEach(function() {
        this.ProjectEntityUpdateHandler.upsertDocWithPath = sinon
          .stub()
          .yields(null, this.doc, true, [], this.folder)
        return this.EditorController.upsertDocWithPath(
          this.project_id,
          this.docPath,
          this.docLines,
          this.source,
          this.user_id,
          this.callback
        )
      })

      it('should send the update for the doc out to users in the project', function() {
        return this.EditorRealTimeController.emitToRoom
          .calledWith(
            this.project_id,
            'reciveNewDoc',
            this.folder_id,
            this.doc,
            this.source,
            this.user_id
          )
          .should.equal(true)
      })
    })

    describe('folders required for doc do not exist', function() {
      beforeEach(function() {
        const folders = [
          (this.folderA = { _id: 2, parentFolder_id: 1 }),
          (this.folderB = { _id: 3, parentFolder_id: 2 })
        ]
        this.ProjectEntityUpdateHandler.upsertDocWithPath = sinon
          .stub()
          .yields(null, this.doc, true, folders, this.folderB)
        return this.EditorController.upsertDocWithPath(
          this.project_id,
          this.docPath,
          this.docLines,
          this.source,
          this.user_id,
          this.callback
        )
      })

      it('should send the update for each folder to users in the project', function() {
        this.EditorRealTimeController.emitToRoom
          .calledWith(
            this.project_id,
            'reciveNewFolder',
            this.folderA.parentFolder_id,
            this.folderA
          )
          .should.equal(true)
        return this.EditorRealTimeController.emitToRoom
          .calledWith(
            this.project_id,
            'reciveNewFolder',
            this.folderB.parentFolder_id,
            this.folderB
          )
          .should.equal(true)
      })
    })
  })

  describe('upsertFileWithPath', function() {
    beforeEach(function() {
      this.filePath = '/folder/file'

      this.ProjectEntityUpdateHandler.upsertFileWithPath = sinon
        .stub()
        .yields(null, this.newFile, false, this.file, [], this.folder)
      return this.EditorController.upsertFileWithPath(
        this.project_id,
        this.filePath,
        this.fsPath,
        this.linkedFileData,
        this.source,
        this.user_id,
        this.callback
      )
    })

    it('upserts the file using the project entity handler', function() {
      return this.ProjectEntityUpdateHandler.upsertFileWithPath
        .calledWith(
          this.project_id,
          this.filePath,
          this.fsPath,
          this.linkedFileData
        )
        .should.equal(true)
    })

    describe('file does not exist', function() {
      beforeEach(function() {
        this.ProjectEntityUpdateHandler.upsertFileWithPath = sinon
          .stub()
          .yields(null, this.file, true, undefined, [], this.folder)
        return this.EditorController.upsertFileWithPath(
          this.project_id,
          this.filePath,
          this.fsPath,
          this.linkedFileData,
          this.source,
          this.user_id,
          this.callback
        )
      })

      it('should send the update for the file out to users in the project', function() {
        return this.EditorRealTimeController.emitToRoom
          .calledWith(
            this.project_id,
            'reciveNewFile',
            this.folder_id,
            this.file,
            this.source,
            this.linkedFileData,
            this.user_id
          )
          .should.equal(true)
      })
    })

    describe('folders required for file do not exist', function() {
      beforeEach(function() {
        const folders = [
          (this.folderA = { _id: 2, parentFolder_id: 1 }),
          (this.folderB = { _id: 3, parentFolder_id: 2 })
        ]
        this.ProjectEntityUpdateHandler.upsertFileWithPath = sinon
          .stub()
          .yields(null, this.file, true, undefined, folders, this.folderB)
        return this.EditorController.upsertFileWithPath(
          this.project_id,
          this.filePath,
          this.fsPath,
          this.linkedFileData,
          this.source,
          this.user_id,
          this.callback
        )
      })

      it('should send the update for each folder to users in the project', function() {
        this.EditorRealTimeController.emitToRoom
          .calledWith(
            this.project_id,
            'reciveNewFolder',
            this.folderA.parentFolder_id,
            this.folderA
          )
          .should.equal(true)
        return this.EditorRealTimeController.emitToRoom
          .calledWith(
            this.project_id,
            'reciveNewFolder',
            this.folderB.parentFolder_id,
            this.folderB
          )
          .should.equal(true)
      })
    })
  })

  describe('addFolder', function() {
    beforeEach(function() {
      this.EditorController._notifyProjectUsersOfNewFolder = sinon
        .stub()
        .yields()
      this.ProjectEntityUpdateHandler.addFolder = sinon
        .stub()
        .yields(null, this.folder, this.folder_id)
      return this.EditorController.addFolder(
        this.project_id,
        this.folder_id,
        this.folderName,
        this.source,
        this.user_id,
        this.callback
      )
    })

    it('should add the folder using the project entity handler', function() {
      return this.ProjectEntityUpdateHandler.addFolder
        .calledWith(this.project_id, this.folder_id, this.folderName)
        .should.equal(true)
    })

    it('should notifyProjectUsersOfNewFolder', function() {
      return this.EditorController._notifyProjectUsersOfNewFolder
        .calledWith(this.project_id, this.folder_id, this.folder, this.user_id)
        .should.equal(true)
    })

    it('should return the folder in the callback', function() {
      return this.callback.calledWith(null, this.folder).should.equal(true)
    })
  })

  describe('mkdirp', function() {
    beforeEach(function() {
      this.path = 'folder1/folder2'
      this.folders = [
        (this.folderA = { _id: 2, parentFolder_id: 1 }),
        (this.folderB = { _id: 3, parentFolder_id: 2 })
      ]
      this.EditorController._notifyProjectUsersOfNewFolders = sinon
        .stub()
        .yields()
      this.ProjectEntityUpdateHandler.mkdirp = sinon
        .stub()
        .yields(null, this.folders, this.folder)
      return this.EditorController.mkdirp(
        this.project_id,
        this.path,
        this.callback
      )
    })

    it('should create the folder using the project entity handler', function() {
      return this.ProjectEntityUpdateHandler.mkdirp
        .calledWith(this.project_id, this.path)
        .should.equal(true)
    })

    it('should notifyProjectUsersOfNewFolder', function() {
      return this.EditorController._notifyProjectUsersOfNewFolders.calledWith(
        this.project_id,
        this.folders
      )
    })

    it('should return the folder in the callback', function() {
      return this.callback
        .calledWith(null, this.folders, this.folder)
        .should.equal(true)
    })
  })

  describe('deleteEntity', function() {
    beforeEach(function() {
      this.entity_id = 'entity_id_here'
      this.type = 'doc'
      this.ProjectEntityUpdateHandler.deleteEntity = sinon.stub().yields()
      return this.EditorController.deleteEntity(
        this.project_id,
        this.entity_id,
        this.type,
        this.source,
        this.user_id,
        this.callback
      )
    })

    it('should delete the folder using the project entity handler', function() {
      return this.ProjectEntityUpdateHandler.deleteEntity
        .calledWith(this.project_id, this.entity_id, this.type, this.user_id)
        .should.equal(true)
    })

    it('notify users an entity has been deleted', function() {
      return this.EditorRealTimeController.emitToRoom
        .calledWith(
          this.project_id,
          'removeEntity',
          this.entity_id,
          this.source
        )
        .should.equal(true)
    })
  })

  describe('deleteEntityWithPath', function() {
    beforeEach(function() {
      this.entity_id = 'entity_id_here'
      this.ProjectEntityUpdateHandler.deleteEntityWithPath = sinon
        .stub()
        .yields(null, this.entity_id)
      this.path = 'folder1/folder2'
      return this.EditorController.deleteEntityWithPath(
        this.project_id,
        this.path,
        this.source,
        this.user_id,
        this.callback
      )
    })

    it('should delete the folder using the project entity handler', function() {
      return this.ProjectEntityUpdateHandler.deleteEntityWithPath
        .calledWith(this.project_id, this.path, this.user_id)
        .should.equal(true)
    })

    it('notify users an entity has been deleted', function() {
      return this.EditorRealTimeController.emitToRoom
        .calledWith(
          this.project_id,
          'removeEntity',
          this.entity_id,
          this.source
        )
        .should.equal(true)
    })
  })

  describe('updateProjectDescription', function() {
    beforeEach(function() {
      this.description = 'new description'
      return this.EditorController.updateProjectDescription(
        this.project_id,
        this.description,
        this.callback
      )
    })

    it('should send the new description to the project details handler', function() {
      return this.ProjectDetailsHandler.setProjectDescription
        .calledWith(this.project_id, this.description)
        .should.equal(true)
    })

    it('should notify the other clients about the updated description', function() {
      return this.EditorRealTimeController.emitToRoom
        .calledWith(
          this.project_id,
          'projectDescriptionUpdated',
          this.description
        )
        .should.equal(true)
    })
  })

  describe('deleteProject', function() {
    beforeEach(function() {
      this.err = 'errro'
      return (this.ProjectDeleter.deleteProject = sinon
        .stub()
        .callsArgWith(1, this.err))
    })

    it('should call the project handler', function(done) {
      return this.EditorController.deleteProject(this.project_id, err => {
        err.should.equal(this.err)
        this.ProjectDeleter.deleteProject
          .calledWith(this.project_id)
          .should.equal(true)
        return done()
      })
    })
  })

  describe('renameEntity', function() {
    beforeEach(function(done) {
      this.entity_id = 'entity_id_here'
      this.entityType = 'doc'
      this.newName = 'bobsfile.tex'
      this.ProjectEntityUpdateHandler.renameEntity = sinon.stub().yields()

      return this.EditorController.renameEntity(
        this.project_id,
        this.entity_id,
        this.entityType,
        this.newName,
        this.user_id,
        done
      )
    })

    it('should call the project handler', function() {
      return this.ProjectEntityUpdateHandler.renameEntity
        .calledWith(
          this.project_id,
          this.entity_id,
          this.entityType,
          this.newName,
          this.user_id
        )
        .should.equal(true)
    })

    it('should emit the update to the room', function() {
      return this.EditorRealTimeController.emitToRoom
        .calledWith(
          this.project_id,
          'reciveEntityRename',
          this.entity_id,
          this.newName
        )
        .should.equal(true)
    })
  })

  describe('moveEntity', function() {
    beforeEach(function() {
      this.entity_id = 'entity_id_here'
      this.entityType = 'doc'
      this.ProjectEntityUpdateHandler.moveEntity = sinon.stub().yields()
      return this.EditorController.moveEntity(
        this.project_id,
        this.entity_id,
        this.folder_id,
        this.entityType,
        this.user_id,
        this.callback
      )
    })

    it('should call the ProjectEntityUpdateHandler', function() {
      return this.ProjectEntityUpdateHandler.moveEntity
        .calledWith(
          this.project_id,
          this.entity_id,
          this.folder_id,
          this.entityType,
          this.user_id
        )
        .should.equal(true)
    })

    it('should emit the update to the room', function() {
      return this.EditorRealTimeController.emitToRoom
        .calledWith(
          this.project_id,
          'reciveEntityMove',
          this.entity_id,
          this.folder_id
        )
        .should.equal(true)
    })

    it('calls the callback', function() {
      return this.callback.called.should.equal(true)
    })
  })

  describe('renameProject', function() {
    beforeEach(function() {
      this.err = 'errro'
      this.newName = 'new name here'
      return this.EditorController.renameProject(
        this.project_id,
        this.newName,
        this.callback
      )
    })

    it('should call the EditorController', function() {
      return this.ProjectDetailsHandler.renameProject
        .calledWith(this.project_id, this.newName)
        .should.equal(true)
    })

    it('should emit the update to the room', function() {
      return this.EditorRealTimeController.emitToRoom
        .calledWith(this.project_id, 'projectNameUpdated', this.newName)
        .should.equal(true)
    })
  })

  describe('setCompiler', function() {
    beforeEach(function() {
      this.compiler = 'latex'
      return this.EditorController.setCompiler(
        this.project_id,
        this.compiler,
        this.callback
      )
    })

    it('should send the new compiler and project id to the project options handler', function() {
      this.ProjectOptionsHandler.setCompiler
        .calledWith(this.project_id, this.compiler)
        .should.equal(true)
      return this.EditorRealTimeController.emitToRoom
        .calledWith(this.project_id, 'compilerUpdated', this.compiler)
        .should.equal(true)
    })
  })

  describe('setImageName', function() {
    beforeEach(function() {
      this.imageName = 'texlive-1234.5'
      return this.EditorController.setImageName(
        this.project_id,
        this.imageName,
        this.callback
      )
    })

    it('should send the new imageName and project id to the project options handler', function() {
      this.ProjectOptionsHandler.setImageName
        .calledWith(this.project_id, this.imageName)
        .should.equal(true)
      return this.EditorRealTimeController.emitToRoom
        .calledWith(this.project_id, 'imageNameUpdated', this.imageName)
        .should.equal(true)
    })
  })

  describe('setSpellCheckLanguage', function() {
    beforeEach(function() {
      this.languageCode = 'fr'
      return this.EditorController.setSpellCheckLanguage(
        this.project_id,
        this.languageCode,
        this.callback
      )
    })

    it('should send the new languageCode and project id to the project options handler', function() {
      this.ProjectOptionsHandler.setSpellCheckLanguage
        .calledWith(this.project_id, this.languageCode)
        .should.equal(true)
      return this.EditorRealTimeController.emitToRoom
        .calledWith(
          this.project_id,
          'spellCheckLanguageUpdated',
          this.languageCode
        )
        .should.equal(true)
    })
  })

  describe('setPublicAccessLevel', function() {
    describe('when setting to private', function() {
      beforeEach(function() {
        this.newAccessLevel = 'private'
        this.ProjectDetailsHandler.ensureTokensArePresent = sinon
          .stub()
          .yields(null, this.tokens)
        return this.EditorController.setPublicAccessLevel(
          this.project_id,
          this.newAccessLevel,
          this.callback
        )
      })

      it('should set the access level', function() {
        return this.ProjectDetailsHandler.setPublicAccessLevel
          .calledWith(this.project_id, this.newAccessLevel)
          .should.equal(true)
      })

      it('should broadcast the access level change', function() {
        return this.EditorRealTimeController.emitToRoom
          .calledWith(this.project_id, 'project:publicAccessLevel:changed')
          .should.equal(true)
      })

      it('should not ensure tokens are present for project', function() {
        return this.ProjectDetailsHandler.ensureTokensArePresent
          .calledWith(this.project_id)
          .should.equal(false)
      })

      it('should not broadcast a token change', function() {
        return this.EditorRealTimeController.emitToRoom
          .calledWith(this.project_id, 'project:tokens:changed', {
            tokens: this.tokens
          })
          .should.equal(false)
      })
    })

    describe('when setting to tokenBased', function() {
      beforeEach(function() {
        this.newAccessLevel = 'tokenBased'
        this.tokens = { readOnly: 'aaa', readAndWrite: '42bbb' }
        this.ProjectDetailsHandler.ensureTokensArePresent = sinon
          .stub()
          .yields(null, this.tokens)
        return this.EditorController.setPublicAccessLevel(
          this.project_id,
          this.newAccessLevel,
          this.callback
        )
      })

      it('should set the access level', function() {
        return this.ProjectDetailsHandler.setPublicAccessLevel
          .calledWith(this.project_id, this.newAccessLevel)
          .should.equal(true)
      })

      it('should broadcast the access level change', function() {
        return this.EditorRealTimeController.emitToRoom
          .calledWith(this.project_id, 'project:publicAccessLevel:changed')
          .should.equal(true)
      })

      it('should ensure tokens are present for project', function() {
        return this.ProjectDetailsHandler.ensureTokensArePresent
          .calledWith(this.project_id)
          .should.equal(true)
      })

      it('should broadcast the token change too', function() {
        return this.EditorRealTimeController.emitToRoom
          .calledWith(this.project_id, 'project:tokens:changed', {
            tokens: this.tokens
          })
          .should.equal(true)
      })
    })
  })

  describe('setRootDoc', function() {
    beforeEach(function() {
      this.newRootDocID = '21312321321'
      this.ProjectEntityUpdateHandler.setRootDoc = sinon.stub().yields()
      return this.EditorController.setRootDoc(
        this.project_id,
        this.newRootDocID,
        this.callback
      )
    })

    it('should call the ProjectEntityUpdateHandler', function() {
      return this.ProjectEntityUpdateHandler.setRootDoc
        .calledWith(this.project_id, this.newRootDocID)
        .should.equal(true)
    })

    it('should emit the update to the room', function() {
      return this.EditorRealTimeController.emitToRoom
        .calledWith(this.project_id, 'rootDocUpdated', this.newRootDocID)
        .should.equal(true)
    })
  })
})
