ReferencesHandlerTests.mjs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. // TODO: This file was created by bulk-decaffeinate.
  2. // Fix any style issues and re-enable lint.
  3. /*
  4. * decaffeinate suggestions:
  5. * DS102: Remove unnecessary code created because of implicit returns
  6. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  7. */
  8. import esmock from 'esmock'
  9. import { expect } from 'chai'
  10. import sinon from 'sinon'
  11. import Errors from '../../../../app/src/Features/Errors/Errors.js'
  12. const modulePath =
  13. '../../../../app/src/Features/References/ReferencesHandler.mjs'
  14. describe('ReferencesHandler', function () {
  15. beforeEach(async function () {
  16. this.projectId = '222'
  17. this.fakeProject = {
  18. _id: this.projectId,
  19. owner_ref: (this.fakeOwner = {
  20. _id: 'some_owner',
  21. features: {
  22. references: false,
  23. },
  24. }),
  25. rootFolder: [
  26. {
  27. docs: [
  28. { name: 'one.bib', _id: 'aaa' },
  29. { name: 'two.txt', _id: 'bbb' },
  30. ],
  31. folders: [
  32. {
  33. docs: [{ name: 'three.bib', _id: 'ccc' }],
  34. fileRefs: [{ name: 'four.bib', _id: 'ghg' }],
  35. folders: [],
  36. },
  37. ],
  38. },
  39. ],
  40. }
  41. this.docIds = ['aaa', 'ccc']
  42. this.handler = await esmock.strict(modulePath, {
  43. '@overleaf/settings': (this.settings = {
  44. apis: {
  45. references: { url: 'http://some.url/references' },
  46. docstore: { url: 'http://some.url/docstore' },
  47. filestore: { url: 'http://some.url/filestore' },
  48. },
  49. }),
  50. request: (this.request = {
  51. get: sinon.stub(),
  52. post: sinon.stub(),
  53. }),
  54. '../../../../app/src/Features/Project/ProjectGetter':
  55. (this.ProjectGetter = {
  56. getProject: sinon.stub().callsArgWith(2, null, this.fakeProject),
  57. }),
  58. '../../../../app/src/Features/User/UserGetter': (this.UserGetter = {
  59. getUser: sinon.stub(),
  60. }),
  61. '../../../../app/src/Features/DocumentUpdater/DocumentUpdaterHandler':
  62. (this.DocumentUpdaterHandler = {
  63. flushDocToMongo: sinon.stub().callsArgWith(2, null),
  64. }),
  65. '../../../../app/src/infrastructure/Features': (this.Features = {
  66. hasFeature: sinon.stub().returns(true),
  67. }),
  68. })
  69. this.fakeResponseData = {
  70. projectId: this.projectId,
  71. keys: ['k1', 'k2'],
  72. }
  73. })
  74. describe('indexAll', function () {
  75. beforeEach(function () {
  76. sinon.stub(this.handler, '_findBibDocIds').returns(['aaa', 'ccc'])
  77. sinon.stub(this.handler, '_findBibFileIds').returns(['fff', 'ggg'])
  78. sinon.stub(this.handler, '_isFullIndex').callsArgWith(1, null, true)
  79. this.request.post.callsArgWith(
  80. 1,
  81. null,
  82. { statusCode: 200 },
  83. this.fakeResponseData
  84. )
  85. return (this.call = callback => {
  86. return this.handler.indexAll(this.projectId, callback)
  87. })
  88. })
  89. it('should call _findBibDocIds', function (done) {
  90. return this.call((err, data) => {
  91. expect(err).to.be.null
  92. this.handler._findBibDocIds.callCount.should.equal(1)
  93. this.handler._findBibDocIds
  94. .calledWith(this.fakeProject)
  95. .should.equal(true)
  96. return done()
  97. })
  98. })
  99. it('should call _findBibFileIds', function (done) {
  100. return this.call((err, data) => {
  101. expect(err).to.be.null
  102. this.handler._findBibDocIds.callCount.should.equal(1)
  103. this.handler._findBibDocIds
  104. .calledWith(this.fakeProject)
  105. .should.equal(true)
  106. return done()
  107. })
  108. })
  109. it('should call DocumentUpdaterHandler.flushDocToMongo', function (done) {
  110. return this.call((err, data) => {
  111. expect(err).to.be.null
  112. this.DocumentUpdaterHandler.flushDocToMongo.callCount.should.equal(2)
  113. return done()
  114. })
  115. })
  116. it('should make a request to references service', function (done) {
  117. return this.call((err, data) => {
  118. expect(err).to.be.null
  119. this.request.post.callCount.should.equal(1)
  120. const arg = this.request.post.firstCall.args[0]
  121. expect(arg.json).to.have.all.keys('docUrls', 'fullIndex')
  122. expect(arg.json.docUrls.length).to.equal(4)
  123. expect(arg.json.fullIndex).to.equal(true)
  124. return done()
  125. })
  126. })
  127. it('should not produce an error', function (done) {
  128. return this.call((err, data) => {
  129. expect(err).to.equal(null)
  130. return done()
  131. })
  132. })
  133. it('should return data', function (done) {
  134. return this.call((err, data) => {
  135. expect(err).to.be.null
  136. expect(data).to.not.equal(null)
  137. expect(data).to.not.equal(undefined)
  138. expect(data).to.equal(this.fakeResponseData)
  139. return done()
  140. })
  141. })
  142. describe('when ProjectGetter.getProject produces an error', function () {
  143. beforeEach(function () {
  144. return this.ProjectGetter.getProject.callsArgWith(2, new Error('woops'))
  145. })
  146. it('should produce an error', function (done) {
  147. return this.call((err, data) => {
  148. expect(err).to.not.equal(null)
  149. expect(err).to.be.instanceof(Error)
  150. expect(data).to.equal(undefined)
  151. return done()
  152. })
  153. })
  154. it('should not send request', function (done) {
  155. return this.call(() => {
  156. this.request.post.callCount.should.equal(0)
  157. return done()
  158. })
  159. })
  160. })
  161. describe('when ProjectGetter.getProject returns null', function () {
  162. beforeEach(function () {
  163. return this.ProjectGetter.getProject.callsArgWith(2, null)
  164. })
  165. it('should produce an error', function (done) {
  166. return this.call((err, data) => {
  167. expect(err).to.not.equal(null)
  168. expect(err).to.be.instanceof(Errors.NotFoundError)
  169. expect(data).to.equal(undefined)
  170. return done()
  171. })
  172. })
  173. it('should not send request', function (done) {
  174. return this.call(() => {
  175. this.request.post.callCount.should.equal(0)
  176. return done()
  177. })
  178. })
  179. })
  180. describe('when _isFullIndex produces an error', function () {
  181. beforeEach(function () {
  182. this.ProjectGetter.getProject.callsArgWith(2, null, this.fakeProject)
  183. return this.handler._isFullIndex.callsArgWith(1, new Error('woops'))
  184. })
  185. it('should produce an error', function (done) {
  186. return this.call((err, data) => {
  187. expect(err).to.not.equal(null)
  188. expect(err).to.be.instanceof(Error)
  189. expect(data).to.equal(undefined)
  190. return done()
  191. })
  192. })
  193. it('should not send request', function (done) {
  194. return this.call(() => {
  195. this.request.post.callCount.should.equal(0)
  196. return done()
  197. })
  198. })
  199. })
  200. describe('when flushDocToMongo produces an error', function () {
  201. beforeEach(function () {
  202. this.ProjectGetter.getProject.callsArgWith(2, null, this.fakeProject)
  203. this.handler._isFullIndex.callsArgWith(1, false)
  204. return this.DocumentUpdaterHandler.flushDocToMongo.callsArgWith(
  205. 2,
  206. new Error('woops')
  207. )
  208. })
  209. it('should produce an error', function (done) {
  210. return this.call((err, data) => {
  211. expect(err).to.not.equal(null)
  212. expect(err).to.be.instanceof(Error)
  213. expect(data).to.equal(undefined)
  214. return done()
  215. })
  216. })
  217. it('should not send request', function (done) {
  218. return this.call(() => {
  219. this.request.post.callCount.should.equal(0)
  220. return done()
  221. })
  222. })
  223. })
  224. })
  225. describe('_findBibDocIds', function () {
  226. beforeEach(function () {
  227. this.fakeProject = {
  228. rootFolder: [
  229. {
  230. docs: [
  231. { name: 'one.bib', _id: 'aaa' },
  232. { name: 'two.txt', _id: 'bbb' },
  233. ],
  234. folders: [
  235. { docs: [{ name: 'three.bib', _id: 'ccc' }], folders: [] },
  236. ],
  237. },
  238. ],
  239. }
  240. return (this.expectedIds = ['aaa', 'ccc'])
  241. })
  242. it('should select the correct docIds', function () {
  243. const result = this.handler._findBibDocIds(this.fakeProject)
  244. return expect(result).to.deep.equal(this.expectedIds)
  245. })
  246. it('should not error with a non array of folders from dirty data', function () {
  247. this.fakeProject.rootFolder[0].folders[0].folders = {}
  248. const result = this.handler._findBibDocIds(this.fakeProject)
  249. return expect(result).to.deep.equal(this.expectedIds)
  250. })
  251. })
  252. describe('_findBibFileIds', function () {
  253. beforeEach(function () {
  254. this.fakeProject = {
  255. rootFolder: [
  256. {
  257. docs: [
  258. { name: 'one.bib', _id: 'aaa' },
  259. { name: 'two.txt', _id: 'bbb' },
  260. ],
  261. fileRefs: [{ name: 'other.bib', _id: 'ddd' }],
  262. folders: [
  263. {
  264. docs: [{ name: 'three.bib', _id: 'ccc' }],
  265. fileRefs: [{ name: 'four.bib', _id: 'ghg' }],
  266. folders: [],
  267. },
  268. ],
  269. },
  270. ],
  271. }
  272. return (this.expectedIds = ['ddd', 'ghg'])
  273. })
  274. it('should select the correct docIds', function () {
  275. const result = this.handler._findBibFileIds(this.fakeProject)
  276. return expect(result).to.deep.equal(this.expectedIds)
  277. })
  278. })
  279. describe('_isFullIndex', function () {
  280. beforeEach(function () {
  281. this.fakeProject = { owner_ref: (this.owner_ref = 'owner-ref-123') }
  282. this.owner = {
  283. features: {
  284. references: false,
  285. },
  286. }
  287. this.UserGetter.getUser = sinon.stub()
  288. this.UserGetter.getUser
  289. .withArgs(this.owner_ref, { features: true })
  290. .yields(null, this.owner)
  291. return (this.call = callback => {
  292. return this.handler._isFullIndex(this.fakeProject, callback)
  293. })
  294. })
  295. describe('with references feature on', function () {
  296. beforeEach(function () {
  297. return (this.owner.features.references = true)
  298. })
  299. it('should return true', function () {
  300. return this.call((err, isFullIndex) => {
  301. expect(err).to.equal(null)
  302. return expect(isFullIndex).to.equal(true)
  303. })
  304. })
  305. })
  306. describe('with references feature off', function () {
  307. beforeEach(function () {
  308. return (this.owner.features.references = false)
  309. })
  310. it('should return false', function () {
  311. return this.call((err, isFullIndex) => {
  312. expect(err).to.equal(null)
  313. return expect(isFullIndex).to.equal(false)
  314. })
  315. })
  316. })
  317. describe('with referencesSearch', function () {
  318. beforeEach(function () {
  319. return (this.owner.features = {
  320. referencesSearch: true,
  321. references: false,
  322. })
  323. })
  324. it('should return true', function () {
  325. return this.call((err, isFullIndex) => {
  326. expect(err).to.equal(null)
  327. return expect(isFullIndex).to.equal(true)
  328. })
  329. })
  330. })
  331. })
  332. })