ProjectCreationHandlerTests.coffee 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. spies = require('chai-spies')
  2. chai = require('chai').use(spies)
  3. sinon = require("sinon")
  4. should = chai.should()
  5. expect = chai.expect
  6. modulePath = "../../../../app/js/Features/Project/ProjectCreationHandler.js"
  7. SandboxedModule = require('sandboxed-module')
  8. Settings = require('settings-sharelatex')
  9. Path = require "path"
  10. _ = require("underscore")
  11. describe 'ProjectCreationHandler', ->
  12. ownerId = '4eecb1c1bffa66588e0000a1'
  13. projectName = 'project name goes here'
  14. project_id = "4eecaffcbffa66588e000008"
  15. docId = '4eecb17ebffa66588e00003f'
  16. rootFolderId = "234adfa3r2afe"
  17. beforeEach ->
  18. @ProjectModel = class Project
  19. constructor:(options = {})->
  20. @._id = project_id
  21. @owner_ref = options.owner_ref
  22. @name = options.name
  23. @overleaf =
  24. history: {}
  25. save: sinon.stub().callsArg(0)
  26. rootFolder:[{
  27. _id: rootFolderId
  28. docs: []
  29. }]
  30. @FolderModel = class Folder
  31. constructor:(options)->
  32. {@name} = options
  33. @ProjectEntityUpdateHandler =
  34. addDoc: sinon.stub().callsArgWith(5, null, {_id: docId})
  35. addFile: sinon.stub().callsArg(6)
  36. setRootDoc: sinon.stub().callsArg(2)
  37. @ProjectDetailsHandler =
  38. validateProjectName: sinon.stub().yields()
  39. @HistoryManager =
  40. initializeProject: sinon.stub().callsArg(0)
  41. @user =
  42. first_name:"first name here"
  43. last_name:"last name here"
  44. ace:
  45. spellCheckLanguage:"de"
  46. @User = findById:sinon.stub().callsArgWith(2, null, @user)
  47. @callback = sinon.stub()
  48. @Settings = apis: { project_history: {} }
  49. @AnalyticsManager = recordEvent: sinon.stub()
  50. @handler = SandboxedModule.require modulePath, requires:
  51. '../../models/User': User:@User
  52. '../../models/Project':{Project:@ProjectModel}
  53. '../../models/Folder':{Folder:@FolderModel}
  54. '../History/HistoryManager': @HistoryManager
  55. './ProjectEntityUpdateHandler':@ProjectEntityUpdateHandler
  56. "./ProjectDetailsHandler":@ProjectDetailsHandler
  57. "settings-sharelatex": @Settings
  58. "../Analytics/AnalyticsManager": @AnalyticsManager
  59. 'logger-sharelatex': {log:->}
  60. "metrics-sharelatex": {
  61. inc: ()->,
  62. timeAsyncMethod: ()->
  63. }
  64. describe 'Creating a Blank project', ->
  65. beforeEach ->
  66. @overleaf_id = 1234
  67. @HistoryManager.initializeProject = sinon.stub().callsArgWith(0, null, { @overleaf_id })
  68. @ProjectModel::save = sinon.stub().callsArg(0)
  69. describe "successfully", ->
  70. it "should save the project", (done)->
  71. @handler.createBlankProject ownerId, projectName, =>
  72. @ProjectModel::save.called.should.equal true
  73. done()
  74. it "should return the project in the callback", (done)->
  75. @handler.createBlankProject ownerId, projectName, (err, project)->
  76. project.name.should.equal projectName
  77. (project.owner_ref + "").should.equal ownerId
  78. done()
  79. it "should initialize the project overleaf if history id not provided", (done)->
  80. @handler.createBlankProject ownerId, projectName, done
  81. @HistoryManager.initializeProject.calledWith().should.equal true
  82. it "should set the overleaf id if overleaf id not provided", (done)->
  83. @handler.createBlankProject ownerId, projectName, (err, project)=>
  84. project.overleaf.history.id.should.equal @overleaf_id
  85. done()
  86. it "should set the overleaf id if overleaf id provided", (done)->
  87. overleaf_id = 2345
  88. attributes =
  89. overleaf:
  90. history:
  91. id: overleaf_id
  92. @handler.createBlankProject ownerId, projectName, attributes, (err, project)->
  93. project.overleaf.history.id.should.equal overleaf_id
  94. done()
  95. it "should set the language from the user", (done)->
  96. @handler.createBlankProject ownerId, projectName, (err, project)->
  97. project.spellCheckLanguage.should.equal "de"
  98. done()
  99. it "should set the imageName to currentImageName if set and no imageName attribute", (done) ->
  100. @Settings.currentImageName = "mock-image-name"
  101. @handler.createBlankProject ownerId, projectName, (err, project)=>
  102. project.imageName.should.equal @Settings.currentImageName
  103. done()
  104. it "should not set the imageName if no currentImageName", (done) ->
  105. @Settings.currentImageName = null
  106. @handler.createBlankProject ownerId, projectName, (err, project)=>
  107. expect(project.imageName).to.not.exist
  108. done()
  109. it "should set the imageName to the attribute value if set and not overwrite it with the currentImageName", (done) ->
  110. @Settings.currentImageName = "mock-image-name"
  111. attributes =
  112. imageName: "attribute-image-name"
  113. @handler.createBlankProject ownerId, projectName, attributes, (err, project)=>
  114. project.imageName.should.equal attributes.imageName
  115. done()
  116. it "should not set the overleaf.history.display if not configured in settings", (done) ->
  117. @Settings.apis.project_history.displayHistoryForNewProjects = false
  118. @handler.createBlankProject ownerId, projectName, (err, project)=>
  119. expect(project.overleaf.history.display).to.not.exist
  120. done()
  121. it "should set the overleaf.history.display if configured in settings", (done) ->
  122. @Settings.apis.project_history.displayHistoryForNewProjects = true
  123. @handler.createBlankProject ownerId, projectName, (err, project)=>
  124. expect(project.overleaf.history.display).to.equal true
  125. done()
  126. it "should send a project-created event to analytics", (done) ->
  127. @handler.createBlankProject ownerId, projectName, (err, project) =>
  128. expect(@AnalyticsManager.recordEvent.callCount).to.equal 1
  129. expect(
  130. @AnalyticsManager.recordEvent.calledWith(ownerId, 'project-created')
  131. ).to.equal true
  132. done()
  133. it "should send a project-imported event when importing a project", (done) ->
  134. @handler.createBlankProject ownerId, projectName, 1234, (err, project) =>
  135. expect(@AnalyticsManager.recordEvent.callCount).to.equal 1
  136. expect(
  137. @AnalyticsManager.recordEvent.calledWith(ownerId, 'project-imported')
  138. ).to.equal true
  139. done()
  140. describe "with an error", ->
  141. beforeEach ->
  142. @ProjectModel::save = sinon.stub().callsArgWith(0, new Error("something went wrong"))
  143. @handler.createBlankProject ownerId, projectName, @callback
  144. it 'should return the error to the callback', ->
  145. should.exist @callback.args[0][0]
  146. describe "with an invalid name", ->
  147. beforeEach ->
  148. @ProjectDetailsHandler.validateProjectName = sinon.stub().yields(new Error("bad name"))
  149. @handler.createBlankProject ownerId, projectName, @callback
  150. it 'should return the error to the callback', ->
  151. should.exist @callback.args[0][0]
  152. it 'should not try to create the project', ->
  153. @ProjectModel::save.called.should.equal false
  154. describe 'Creating a basic project', ->
  155. beforeEach ->
  156. @project = new @ProjectModel()
  157. @handler._buildTemplate = (template_name, user, project_name, callback) ->
  158. if template_name == "mainbasic.tex"
  159. return callback(null, ["mainbasic.tex", "lines"])
  160. throw new Error("unknown template: #{template_name}")
  161. sinon.spy @handler, "_buildTemplate"
  162. @handler.createBlankProject = sinon.stub().callsArgWith(2, null, @project)
  163. @handler._createRootDoc = sinon.stub().callsArgWith(3, null, @project)
  164. @handler.createBasicProject(ownerId, projectName, @callback)
  165. it "should create a blank project first", ->
  166. @handler.createBlankProject.calledWith(ownerId, projectName)
  167. .should.equal true
  168. it 'should create the root document', ->
  169. @handler._createRootDoc
  170. .calledWith(@project, ownerId, ["mainbasic.tex", "lines"])
  171. .should.equal true
  172. it 'should build the mainbasic.tex template', ->
  173. @handler._buildTemplate
  174. .calledWith("mainbasic.tex", ownerId, projectName)
  175. .should.equal true
  176. describe 'Creating a project from a snippet', ->
  177. beforeEach ->
  178. @project = new @ProjectModel
  179. @handler.createBlankProject = sinon.stub().callsArgWith(2, null, @project)
  180. @handler._createRootDoc = sinon.stub().callsArgWith(3, null, @project)
  181. @handler.createProjectFromSnippet(ownerId, projectName, ["snippet line 1", "snippet line 2"], @callback)
  182. it "should create a blank project first", ->
  183. @handler.createBlankProject.calledWith(ownerId, projectName)
  184. .should.equal true
  185. it 'should create the root document', ->
  186. @handler._createRootDoc
  187. .calledWith(@project, ownerId, ["snippet line 1", "snippet line 2"])
  188. .should.equal true
  189. describe 'Creating an example project', ->
  190. beforeEach ->
  191. @project = new @ProjectModel()
  192. @handler._buildTemplate = (template_name, user, project_name, callback) ->
  193. if template_name == "main.tex"
  194. return callback(null, ["main.tex", "lines"])
  195. if template_name == "references.bib"
  196. return callback(null, ["references.bib", "lines"])
  197. throw new Error("unknown template: #{template_name}")
  198. sinon.spy @handler, "_buildTemplate"
  199. @handler.createBlankProject = sinon.stub().callsArgWith(2, null, @project)
  200. @handler._createRootDoc = sinon.stub().callsArgWith(3, null, @project)
  201. @handler.createExampleProject(ownerId, projectName, @callback)
  202. it "should create a blank project first", ->
  203. @handler.createBlankProject.calledWith(ownerId, projectName)
  204. .should.equal true
  205. it 'should create the root document', ->
  206. @handler._createRootDoc
  207. .calledWith(@project, ownerId, ["main.tex", "lines"])
  208. .should.equal true
  209. it 'should insert references.bib', ->
  210. @ProjectEntityUpdateHandler.addDoc
  211. .calledWith(project_id, rootFolderId, "references.bib", ["references.bib", "lines"], ownerId)
  212. .should.equal true
  213. it 'should insert universe.jpg', ->
  214. @ProjectEntityUpdateHandler.addFile
  215. .calledWith(
  216. project_id, rootFolderId, "universe.jpg",
  217. Path.resolve(__dirname + "/../../../../app/templates/project_files/universe.jpg"),
  218. null,
  219. ownerId
  220. )
  221. .should.equal true
  222. it 'should build the main.tex template', ->
  223. @handler._buildTemplate
  224. .calledWith("main.tex", ownerId, projectName)
  225. .should.equal true
  226. it 'should build the references.bib template', ->
  227. @handler._buildTemplate
  228. .calledWith("references.bib", ownerId, projectName)
  229. .should.equal true
  230. describe "_buildTemplate", ->
  231. beforeEach (done)->
  232. @handler._buildTemplate "main.tex", @user_id, projectName, (err, templateLines)=>
  233. @template = templateLines.reduce (singleLine, line)-> "#{singleLine}\n#{line}"
  234. done()
  235. it "should insert the project name into the template", (done)->
  236. @template.indexOf(projectName).should.not.equal -1
  237. done()
  238. it "should insert the users name into the template", (done)->
  239. @template.indexOf(@user.first_name).should.not.equal -1
  240. @template.indexOf(@user.last_name).should.not.equal -1
  241. done()
  242. it "should not have undefined in the template", (done)->
  243. @template.indexOf("undefined").should.equal -1
  244. done()
  245. it "should not have any underscore brackets in the output", (done)->
  246. @template.indexOf("{{").should.equal -1
  247. @template.indexOf("<%=").should.equal -1
  248. done()
  249. it "should put the year in", (done)->
  250. @template.indexOf(new Date().getUTCFullYear()).should.not.equal -1
  251. done()
  252. describe "_createRootDoc", ->
  253. beforeEach (done)->
  254. @project = new @ProjectModel()
  255. @handler._createRootDoc @project, ownerId, ["line 1", "line 2"], done
  256. it 'should insert main.tex', ->
  257. @ProjectEntityUpdateHandler.addDoc
  258. .calledWith(project_id, rootFolderId, "main.tex", ["line 1", "line 2"], ownerId)
  259. .should.equal true
  260. it 'should set the main doc id', ->
  261. @ProjectEntityUpdateHandler.setRootDoc.calledWith(project_id, docId).should.equal true