auto-select-file.test.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. import { expect } from 'chai'
  2. import type { HistoryContextValue } from '../../../../../frontend/js/features/history/context/types/history-context-value'
  3. import type { FileDiff } from '../../../../../frontend/js/features/history/services/types/file'
  4. import { autoSelectFile } from '../../../../../frontend/js/features/history/utils/auto-select-file'
  5. import type { User } from '../../../../../frontend/js/features/history/services/types/shared'
  6. describe('autoSelectFile', function () {
  7. const historyUsers: User[] = [
  8. {
  9. first_name: 'first_name',
  10. last_name: 'last_name',
  11. email: 'email@overleaf.com',
  12. id: '6266xb6b7a366460a66186xx',
  13. },
  14. ]
  15. const emptySelection: HistoryContextValue['selection'] = {
  16. docs: {},
  17. pathname: null,
  18. range: {
  19. fromV: null,
  20. toV: null,
  21. },
  22. hoveredRange: {
  23. fromV: null,
  24. toV: null,
  25. },
  26. diff: null,
  27. files: [],
  28. file: null,
  29. }
  30. describe('for `point_in_time` view mode', function () {
  31. const viewMode: HistoryContextValue['viewMode'] = 'point_in_time'
  32. it('return the file with `edited` as the last operation', function () {
  33. const files: FileDiff[] = [
  34. {
  35. pathname: 'main.tex',
  36. },
  37. {
  38. pathname: 'sample.bib',
  39. },
  40. {
  41. pathname: 'frog.jpg',
  42. },
  43. {
  44. pathname: 'newfile5.tex',
  45. },
  46. {
  47. pathname: 'newfolder1/newfolder2/newfile2.tex',
  48. },
  49. {
  50. pathname: 'newfolder1/newfile10.tex',
  51. operation: 'edited',
  52. },
  53. ]
  54. const selection: HistoryContextValue['selection'] = {
  55. ...emptySelection,
  56. range: {
  57. fromV: 26,
  58. toV: 26,
  59. },
  60. }
  61. const updates: HistoryContextValue['updates'] = [
  62. {
  63. fromV: 25,
  64. toV: 26,
  65. meta: {
  66. users: historyUsers,
  67. start_ts: 1680888731881,
  68. end_ts: 1680888731881,
  69. },
  70. labels: [],
  71. pathnames: ['newfolder1/newfile10.tex'],
  72. project_ops: [],
  73. },
  74. {
  75. fromV: 23,
  76. toV: 25,
  77. meta: {
  78. users: historyUsers,
  79. start_ts: 1680888725098,
  80. end_ts: 1680888729123,
  81. },
  82. labels: [],
  83. pathnames: [],
  84. project_ops: [
  85. {
  86. rename: {
  87. pathname: 'newfolder1/newfile3.tex',
  88. newPathname: 'newfolder1/newfile10.tex',
  89. },
  90. atV: 24,
  91. },
  92. {
  93. rename: {
  94. pathname: 'newfile3.tex',
  95. newPathname: 'newfolder1/newfile3.tex',
  96. },
  97. atV: 23,
  98. },
  99. ],
  100. },
  101. {
  102. fromV: 22,
  103. toV: 23,
  104. meta: {
  105. users: historyUsers,
  106. start_ts: 1680888721015,
  107. end_ts: 1680888721015,
  108. },
  109. labels: [],
  110. pathnames: ['newfile3.tex'],
  111. project_ops: [],
  112. },
  113. {
  114. fromV: 19,
  115. toV: 22,
  116. meta: {
  117. users: historyUsers,
  118. start_ts: 1680888715364,
  119. end_ts: 1680888718726,
  120. },
  121. labels: [],
  122. pathnames: [],
  123. project_ops: [
  124. {
  125. rename: {
  126. pathname: 'newfolder1/newfolder2/newfile3.tex',
  127. newPathname: 'newfile3.tex',
  128. },
  129. atV: 21,
  130. },
  131. {
  132. rename: {
  133. pathname: 'newfolder1/newfile2.tex',
  134. newPathname: 'newfolder1/newfolder2/newfile2.tex',
  135. },
  136. atV: 20,
  137. },
  138. {
  139. rename: {
  140. pathname: 'newfolder1/newfile5.tex',
  141. newPathname: 'newfile5.tex',
  142. },
  143. atV: 19,
  144. },
  145. ],
  146. },
  147. {
  148. fromV: 16,
  149. toV: 19,
  150. meta: {
  151. users: historyUsers,
  152. start_ts: 1680888705042,
  153. end_ts: 1680888712662,
  154. },
  155. labels: [],
  156. pathnames: [
  157. 'main.tex',
  158. 'newfolder1/newfile2.tex',
  159. 'newfolder1/newfile5.tex',
  160. ],
  161. project_ops: [],
  162. },
  163. {
  164. fromV: 0,
  165. toV: 16,
  166. meta: {
  167. users: historyUsers,
  168. start_ts: 1680888456499,
  169. end_ts: 1680888640774,
  170. },
  171. labels: [],
  172. pathnames: [],
  173. project_ops: [
  174. {
  175. add: {
  176. pathname: 'newfolder1/newfile2.tex',
  177. },
  178. atV: 15,
  179. },
  180. {
  181. remove: {
  182. pathname: 'newfile2.tex',
  183. },
  184. atV: 14,
  185. },
  186. {
  187. rename: {
  188. pathname: 'newfolder1/frog.jpg',
  189. newPathname: 'frog.jpg',
  190. },
  191. atV: 13,
  192. },
  193. {
  194. rename: {
  195. pathname: 'newfolder1/newfile2.tex',
  196. newPathname: 'newfile2.tex',
  197. },
  198. atV: 12,
  199. },
  200. {
  201. rename: {
  202. pathname: 'newfile5.tex',
  203. newPathname: 'newfolder1/newfile5.tex',
  204. },
  205. atV: 11,
  206. },
  207. {
  208. rename: {
  209. pathname: 'newfile4.tex',
  210. newPathname: 'newfile5.tex',
  211. },
  212. atV: 10,
  213. },
  214. {
  215. add: {
  216. pathname: 'newfile4.tex',
  217. },
  218. atV: 9,
  219. },
  220. {
  221. remove: {
  222. pathname: 'newfolder1/newfolder2/newfile1.tex',
  223. },
  224. atV: 8,
  225. },
  226. {
  227. rename: {
  228. pathname: 'frog.jpg',
  229. newPathname: 'newfolder1/frog.jpg',
  230. },
  231. atV: 7,
  232. },
  233. {
  234. add: {
  235. pathname: 'newfolder1/newfolder2/newfile3.tex',
  236. },
  237. atV: 6,
  238. },
  239. {
  240. add: {
  241. pathname: 'newfolder1/newfile2.tex',
  242. },
  243. atV: 5,
  244. },
  245. {
  246. rename: {
  247. pathname: 'newfolder1/newfile1.tex',
  248. newPathname: 'newfolder1/newfolder2/newfile1.tex',
  249. },
  250. atV: 4,
  251. },
  252. {
  253. add: {
  254. pathname: 'newfolder1/newfile1.tex',
  255. },
  256. atV: 3,
  257. },
  258. {
  259. add: {
  260. pathname: 'frog.jpg',
  261. },
  262. atV: 2,
  263. },
  264. {
  265. add: {
  266. pathname: 'sample.bib',
  267. },
  268. atV: 1,
  269. },
  270. {
  271. add: {
  272. pathname: 'main.tex',
  273. },
  274. atV: 0,
  275. },
  276. ],
  277. },
  278. ]
  279. const defaultSelection = autoSelectFile(
  280. files,
  281. selection,
  282. viewMode,
  283. updates
  284. )
  285. expect(defaultSelection.pathname).to.equal('newfolder1/newfile10.tex')
  286. })
  287. it('return file with `added` operation on highest `atV` value if no other operation is available on the latest `updates` entry', function () {
  288. const files: FileDiff[] = [
  289. {
  290. pathname: 'main.tex',
  291. operation: 'added',
  292. },
  293. {
  294. pathname: 'sample.bib',
  295. operation: 'added',
  296. },
  297. {
  298. pathname: 'frog.jpg',
  299. operation: 'added',
  300. },
  301. {
  302. pathname: 'newfile1.tex',
  303. operation: 'added',
  304. },
  305. ]
  306. const selection: HistoryContextValue['selection'] = {
  307. ...emptySelection,
  308. range: {
  309. fromV: 4,
  310. toV: 4,
  311. },
  312. }
  313. const updates: HistoryContextValue['updates'] = [
  314. {
  315. fromV: 0,
  316. toV: 4,
  317. meta: {
  318. users: historyUsers,
  319. start_ts: 1680861468999,
  320. end_ts: 1680861491861,
  321. },
  322. labels: [],
  323. pathnames: [],
  324. project_ops: [
  325. {
  326. add: {
  327. pathname: 'newfile1.tex',
  328. },
  329. atV: 3,
  330. },
  331. {
  332. add: {
  333. pathname: 'frog.jpg',
  334. },
  335. atV: 2,
  336. },
  337. {
  338. add: {
  339. pathname: 'sample.bib',
  340. },
  341. atV: 1,
  342. },
  343. {
  344. add: {
  345. pathname: 'main.tex',
  346. },
  347. atV: 0,
  348. },
  349. ],
  350. },
  351. ]
  352. const defaultSelection = autoSelectFile(
  353. files,
  354. selection,
  355. viewMode,
  356. updates
  357. )
  358. expect(defaultSelection.pathname).to.equal('newfile1.tex')
  359. })
  360. it('return the last non-`removed` operation with the highest `atV` value', function () {
  361. const files: FileDiff[] = [
  362. {
  363. pathname: 'main.tex',
  364. operation: 'removed',
  365. deletedAtV: 6,
  366. },
  367. {
  368. pathname: 'sample.bib',
  369. },
  370. {
  371. pathname: 'main2.tex',
  372. operation: 'added',
  373. },
  374. {
  375. pathname: 'main3.tex',
  376. operation: 'added',
  377. },
  378. ]
  379. const selection: HistoryContextValue['selection'] = {
  380. ...emptySelection,
  381. range: {
  382. fromV: 7,
  383. toV: 7,
  384. },
  385. }
  386. const updates: HistoryContextValue['updates'] = [
  387. {
  388. fromV: 4,
  389. toV: 7,
  390. meta: {
  391. users: historyUsers,
  392. start_ts: 1680874742389,
  393. end_ts: 1680874755552,
  394. },
  395. labels: [],
  396. pathnames: [],
  397. project_ops: [
  398. {
  399. remove: {
  400. pathname: 'main.tex',
  401. },
  402. atV: 6,
  403. },
  404. {
  405. add: {
  406. pathname: 'main3.tex',
  407. },
  408. atV: 5,
  409. },
  410. {
  411. add: {
  412. pathname: 'main2.tex',
  413. },
  414. atV: 4,
  415. },
  416. ],
  417. },
  418. {
  419. fromV: 0,
  420. toV: 4,
  421. meta: {
  422. users: historyUsers,
  423. start_ts: 1680861975947,
  424. end_ts: 1680861988442,
  425. },
  426. labels: [],
  427. pathnames: [],
  428. project_ops: [
  429. {
  430. remove: {
  431. pathname: 'frog.jpg',
  432. },
  433. atV: 3,
  434. },
  435. {
  436. add: {
  437. pathname: 'frog.jpg',
  438. },
  439. atV: 2,
  440. },
  441. {
  442. add: {
  443. pathname: 'sample.bib',
  444. },
  445. atV: 1,
  446. },
  447. {
  448. add: {
  449. pathname: 'main.tex',
  450. },
  451. atV: 0,
  452. },
  453. ],
  454. },
  455. ]
  456. const defaultSelection = autoSelectFile(
  457. files,
  458. selection,
  459. viewMode,
  460. updates
  461. )
  462. expect(defaultSelection.pathname).to.equal('main3.tex')
  463. })
  464. it('if `removed` is the last operation, and no other operation is available on the latest `updates` entry, with `main.tex` available as a file name somewhere in the file tree, return `main.tex`', function () {
  465. const files: FileDiff[] = [
  466. {
  467. pathname: 'main.tex',
  468. },
  469. {
  470. pathname: 'sample.bib',
  471. },
  472. {
  473. pathname: 'frog.jpg',
  474. },
  475. {
  476. pathname: 'newfolder/maybewillbedeleted.tex',
  477. newPathname: 'newfolder2/maybewillbedeleted.tex',
  478. operation: 'removed',
  479. deletedAtV: 10,
  480. },
  481. ]
  482. const selection: HistoryContextValue['selection'] = {
  483. ...emptySelection,
  484. range: {
  485. fromV: 11,
  486. toV: 11,
  487. },
  488. }
  489. const updates: HistoryContextValue['updates'] = [
  490. {
  491. fromV: 9,
  492. toV: 11,
  493. meta: {
  494. users: historyUsers,
  495. start_ts: 1680904414419,
  496. end_ts: 1680904417538,
  497. },
  498. labels: [],
  499. pathnames: [],
  500. project_ops: [
  501. {
  502. remove: {
  503. pathname: 'newfolder2/maybewillbedeleted.tex',
  504. },
  505. atV: 10,
  506. },
  507. {
  508. rename: {
  509. pathname: 'newfolder/maybewillbedeleted.tex',
  510. newPathname: 'newfolder2/maybewillbedeleted.tex',
  511. },
  512. atV: 9,
  513. },
  514. ],
  515. },
  516. {
  517. fromV: 8,
  518. toV: 9,
  519. meta: {
  520. users: historyUsers,
  521. start_ts: 1680904410333,
  522. end_ts: 1680904410333,
  523. },
  524. labels: [],
  525. pathnames: ['newfolder/maybewillbedeleted.tex'],
  526. project_ops: [],
  527. },
  528. {
  529. fromV: 7,
  530. toV: 8,
  531. meta: {
  532. users: historyUsers,
  533. start_ts: 1680904407448,
  534. end_ts: 1680904407448,
  535. },
  536. labels: [],
  537. pathnames: [],
  538. project_ops: [
  539. {
  540. rename: {
  541. pathname: 'newfolder/tobedeleted.tex',
  542. newPathname: 'newfolder/maybewillbedeleted.tex',
  543. },
  544. atV: 7,
  545. },
  546. ],
  547. },
  548. {
  549. fromV: 6,
  550. toV: 7,
  551. meta: {
  552. users: historyUsers,
  553. start_ts: 1680904400839,
  554. end_ts: 1680904400839,
  555. },
  556. labels: [],
  557. pathnames: ['newfolder/tobedeleted.tex'],
  558. project_ops: [],
  559. },
  560. {
  561. fromV: 5,
  562. toV: 6,
  563. meta: {
  564. users: historyUsers,
  565. start_ts: 1680904398544,
  566. end_ts: 1680904398544,
  567. },
  568. labels: [],
  569. pathnames: [],
  570. project_ops: [
  571. {
  572. rename: {
  573. pathname: 'tobedeleted.tex',
  574. newPathname: 'newfolder/tobedeleted.tex',
  575. },
  576. atV: 5,
  577. },
  578. ],
  579. },
  580. {
  581. fromV: 4,
  582. toV: 5,
  583. meta: {
  584. users: historyUsers,
  585. start_ts: 1680904389891,
  586. end_ts: 1680904389891,
  587. },
  588. labels: [],
  589. pathnames: ['tobedeleted.tex'],
  590. project_ops: [],
  591. },
  592. {
  593. fromV: 0,
  594. toV: 4,
  595. meta: {
  596. users: historyUsers,
  597. start_ts: 1680904363778,
  598. end_ts: 1680904385308,
  599. },
  600. labels: [],
  601. pathnames: [],
  602. project_ops: [
  603. {
  604. add: {
  605. pathname: 'tobedeleted.tex',
  606. },
  607. atV: 3,
  608. },
  609. {
  610. add: {
  611. pathname: 'frog.jpg',
  612. },
  613. atV: 2,
  614. },
  615. {
  616. add: {
  617. pathname: 'sample.bib',
  618. },
  619. atV: 1,
  620. },
  621. {
  622. add: {
  623. pathname: 'main.tex',
  624. },
  625. atV: 0,
  626. },
  627. ],
  628. },
  629. ]
  630. const defaultSelection = autoSelectFile(
  631. files,
  632. selection,
  633. viewMode,
  634. updates
  635. )
  636. expect(defaultSelection.pathname).to.equal('main.tex')
  637. })
  638. it('if `removed` is the last operation, and no other operation is available on the latest `updates` entry, with `main.tex` is not available as a file name somewhere in the file tree, return any tex file based on ascending alphabetical order', function () {
  639. const files: FileDiff[] = [
  640. {
  641. pathname: 'certainly_not_main.tex',
  642. },
  643. {
  644. pathname: 'newfile.tex',
  645. },
  646. {
  647. pathname: 'file2.tex',
  648. },
  649. ]
  650. const selection: HistoryContextValue['selection'] = {
  651. ...emptySelection,
  652. range: {
  653. fromV: 8,
  654. toV: 8,
  655. },
  656. }
  657. const updates: HistoryContextValue['updates'] = [
  658. {
  659. fromV: 7,
  660. toV: 8,
  661. meta: {
  662. users: historyUsers,
  663. start_ts: 1680905536168,
  664. end_ts: 1680905536168,
  665. },
  666. labels: [],
  667. pathnames: [],
  668. project_ops: [
  669. {
  670. remove: {
  671. pathname: 'newfolder/tobedeleted.txt',
  672. },
  673. atV: 7,
  674. },
  675. ],
  676. },
  677. {
  678. fromV: 6,
  679. toV: 7,
  680. meta: {
  681. users: historyUsers,
  682. start_ts: 1680905531816,
  683. end_ts: 1680905531816,
  684. },
  685. labels: [],
  686. pathnames: ['newfolder/tobedeleted.txt'],
  687. project_ops: [],
  688. },
  689. {
  690. fromV: 0,
  691. toV: 6,
  692. meta: {
  693. users: historyUsers,
  694. start_ts: 1680905492130,
  695. end_ts: 1680905529186,
  696. },
  697. labels: [],
  698. pathnames: [],
  699. project_ops: [
  700. {
  701. rename: {
  702. pathname: 'tobedeleted.txt',
  703. newPathname: 'newfolder/tobedeleted.txt',
  704. },
  705. atV: 5,
  706. },
  707. {
  708. add: {
  709. pathname: 'file2.tex',
  710. },
  711. atV: 4,
  712. },
  713. {
  714. add: {
  715. pathname: 'newfile.tex',
  716. },
  717. atV: 3,
  718. },
  719. {
  720. add: {
  721. pathname: 'tobedeleted.txt',
  722. },
  723. atV: 2,
  724. },
  725. {
  726. rename: {
  727. pathname: 'main.tex',
  728. newPathname: 'certainly_not_main.tex',
  729. },
  730. atV: 1,
  731. },
  732. {
  733. add: {
  734. pathname: 'main.tex',
  735. },
  736. atV: 0,
  737. },
  738. ],
  739. },
  740. ]
  741. const defaultSelection = autoSelectFile(
  742. files,
  743. selection,
  744. viewMode,
  745. updates
  746. )
  747. expect(defaultSelection.pathname).to.equal('certainly_not_main.tex')
  748. })
  749. })
  750. })