Просмотр исходного кода

Merge pull request #18705 from overleaf/jpa-test-synctex

[server-pro] add tests for SyncTeX

GitOrigin-RevId: 2c914cd7e3859fb82c6e560fda1248d98415da2f
Jakob Ackermann 2 лет назад
Родитель
Сommit
b13938ce7d

+ 39 - 0
server-ce/test/helpers/waitUntilScrollingFinished.ts

@@ -0,0 +1,39 @@
+export function waitUntilScrollingFinished(selector: string, start = -1) {
+  const pollSlow = 100
+  const pollFast = 10
+  const deadline =
+    performance.now() + Cypress.config('defaultCommandTimeout') - pollSlow * 2
+  return cy.get(selector).then(el => {
+    cy.log(
+      `waiting until scrolling finished for ${selector}, starting from ${start}`
+    )
+    return new Cypress.Promise<number>((resolve, reject) => {
+      const waitForStable = (prev: number, stableFor: number) => {
+        if (performance.now() > deadline) {
+          return reject(new Error('timeout waiting for scrolling to finish'))
+        }
+        const current = el.scrollTop()!
+        if (current !== prev) {
+          setTimeout(() => waitForStable(current, 0), pollFast)
+        } else if (stableFor < 3) {
+          setTimeout(() => waitForStable(current, stableFor + 1), pollFast)
+        } else {
+          resolve(current)
+        }
+      }
+
+      const waitForChange = () => {
+        if (performance.now() > deadline) {
+          return reject(new Error('timeout waiting for scrolling to start'))
+        }
+        const current = el.scrollTop()!
+        if (current === start) {
+          setTimeout(() => waitForChange(), pollSlow)
+        } else {
+          setTimeout(() => waitForStable(current, 0), pollFast)
+        }
+      }
+      waitForChange()
+    })
+  })
+}

+ 103 - 0
server-ce/test/sandboxed-compiles.spec.ts

@@ -2,6 +2,8 @@ import { ensureUserExists, login } from './helpers/login'
 import { createProject } from './helpers/project'
 import { startWith } from './helpers/config'
 import { throttledRecompile } from './helpers/compile'
+import { v4 as uuid } from 'uuid'
+import { waitUntilScrollingFinished } from './helpers/waitUntilScrollingFinished'
 
 describe('SandboxedCompiles', function () {
   ensureUserExists({ email: 'user@example.com' })
@@ -47,9 +49,108 @@ describe('SandboxedCompiles', function () {
       cy.findByText(/This is pdfTeX, Version .+ \(TeX Live 2022\) /)
     })
 
+    checkSyncTeX()
     checkXeTeX()
   })
 
+  function checkSyncTeX() {
+    describe('SyncTeX', () => {
+      const projectName = `Project ${uuid()}`
+      before(function () {
+        login('user@example.com')
+        cy.visit('/project')
+        createProject(projectName)
+        const recompile = throttledRecompile()
+        cy.findByText('\\maketitle').parent().click()
+        cy.findByText('\\maketitle')
+          .parent()
+          .type(
+            `\n\\pagebreak\n\\section{{}Section A}\n\\pagebreak\n\\section{{}Section B}\n\\pagebreak`
+          )
+        recompile()
+      })
+
+      it('should sync to code', () => {
+        cy.visit('/project')
+        cy.findByText(projectName).click()
+
+        cy.log('navigate to \\maketitle using double click in PDF')
+        cy.get('.pdf-viewer').within(() => {
+          cy.findByText(projectName).dblclick()
+        })
+        cy.get('.cm-activeLine').should('have.text', '\\maketitle')
+
+        cy.log('navigate to Section A using double click in PDF')
+        cy.get('.pdf-viewer').within(() => {
+          cy.findByText('Section A').dblclick()
+        })
+        cy.get('.cm-activeLine').should('have.text', '\\section{Section A}')
+
+        cy.log('navigate to Section B using arrow button')
+        cy.get('.pdfjs-viewer-inner')
+          .should('have.prop', 'scrollTop')
+          .as('start')
+        cy.get('.pdf-viewer').within(() => {
+          cy.findByText('Section B').scrollIntoView()
+        })
+        cy.get('@start').then((start: any) => {
+          waitUntilScrollingFinished('.pdfjs-viewer-inner', start)
+        })
+        cy.get('[aria-label^="Go to PDF location in code"]').click()
+        cy.get('.cm-activeLine').should('have.text', '\\section{Section B}')
+      })
+
+      // Waiting for a fix of https://github.com/overleaf/internal/issues/18603
+      it.skip('should sync to pdf', () => {
+        cy.visit('/project')
+        cy.findByText(projectName).click()
+
+        cy.log('wait for compile')
+        cy.get('.pdf-viewer').within(() => {
+          cy.findByText(projectName)
+        })
+
+        cy.log('zoom in')
+        for (let i = 0; i < 8; i++) {
+          cy.get('[aria-label="Zoom in"]').click({ force: true })
+        }
+        cy.log('scroll to top')
+        cy.get('.pdfjs-viewer-inner').scrollTo('top')
+        waitUntilScrollingFinished('.pdfjs-viewer-inner', -1)
+        cy.get('.pdfjs-viewer-inner')
+          .should('have.prop', 'scrollTop')
+          .as('start')
+
+        cy.log('navigate to title')
+        cy.findByText('\\maketitle').parent().click()
+        cy.get('[aria-label="Go to code location in PDF"]').click()
+        cy.get('@start').then((start: any) => {
+          waitUntilScrollingFinished('.pdfjs-viewer-inner', start)
+            .as('title')
+            .should('be.greaterThan', start)
+        })
+
+        cy.log('navigate to Section A')
+        cy.get('.cm-content').within(() => cy.findByText('Section A').click())
+        cy.get('[aria-label="Go to code location in PDF"]').click()
+        cy.get('@title').then((title: any) => {
+          waitUntilScrollingFinished('.pdfjs-viewer-inner', title)
+            .as('sectionA')
+            .should('be.greaterThan', title)
+        })
+
+        cy.log('navigate to Section B')
+        cy.get('.cm-content').within(() => cy.findByText('Section B').click())
+        cy.get('[aria-label="Go to code location in PDF"]').click()
+        cy.get('@sectionA').then((title: any) => {
+          waitUntilScrollingFinished('.pdfjs-viewer-inner', title)
+            .as('sectionB')
+            .should('be.greaterThan', title)
+        })
+      })
+    })
+  }
+
   function checkXeTeX() {
     it('should be able to use XeLaTeX', () => {
       cy.visit('/project')
@@ -102,6 +203,7 @@ describe('SandboxedCompiles', function () {
     startWith({ pro: true })
 
     checkUsesDefaultCompiler()
+    checkSyncTeX()
     checkXeTeX()
   })
 
@@ -109,6 +211,7 @@ describe('SandboxedCompiles', function () {
     startWith({ pro: false, vars: enabledVars })
 
     checkUsesDefaultCompiler()
+    checkSyncTeX()
     checkXeTeX()
   })
 })