Browse Source

[server-pro] tests: wait for editor to finish loading before interacting (#23841)

GitOrigin-RevId: bef74f336c3a240da43cd5f9563629b96bc1d7ca
Jakob Ackermann 1 year ago
parent
commit
8b64325e89

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

@@ -127,9 +127,7 @@ describe('admin panel', function () {
       testProjectName = `project-${uuid()}`
       deletedProjectName = `deleted-project-${uuid()}`
       login(user1)
-      cy.visit('/project')
       createProject(testProjectName).then(id => (testProjectId = id))
-      cy.visit('/project')
       createProject(deletedProjectName).then(id => (projectToDeleteId = id))
     })
 

+ 6 - 21
server-ce/test/create-and-compile-project.spec.ts

@@ -1,5 +1,8 @@
 import { ensureUserExists, login } from './helpers/login'
-import { createProject } from './helpers/project'
+import {
+  createProject,
+  openProjectViaInviteNotification,
+} from './helpers/project'
 import { isExcludedBySharding, startWith } from './helpers/config'
 import { throttledRecompile } from './helpers/compile'
 
@@ -11,10 +14,7 @@ describe('Project creation and compilation', function () {
 
   it('users can create project and compile it', function () {
     login('user@example.com')
-    cy.visit('/project')
-    // this is the first project created, the welcome screen is displayed instead of the project list
     createProject('test-project')
-    cy.url().should('match', /\/project\/[a-fA-F0-9]{24}/)
     const recompile = throttledRecompile()
     cy.findByText('\\maketitle').parent().click()
     cy.findByText('\\maketitle').parent().type('\n\\section{{}Test Section}')
@@ -26,8 +26,8 @@ describe('Project creation and compilation', function () {
     const fileName = `test-${Date.now()}.md`
     const markdownContent = '# Markdown title'
     login('user@example.com')
-    cy.visit('/project')
     createProject('test-project')
+
     // FIXME: Add aria-label maybe? or at least data-test-id
     cy.findByText('New file').click({ force: true })
     cy.findByRole('dialog').within(() => {
@@ -50,12 +50,9 @@ describe('Project creation and compilation', function () {
     const targetProjectName = `${sourceProjectName}-target`
     login('user@example.com')
 
-    cy.visit('/project')
     createProject(sourceProjectName, { type: 'Example Project' }).as(
       'sourceProjectId'
     )
-
-    cy.visit('/project')
     createProject(targetProjectName)
 
     // link the image from `projectName` into this project
@@ -80,13 +77,9 @@ describe('Project creation and compilation', function () {
     const sourceProjectName = `test-project-${Date.now()}`
     const targetProjectName = `${sourceProjectName}-target`
     login('user@example.com')
-
-    cy.visit('/project')
     createProject(sourceProjectName, { type: 'Example Project' }).as(
       'sourceProjectId'
     )
-
-    cy.visit('/project')
     createProject(targetProjectName).as('targetProjectId')
 
     // link the image from `projectName` into this project
@@ -110,15 +103,7 @@ describe('Project creation and compilation', function () {
     cy.findByText('Log Out').click()
 
     login('collaborator@example.com')
-    cy.visit('/project')
-    cy.findByText(targetProjectName)
-      .parent()
-      .parent()
-      .within(() => {
-        cy.findByText('Join Project').click()
-      })
-    cy.findByText('Open Project').click()
-    cy.url().should('match', /\/project\/[a-fA-F0-9]{24}/)
+    openProjectViaInviteNotification(targetProjectName)
     cy.get('@targetProjectId').then(targetProjectId => {
       cy.url().should('include', targetProjectId)
     })

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

@@ -13,7 +13,6 @@ describe('editor', () => {
     const fileName = 'test.tex'
     const word = createRandomLetterString()
     login('user@example.com')
-    cy.visit('/project')
     createProject('test-project')
 
     cy.log('create new project file')
@@ -214,7 +213,7 @@ describe('editor', () => {
       projectName = `project-${uuid()}`
       login('user@example.com')
       cy.visit(`/project`)
-      createProject(projectName, { type: 'Example Project' })
+      createProject(projectName)
       cy.get('button').contains('New file').click({ force: true })
     })
 

+ 6 - 0
server-ce/test/external-auth.spec.ts

@@ -32,6 +32,9 @@ describe('SAML', () => {
       cy.get('button[type="submit"]').click()
     })
 
+    cy.log('wait for login to finish')
+    cy.url().should('contain', '/project')
+
     createProject('via SAML')
   })
 })
@@ -62,6 +65,9 @@ describe('LDAP', () => {
     cy.get('input[name="password"]').type('fry')
     cy.get('button[type="submit"]').click()
 
+    cy.log('wait for login to finish')
+    cy.url().should('contain', '/project')
+
     createProject('via LDAP')
   })
 })

+ 19 - 17
server-ce/test/git-bridge.spec.ts

@@ -4,6 +4,8 @@ import { ensureUserExists, login } from './helpers/login'
 import {
   createProject,
   enableLinkSharing,
+  openProjectByName,
+  openProjectViaLinkSharingAsUser,
   shareProjectByEmailAndAcceptInviteViaDash,
 } from './helpers/project'
 
@@ -77,7 +79,6 @@ describe('git-bridge', function () {
 
     it('should render the git-bridge UI in the editor', function () {
       maybeClearAllTokens()
-      cy.visit('/project')
       createProject('git').as('projectId')
       cy.get('header').findByText('Menu').click()
       cy.findByText('Sync')
@@ -120,15 +121,13 @@ describe('git-bridge', function () {
 
       let projectName: string
       beforeEach(() => {
-        cy.visit('/project')
         projectName = uuid()
         createProject(projectName).as('projectId')
       })
 
       it('should expose r/w interface to owner', () => {
         maybeClearAllTokens()
-        cy.visit('/project')
-        cy.findByText(projectName).click()
+        openProjectByName(projectName)
         checkGitAccess('readAndWrite')
       })
 
@@ -139,8 +138,7 @@ describe('git-bridge', function () {
           'Can edit'
         )
         maybeClearAllTokens()
-        cy.visit('/project')
-        cy.findByText(projectName).click()
+        openProjectByName(projectName)
         checkGitAccess('readAndWrite')
       })
 
@@ -151,29 +149,34 @@ describe('git-bridge', function () {
           'Can view'
         )
         maybeClearAllTokens()
-        cy.visit('/project')
-        cy.findByText(projectName).click()
+        openProjectByName(projectName)
         checkGitAccess('readOnly')
       })
 
       it('should expose r/w interface to link-sharing r/w collaborator', () => {
         enableLinkSharing().then(({ linkSharingReadAndWrite }) => {
-          login('collaborator-link-rw@example.com')
+          const email = 'collaborator-link-rw@example.com'
+          login(email)
           maybeClearAllTokens()
-          cy.visit(linkSharingReadAndWrite)
-          cy.findByText(projectName) // wait for lazy loading
-          cy.findByText('OK, join project').click()
+          openProjectViaLinkSharingAsUser(
+            linkSharingReadAndWrite,
+            projectName,
+            email
+          )
           checkGitAccess('readAndWrite')
         })
       })
 
       it('should expose r/o interface to link-sharing r/o collaborator', () => {
         enableLinkSharing().then(({ linkSharingReadOnly }) => {
-          login('collaborator-link-ro@example.com')
+          const email = 'collaborator-link-ro@example.com'
+          login(email)
           maybeClearAllTokens()
-          cy.visit(linkSharingReadOnly)
-          cy.findByText(projectName) // wait for lazy loading
-          cy.findByText('OK, join project').click()
+          openProjectViaLinkSharingAsUser(
+            linkSharingReadOnly,
+            projectName,
+            email
+          )
           checkGitAccess('readOnly')
         })
       })
@@ -363,7 +366,6 @@ Hello world
     })
     it('should not render the git-bridge UI in the editor', function () {
       login('user@example.com')
-      cy.visit('/project')
       createProject('maybe git')
       cy.get('header').findByText('Menu').click()
       cy.findByText('Word Count') // wait for lazy loading

+ 0 - 2
server-ce/test/graceful-shutdown.spec.ts

@@ -31,8 +31,6 @@ describe('GracefulShutdown', function () {
   it('should display banner and flush changes out of redis', () => {
     bringServerProBackUp()
     login(USER)
-
-    cy.visit('/project')
     createProject(PROJECT_NAME).then(id => {
       projectId = id
     })

+ 51 - 9
server-ce/test/helpers/project.ts

@@ -11,6 +11,11 @@ export function createProject(
     newProjectButtonMatcher?: RegExp
   } = {}
 ): Cypress.Chainable<string> {
+  cy.url().then(url => {
+    if (!url.endsWith('/project')) {
+      cy.visit('/project')
+    }
+  })
   cy.findAllByRole('button').contains(newProjectButtonMatcher).click()
   // FIXME: This should only look in the left menu
   cy.findAllByText(type).first().click()
@@ -18,19 +23,55 @@ export function createProject(
     cy.get('input').type(name)
     cy.findByText('Create').click()
   })
+  cy.url().should('match', /\/project\/[a-fA-F0-9]{24}/)
+  waitForMainDocToLoad()
   return cy
     .url()
     .should('match', /\/project\/[a-fA-F0-9]{24}/)
     .then(url => url.split('/').pop())
 }
 
+export function openProjectByName(projectName: string) {
+  cy.visit('/project')
+  cy.findByText(projectName).click()
+  waitForMainDocToLoad()
+}
+
+export function openProjectViaLinkSharingAsAnon(url: string) {
+  cy.visit(url)
+  waitForMainDocToLoad()
+}
+
+export function openProjectViaLinkSharingAsUser(
+  url: string,
+  projectName: string,
+  email: string
+) {
+  cy.visit(url)
+  cy.findByText(projectName) // wait for lazy loading
+  cy.findByText(email)
+  cy.findByText('OK, join project').click()
+  waitForMainDocToLoad()
+}
+
+export function openProjectViaInviteNotification(projectName: string) {
+  cy.visit('/project')
+  cy.findByText(projectName)
+    .parent()
+    .parent()
+    .within(() => {
+      cy.findByText('Join Project').click()
+    })
+  cy.findByText('Open Project').click()
+  cy.url().should('match', /\/project\/[a-fA-F0-9]{24}/)
+}
+
 function shareProjectByEmail(
   projectName: string,
   email: string,
   level: 'Can view' | 'Can edit'
 ) {
-  cy.visit('/project')
-  cy.findByText(projectName).click()
+  openProjectByName(projectName)
   cy.findByText('Share').click()
   cy.findByRole('dialog').within(() => {
     cy.get('input').type(`${email},`)
@@ -50,13 +91,7 @@ export function shareProjectByEmailAndAcceptInviteViaDash(
   shareProjectByEmail(projectName, email, level)
 
   login(email)
-  cy.visit('/project')
-  cy.findByText(new RegExp(projectName))
-    .parent()
-    .parent()
-    .within(() => {
-      cy.findByText('Join Project').click()
-    })
+  openProjectViaInviteNotification(projectName)
 }
 
 export function shareProjectByEmailAndAcceptInviteViaEmail(
@@ -86,6 +121,8 @@ export function enableLinkSharing() {
   let linkSharingReadOnly: string
   let linkSharingReadAndWrite: string
 
+  waitForMainDocToLoad()
+
   cy.findByText('Share').click()
   cy.findByText('Turn on link sharing').click()
   cy.findByText('Anyone with this link can view this project')
@@ -105,3 +142,8 @@ export function enableLinkSharing() {
     return { linkSharingReadOnly, linkSharingReadAndWrite }
   })
 }
+
+export function waitForMainDocToLoad() {
+  cy.log('Wait for main doc to load; it will steal the focus after loading')
+  cy.get('.cm-content').should('contain.text', 'Introduction')
+}

+ 0 - 1
server-ce/test/history.spec.ts

@@ -40,7 +40,6 @@ describe('History', function () {
   const CLASS_DELETION = 'ol-cm-deletion-marker'
 
   it('should support labels, comparison and download', () => {
-    cy.visit('/project')
     createProject('labels')
     const recompile = throttledRecompile()
 

+ 0 - 2
server-ce/test/project-list.spec.ts

@@ -32,7 +32,6 @@ describe('Project List', () => {
 
     before(() => {
       login(REGULAR_USER)
-      cy.visit('/project')
       createProject(projectName, { type: 'Example Project' })
     })
 
@@ -90,7 +89,6 @@ describe('Project List', () => {
       cy.log('create a separate project to filter')
       const nonTaggedProjectName = `project-${uuid()}`
       login(REGULAR_USER)
-      cy.visit('/project')
       createProject(nonTaggedProjectName)
       cy.visit('/project')
 

+ 19 - 16
server-ce/test/project-sharing.spec.ts

@@ -4,6 +4,9 @@ import { ensureUserExists, login } from './helpers/login'
 import {
   createProject,
   enableLinkSharing,
+  openProjectByName,
+  openProjectViaLinkSharingAsAnon,
+  openProjectViaLinkSharingAsUser,
   shareProjectByEmailAndAcceptInviteViaDash,
   shareProjectByEmailAndAcceptInviteViaEmail,
 } from './helpers/project'
@@ -31,7 +34,6 @@ describe('Project Sharing', function () {
 
   function setupTestProject() {
     login('user@example.com')
-    cy.visit('/project')
     createProject(projectName)
 
     // Add chat message
@@ -156,8 +158,7 @@ describe('Project Sharing', function () {
     })
 
     it('should grant the collaborator read access', () => {
-      cy.visit('/project')
-      cy.findByText(projectName).click()
+      openProjectByName(projectName)
       expectFullReadOnlyAccess()
       expectProjectDashboardEntry()
     })
@@ -174,8 +175,7 @@ describe('Project Sharing', function () {
 
     it('should grant the collaborator read access', () => {
       login(email)
-      cy.visit('/project')
-      cy.findByText(projectName).click()
+      openProjectByName(projectName)
       expectFullReadOnlyAccess()
       expectProjectDashboardEntry()
     })
@@ -192,8 +192,7 @@ describe('Project Sharing', function () {
 
     it('should grant the collaborator write access', () => {
       login(email)
-      cy.visit('/project')
-      cy.findByText(projectName).click()
+      openProjectByName(projectName)
       expectReadAndWriteAccess()
       expectEditAuthoredAs('You')
       expectProjectDashboardEntry()
@@ -208,9 +207,11 @@ describe('Project Sharing', function () {
 
         it('should grant restricted read access', () => {
           login(email)
-          cy.visit(linkSharingReadOnly)
-          cy.findByText(projectName) // wait for lazy loading
-          cy.findByText('OK, join project').click()
+          openProjectViaLinkSharingAsUser(
+            linkSharingReadOnly,
+            projectName,
+            email
+          )
           expectRestrictedReadOnlyAccess()
           expectProjectDashboardEntry()
         })
@@ -222,9 +223,11 @@ describe('Project Sharing', function () {
 
         it('should grant full write access', () => {
           login(email)
-          cy.visit(linkSharingReadAndWrite)
-          cy.findByText(projectName) // wait for lazy loading
-          cy.findByText('OK, join project').click()
+          openProjectViaLinkSharingAsUser(
+            linkSharingReadAndWrite,
+            projectName,
+            email
+          )
           expectReadAndWriteAccess()
           expectEditAuthoredAs('You')
           expectProjectDashboardEntry()
@@ -268,7 +271,7 @@ describe('Project Sharing', function () {
           withDataDir: true,
         })
         it('should grant read access with read link', () => {
-          cy.visit(linkSharingReadOnly)
+          openProjectViaLinkSharingAsAnon(linkSharingReadOnly)
           expectRestrictedReadOnlyAccess()
         })
 
@@ -288,12 +291,12 @@ describe('Project Sharing', function () {
         })
 
         it('should grant read access with read link', () => {
-          cy.visit(linkSharingReadOnly)
+          openProjectViaLinkSharingAsAnon(linkSharingReadOnly)
           expectRestrictedReadOnlyAccess()
         })
 
         it('should grant write access with write link', () => {
-          cy.visit(linkSharingReadAndWrite)
+          openProjectViaLinkSharingAsAnon(linkSharingReadAndWrite)
           expectReadAndWriteAccess()
           expectEditAuthoredAs('Anonymous')
         })

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

@@ -29,7 +29,6 @@ describe('SandboxedCompiles', function () {
     })
 
     it('should offer TexLive images and switch the compiler', function () {
-      cy.visit('/project')
       createProject('sandboxed')
       const recompile = throttledRecompile()
       cy.log('wait for compile')
@@ -66,7 +65,6 @@ describe('SandboxedCompiles', function () {
       let projectName: string
       beforeEach(function () {
         projectName = `Project ${uuid()}`
-        cy.visit('/project')
         createProject(projectName)
         const recompile = throttledRecompile()
         cy.findByText('\\maketitle').parent().click()
@@ -154,7 +152,6 @@ describe('SandboxedCompiles', function () {
   function checkRecompilesAfterErrors() {
     it('recompiles even if there are Latex errors', function () {
       login('user@example.com')
-      cy.visit('/project')
       createProject('test-project')
       const recompile = throttledRecompile()
       cy.findByText('\\maketitle').parent().click()
@@ -170,7 +167,6 @@ describe('SandboxedCompiles', function () {
 
   function checkXeTeX() {
     it('should be able to use XeLaTeX', function () {
-      cy.visit('/project')
       createProject('XeLaTeX')
       const recompile = throttledRecompile()
       cy.log('wait for compile')
@@ -204,7 +200,6 @@ describe('SandboxedCompiles', function () {
     })
 
     it('should not offer TexLive images and use default compiler', function () {
-      cy.visit('/project')
       createProject('sandboxed')
       cy.log('wait for compile')
       cy.get('.pdf-viewer').should('contain.text', 'sandboxed')

+ 2 - 5
server-ce/test/upgrading.spec.ts

@@ -1,7 +1,7 @@
 import { ensureUserExists, login } from './helpers/login'
 import { isExcludedBySharding, startWith } from './helpers/config'
 import { dockerCompose, runScript } from './helpers/hostAdminClient'
-import { createProject } from './helpers/project'
+import { createProject, openProjectByName } from './helpers/project'
 import { throttledRecompile } from './helpers/compile'
 import { v4 as uuid } from 'uuid'
 
@@ -38,8 +38,6 @@ describe('Upgrading', function () {
     before(() => {
       cy.log('Populate old instance')
       login(USER)
-
-      cy.visit('/project')
       createProject(PROJECT_NAME, {
         newProjectButtonMatcher: startOptions.newProjectButtonMatcher,
       })
@@ -115,8 +113,7 @@ describe('Upgrading', function () {
     })
 
     it('should open the old project', () => {
-      cy.visit('/project')
-      cy.findByText(PROJECT_NAME).click()
+      openProjectByName(PROJECT_NAME)
 
       cy.url().should('match', /\/project\/[a-fA-F0-9]{24}/)
       cy.findByRole('navigation').within(() => {