ChatControllerTests.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /* eslint-disable
  2. camelcase,
  3. n/handle-callback-err,
  4. max-len,
  5. no-return-assign,
  6. no-unused-vars,
  7. */
  8. // TODO: This file was created by bulk-decaffeinate.
  9. // Fix any style issues and re-enable lint.
  10. /*
  11. * decaffeinate suggestions:
  12. * DS102: Remove unnecessary code created because of implicit returns
  13. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  14. */
  15. const SandboxedModule = require('sandboxed-module')
  16. const assert = require('assert')
  17. const path = require('path')
  18. const sinon = require('sinon')
  19. const modulePath = path.join(
  20. __dirname,
  21. '../../../../app/src/Features/Chat/ChatController'
  22. )
  23. const { expect } = require('chai')
  24. describe('ChatController', function () {
  25. beforeEach(function () {
  26. this.user_id = 'mock-user-id'
  27. this.settings = {}
  28. this.ChatApiHandler = {}
  29. this.EditorRealTimeController = { emitToRoom: sinon.stub() }
  30. this.SessionManager = {
  31. getLoggedInUserId: sinon.stub().returns(this.user_id),
  32. }
  33. this.ChatController = SandboxedModule.require(modulePath, {
  34. requires: {
  35. '@overleaf/settings': this.settings,
  36. './ChatApiHandler': this.ChatApiHandler,
  37. '../Editor/EditorRealTimeController': this.EditorRealTimeController,
  38. '../Authentication/SessionManager': this.SessionManager,
  39. '../User/UserInfoManager': (this.UserInfoManager = {}),
  40. '../User/UserInfoController': (this.UserInfoController = {}),
  41. },
  42. })
  43. this.req = {
  44. params: {
  45. project_id: this.project_id,
  46. },
  47. }
  48. this.res = {
  49. json: sinon.stub(),
  50. send: sinon.stub(),
  51. sendStatus: sinon.stub(),
  52. }
  53. })
  54. describe('sendMessage', function () {
  55. beforeEach(function () {
  56. this.req.body = { content: (this.content = 'message-content') }
  57. this.UserInfoManager.getPersonalInfo = sinon
  58. .stub()
  59. .yields(null, (this.user = { unformatted: 'user' }))
  60. this.UserInfoController.formatPersonalInfo = sinon
  61. .stub()
  62. .returns((this.formatted_user = { formatted: 'user' }))
  63. this.ChatApiHandler.sendGlobalMessage = sinon
  64. .stub()
  65. .yields(
  66. null,
  67. (this.message = { mock: 'message', user_id: this.user_id })
  68. )
  69. return this.ChatController.sendMessage(this.req, this.res)
  70. })
  71. it('should look up the user', function () {
  72. return this.UserInfoManager.getPersonalInfo
  73. .calledWith(this.user_id)
  74. .should.equal(true)
  75. })
  76. it('should format and inject the user into the message', function () {
  77. this.UserInfoController.formatPersonalInfo
  78. .calledWith(this.user)
  79. .should.equal(true)
  80. return this.message.user.should.deep.equal(this.formatted_user)
  81. })
  82. it('should tell the chat handler about the message', function () {
  83. return this.ChatApiHandler.sendGlobalMessage
  84. .calledWith(this.project_id, this.user_id, this.content)
  85. .should.equal(true)
  86. })
  87. it('should tell the editor real time controller about the update with the data from the chat handler', function () {
  88. return this.EditorRealTimeController.emitToRoom
  89. .calledWith(this.project_id, 'new-chat-message', this.message)
  90. .should.equal(true)
  91. })
  92. it('should return a 204 status code', function () {
  93. return this.res.sendStatus.calledWith(204).should.equal(true)
  94. })
  95. })
  96. describe('getMessages', function () {
  97. beforeEach(function () {
  98. this.req.query = {
  99. limit: (this.limit = '30'),
  100. before: (this.before = '12345'),
  101. }
  102. this.ChatController._injectUserInfoIntoThreads = sinon.stub().yields()
  103. this.ChatApiHandler.getGlobalMessages = sinon
  104. .stub()
  105. .yields(null, (this.messages = ['mock', 'messages']))
  106. return this.ChatController.getMessages(this.req, this.res)
  107. })
  108. it('should ask the chat handler about the request', function () {
  109. return this.ChatApiHandler.getGlobalMessages
  110. .calledWith(this.project_id, this.limit, this.before)
  111. .should.equal(true)
  112. })
  113. it('should return the messages', function () {
  114. return this.res.json.calledWith(this.messages).should.equal(true)
  115. })
  116. })
  117. describe('_injectUserInfoIntoThreads', function () {
  118. beforeEach(function () {
  119. this.users = {
  120. user_id_1: {
  121. mock: 'user_1',
  122. },
  123. user_id_2: {
  124. mock: 'user_2',
  125. },
  126. }
  127. this.UserInfoManager.getPersonalInfo = (user_id, callback) => {
  128. return callback(null, this.users[user_id])
  129. }
  130. sinon.spy(this.UserInfoManager, 'getPersonalInfo')
  131. return (this.UserInfoController.formatPersonalInfo = user => ({
  132. formatted: user.mock,
  133. }))
  134. })
  135. it('should inject a user object into messaged and resolved data', function (done) {
  136. return this.ChatController._injectUserInfoIntoThreads(
  137. {
  138. thread1: {
  139. resolved: true,
  140. resolved_by_user_id: 'user_id_1',
  141. messages: [
  142. {
  143. user_id: 'user_id_1',
  144. content: 'foo',
  145. },
  146. {
  147. user_id: 'user_id_2',
  148. content: 'bar',
  149. },
  150. ],
  151. },
  152. thread2: {
  153. messages: [
  154. {
  155. user_id: 'user_id_1',
  156. content: 'baz',
  157. },
  158. ],
  159. },
  160. },
  161. (error, threads) => {
  162. expect(threads).to.deep.equal({
  163. thread1: {
  164. resolved: true,
  165. resolved_by_user_id: 'user_id_1',
  166. resolved_by_user: { formatted: 'user_1' },
  167. messages: [
  168. {
  169. user_id: 'user_id_1',
  170. user: { formatted: 'user_1' },
  171. content: 'foo',
  172. },
  173. {
  174. user_id: 'user_id_2',
  175. user: { formatted: 'user_2' },
  176. content: 'bar',
  177. },
  178. ],
  179. },
  180. thread2: {
  181. messages: [
  182. {
  183. user_id: 'user_id_1',
  184. user: { formatted: 'user_1' },
  185. content: 'baz',
  186. },
  187. ],
  188. },
  189. })
  190. return done()
  191. }
  192. )
  193. })
  194. it('should only need to look up each user once', function (done) {
  195. return this.ChatController._injectUserInfoIntoThreads(
  196. [
  197. {
  198. messages: [
  199. {
  200. user_id: 'user_id_1',
  201. content: 'foo',
  202. },
  203. {
  204. user_id: 'user_id_1',
  205. content: 'bar',
  206. },
  207. ],
  208. },
  209. ],
  210. (error, threads) => {
  211. this.UserInfoManager.getPersonalInfo.calledOnce.should.equal(true)
  212. return done()
  213. }
  214. )
  215. })
  216. })
  217. })