cursor-position.test.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import sinon from 'sinon'
  2. import { waitFor } from '@testing-library/react'
  3. import { expect } from 'chai'
  4. import { EditorView } from '@codemirror/view'
  5. import { EditorSelection, EditorState } from '@codemirror/state'
  6. import {
  7. cursorPosition,
  8. restoreCursorPosition,
  9. } from '../../../../../frontend/js/features/source-editor/extensions/cursor-position'
  10. const doc = `
  11. \\documentclass{article}
  12. \\title{Your Paper}
  13. \\author{You}
  14. \\begin{document}
  15. \\maketitle
  16. \\begin{abstract}
  17. Your abstract.
  18. \\end{abstract}
  19. \\section{Introduction}
  20. Your introduction goes here!
  21. \\end{document}`
  22. const mockDoc = () => {
  23. return {
  24. doc_id: 'test-doc',
  25. }
  26. }
  27. describe('CodeMirror cursor position extension', function () {
  28. afterEach(function () {
  29. sinon.restore()
  30. })
  31. it('stores cursor position when the view is destroyed', async function () {
  32. const currentDoc = mockDoc()
  33. sinon.stub(window.Storage.prototype, 'getItem').callsFake(key => {
  34. switch (key) {
  35. case 'doc.position.test-doc':
  36. return JSON.stringify({
  37. cursorPosition: { row: 1, column: 1 },
  38. firstVisibleLine: 5,
  39. })
  40. default:
  41. return null
  42. }
  43. })
  44. const setItem = sinon.spy(window.Storage.prototype, 'setItem')
  45. const view = new EditorView({
  46. state: EditorState.create({
  47. doc,
  48. extensions: [cursorPosition({ currentDoc })],
  49. }),
  50. })
  51. view.dispatch({
  52. selection: EditorSelection.cursor(50),
  53. })
  54. view.destroy()
  55. await waitFor(() => {
  56. expect(setItem).to.have.been.calledWith(
  57. 'doc.position.test-doc',
  58. JSON.stringify({
  59. cursorPosition: {
  60. row: 3,
  61. column: 6,
  62. },
  63. firstVisibleLine: 5,
  64. })
  65. )
  66. })
  67. })
  68. it('restores cursor position', async function () {
  69. const currentDoc = mockDoc()
  70. const getItem = sinon
  71. .stub(window.Storage.prototype, 'getItem')
  72. .callsFake(key => {
  73. switch (key) {
  74. case 'doc.position.test-doc':
  75. return JSON.stringify({
  76. cursorPosition: { row: 3, column: 5 },
  77. firstVisibleLine: 0,
  78. })
  79. default:
  80. return null
  81. }
  82. })
  83. const view = new EditorView({
  84. state: EditorState.create({
  85. doc,
  86. extensions: [cursorPosition({ currentDoc })],
  87. }),
  88. })
  89. view.dispatch(restoreCursorPosition(view.state.doc, 'test-doc'))
  90. expect(getItem).to.have.been.calledWith('doc.position.test-doc')
  91. await waitFor(() => {
  92. const [range] = view.state.selection.ranges
  93. expect(range.head).to.eq(49)
  94. expect(range.anchor).to.eq(49)
  95. expect(range.empty).to.eq(true)
  96. })
  97. })
  98. })