pdf-synctex-controls.test.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import PdfSynctexControls from '../../../../../frontend/js/features/pdf-preview/components/pdf-synctex-controls'
  2. import { EditorProviders } from '../../../helpers/render-with-context'
  3. import { cloneDeep } from 'lodash'
  4. import fetchMock from 'fetch-mock'
  5. import { fireEvent, screen, waitFor, render } from '@testing-library/react'
  6. import fs from 'fs'
  7. import path from 'path'
  8. import { expect } from 'chai'
  9. import { useCompileContext } from '../../../../../frontend/js/shared/context/compile-context'
  10. import { useEffect } from 'react'
  11. const examplePDF = path.join(__dirname, '../fixtures/test-example.pdf')
  12. const scope = {
  13. settings: {
  14. syntaxValidation: false,
  15. pdfViewer: 'pdfjs',
  16. },
  17. editor: {
  18. sharejs_doc: {
  19. doc_id: 'test-doc',
  20. getSnapshot: () => 'some doc content',
  21. },
  22. },
  23. }
  24. const outputFiles = [
  25. {
  26. path: 'output.pdf',
  27. build: '123',
  28. url: '/build/output.pdf',
  29. type: 'pdf',
  30. },
  31. {
  32. path: 'output.log',
  33. build: '123',
  34. url: '/build/output.log',
  35. type: 'log',
  36. },
  37. ]
  38. const mockCompile = () =>
  39. fetchMock.post('express:/project/:projectId/compile', {
  40. body: {
  41. status: 'success',
  42. clsiServerId: 'foo',
  43. compileGroup: 'standard',
  44. pdfDownloadDomain: 'https://clsi.test-overleaf.com',
  45. outputFiles: cloneDeep(outputFiles),
  46. },
  47. })
  48. const fileResponses = {
  49. '/build/output.pdf': () => fs.createReadStream(examplePDF),
  50. '/build/output.log': '',
  51. }
  52. const mockBuildFile = () =>
  53. fetchMock.get('begin:https://clsi.test-overleaf.com/', _url => {
  54. const url = new URL(_url, 'https://clsi.test-overleaf.com')
  55. if (url.pathname in fileResponses) {
  56. return fileResponses[url.pathname]
  57. }
  58. return 404
  59. })
  60. const mockHighlights = [
  61. {
  62. page: 1,
  63. h: 85.03936,
  64. v: 509.999878,
  65. width: 441.921265,
  66. height: 8.855677,
  67. },
  68. {
  69. page: 1,
  70. h: 85.03936,
  71. v: 486.089539,
  72. width: 441.921265,
  73. height: 8.855677,
  74. },
  75. ]
  76. const mockSynctex = () =>
  77. fetchMock
  78. .get('express:/project/:projectId/sync/code', () => {
  79. return { pdf: cloneDeep(mockHighlights) }
  80. })
  81. .get('express:/project/:projectId/sync/pdf', () => {
  82. return { code: [{ file: 'main.tex', line: 100 }] }
  83. })
  84. describe('<PdfSynctexControls/>', function () {
  85. beforeEach(function () {
  86. window.showNewPdfPreview = true
  87. fetchMock.restore()
  88. })
  89. afterEach(function () {
  90. window.showNewPdfPreview = undefined
  91. fetchMock.restore()
  92. })
  93. it('handles clicks on sync buttons', async function () {
  94. mockCompile()
  95. mockSynctex()
  96. mockBuildFile()
  97. const Inner = () => {
  98. const { setPosition } = useCompileContext()
  99. // mock PDF scroll position update
  100. useEffect(() => {
  101. setPosition({
  102. page: 1,
  103. offset: { top: 10, left: 10 },
  104. pageSize: { height: 500, width: 500 },
  105. })
  106. }, [setPosition])
  107. return null
  108. }
  109. render(
  110. <EditorProviders scope={scope}>
  111. <Inner />
  112. <PdfSynctexControls />
  113. </EditorProviders>
  114. )
  115. const syncToPdfButton = await screen.findByRole('button', {
  116. name: 'Go to code location in PDF',
  117. })
  118. const syncToCodeButton = await screen.findByRole('button', {
  119. name: 'Go to PDF location in code',
  120. })
  121. // mock editor cursor position update
  122. fireEvent(
  123. window,
  124. new CustomEvent('cursor:editor:update', {
  125. detail: { row: 100, column: 10 },
  126. })
  127. )
  128. fireEvent.click(syncToPdfButton)
  129. expect(syncToPdfButton.disabled).to.be.true
  130. await waitFor(() => {
  131. expect(fetchMock.called('express:/project/:projectId/sync/code')).to.be
  132. .true
  133. })
  134. fireEvent.click(syncToCodeButton)
  135. expect(syncToCodeButton.disabled).to.be.true
  136. await waitFor(() => {
  137. expect(fetchMock.called('express:/project/:projectId/sync/pdf')).to.be
  138. .true
  139. })
  140. })
  141. })