EditorControllerTests.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. /* eslint-disable
  2. handle-callback-err,
  3. max-len,
  4. no-return-assign,
  5. no-unused-vars,
  6. */
  7. // TODO: This file was created by bulk-decaffeinate.
  8. // Fix any style issues and re-enable lint.
  9. /*
  10. * decaffeinate suggestions:
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. const SandboxedModule = require('sandboxed-module')
  15. const sinon = require('sinon')
  16. require('chai').should()
  17. const { expect } = require('chai')
  18. const modulePath = require('path').join(
  19. __dirname,
  20. '../../../../app/src/Features/Editor/EditorController'
  21. )
  22. const MockClient = require('../helpers/MockClient')
  23. const assert = require('assert')
  24. describe('EditorController', function() {
  25. beforeEach(function() {
  26. this.project_id = 'test-project-id'
  27. this.source = 'dropbox'
  28. this.doc = { _id: (this.doc_id = 'test-doc-id') }
  29. this.docName = 'doc.tex'
  30. this.docLines = ['1234', 'dskl']
  31. this.file = { _id: (this.file_id = 'dasdkjk') }
  32. this.fileName = 'file.png'
  33. this.fsPath = '/folder/file.png'
  34. this.linkedFileData = { provider: 'url' }
  35. this.newFile = { _id: 'new-file-id' }
  36. this.folder_id = '123ksajdn'
  37. this.folder = { _id: this.folder_id }
  38. this.folderName = 'folder'
  39. this.callback = sinon.stub()
  40. return (this.EditorController = SandboxedModule.require(modulePath, {
  41. globals: {
  42. console: console
  43. },
  44. requires: {
  45. '../Project/ProjectEntityUpdateHandler': (this.ProjectEntityUpdateHandler = {}),
  46. '../Project/ProjectOptionsHandler': (this.ProjectOptionsHandler = {
  47. setCompiler: sinon.stub().yields(),
  48. setImageName: sinon.stub().yields(),
  49. setSpellCheckLanguage: sinon.stub().yields()
  50. }),
  51. '../Project/ProjectDetailsHandler': (this.ProjectDetailsHandler = {
  52. setProjectDescription: sinon.stub().yields(),
  53. renameProject: sinon.stub().yields(),
  54. setPublicAccessLevel: sinon.stub().yields()
  55. }),
  56. '../Project/ProjectDeleter': (this.ProjectDeleter = {}),
  57. '../DocumentUpdater/DocumentUpdaterHandler': (this.DocumentUpdaterHandler = {
  58. flushDocToMongo: sinon.stub().yields(),
  59. setDocument: sinon.stub().yields()
  60. }),
  61. './EditorRealTimeController': (this.EditorRealTimeController = {
  62. emitToRoom: sinon.stub()
  63. }),
  64. 'metrics-sharelatex': (this.Metrics = { inc: sinon.stub() }),
  65. 'logger-sharelatex': (this.logger = {
  66. log: sinon.stub(),
  67. err: sinon.stub()
  68. })
  69. }
  70. }))
  71. })
  72. describe('addDoc', function() {
  73. beforeEach(function() {
  74. this.ProjectEntityUpdateHandler.addDocWithRanges = sinon
  75. .stub()
  76. .yields(null, this.doc, this.folder_id)
  77. return this.EditorController.addDoc(
  78. this.project_id,
  79. this.folder_id,
  80. this.docName,
  81. this.docLines,
  82. this.source,
  83. this.user_id,
  84. this.callback
  85. )
  86. })
  87. it('should add the doc using the project entity handler', function() {
  88. return this.ProjectEntityUpdateHandler.addDocWithRanges
  89. .calledWith(
  90. this.project_id,
  91. this.folder_id,
  92. this.docName,
  93. this.docLines,
  94. {}
  95. )
  96. .should.equal(true)
  97. })
  98. it('should send the update out to the users in the project', function() {
  99. return this.EditorRealTimeController.emitToRoom
  100. .calledWith(
  101. this.project_id,
  102. 'reciveNewDoc',
  103. this.folder_id,
  104. this.doc,
  105. this.source
  106. )
  107. .should.equal(true)
  108. })
  109. it('calls the callback', function() {
  110. return this.callback.calledWith(null, this.doc).should.equal(true)
  111. })
  112. })
  113. describe('addFile', function() {
  114. beforeEach(function() {
  115. this.ProjectEntityUpdateHandler.addFile = sinon
  116. .stub()
  117. .yields(null, this.file, this.folder_id)
  118. return this.EditorController.addFile(
  119. this.project_id,
  120. this.folder_id,
  121. this.fileName,
  122. this.fsPath,
  123. this.linkedFileData,
  124. this.source,
  125. this.user_id,
  126. this.callback
  127. )
  128. })
  129. it('should add the folder using the project entity handler', function() {
  130. return this.ProjectEntityUpdateHandler.addFile
  131. .calledWith(
  132. this.project_id,
  133. this.folder_id,
  134. this.fileName,
  135. this.fsPath,
  136. this.linkedFileData,
  137. this.user_id
  138. )
  139. .should.equal(true)
  140. })
  141. it('should send the update of a new folder out to the users in the project', function() {
  142. return this.EditorRealTimeController.emitToRoom
  143. .calledWith(
  144. this.project_id,
  145. 'reciveNewFile',
  146. this.folder_id,
  147. this.file,
  148. this.source,
  149. this.linkedFileData
  150. )
  151. .should.equal(true)
  152. })
  153. it('calls the callback', function() {
  154. return this.callback.calledWith(null, this.file).should.equal(true)
  155. })
  156. })
  157. describe('upsertDoc', function() {
  158. beforeEach(function() {
  159. this.ProjectEntityUpdateHandler.upsertDoc = sinon
  160. .stub()
  161. .yields(null, this.doc, false)
  162. return this.EditorController.upsertDoc(
  163. this.project_id,
  164. this.folder_id,
  165. this.docName,
  166. this.docLines,
  167. this.source,
  168. this.user_id,
  169. this.callback
  170. )
  171. })
  172. it('upserts the doc using the project entity handler', function() {
  173. return this.ProjectEntityUpdateHandler.upsertDoc
  174. .calledWith(
  175. this.project_id,
  176. this.folder_id,
  177. this.docName,
  178. this.docLines,
  179. this.source
  180. )
  181. .should.equal(true)
  182. })
  183. it('returns the doc', function() {
  184. return this.callback.calledWith(null, this.doc).should.equal(true)
  185. })
  186. describe('doc does not exist', function() {
  187. beforeEach(function() {
  188. this.ProjectEntityUpdateHandler.upsertDoc = sinon
  189. .stub()
  190. .yields(null, this.doc, true)
  191. return this.EditorController.upsertDoc(
  192. this.project_id,
  193. this.folder_id,
  194. this.docName,
  195. this.docLines,
  196. this.source,
  197. this.user_id,
  198. this.callback
  199. )
  200. })
  201. it('sends an update out to users in the project', function() {
  202. return this.EditorRealTimeController.emitToRoom
  203. .calledWith(
  204. this.project_id,
  205. 'reciveNewDoc',
  206. this.folder_id,
  207. this.doc,
  208. this.source
  209. )
  210. .should.equal(true)
  211. })
  212. })
  213. })
  214. describe('upsertFile', function() {
  215. beforeEach(function() {
  216. this.ProjectEntityUpdateHandler.upsertFile = sinon
  217. .stub()
  218. .yields(null, this.newFile, false, this.file)
  219. return this.EditorController.upsertFile(
  220. this.project_id,
  221. this.folder_id,
  222. this.fileName,
  223. this.fsPath,
  224. this.linkedFileData,
  225. this.source,
  226. this.user_id,
  227. this.callback
  228. )
  229. })
  230. it('upserts the file using the project entity handler', function() {
  231. return this.ProjectEntityUpdateHandler.upsertFile
  232. .calledWith(
  233. this.project_id,
  234. this.folder_id,
  235. this.fileName,
  236. this.fsPath,
  237. this.linkedFileData,
  238. this.user_id
  239. )
  240. .should.equal(true)
  241. })
  242. it('returns the file', function() {
  243. return this.callback.calledWith(null, this.newFile).should.equal(true)
  244. })
  245. describe('file does not exist', function() {
  246. beforeEach(function() {
  247. this.ProjectEntityUpdateHandler.upsertFile = sinon
  248. .stub()
  249. .yields(null, this.file, true)
  250. return this.EditorController.upsertFile(
  251. this.project_id,
  252. this.folder_id,
  253. this.fileName,
  254. this.fsPath,
  255. this.linkedFileData,
  256. this.source,
  257. this.user_id,
  258. this.callback
  259. )
  260. })
  261. it('should send the update out to users in the project', function() {
  262. return this.EditorRealTimeController.emitToRoom
  263. .calledWith(
  264. this.project_id,
  265. 'reciveNewFile',
  266. this.folder_id,
  267. this.file,
  268. this.source,
  269. this.linkedFileData
  270. )
  271. .should.equal(true)
  272. })
  273. })
  274. })
  275. describe('upsertDocWithPath', function() {
  276. beforeEach(function() {
  277. this.docPath = '/folder/doc'
  278. this.ProjectEntityUpdateHandler.upsertDocWithPath = sinon
  279. .stub()
  280. .yields(null, this.doc, false, [], this.folder)
  281. return this.EditorController.upsertDocWithPath(
  282. this.project_id,
  283. this.docPath,
  284. this.docLines,
  285. this.source,
  286. this.user_id,
  287. this.callback
  288. )
  289. })
  290. it('upserts the doc using the project entity handler', function() {
  291. return this.ProjectEntityUpdateHandler.upsertDocWithPath
  292. .calledWith(this.project_id, this.docPath, this.docLines, this.source)
  293. .should.equal(true)
  294. })
  295. describe('doc does not exist', function() {
  296. beforeEach(function() {
  297. this.ProjectEntityUpdateHandler.upsertDocWithPath = sinon
  298. .stub()
  299. .yields(null, this.doc, true, [], this.folder)
  300. return this.EditorController.upsertDocWithPath(
  301. this.project_id,
  302. this.docPath,
  303. this.docLines,
  304. this.source,
  305. this.user_id,
  306. this.callback
  307. )
  308. })
  309. it('should send the update for the doc out to users in the project', function() {
  310. return this.EditorRealTimeController.emitToRoom
  311. .calledWith(
  312. this.project_id,
  313. 'reciveNewDoc',
  314. this.folder_id,
  315. this.doc,
  316. this.source
  317. )
  318. .should.equal(true)
  319. })
  320. })
  321. describe('folders required for doc do not exist', function() {
  322. beforeEach(function() {
  323. const folders = [
  324. (this.folderA = { _id: 2, parentFolder_id: 1 }),
  325. (this.folderB = { _id: 3, parentFolder_id: 2 })
  326. ]
  327. this.ProjectEntityUpdateHandler.upsertDocWithPath = sinon
  328. .stub()
  329. .yields(null, this.doc, true, folders, this.folderB)
  330. return this.EditorController.upsertDocWithPath(
  331. this.project_id,
  332. this.docPath,
  333. this.docLines,
  334. this.source,
  335. this.user_id,
  336. this.callback
  337. )
  338. })
  339. it('should send the update for each folder to users in the project', function() {
  340. this.EditorRealTimeController.emitToRoom
  341. .calledWith(
  342. this.project_id,
  343. 'reciveNewFolder',
  344. this.folderA.parentFolder_id,
  345. this.folderA
  346. )
  347. .should.equal(true)
  348. return this.EditorRealTimeController.emitToRoom
  349. .calledWith(
  350. this.project_id,
  351. 'reciveNewFolder',
  352. this.folderB.parentFolder_id,
  353. this.folderB
  354. )
  355. .should.equal(true)
  356. })
  357. })
  358. })
  359. describe('upsertFileWithPath', function() {
  360. beforeEach(function() {
  361. this.filePath = '/folder/file'
  362. this.ProjectEntityUpdateHandler.upsertFileWithPath = sinon
  363. .stub()
  364. .yields(null, this.newFile, false, this.file, [], this.folder)
  365. return this.EditorController.upsertFileWithPath(
  366. this.project_id,
  367. this.filePath,
  368. this.fsPath,
  369. this.linkedFileData,
  370. this.source,
  371. this.user_id,
  372. this.callback
  373. )
  374. })
  375. it('upserts the file using the project entity handler', function() {
  376. return this.ProjectEntityUpdateHandler.upsertFileWithPath
  377. .calledWith(
  378. this.project_id,
  379. this.filePath,
  380. this.fsPath,
  381. this.linkedFileData
  382. )
  383. .should.equal(true)
  384. })
  385. describe('file does not exist', function() {
  386. beforeEach(function() {
  387. this.ProjectEntityUpdateHandler.upsertFileWithPath = sinon
  388. .stub()
  389. .yields(null, this.file, true, undefined, [], this.folder)
  390. return this.EditorController.upsertFileWithPath(
  391. this.project_id,
  392. this.filePath,
  393. this.fsPath,
  394. this.linkedFileData,
  395. this.source,
  396. this.user_id,
  397. this.callback
  398. )
  399. })
  400. it('should send the update for the file out to users in the project', function() {
  401. return this.EditorRealTimeController.emitToRoom
  402. .calledWith(
  403. this.project_id,
  404. 'reciveNewFile',
  405. this.folder_id,
  406. this.file,
  407. this.source,
  408. this.linkedFileData
  409. )
  410. .should.equal(true)
  411. })
  412. })
  413. describe('folders required for file do not exist', function() {
  414. beforeEach(function() {
  415. const folders = [
  416. (this.folderA = { _id: 2, parentFolder_id: 1 }),
  417. (this.folderB = { _id: 3, parentFolder_id: 2 })
  418. ]
  419. this.ProjectEntityUpdateHandler.upsertFileWithPath = sinon
  420. .stub()
  421. .yields(null, this.file, true, undefined, folders, this.folderB)
  422. return this.EditorController.upsertFileWithPath(
  423. this.project_id,
  424. this.filePath,
  425. this.fsPath,
  426. this.linkedFileData,
  427. this.source,
  428. this.user_id,
  429. this.callback
  430. )
  431. })
  432. it('should send the update for each folder to users in the project', function() {
  433. this.EditorRealTimeController.emitToRoom
  434. .calledWith(
  435. this.project_id,
  436. 'reciveNewFolder',
  437. this.folderA.parentFolder_id,
  438. this.folderA
  439. )
  440. .should.equal(true)
  441. return this.EditorRealTimeController.emitToRoom
  442. .calledWith(
  443. this.project_id,
  444. 'reciveNewFolder',
  445. this.folderB.parentFolder_id,
  446. this.folderB
  447. )
  448. .should.equal(true)
  449. })
  450. })
  451. })
  452. describe('addFolder', function() {
  453. beforeEach(function() {
  454. this.EditorController._notifyProjectUsersOfNewFolder = sinon
  455. .stub()
  456. .yields()
  457. this.ProjectEntityUpdateHandler.addFolder = sinon
  458. .stub()
  459. .yields(null, this.folder, this.folder_id)
  460. return this.EditorController.addFolder(
  461. this.project_id,
  462. this.folder_id,
  463. this.folderName,
  464. this.source,
  465. this.callback
  466. )
  467. })
  468. it('should add the folder using the project entity handler', function() {
  469. return this.ProjectEntityUpdateHandler.addFolder
  470. .calledWith(this.project_id, this.folder_id, this.folderName)
  471. .should.equal(true)
  472. })
  473. it('should notifyProjectUsersOfNewFolder', function() {
  474. return this.EditorController._notifyProjectUsersOfNewFolder.calledWith(
  475. this.project_id,
  476. this.folder_id,
  477. this.folder
  478. )
  479. })
  480. it('should return the folder in the callback', function() {
  481. return this.callback.calledWith(null, this.folder).should.equal(true)
  482. })
  483. })
  484. describe('mkdirp', function() {
  485. beforeEach(function() {
  486. this.path = 'folder1/folder2'
  487. this.folders = [
  488. (this.folderA = { _id: 2, parentFolder_id: 1 }),
  489. (this.folderB = { _id: 3, parentFolder_id: 2 })
  490. ]
  491. this.EditorController._notifyProjectUsersOfNewFolders = sinon
  492. .stub()
  493. .yields()
  494. this.ProjectEntityUpdateHandler.mkdirp = sinon
  495. .stub()
  496. .yields(null, this.folders, this.folder)
  497. return this.EditorController.mkdirp(
  498. this.project_id,
  499. this.path,
  500. this.callback
  501. )
  502. })
  503. it('should create the folder using the project entity handler', function() {
  504. return this.ProjectEntityUpdateHandler.mkdirp
  505. .calledWith(this.project_id, this.path)
  506. .should.equal(true)
  507. })
  508. it('should notifyProjectUsersOfNewFolder', function() {
  509. return this.EditorController._notifyProjectUsersOfNewFolders.calledWith(
  510. this.project_id,
  511. this.folders
  512. )
  513. })
  514. it('should return the folder in the callback', function() {
  515. return this.callback
  516. .calledWith(null, this.folders, this.folder)
  517. .should.equal(true)
  518. })
  519. })
  520. describe('deleteEntity', function() {
  521. beforeEach(function() {
  522. this.entity_id = 'entity_id_here'
  523. this.type = 'doc'
  524. this.ProjectEntityUpdateHandler.deleteEntity = sinon.stub().yields()
  525. return this.EditorController.deleteEntity(
  526. this.project_id,
  527. this.entity_id,
  528. this.type,
  529. this.source,
  530. this.user_id,
  531. this.callback
  532. )
  533. })
  534. it('should delete the folder using the project entity handler', function() {
  535. return this.ProjectEntityUpdateHandler.deleteEntity
  536. .calledWith(this.project_id, this.entity_id, this.type, this.user_id)
  537. .should.equal(true)
  538. })
  539. it('notify users an entity has been deleted', function() {
  540. return this.EditorRealTimeController.emitToRoom
  541. .calledWith(
  542. this.project_id,
  543. 'removeEntity',
  544. this.entity_id,
  545. this.source
  546. )
  547. .should.equal(true)
  548. })
  549. })
  550. describe('deleteEntityWithPath', function() {
  551. beforeEach(function() {
  552. this.entity_id = 'entity_id_here'
  553. this.ProjectEntityUpdateHandler.deleteEntityWithPath = sinon
  554. .stub()
  555. .yields(null, this.entity_id)
  556. this.path = 'folder1/folder2'
  557. return this.EditorController.deleteEntityWithPath(
  558. this.project_id,
  559. this.path,
  560. this.source,
  561. this.user_id,
  562. this.callback
  563. )
  564. })
  565. it('should delete the folder using the project entity handler', function() {
  566. return this.ProjectEntityUpdateHandler.deleteEntityWithPath
  567. .calledWith(this.project_id, this.path, this.user_id)
  568. .should.equal(true)
  569. })
  570. it('notify users an entity has been deleted', function() {
  571. return this.EditorRealTimeController.emitToRoom
  572. .calledWith(
  573. this.project_id,
  574. 'removeEntity',
  575. this.entity_id,
  576. this.source
  577. )
  578. .should.equal(true)
  579. })
  580. })
  581. describe('updateProjectDescription', function() {
  582. beforeEach(function() {
  583. this.description = 'new description'
  584. return this.EditorController.updateProjectDescription(
  585. this.project_id,
  586. this.description,
  587. this.callback
  588. )
  589. })
  590. it('should send the new description to the project details handler', function() {
  591. return this.ProjectDetailsHandler.setProjectDescription
  592. .calledWith(this.project_id, this.description)
  593. .should.equal(true)
  594. })
  595. it('should notify the other clients about the updated description', function() {
  596. return this.EditorRealTimeController.emitToRoom
  597. .calledWith(
  598. this.project_id,
  599. 'projectDescriptionUpdated',
  600. this.description
  601. )
  602. .should.equal(true)
  603. })
  604. })
  605. describe('deleteProject', function() {
  606. beforeEach(function() {
  607. this.err = 'errro'
  608. return (this.ProjectDeleter.deleteProject = sinon
  609. .stub()
  610. .callsArgWith(1, this.err))
  611. })
  612. it('should call the project handler', function(done) {
  613. return this.EditorController.deleteProject(this.project_id, err => {
  614. err.should.equal(this.err)
  615. this.ProjectDeleter.deleteProject
  616. .calledWith(this.project_id)
  617. .should.equal(true)
  618. return done()
  619. })
  620. })
  621. })
  622. describe('renameEntity', function() {
  623. beforeEach(function(done) {
  624. this.entity_id = 'entity_id_here'
  625. this.entityType = 'doc'
  626. this.newName = 'bobsfile.tex'
  627. this.ProjectEntityUpdateHandler.renameEntity = sinon.stub().yields()
  628. return this.EditorController.renameEntity(
  629. this.project_id,
  630. this.entity_id,
  631. this.entityType,
  632. this.newName,
  633. this.user_id,
  634. done
  635. )
  636. })
  637. it('should call the project handler', function() {
  638. return this.ProjectEntityUpdateHandler.renameEntity
  639. .calledWith(
  640. this.project_id,
  641. this.entity_id,
  642. this.entityType,
  643. this.newName,
  644. this.user_id
  645. )
  646. .should.equal(true)
  647. })
  648. it('should emit the update to the room', function() {
  649. return this.EditorRealTimeController.emitToRoom
  650. .calledWith(
  651. this.project_id,
  652. 'reciveEntityRename',
  653. this.entity_id,
  654. this.newName
  655. )
  656. .should.equal(true)
  657. })
  658. })
  659. describe('moveEntity', function() {
  660. beforeEach(function() {
  661. this.entity_id = 'entity_id_here'
  662. this.entityType = 'doc'
  663. this.ProjectEntityUpdateHandler.moveEntity = sinon.stub().yields()
  664. return this.EditorController.moveEntity(
  665. this.project_id,
  666. this.entity_id,
  667. this.folder_id,
  668. this.entityType,
  669. this.user_id,
  670. this.callback
  671. )
  672. })
  673. it('should call the ProjectEntityUpdateHandler', function() {
  674. return this.ProjectEntityUpdateHandler.moveEntity
  675. .calledWith(
  676. this.project_id,
  677. this.entity_id,
  678. this.folder_id,
  679. this.entityType,
  680. this.user_id
  681. )
  682. .should.equal(true)
  683. })
  684. it('should emit the update to the room', function() {
  685. return this.EditorRealTimeController.emitToRoom
  686. .calledWith(
  687. this.project_id,
  688. 'reciveEntityMove',
  689. this.entity_id,
  690. this.folder_id
  691. )
  692. .should.equal(true)
  693. })
  694. it('calls the callback', function() {
  695. return this.callback.called.should.equal(true)
  696. })
  697. })
  698. describe('renameProject', function() {
  699. beforeEach(function() {
  700. this.err = 'errro'
  701. this.newName = 'new name here'
  702. return this.EditorController.renameProject(
  703. this.project_id,
  704. this.newName,
  705. this.callback
  706. )
  707. })
  708. it('should call the EditorController', function() {
  709. return this.ProjectDetailsHandler.renameProject
  710. .calledWith(this.project_id, this.newName)
  711. .should.equal(true)
  712. })
  713. it('should emit the update to the room', function() {
  714. return this.EditorRealTimeController.emitToRoom
  715. .calledWith(this.project_id, 'projectNameUpdated', this.newName)
  716. .should.equal(true)
  717. })
  718. })
  719. describe('setCompiler', function() {
  720. beforeEach(function() {
  721. this.compiler = 'latex'
  722. return this.EditorController.setCompiler(
  723. this.project_id,
  724. this.compiler,
  725. this.callback
  726. )
  727. })
  728. it('should send the new compiler and project id to the project options handler', function() {
  729. this.ProjectOptionsHandler.setCompiler
  730. .calledWith(this.project_id, this.compiler)
  731. .should.equal(true)
  732. return this.EditorRealTimeController.emitToRoom
  733. .calledWith(this.project_id, 'compilerUpdated', this.compiler)
  734. .should.equal(true)
  735. })
  736. })
  737. describe('setImageName', function() {
  738. beforeEach(function() {
  739. this.imageName = 'texlive-1234.5'
  740. return this.EditorController.setImageName(
  741. this.project_id,
  742. this.imageName,
  743. this.callback
  744. )
  745. })
  746. it('should send the new imageName and project id to the project options handler', function() {
  747. this.ProjectOptionsHandler.setImageName
  748. .calledWith(this.project_id, this.imageName)
  749. .should.equal(true)
  750. return this.EditorRealTimeController.emitToRoom
  751. .calledWith(this.project_id, 'imageNameUpdated', this.imageName)
  752. .should.equal(true)
  753. })
  754. })
  755. describe('setSpellCheckLanguage', function() {
  756. beforeEach(function() {
  757. this.languageCode = 'fr'
  758. return this.EditorController.setSpellCheckLanguage(
  759. this.project_id,
  760. this.languageCode,
  761. this.callback
  762. )
  763. })
  764. it('should send the new languageCode and project id to the project options handler', function() {
  765. this.ProjectOptionsHandler.setSpellCheckLanguage
  766. .calledWith(this.project_id, this.languageCode)
  767. .should.equal(true)
  768. return this.EditorRealTimeController.emitToRoom
  769. .calledWith(
  770. this.project_id,
  771. 'spellCheckLanguageUpdated',
  772. this.languageCode
  773. )
  774. .should.equal(true)
  775. })
  776. })
  777. describe('setPublicAccessLevel', function() {
  778. describe('when setting to private', function() {
  779. beforeEach(function() {
  780. this.newAccessLevel = 'private'
  781. this.ProjectDetailsHandler.ensureTokensArePresent = sinon
  782. .stub()
  783. .yields(null, this.tokens)
  784. return this.EditorController.setPublicAccessLevel(
  785. this.project_id,
  786. this.newAccessLevel,
  787. this.callback
  788. )
  789. })
  790. it('should set the access level', function() {
  791. return this.ProjectDetailsHandler.setPublicAccessLevel
  792. .calledWith(this.project_id, this.newAccessLevel)
  793. .should.equal(true)
  794. })
  795. it('should broadcast the access level change', function() {
  796. return this.EditorRealTimeController.emitToRoom
  797. .calledWith(this.project_id, 'project:publicAccessLevel:changed')
  798. .should.equal(true)
  799. })
  800. it('should not ensure tokens are present for project', function() {
  801. return this.ProjectDetailsHandler.ensureTokensArePresent
  802. .calledWith(this.project_id)
  803. .should.equal(false)
  804. })
  805. it('should not broadcast a token change', function() {
  806. return this.EditorRealTimeController.emitToRoom
  807. .calledWith(this.project_id, 'project:tokens:changed', {
  808. tokens: this.tokens
  809. })
  810. .should.equal(false)
  811. })
  812. })
  813. describe('when setting to tokenBased', function() {
  814. beforeEach(function() {
  815. this.newAccessLevel = 'tokenBased'
  816. this.tokens = { readOnly: 'aaa', readAndWrite: '42bbb' }
  817. this.ProjectDetailsHandler.ensureTokensArePresent = sinon
  818. .stub()
  819. .yields(null, this.tokens)
  820. return this.EditorController.setPublicAccessLevel(
  821. this.project_id,
  822. this.newAccessLevel,
  823. this.callback
  824. )
  825. })
  826. it('should set the access level', function() {
  827. return this.ProjectDetailsHandler.setPublicAccessLevel
  828. .calledWith(this.project_id, this.newAccessLevel)
  829. .should.equal(true)
  830. })
  831. it('should broadcast the access level change', function() {
  832. return this.EditorRealTimeController.emitToRoom
  833. .calledWith(this.project_id, 'project:publicAccessLevel:changed')
  834. .should.equal(true)
  835. })
  836. it('should ensure tokens are present for project', function() {
  837. return this.ProjectDetailsHandler.ensureTokensArePresent
  838. .calledWith(this.project_id)
  839. .should.equal(true)
  840. })
  841. it('should broadcast the token change too', function() {
  842. return this.EditorRealTimeController.emitToRoom
  843. .calledWith(this.project_id, 'project:tokens:changed', {
  844. tokens: this.tokens
  845. })
  846. .should.equal(true)
  847. })
  848. })
  849. })
  850. describe('setRootDoc', function() {
  851. beforeEach(function() {
  852. this.newRootDocID = '21312321321'
  853. this.ProjectEntityUpdateHandler.setRootDoc = sinon.stub().yields()
  854. return this.EditorController.setRootDoc(
  855. this.project_id,
  856. this.newRootDocID,
  857. this.callback
  858. )
  859. })
  860. it('should call the ProjectEntityUpdateHandler', function() {
  861. return this.ProjectEntityUpdateHandler.setRootDoc
  862. .calledWith(this.project_id, this.newRootDocID)
  863. .should.equal(true)
  864. })
  865. it('should emit the update to the room', function() {
  866. return this.EditorRealTimeController.emitToRoom
  867. .calledWith(this.project_id, 'rootDocUpdated', this.newRootDocID)
  868. .should.equal(true)
  869. })
  870. })
  871. })