ChatControllerTests.js 6.8 KB

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