Răsfoiți Sursa

Merge pull request #19170 from overleaf/jpa-server-ce-re-run-before

[server-ce] make tests more robust

GitOrigin-RevId: f070b8bbbf87842a69d88ca56cecf5dd0f3a286c
Jakob Ackermann 2 ani în urmă
părinte
comite
9075c82b88

+ 2 - 1
server-ce/test/admin.spec.ts

@@ -2,6 +2,7 @@ import { startWith } from './helpers/config'
 import { activateUser, ensureUserExists, login } from './helpers/login'
 import { v4 as uuid } from 'uuid'
 import { createProject } from './helpers/project'
+import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry'
 
 describe('admin panel', function () {
   describe('in server pro', () => {
@@ -26,7 +27,7 @@ describe('admin panel', function () {
     ensureUserExists({ email: user1 })
     ensureUserExists({ email: user2 })
 
-    before(() => {
+    beforeWithReRunOnTestRetry(() => {
       login(user1)
       cy.visit('/project')
       createProject(testProjectName).then(id => (testProjectId = id))

+ 2 - 1
server-ce/test/editor.spec.ts

@@ -2,6 +2,7 @@ import { createProject } from './helpers/project'
 import { startWith } from './helpers/config'
 import { ensureUserExists, login } from './helpers/login'
 import { v4 as uuid } from 'uuid'
+import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry'
 
 describe('editor', () => {
   startWith({ pro: true })
@@ -168,7 +169,7 @@ describe('editor', () => {
   describe('editor', () => {
     let projectId: string
 
-    before(() => {
+    beforeWithReRunOnTestRetry(() => {
       login('user@example.com')
       cy.visit(`/project`)
       createProject(`project-${uuid()}`, { type: 'Example Project' }).then(

+ 8 - 0
server-ce/test/helpers/beforeWithReRunOnTestRetry.ts

@@ -0,0 +1,8 @@
+export function beforeWithReRunOnTestRetry(fn: () => void | Promise<any>) {
+  let ranOnce = false
+  beforeEach(() => {
+    if (ranOnce && Cypress.currentRetry === 0) return
+    ranOnce = true
+    return fn()
+  })
+}

+ 2 - 0
server-ce/test/helpers/compile.ts

@@ -19,5 +19,7 @@ export function throttledRecompile() {
       cy.wait(Math.max(0, 1_000 - msSinceLastCompile))
       cy.findByText('Recompile').click()
       queueReset()
+      cy.log('Wait for recompile to finish')
+      cy.findByText('Recompile')
     })
 }

+ 1 - 1
server-ce/test/helpers/waitUntilScrollingFinished.ts

@@ -15,7 +15,7 @@ export function waitUntilScrollingFinished(selector: string, start = -1) {
         const current = el.scrollTop()!
         if (current !== prev) {
           setTimeout(() => waitForStable(current, 0), pollFast)
-        } else if (stableFor < 3) {
+        } else if (stableFor < 5) {
           setTimeout(() => waitForStable(current, stableFor + 1), pollFast)
         } else {
           resolve(current)

+ 4 - 3
server-ce/test/project-sharing.spec.ts

@@ -3,13 +3,14 @@ import { startWith } from './helpers/config'
 import { ensureUserExists, login } from './helpers/login'
 import { createProject } from './helpers/project'
 import { throttledRecompile } from './helpers/compile'
+import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry'
 
 describe('Project Sharing', function () {
   ensureUserExists({ email: 'user@example.com' })
   startWith({ withDataDir: true })
 
   let projectName: string
-  before(function () {
+  beforeWithReRunOnTestRetry(function () {
     projectName = `Project ${uuid()}`
     setupTestProject()
   })
@@ -175,7 +176,7 @@ describe('Project Sharing', function () {
     const email = 'collaborator-ro@example.com'
     ensureUserExists({ email })
 
-    before(function () {
+    beforeWithReRunOnTestRetry(function () {
       shareProjectByEmailAndAcceptInvite(email, 'Read Only')
     })
 
@@ -192,7 +193,7 @@ describe('Project Sharing', function () {
     const email = 'collaborator-rw@example.com'
     ensureUserExists({ email })
 
-    before(function () {
+    beforeWithReRunOnTestRetry(function () {
       shareProjectByEmailAndAcceptInvite(email, 'Can Edit')
     })
 

+ 8 - 2
server-ce/test/sandboxed-compiles.spec.ts

@@ -4,6 +4,7 @@ import { startWith } from './helpers/config'
 import { throttledRecompile } from './helpers/compile'
 import { v4 as uuid } from 'uuid'
 import { waitUntilScrollingFinished } from './helpers/waitUntilScrollingFinished'
+import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry'
 
 const LABEL_TEX_LIVE_VERSION = 'TeX Live version'
 
@@ -60,8 +61,9 @@ describe('SandboxedCompiles', function () {
 
   function checkSyncTeX() {
     describe('SyncTeX', () => {
-      const projectName = `Project ${uuid()}`
-      before(function () {
+      let projectName: string
+      beforeWithReRunOnTestRetry(function () {
+        projectName = `Project ${uuid()}`
         login('user@example.com')
         cy.visit('/project')
         createProject(projectName)
@@ -101,6 +103,10 @@ describe('SandboxedCompiles', function () {
         cy.get('@start').then((start: any) => {
           waitUntilScrollingFinished('.pdfjs-viewer-inner', start)
         })
+        // The sync button is swapped as the position in the PDF changes.
+        // Cypress appears to click on a button that references a stale position.
+        // Adding a cy.wait() statement is the most reliable "fix" so far :/
+        cy.wait(1000)
         cy.get('[aria-label^="Go to PDF location in code"]').click()
         cy.get('.cm-activeLine').should('have.text', '\\section{Section B}')
       })

+ 30 - 24
server-ce/test/upgrading.spec.ts

@@ -7,6 +7,7 @@ import { startWith } from './helpers/config'
 import { dockerCompose, resetData, runScript } from './helpers/hostAdminClient'
 import { createProject } from './helpers/project'
 import { throttledRecompile } from './helpers/compile'
+import { v4 as uuid } from 'uuid'
 
 const USER = 'user@example.com'
 const PROJECT_NAME = 'Old Project'
@@ -22,23 +23,25 @@ describe('Upgrading', function () {
   ) {
     const startOptions = steps.shift()!
 
-    // Reset mongo/redis/on-disk data
     before(async () => {
+      cy.log('Reset mongo/redis/on-disk data')
       resetCreatedUsersCache()
       await resetData()
-    })
 
-    // Create old instance
+      cy.log('Create old instance')
+    })
     startWith({
       pro: true,
       version: startOptions.version,
       withDataDir: true,
       vars: startOptions.vars,
     })
+    before(function () {
+      cy.log('Create initial user after deleting it')
+    })
     ensureUserExists({ email: USER })
-
-    // Populate old instance
     before(() => {
+      cy.log('Populate old instance')
       login(USER)
 
       cy.visit('/project')
@@ -46,26 +49,25 @@ describe('Upgrading', function () {
         newProjectButtonMatcher: startOptions.newProjectButtonMatcher,
       })
       const recompile = throttledRecompile()
-      // // wait for successful compile
+      cy.log('Wait for successful compile')
       cy.get('.pdf-viewer').should('contain.text', PROJECT_NAME)
 
-      // Increment the doc version three times
+      cy.log('Increment the doc version three times')
       for (let i = 0; i < 3; i++) {
-        // Add content
+        cy.log('Add content')
         cy.findByText('\\maketitle').parent().click()
         cy.findByText('\\maketitle')
           .parent()
           .type(`\n\\section{{}Old Section ${i}}`)
 
-        // Trigger full flush
+        cy.log('Trigger full flush')
         recompile()
         cy.get('header').findByText('Menu').click()
         cy.findByText('Source').click()
-        // close editor menu
         cy.get('#left-menu-modal').click()
       }
 
-      // Check compile and history
+      cy.log('Check compile and history')
       for (let i = 0; i < 3; i++) {
         cy.get('.pdf-viewer').should('contain.text', `Old Section ${i}`)
       }
@@ -75,14 +77,15 @@ describe('Upgrading', function () {
       }
     })
 
-    // Upgrades
     for (const step of steps) {
       before(() => {
+        cy.log(`Upgrade to version ${step.version}`)
+
         // Navigate way from editor to avoid redirect to /login when the next instance comes up (which slows down tests)
         cy.visit('/project', {})
       })
-      // Graceful shutdown
       before(async function () {
+        cy.log('Graceful shutdown: flush all the things')
         this.timeout(20 * 1000)
         // Ideally we could use the container shutdown procedure, but it's too slow and unreliable for tests.
         // TODO(das7pad): adopt the below after speeding up the graceful shutdown procedure on all supported releases
@@ -126,20 +129,21 @@ describe('Upgrading', function () {
       })
       const recompile = throttledRecompile()
 
-      // wait for successful compile
+      cy.log('wait for successful compile')
       cy.get('.pdf-viewer').should('contain.text', PROJECT_NAME)
       cy.get('.pdf-viewer').should('contain.text', 'Old Section 2')
 
-      // // Add more content
+      cy.log('Add more content')
+      const newSection = `New Section ${uuid()}`
       cy.findByText('\\maketitle').parent().click()
-      cy.findByText('\\maketitle').parent().type('\n\\section{{}New Section}')
+      cy.findByText('\\maketitle').parent().type(`\n\\section{{}${newSection}}`)
 
-      // Check compile and history
+      cy.log('Check compile and history')
       recompile()
-      cy.get('.pdf-viewer').should('contain.text', 'New Section')
+      cy.get('.pdf-viewer').should('contain.text', newSection)
       cy.findByText('History').click()
       cy.findByText(/\\section\{Old Section 2}/)
-      cy.findByText(/\\section\{New Section}/)
+      cy.findByText(new RegExp(`\\\\section\\{${newSection}}`))
     })
   }
 
@@ -170,17 +174,17 @@ describe('Upgrading', function () {
             cy.findByText(PROJECT_NAME).click()
             const recompile = throttledRecompile()
 
-            // Make a change
+            cy.log('Make a change')
             cy.findByText('\\maketitle').parent().click()
             cy.findByText('\\maketitle')
               .parent()
               .type('\n\\section{{}FiveOOne Section}')
 
-            // Trigger flush
+            cy.log('Trigger flush')
             recompile()
             cy.get('.pdf-viewer').should('contain.text', 'FiveOOne Section')
 
-            // Check for broken history, i.e. not synced with latest edit
+            cy.log('Check for broken history, i.e. not synced with latest edit')
             cy.findByText('History').click()
             cy.findByText(/\\section\{Old Section 2}/) // wait for lazy loading
             cy.findByText(/\\section\{FiveOOne Section}/).should('not.exist')
@@ -212,11 +216,13 @@ describe('Upgrading', function () {
             cy.visit('/')
             cy.findByText(PROJECT_NAME).click()
 
-            // The edit that was made while the history was broken should be there now.
+            cy.log(
+              'The edit that was made while the history was broken should be there now.'
+            )
             cy.findByText('History').click()
             cy.findByText(/\\section\{FiveOOne Section}/)
 
-            // Check indicator of force resync
+            cy.log('Check indicator of force resync')
             cy.findByText('Overleaf History System')
           })
         },