HistoryV2ManagerTests.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  4. no-undef,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  12. */
  13. define(['ide/history/HistoryV2Manager'], HistoryV2Manager =>
  14. describe('HistoryV2Manager', function() {
  15. beforeEach(function(done) {
  16. this.defaultHistoryScope = {
  17. isV2: true,
  18. updates: [],
  19. viewMode: 'point_in_time',
  20. nextBeforeTimestamp: null,
  21. atEnd: false,
  22. userHasFullFeature: undefined,
  23. freeHistoryLimitHit: false,
  24. selection: {
  25. docs: {},
  26. pathname: null,
  27. range: {
  28. fromV: null,
  29. toV: null
  30. },
  31. hoveredRange: {
  32. fromV: null,
  33. toV: null
  34. },
  35. diff: null,
  36. files: [],
  37. file: null
  38. },
  39. error: null,
  40. showOnlyLabels: false,
  41. labels: null,
  42. loadingFileTree: true
  43. }
  44. this.sampleUpdates = [
  45. {
  46. fromV: 4,
  47. toV: 5,
  48. meta: {
  49. users: [
  50. {
  51. first_name: 'john.doe',
  52. last_name: '',
  53. email: 'john.doe@domain.tld',
  54. id: '5b57299087712202fb599ab4',
  55. hue: 200
  56. }
  57. ],
  58. start_ts: 1544021278346,
  59. end_ts: 1544021278346
  60. },
  61. labels: [
  62. {
  63. id: '5c07e822042e67003b448f18',
  64. comment: 'My first label',
  65. version: 5,
  66. user_id: '5b57299087712202fb599ab4',
  67. created_at: '2018-12-05T15:00:50.688Z'
  68. }
  69. ],
  70. pathnames: [],
  71. project_ops: [
  72. {
  73. add: {
  74. pathname: 'chapters/chapter1.tex'
  75. },
  76. atV: 4
  77. }
  78. ]
  79. },
  80. {
  81. fromV: 3,
  82. toV: 4,
  83. meta: {
  84. users: [
  85. {
  86. first_name: 'john.doe',
  87. last_name: '',
  88. email: 'john.doe@domain.tld',
  89. id: '5b57299087712202fb599ab4',
  90. hue: 200
  91. }
  92. ],
  93. start_ts: 1544021262622,
  94. end_ts: 1544021262622
  95. },
  96. labels: [],
  97. pathnames: ['main.tex'],
  98. project_ops: []
  99. },
  100. {
  101. fromV: 0,
  102. toV: 3,
  103. meta: {
  104. users: [
  105. {
  106. first_name: 'john.doe',
  107. last_name: '',
  108. email: 'john.doe@domain.tld',
  109. id: '5b57299087712202fb599ab4',
  110. hue: 200
  111. }
  112. ],
  113. start_ts: 1544021213540,
  114. end_ts: 1544021213618
  115. },
  116. labels: [],
  117. pathnames: [],
  118. project_ops: [
  119. {
  120. add: {
  121. pathname: 'universe.jpg'
  122. },
  123. atV: 2
  124. },
  125. {
  126. add: {
  127. pathname: 'references.bib'
  128. },
  129. atV: 1
  130. },
  131. {
  132. add: {
  133. pathname: 'main.tex'
  134. },
  135. atV: 0
  136. }
  137. ]
  138. }
  139. ]
  140. inject(($q, $http, $rootScope) => {
  141. this.$scope = $rootScope.$new()
  142. this.$scope.project = {
  143. features: {
  144. versioning: true
  145. }
  146. }
  147. this.$scope.user = {
  148. isAdmin: false
  149. }
  150. this.ide = {
  151. $q: $q,
  152. $http: $http
  153. }
  154. this.localStorage = sinon.stub().returns(null)
  155. this.historyManager = new HistoryV2Manager(
  156. this.ide,
  157. this.$scope,
  158. this.localStorage
  159. )
  160. done()
  161. })
  162. })
  163. it('should setup the history scope on initialization', function() {
  164. expect(this.$scope.history).to.deep.equal(this.defaultHistoryScope)
  165. })
  166. it('should keep history updates after performing a soft reset', function() {
  167. let historyScopeWithUpdates = Object.assign(
  168. {},
  169. this.defaultHistoryScope,
  170. {
  171. updates: this.sampleUpdates
  172. }
  173. )
  174. this.$scope.history.updates = this.sampleUpdates
  175. this.historyManager.softReset()
  176. expect(this.$scope.history).to.deep.equal(historyScopeWithUpdates)
  177. })
  178. it('should discard history updates after performing a hard reset', function() {
  179. this.$scope.history.updates = this.sampleUpdates
  180. this.historyManager.hardReset()
  181. expect(this.$scope.history).to.deep.equal(this.defaultHistoryScope)
  182. })
  183. it('should setup history with full access to the feature if the project has versioning', function() {
  184. this.$scope.$digest()
  185. expect(this.$scope.history.userHasFullFeature).to.equal(true)
  186. })
  187. it('should setup history without full access to the feature if the project does not have versioning', function() {
  188. this.$scope.project.features.versioning = false
  189. this.historyManager = new HistoryV2Manager(
  190. this.ide,
  191. this.$scope,
  192. this.localStorage
  193. )
  194. this.$scope.$digest()
  195. expect(this.$scope.history.userHasFullFeature).to.equal(false)
  196. })
  197. it('should setup history with full access to the feature for admin users even if the project does not have versioning', function() {
  198. this.$scope.project.features.versioning = false
  199. this.$scope.user.isAdmin = true
  200. this.historyManager = new HistoryV2Manager(
  201. this.ide,
  202. this.$scope,
  203. this.localStorage
  204. )
  205. this.$scope.$digest()
  206. expect(this.$scope.history.userHasFullFeature).to.equal(true)
  207. })
  208. describe('autoSelectFile', function() {
  209. describe('for compare mode', function() {
  210. beforeEach(function() {
  211. this.mockedFilesList = [
  212. {
  213. pathname: 'main.tex'
  214. },
  215. {
  216. pathname: 'references.bib'
  217. },
  218. {
  219. pathname: 'universe.jpg'
  220. },
  221. {
  222. pathname: 'chapters/chapter2.tex'
  223. },
  224. {
  225. pathname: 'chapters/draft.tex',
  226. operation: 'removed',
  227. deletedAtV: 47
  228. },
  229. {
  230. pathname: 'chapters/chapter3.tex',
  231. operation: 'added'
  232. },
  233. {
  234. pathname: 'chapters/chapter1.tex',
  235. operation: 'edited'
  236. },
  237. {
  238. pathname: 'chapters/foo.tex',
  239. oldPathname: 'chapters/bar.tex',
  240. operation: 'renamed'
  241. }
  242. ]
  243. this.mockedMainTex = this.mockedFilesList[0]
  244. this.mockedReferencesFile = this.mockedFilesList[1]
  245. this.mockedRemovedFile = this.mockedFilesList[4]
  246. this.mockedAddedFile = this.mockedFilesList[5]
  247. this.mockedEditedFile = this.mockedFilesList[6]
  248. this.mockedRenamedFile = this.mockedFilesList[7]
  249. this.$scope.history.viewMode = 'compare'
  250. this.$scope.history.selection.files = this.mockedFilesList
  251. })
  252. describe('with a previously selected file', function() {
  253. it('should prefer the previously selected file if it is available and has operations', function() {
  254. this.historyManager._previouslySelectedPathname = this.mockedAddedFile.pathname
  255. this.historyManager.autoSelectFile()
  256. expect(this.$scope.history.selection.file).to.deep.equal(
  257. this.mockedAddedFile
  258. )
  259. })
  260. it('should prefer a file with ops if the previously selected file is available but has no operations', function() {
  261. this.historyManager._previouslySelectedPathname = this.mockedReferencesFile.pathname
  262. this.historyManager.autoSelectFile()
  263. expect(this.$scope.history.selection.file.operation).to.exist
  264. })
  265. it('should ignore the previously selected file if it is not available', function() {
  266. this.historyManager._previouslySelectedPathname =
  267. 'non/existent.file'
  268. this.historyManager.autoSelectFile()
  269. expect(this.$scope.history.selection.file.pathname).to.not.equal(
  270. 'non/existent.file'
  271. )
  272. })
  273. })
  274. describe('without a previously selected file, with a list of files containing operations', function() {
  275. it('should prefer edited files', function() {
  276. this.historyManager.autoSelectFile()
  277. expect(this.$scope.history.selection.file).to.deep.equal(
  278. this.mockedEditedFile
  279. )
  280. })
  281. it('should prefer added files if no edited files are present', function() {
  282. const indexOfEditedFile = this.$scope.history.selection.files.indexOf(
  283. this.mockedEditedFile
  284. )
  285. this.$scope.history.selection.files.splice(indexOfEditedFile, 1)
  286. this.historyManager.autoSelectFile()
  287. expect(this.$scope.history.selection.file).to.deep.equal(
  288. this.mockedAddedFile
  289. )
  290. })
  291. it('should prefer renamed files if no edited or added files are present', function() {
  292. const indexOfEditedFile = this.$scope.history.selection.files.indexOf(
  293. this.mockedEditedFile
  294. )
  295. this.$scope.history.selection.files.splice(indexOfEditedFile, 1)
  296. const indexOfAddedFile = this.$scope.history.selection.files.indexOf(
  297. this.mockedAddedFile
  298. )
  299. this.$scope.history.selection.files.splice(indexOfAddedFile, 1)
  300. this.historyManager.autoSelectFile()
  301. expect(this.$scope.history.selection.file).to.deep.equal(
  302. this.mockedRenamedFile
  303. )
  304. })
  305. it('should prefer removed files if no edited, added or renamed files are present', function() {
  306. const indexOfEditedFile = this.$scope.history.selection.files.indexOf(
  307. this.mockedEditedFile
  308. )
  309. this.$scope.history.selection.files.splice(indexOfEditedFile, 1)
  310. const indexOfAddedFile = this.$scope.history.selection.files.indexOf(
  311. this.mockedAddedFile
  312. )
  313. this.$scope.history.selection.files.splice(indexOfAddedFile, 1)
  314. const indexOfRenamedFile = this.$scope.history.selection.files.indexOf(
  315. this.mockedRenamedFile
  316. )
  317. this.$scope.history.selection.files.splice(indexOfRenamedFile, 1)
  318. this.historyManager.autoSelectFile()
  319. expect(this.$scope.history.selection.file).to.deep.equal(
  320. this.mockedRemovedFile
  321. )
  322. })
  323. })
  324. describe('without a previously selected file, with a list of files without operations', function() {
  325. beforeEach(function() {
  326. this.mockedFilesListWithNoOps = [
  327. {
  328. pathname: 'main.tex'
  329. },
  330. {
  331. pathname: 'references.bib'
  332. },
  333. {
  334. pathname: 'other.tex'
  335. },
  336. {
  337. pathname: 'universe.jpg'
  338. }
  339. ]
  340. this.mockedMainTex = this.mockedFilesListWithNoOps[0]
  341. this.mockedReferencesFile = this.mockedFilesListWithNoOps[1]
  342. this.mockedOtherTexFile = this.mockedFilesListWithNoOps[2]
  343. this.$scope.history.selection.files = this.mockedFilesListWithNoOps
  344. })
  345. it('should prefer main.tex if it exists', function() {
  346. this.historyManager.autoSelectFile()
  347. expect(this.$scope.history.selection.file).to.deep.equal(
  348. this.mockedMainTex
  349. )
  350. })
  351. it('should prefer another tex file if main.tex does not exist', function() {
  352. const indexOfMainTex = this.$scope.history.selection.files.indexOf(
  353. this.mockedMainTex
  354. )
  355. this.$scope.history.selection.files.splice(indexOfMainTex, 1)
  356. this.historyManager.autoSelectFile()
  357. expect(this.$scope.history.selection.file).to.deep.equal(
  358. this.mockedOtherTexFile
  359. )
  360. })
  361. it('should pick the first available file if no tex files are available', function() {
  362. const indexOfMainTex = this.$scope.history.selection.files.indexOf(
  363. this.mockedMainTex
  364. )
  365. this.$scope.history.selection.files.splice(indexOfMainTex, 1)
  366. const indexOfOtherTexFile = this.$scope.history.selection.files.indexOf(
  367. this.mockedOtherTexFile
  368. )
  369. this.$scope.history.selection.files.splice(indexOfOtherTexFile, 1)
  370. this.historyManager.autoSelectFile()
  371. expect(this.$scope.history.selection.file).to.deep.equal(
  372. this.mockedReferencesFile
  373. )
  374. })
  375. })
  376. })
  377. describe('for point-in-time mode', function() {
  378. beforeEach(function() {
  379. this.$scope.history.viewMode = 'point_in_time'
  380. this.sampleUpdates[0] = {
  381. fromV: 4,
  382. toV: 5,
  383. meta: {
  384. users: [
  385. {
  386. first_name: 'john.doe',
  387. last_name: '',
  388. email: 'john.doe@domain.tld',
  389. id: '5b57299087712202fb599ab4',
  390. hue: 200
  391. }
  392. ],
  393. start_ts: 1544021278346,
  394. end_ts: 1544021278346
  395. },
  396. pathnames: ['main.tex'],
  397. project_ops: [
  398. {
  399. add: {
  400. pathname: 'chapters/chapter1.tex'
  401. },
  402. atV: 4
  403. },
  404. {
  405. rename: {
  406. pathname: 'foo.tex',
  407. newPathname: 'bar.tex'
  408. }
  409. }
  410. ]
  411. }
  412. this.sampleUpdateEditedFile = this.sampleUpdates[0].pathnames[0]
  413. this.sampleUpdateAddedFile = this.sampleUpdates[0].project_ops[0].add.pathname
  414. this.sampleUpdateRenamedFile = this.sampleUpdates[0].project_ops[1].rename.newPathname
  415. this.$scope.history.updates = this.sampleUpdates
  416. this.$scope.history.selection.range = {
  417. fromV: this.sampleUpdates[0].toV,
  418. toV: this.sampleUpdates[0].toV
  419. }
  420. this.mockedFilesList = [
  421. {
  422. pathname: 'main.tex'
  423. },
  424. {
  425. pathname: 'references.bib'
  426. },
  427. {
  428. pathname: 'universe.jpg'
  429. },
  430. {
  431. pathname: 'chapters/chapter2.tex'
  432. },
  433. {
  434. pathname: 'chapters/draft.tex'
  435. },
  436. {
  437. pathname: 'chapters/chapter3.tex'
  438. },
  439. {
  440. pathname: 'chapters/chapter1.tex'
  441. },
  442. {
  443. pathname: 'bar.tex'
  444. }
  445. ]
  446. this.$scope.history.selection.files = this.mockedFilesList
  447. })
  448. describe('with a previously selected file', function() {
  449. it('should prefer the previously selected file if it is available and has operations', function() {
  450. this.historyManager._previouslySelectedPathname = 'main.tex'
  451. this.historyManager.autoSelectFile()
  452. expect(this.$scope.history.selection.file.pathname).to.equal(
  453. this.sampleUpdateEditedFile
  454. )
  455. })
  456. it('should prefer a file with ops if the previously selected file is available but has no operations', function() {
  457. this.historyManager._previouslySelectedPathname = 'main.tex'
  458. this.sampleUpdates[0].pathnames = []
  459. this.historyManager.autoSelectFile()
  460. expect(this.$scope.history.selection.file.pathname).to.equal(
  461. this.sampleUpdateAddedFile
  462. )
  463. })
  464. it('should ignore the previously selected file if it is not available', function() {
  465. this.historyManager._previouslySelectedPathname =
  466. 'non/existent.file'
  467. this.historyManager.autoSelectFile()
  468. expect(this.$scope.history.selection.file.pathname).to.not.equal(
  469. 'non/existent.file'
  470. )
  471. })
  472. })
  473. describe('without a previously selected file, with a list of files containing operations', function() {
  474. it('should prefer edited files', function() {
  475. this.historyManager.autoSelectFile()
  476. expect(this.$scope.history.selection.file.pathname).to.equal(
  477. this.sampleUpdateEditedFile
  478. )
  479. })
  480. it('should prefer added files if no edited files are present', function() {
  481. this.sampleUpdates[0].pathnames = []
  482. this.historyManager.autoSelectFile()
  483. expect(this.$scope.history.selection.file.pathname).to.equal(
  484. this.sampleUpdateAddedFile
  485. )
  486. })
  487. it('should prefer renamed files if no edited or added files are present', function() {
  488. this.sampleUpdates[0].pathnames = []
  489. this.sampleUpdates[0].project_ops.shift()
  490. this.historyManager.autoSelectFile()
  491. expect(this.$scope.history.selection.file.pathname).to.equal(
  492. this.sampleUpdateRenamedFile
  493. )
  494. })
  495. })
  496. describe('without a previously selected file, with a list of files without operations', function() {
  497. beforeEach(function() {
  498. this.sampleUpdates[0].pathnames = []
  499. this.sampleUpdates[0].project_ops = []
  500. this.mockedMainTex = this.mockedFilesList[0]
  501. this.mockedReferencesFile = this.mockedFilesList[1]
  502. })
  503. it('should prefer main.tex if it exists', function() {
  504. this.historyManager.autoSelectFile()
  505. expect(this.$scope.history.selection.file.pathname).to.equal(
  506. this.mockedMainTex.pathname
  507. )
  508. })
  509. it('should prefer another tex file if main.tex does not exist', function() {
  510. const indexOfMainTex = this.$scope.history.selection.files.indexOf(
  511. this.mockedMainTex
  512. )
  513. this.$scope.history.selection.files.splice(indexOfMainTex, 1)
  514. this.historyManager.autoSelectFile()
  515. expect(this.$scope.history.selection.file.pathname).to.match(
  516. /.tex$/
  517. )
  518. })
  519. })
  520. })
  521. })
  522. }))