From b4bfff1b671dc2f6826c075416573f6b8031b355 Mon Sep 17 00:00:00 2001 From: Rebeka Dekany <50901361+rebekadekany@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:44:03 +0100 Subject: [PATCH] Improve Server Pro tests to use semantic selectors (#29790) * Replace placeholders with labels * Add 'Close dialog' label to modal close button to distinguish from footer Close button * Add and translate heading on the not found page * Update textarea to have id matching label's for attribute Simplify test for template description textarea * Label PDF zoom level dropdown button * Improve test selectors to use semantic roles and accessible names GitOrigin-RevId: d215ddca30ddf844cfffbcf0e528a601b134d772 --- server-ce/test/accounts.spec.ts | 10 +- server-ce/test/admin.spec.ts | 53 +++---- .../test/create-and-compile-project.spec.ts | 4 +- server-ce/test/customization.spec.ts | 12 +- server-ce/test/external-auth.spec.ts | 10 +- server-ce/test/git-bridge.spec.ts | 44 ++++-- server-ce/test/graceful-shutdown.spec.ts | 28 +++- server-ce/test/learn-wiki.spec.ts | 27 ++-- server-ce/test/project-sharing.spec.ts | 24 ++- server-ce/test/sandboxed-compiles.spec.ts | 80 ++++++---- server-ce/test/templates.spec.ts | 142 +++++++++--------- server-ce/test/upgrading.spec.ts | 26 ++-- services/web/app/views/general/404.pug | 2 +- .../web/frontend/extracted-translations.json | 2 + .../components/pdf-zoom-dropdown.tsx | 1 + .../js/shared/components/ol/ol-modal.tsx | 8 +- services/web/locales/en.json | 3 + .../editor-left-menu.spec.tsx | 2 +- .../frontend/components/shared/modal.spec.tsx | 10 +- .../settings/settings-dictionary.test.tsx | 4 +- .../components/new-project-button.test.tsx | 2 +- .../settings/dictionary-setting.test.tsx | 4 +- .../components/leave-section.test.tsx | 2 +- .../components/share-project-modal.test.tsx | 17 +-- 24 files changed, 294 insertions(+), 223 deletions(-) diff --git a/server-ce/test/accounts.spec.ts b/server-ce/test/accounts.spec.ts index 5ea8ec8569..a64da80414 100644 --- a/server-ce/test/accounts.spec.ts +++ b/server-ce/test/accounts.spec.ts @@ -25,13 +25,9 @@ describe('Accounts', function () { cy.get('@url').then(url => { cy.visit(`${url}`) cy.url().should('contain', '/user/activate') - cy.findByText('Please set a password') - cy.get('input[autocomplete="username"]').should( - 'have.attr', - 'value', - email - ) - cy.get('input[name="password"]') + cy.findByRole('heading', { name: 'Please set a password' }) + cy.findByLabelText('Email').should('be.visible') + cy.findByLabelText('Password').should('be.visible') cy.findByRole('button', { name: 'Activate' }) }) }) diff --git a/server-ce/test/admin.spec.ts b/server-ce/test/admin.spec.ts index 2f8ad57169..eeedbf75dd 100644 --- a/server-ce/test/admin.spec.ts +++ b/server-ce/test/admin.spec.ts @@ -16,12 +16,10 @@ describe('admin panel', function () { const user = `${uuid()}@example.com` cy.findByLabelText('Emails to register new users').type(user + '{enter}') - cy.get('td') - .contains(/\/user\/activate/) - .then($td => { - const url = $td.text().trim() - activateUser(url) - }) + cy.findByRole('cell', { name: /\/user\/activate/ }).then($td => { + const url = $td.text().trim() + activateUser(url) + }) }) it('via GUI and email', function () { @@ -29,17 +27,15 @@ describe('admin panel', function () { cy.findByLabelText('Emails to register new users').type(user + '{enter}') let url: string - cy.get('td') - .contains(/\/user\/activate/) - .then($td => { - url = $td.text().trim() - }) + cy.findByRole('cell', { name: /\/user\/activate/ }).then($td => { + url = $td.text().trim() + }) cy.then(() => { openEmail( 'Activate your E2E test Account', (frame, { url }) => { - frame.contains('Set password').then(el => { + frame.contains('a', 'Set password').then(el => { expect(el.attr('href')!).to.equal(url) }) }, @@ -69,7 +65,7 @@ describe('admin panel', function () { openEmail( 'Activate your E2E test Account', (frame, { url }) => { - frame.contains('Set password').then(el => { + frame.contains('a', 'Set password').then(el => { expect(el.attr('href')!).to.equal(url) }) }, @@ -145,10 +141,10 @@ describe('admin panel', function () { const menuitems = ['Manage Site', 'Manage Users', 'Project URL Lookup'] menuitems.forEach(name => { cy.findByRole('menuitem', { name: 'Admin' }).click() - cy.get('ul[role="menu"]') + cy.findByRole('menu') .findAllByRole('menuitem') .should('have.length', menuitems.length) - cy.get('ul[role="menu"]').findByRole('menuitem', { name }).click() + cy.findByRole('menu').findByRole('menuitem', { name }).click() }) }) }) @@ -206,7 +202,7 @@ describe('admin panel', function () { }) it('license usage tab', function () { - cy.get('a').contains('License Usage').click() + cy.findByRole('tab', { name: 'License Usage' }).click() cy.findByText( 'An active user is one who has opened a project in this Server Pro instance in the last 12 months.' ) @@ -214,7 +210,7 @@ describe('admin panel', function () { describe('create users', function () { beforeEach(function () { - cy.get('a').contains('New User').click() + cy.findByRole('link', { name: 'New User' }).click() }) registrationTests() }) @@ -263,8 +259,8 @@ describe('admin panel', function () { it('displays required sections', function () { // not exhaustive list, checks the tab content is rendered - cy.findByText('Profile') - cy.findByText('Editor Settings') + cy.findByRole('heading', { name: 'Profile' }) + cy.findByRole('heading', { name: 'Editor Settings' }) }) it('should not display SaaS-only sections', function () { @@ -290,9 +286,12 @@ describe('admin panel', function () { cy.findByRole('tablist').within(() => { cy.findByRole('tab', { name: 'Projects' }).click() }) - cy.get(`a[href="/admin/project/${testProjectId}"]`) - .should('contain.text', 'Project information') - .click() + cy.findByRole('link', { name: testProjectName }) + .parent() + .parent() + .within(() => { + cy.findByRole('link', { name: 'Project information' }).click() + }) cy.findByRole('button', { name: 'Transfer Ownership' }).click() cy.findByRole('dialog').within(() => { @@ -319,10 +318,12 @@ describe('admin panel', function () { cy.findByRole('tablist').within(() => { cy.findByRole('tab', { name: 'Projects' }).click() }) - cy.get(`a[href="/admin/project/${testProjectId}"]`).should( - 'contain.text', - 'Project information' - ) + cy.findByRole('link', { name: testProjectName }) + .parent() + .parent() + .within(() => { + cy.findByRole('link', { name: 'Project information' }).click() + }) }) }) diff --git a/server-ce/test/create-and-compile-project.spec.ts b/server-ce/test/create-and-compile-project.spec.ts index 43c853d5fd..f7c0712bab 100644 --- a/server-ce/test/create-and-compile-project.spec.ts +++ b/server-ce/test/create-and-compile-project.spec.ts @@ -123,7 +123,9 @@ describe('Project creation and compilation', function () { cy.findByRole('button', { name: 'Share' }).click() }) cy.findByRole('dialog').within(() => { - cy.findByTestId('collaborator-email-input').type(COLLABORATOR + ',') + cy.findByRole('combobox', { name: 'Add email address' }).type( + COLLABORATOR + ',' + ) cy.findByRole('button', { name: 'Invite' }).click() cy.findByText('Invite not yet accepted.') }) diff --git a/server-ce/test/customization.spec.ts b/server-ce/test/customization.spec.ts index d296c57c6b..af8503c680 100644 --- a/server-ce/test/customization.spec.ts +++ b/server-ce/test/customization.spec.ts @@ -8,7 +8,9 @@ describe('Customization', function () { it('should display the default right footer', function () { cy.visit('/') - cy.get('footer').findByRole('link', { name: 'Fork on GitHub!' }) + cy.findByRole('contentinfo').findByRole('link', { + name: 'Fork on GitHub!', + }) }) }) @@ -25,16 +27,18 @@ describe('Customization', function () { it('should display custom name', function () { cy.visit('/') - cy.get('nav').findByText('CUSTOM APP NAME') + cy.findByRole('navigation', { name: 'Primary' }).findByText( + 'CUSTOM APP NAME' + ) }) it('should display custom left footer', function () { cy.visit('/') - cy.get('footer').findByText('CUSTOM LEFT FOOTER') + cy.findByRole('contentinfo').findByText('CUSTOM LEFT FOOTER') }) it('should display custom right footer', function () { cy.visit('/') - cy.get('footer').findByText('CUSTOM RIGHT FOOTER') + cy.findByRole('contentinfo').findByText('CUSTOM RIGHT FOOTER') }) }) }) diff --git a/server-ce/test/external-auth.spec.ts b/server-ce/test/external-auth.spec.ts index 532ed91f20..8c287f2543 100644 --- a/server-ce/test/external-auth.spec.ts +++ b/server-ce/test/external-auth.spec.ts @@ -24,7 +24,7 @@ describe('SAML', function () { it('login', function () { cy.visit('/') - cy.findByText('Log in with SAML Test Server').click() + cy.findByRole('link', { name: 'Log in with SAML Test Server' }).click() cy.origin(samlURL, () => { cy.get('input[name="username"]').type('sally') @@ -59,11 +59,11 @@ describe('LDAP', function () { it('login', function () { cy.visit('/') - cy.findByText('Log in LDAP') + cy.findByRole('heading', { name: 'Log in LDAP' }) - cy.get('input[name="login"]').type('fry') - cy.get('input[name="password"]').type('fry') - cy.get('button[type="submit"]').click() + cy.findByLabelText('Username').type('fry') + cy.findByLabelText('Password').type('fry') + cy.findByRole('button', { name: 'Login' }).click() cy.log('wait for login to finish') cy.url().should('contain', '/project') diff --git a/server-ce/test/git-bridge.spec.ts b/server-ce/test/git-bridge.spec.ts index 219feb92b0..f20dd0d8fb 100644 --- a/server-ce/test/git-bridge.spec.ts +++ b/server-ce/test/git-bridge.spec.ts @@ -72,11 +72,13 @@ describe('git-bridge', function () { cy.findByRole('button', { name: 'Git integration Generate token', }).click() - cy.findByLabelText('Git authentication token') - .contains(/olp_[a-zA-Z0-9]{16}/) - .then(el => el.text()) - .as('newToken') - cy.findAllByText('Close').last().click() + cy.findByRole('dialog').within(() => { + cy.findByLabelText('Git authentication token') + .contains(/olp_[a-zA-Z0-9]{16}/) + .then(el => el.text()) + .as('newToken') + cy.findByRole('button', { name: 'Close dialog' }).click() + }) cy.get('@newToken').then(token => { // There can be more than one token with the same prefix when retrying cy.findAllByText( @@ -258,7 +260,7 @@ describe('git-bridge', function () { const token = tokenEl.text() // close Git modal - cy.get('body').type('{esc}') + cy.findByRole('button', { name: 'Close dialog' }).click() cy.findByTestId('git-bridge-modal').should('not.exist') // close the modal cy.get('body').type('{esc}') @@ -345,8 +347,16 @@ Hello world }) .findByRole('button', { name: 'History' }) .click() - cy.findByText('(via Git)').should('not.exist') - cy.findAllByText('Back to editor').last().click() + cy.findByRole('complementary', { + name: 'Project history and labels', + }).within(() => { + cy.findByText('(via Git)').should('not.exist') + }) + cy.findByRole('navigation', { + name: 'Project actions', + }) + .findByRole('button', { name: 'Back to editor' }) + .click() cy.then(async () => { await git.push({ ...commonOptions, @@ -379,10 +389,10 @@ Hello world // Wait for history sync - trigger flush by toggling the UI cy.findByRole('navigation', { name: 'Project actions', + }).within(() => { + cy.findByRole('button', { name: 'History' }).click() + cy.findByRole('button', { name: 'Back to editor' }).click() }) - .findByRole('button', { name: 'History' }) - .click() - cy.findAllByText('Back to editor').last().click() // check push in history cy.findByRole('navigation', { @@ -391,10 +401,18 @@ Hello world .findByRole('button', { name: 'History' }) .click() cy.findByText(/Hello world/) - cy.findByText('(via Git)').should('exist') + cy.findByRole('complementary', { + name: 'Project history and labels', + }).within(() => { + cy.findByText('(via Git)').should('exist') + }) // Back to the editor - cy.findAllByText('Back to editor').last().click() + cy.findByRole('navigation', { + name: 'Project actions', + }) + .findByRole('button', { name: 'Back to editor' }) + .click() cy.findByText(/\\documentclass/) .parent() .parent() diff --git a/server-ce/test/graceful-shutdown.spec.ts b/server-ce/test/graceful-shutdown.spec.ts index 58fd2760f4..066e06bd86 100644 --- a/server-ce/test/graceful-shutdown.spec.ts +++ b/server-ce/test/graceful-shutdown.spec.ts @@ -39,14 +39,19 @@ describe('GracefulShutdown', function () { }) cy.log('add additional content') - cy.findByText('\\maketitle').parent().click() - cy.findByText('\\maketitle').parent().type(`\n\\section{{}New Section}`) + cy.findByRole('region', { name: 'Editor' }).within(() => { + cy.findByText('\\maketitle').parent().click() + cy.findByText('\\maketitle').parent().type(`\n\\section{{}New Section}`) + }) recompile() cy.log( 'check flush from frontend to backend: should include new section in PDF' ) - cy.get('.pdf-viewer').should('contain.text', 'New Section') + cy.findByRole('region', { name: 'PDF preview and logs' }).should( + 'contain.text', + 'New Section' + ) cy.log('should have unflushed content in redis before shutdown') cy.then(async () => { @@ -62,8 +67,9 @@ describe('GracefulShutdown', function () { }) cy.log('wait for banner') - cy.findByText(/performing maintenance/) + cy.findByRole('dialog').findByText(/performing maintenance/) cy.log('wait for page reload') + cy.findByRole('heading', { name: 'Maintenance' }) cy.findByText(/is currently down for maintenance/) cy.log('wait for shutdown to complete') @@ -85,13 +91,19 @@ describe('GracefulShutdown', function () { }) cy.log('check loading doc from mongo') - cy.findByText('New Section') + cy.findByRole('region', { name: 'Editor' }).findByText('New Section') cy.log('check PDF') - cy.get('.pdf-viewer').should('contain.text', 'New Section') - + cy.findByRole('region', { name: 'PDF preview and logs' }).should( + 'contain.text', + 'New Section' + ) cy.log('check history') - cy.findByText('History').click() + cy.findByRole('navigation', { + name: 'Project actions', + }) + .findByRole('button', { name: 'History' }) + .click() cy.findByText(/\\section\{New Section}/) }) }) diff --git a/server-ce/test/learn-wiki.spec.ts b/server-ce/test/learn-wiki.spec.ts index cea43ed4cf..ab6a55ae4a 100644 --- a/server-ce/test/learn-wiki.spec.ts +++ b/server-ce/test/learn-wiki.spec.ts @@ -26,22 +26,19 @@ describe('LearnWiki', function () { it('should add a documentation entry to the nav bar', function () { login(REGULAR_USER) cy.visit('/project') - cy.findByRole('menuitem', { name: 'Documentation' }).should( - 'have.attr', - 'href', - '/learn' - ) + cy.findByRole('navigation', { name: 'Primary' }).findByRole('menuitem', { + name: 'Documentation', + }) }) it('should display a tutorial link in the welcome page', function () { login(WITHOUT_PROJECTS_USER) cy.visit('/project') - cy.findByRole('link', { name: LABEL_LEARN_LATEX }) - .should('have.attr', 'href', '/learn/latex/Learn_LaTeX_in_30_minutes') - .and('have.attr', 'target', '_blank') - .within(() => { - cy.get('img').should('have.attr', 'src').and('not.be.empty') - }) + cy.findByRole('link', { name: LABEL_LEARN_LATEX }).should( + 'have.attr', + 'href', + '/learn/latex/Learn_LaTeX_in_30_minutes' + ) }) it('should render wiki page', function () { @@ -102,7 +99,11 @@ describe('LearnWiki', function () { it('should not add a documentation entry to the nav bar', function () { login(REGULAR_USER) cy.visit('/project') - cy.findByText('Documentation').should('not.exist') + cy.findByRole('navigation', { name: 'Primary' }) + .findByRole('menuitem', { + name: 'Documentation', + }) + .should('not.exist') }) it('should not render wiki page', function () { @@ -110,7 +111,7 @@ describe('LearnWiki', function () { cy.visit(COPYING_A_PROJECT_URL, { failOnStatusCode: false, }) - cy.findByText('Not found') + cy.findByRole('heading', { name: 'Not found' }) }) it('should not display a tutorial link in the welcome page', function () { diff --git a/server-ce/test/project-sharing.spec.ts b/server-ce/test/project-sharing.spec.ts index e4a40fb59d..2c6392bc31 100644 --- a/server-ce/test/project-sharing.spec.ts +++ b/server-ce/test/project-sharing.spec.ts @@ -50,10 +50,12 @@ describe('Project Sharing', function () { // Add chat message cy.findByRole('button', { name: 'Chat' }).click() // wait for lazy loading of the chat pane - cy.findByText('Send your first message to your collaborators') - cy.get( - 'textarea[placeholder="Send a message to your collaborators…"]' - ).type('New Chat Message{enter}') + cy.findByRole('complementary', { name: 'Chat' }).findByText( + 'Send your first message to your collaborators' + ) + cy.findByLabelText('Send a message to your collaborators…').type( + 'New Chat Message{enter}' + ) // Get link sharing links enableLinkSharing().then( @@ -130,7 +132,9 @@ describe('Project Sharing', function () { function expectChatAccess() { cy.findByRole('button', { name: 'Chat' }).click() - cy.findByText('New Chat Message') + cy.findByRole('complementary', { name: 'Chat' }).findByText( + 'New Chat Message' + ) } function expectHistoryAccess() { @@ -451,8 +455,14 @@ describe('Project Sharing', function () { it('should not display link sharing in the sharing modal', function () { login('user@example.com') openProjectByName(projectName) - cy.findByText('Share').click() - cy.findByText('Turn on link sharing').should('not.exist') + cy.findByRole('navigation', { + name: 'Project actions', + }) + .findByRole('button', { name: 'Share' }) + .click() + cy.findByRole('button', { name: 'Turn on link sharing' }).should( + 'not.exist' + ) }) it('should block new access to read-only link shared projects', function () { diff --git a/server-ce/test/sandboxed-compiles.spec.ts b/server-ce/test/sandboxed-compiles.spec.ts index 872565ff49..33fd4208a3 100644 --- a/server-ce/test/sandboxed-compiles.spec.ts +++ b/server-ce/test/sandboxed-compiles.spec.ts @@ -38,7 +38,9 @@ describe('SandboxedCompiles', function () { cy.log('Check which compiler version was used, expect 2023') cy.findByRole('button', { name: 'View logs' }).click() - cy.findByText(/This is pdfTeX, Version .+ \(TeX Live 2023\) /) + cy.findByLabelText('Raw logs from the LaTeX compiler').findByText( + /This is pdfTeX, Version .+ \(TeX Live 2023\) / + ) cy.log('Switch TeXLive version from 2023 to 2022') cy.findByRole('navigation', { @@ -59,7 +61,9 @@ describe('SandboxedCompiles', function () { cy.log('Check which compiler version was used, expect 2022') cy.findByRole('button', { name: 'View logs' }).click() - cy.findByText(/This is pdfTeX, Version .+ \(TeX Live 2022\) /) + cy.findByLabelText('Raw logs from the LaTeX compiler').findByText( + /This is pdfTeX, Version .+ \(TeX Live 2022\) / + ) }) checkSyncTeX() @@ -85,10 +89,10 @@ describe('SandboxedCompiles', function () { waitForCompileRateLimitCoolOff() cy.log('Start compile') // We need to start the compile manually because we do not want to wait for it to finish - cy.findByText('Recompile').click() + cy.findByRole('button', { name: 'Recompile' }).click() // Now stop the compile and kill the latex process stopCompile({ delay: 1000 }) - cy.get('.logs-pane') + cy.findByRole('region', { name: 'PDF preview and logs' }) .invoke('text') .should('match', /PDF Rendering Error|Compilation cancelled/) // Check that the previous compile is not running in the background by @@ -96,11 +100,9 @@ describe('SandboxedCompiles', function () { cy.findByText('\\def').parent().click() cy.findByText('\\def').parent().type('{home}disabled loop% ') recompile() - cy.get('.pdf-viewer').should('contain.text', 'disabled loop') - cy.get('.logs-pane').should( - 'not.contain.text', - 'A previous compile is still running' - ) + cy.findByRole('region', { name: 'PDF preview and logs' }) + .should('contain.text', 'disabled loop') + .should('not.contain.text', 'A previous compile is still running') }) } @@ -151,7 +153,10 @@ describe('SandboxedCompiles', function () { .findByText('Section B') .scrollIntoView() cy.get('@start').then((start: any) => { - waitUntilScrollingFinished('.pdfjs-viewer-inner', start) + waitUntilScrollingFinished( + '[data-testid="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. @@ -166,11 +171,13 @@ describe('SandboxedCompiles', function () { it('should sync to pdf', function () { cy.log('zoom in') - cy.findByRole('button', { name: /^\d+%$/ }).click() // TODO: ARIA label + cy.findByRole('button', { name: 'PDF zoom level' }).click() cy.findByRole('menuitem', { name: '400%' }).click() cy.log('scroll to top') cy.findByTestId('pdfjs-viewer-inner').scrollTo('top') - waitUntilScrollingFinished('.pdfjs-viewer-inner', -1).as('start') + waitUntilScrollingFinished('[data-testid="pdfjs-viewer-inner"]', -1).as( + 'start' + ) cy.log('navigate to title') cy.findByRole('textbox', { name: 'Source Editor editing' }).within( @@ -180,7 +187,10 @@ describe('SandboxedCompiles', function () { ) cy.findByRole('button', { name: 'Go to code location in PDF' }).click() cy.get('@start').then((start: any) => { - waitUntilScrollingFinished('.pdfjs-viewer-inner', start) + waitUntilScrollingFinished( + '[data-testid="pdfjs-viewer-inner"]', + start + ) .as('title') .should('be.greaterThan', start) }) @@ -191,7 +201,10 @@ describe('SandboxedCompiles', function () { ) cy.findByRole('button', { name: 'Go to code location in PDF' }).click() cy.get('@title').then((title: any) => { - waitUntilScrollingFinished('.pdfjs-viewer-inner', title) + waitUntilScrollingFinished( + '[data-testid="pdfjs-viewer-inner"]', + title + ) .as('sectionA') .should('be.greaterThan', title) }) @@ -202,7 +215,10 @@ describe('SandboxedCompiles', function () { ) cy.findByRole('button', { name: 'Go to code location in PDF' }).click() cy.get('@sectionA').then((title: any) => { - waitUntilScrollingFinished('.pdfjs-viewer-inner', title) + waitUntilScrollingFinished( + '[data-testid="pdfjs-viewer-inner"]', + title + ) .as('sectionB') .should('be.greaterThan', title) }) @@ -225,10 +241,9 @@ describe('SandboxedCompiles', function () { }) recompile() recompile() - cy.findByRole('region', { name: 'PDF preview and logs' }).within(() => { - cy.findByText('Test Section').should('contain.text', 'Test Section') - }) - cy.findByTestId('logs-pane').should('not.contain.text', 'No PDF') + cy.findByRole('region', { name: 'PDF preview and logs' }) + .findByText('Test Section') + .should('not.contain.text', 'No PDF') }) } @@ -239,13 +254,14 @@ describe('SandboxedCompiles', function () { createProject('XeLaTeX') }) cy.log('wait for compile') - cy.findByRole('region', { name: 'PDF preview and logs' }).should( - 'contain.text', + cy.findByRole('region', { name: 'PDF preview and logs' }).findByText( 'XeLaTeX' ) cy.log('Check which compiler was used, expect pdfLaTeX') cy.findByRole('button', { name: 'View logs' }).click() - cy.findByText(/This is pdfTeX/) + cy.findByLabelText('Raw logs from the LaTeX compiler').findByText( + /This is pdfTeX/ + ) cy.log('Switch compiler to from pdfLaTeX to XeLaTeX') cy.findByRole('navigation', { @@ -265,7 +281,9 @@ describe('SandboxedCompiles', function () { cy.log('Check which compiler was used, expect XeLaTeX') cy.findByRole('button', { name: 'View logs' }).click() - cy.findByText(/This is XeTeX/) + cy.findByLabelText('Raw logs from the LaTeX compiler').findByText( + /This is XeTeX/ + ) }) } @@ -277,11 +295,15 @@ describe('SandboxedCompiles', function () { it('should not offer TexLive images and use default compiler', function () { createProject('sandboxed') cy.log('wait for compile') - cy.get('.pdf-viewer').should('contain.text', 'sandboxed') + cy.findByRole('region', { name: 'PDF preview and logs' }).findByText( + 'sandboxed' + ) cy.log('Check which compiler version was used, expect 2025') - cy.get('[aria-label="View logs"]').click() - cy.findByText(/This is pdfTeX, Version .+ \(TeX Live 2025\) /) + cy.findByRole('button', { name: 'View logs' }).click() + cy.findByLabelText('Raw logs from the LaTeX compiler').findByText( + /This is pdfTeX, Version .+ \(TeX Live 2025\) / + ) cy.log('Check that there is no TeX Live version toggle') cy.findByRole('navigation', { @@ -289,8 +311,10 @@ describe('SandboxedCompiles', function () { }) .findByRole('button', { name: 'Menu' }) .click() - cy.findByText('Word Count') // wait for lazy loading - cy.findByText(LABEL_TEX_LIVE_VERSION).should('not.exist') + cy.findByTestId('left-menu').within(() => { + cy.findByRole('button', { name: 'Word Count' }) // wait for lazy loading + cy.findByText(LABEL_TEX_LIVE_VERSION).should('not.exist') + }) }) } diff --git a/server-ce/test/templates.spec.ts b/server-ce/test/templates.spec.ts index 8aba716af2..f1804fca87 100644 --- a/server-ce/test/templates.spec.ts +++ b/server-ce/test/templates.spec.ts @@ -43,9 +43,7 @@ describe('Templates', function () { it('should show templates link on welcome page', function () { login(WITHOUT_PROJECTS_USER) cy.visit('/') - cy.findByRole('link', { name: LABEL_BROWSE_TEMPLATES }) - .should('have.attr', 'href', '/templates') - .click() + cy.findByRole('link', { name: LABEL_BROWSE_TEMPLATES }).click() cy.url().should('match', /\/templates$/) }) @@ -62,32 +60,31 @@ describe('Templates', function () { }) .findByRole('button', { name: 'Menu' }) .click() - cy.findByText('Manage Template').click() + cy.findByRole('button', { name: 'Manage Template' }).click() - cy.findByText('Template Description').as('description').click() - cy.get('@description').parent().get('textarea').type(description) - cy.findByText('Publish').click() - cy.findByText('Publishing…').parent().should('be.disabled') - cy.findByText('Publish').should('not.exist') - cy.findByText('Unpublish', { timeout: 60_000 }) - cy.findByText('Republish') + cy.findByLabelText('Template Description').type(description) + cy.findByRole('button', { name: 'Publish' }).click() + cy.findByRole('button', { name: 'Publishing…' }).should('be.disabled') + cy.findByRole('button', { name: 'Publish' }).should('not.exist') + cy.findByRole('button', { name: 'Unpublish', timeout: 60_000 }) + cy.findByRole('button', { name: 'Republish' }) - cy.findByText('View it in the template gallery').click() + cy.findByRole('link', { name: 'View it in the template gallery' }).click() cy.url() .should('match', /\/templates\/[a-f0-9]{24}$/) .as('templateURL') - cy.findAllByText(name).first().should('exist') + cy.findByRole('heading', { level: 2 }).findByText(name) cy.findByText(description) - cy.findByText('Open as Template') - cy.findByText('Unpublish') - cy.findByText('Republish') + cy.findByRole('link', { name: 'Open as Template' }) + cy.findByRole('button', { name: 'Unpublish' }) + cy.findByRole('button', { name: 'Republish' }) cy.get('img') .should('have.attr', 'src') .and('match', /\/v\/0\//) - cy.findByText('Republish').click() - cy.findByText('Publishing…').parent().should('be.disabled') - cy.findByText('Republish', { timeout: 60_000 }) + cy.findByRole('button', { name: 'Republish' }).click() + cy.findByRole('button', { name: 'Publishing…' }).should('be.disabled') + cy.findByRole('button', { name: 'Republish', timeout: 60_000 }) cy.get('img', { timeout: 60_000 }) .should('have.attr', 'src') .and('match', /\/v\/1\//) @@ -95,43 +92,38 @@ describe('Templates', function () { // custom tag const tagName = `${Date.now()}` cy.visit('/') - cy.findByText(name) - .parent() - .parent() - .within(() => cy.get('input[type="checkbox"]').first().check()) - cy.get('.project-list-sidebar-scroll').within(() => { - cy.findAllByText('New tag').first().click() - }) + cy.findByRole('checkbox', { name: `Select ${name}` }).check() + cy.findByRole('navigation', { name: 'Project categories and tags' }) + .findByRole('button', { name: 'New tag' }) + .click() cy.focused().type(tagName) - cy.findByText('Create').click() - cy.get('.project-list-sidebar-scroll').within(() => { - cy.findByText(tagName) - .parent() - .within(() => cy.get('.name').should('have.text', `${tagName} (1)`)) - }) + cy.findByRole('button', { name: 'Create' }).click() + cy.findByRole('navigation', { + name: 'Project categories and tags', + }).should('contain', `${tagName} (1)`) // Check listing cy.visit('/templates') - cy.findByText(tagName) + cy.findByRole('link', { name: tagName }) cy.visit('/templates/all') - cy.findByText(name) + cy.findByRole('heading', { name }) cy.visit(`/templates/${tagName}`) - cy.findByText(name) + cy.findByRole('heading', { name }) // Unpublish via template page cy.get('@templateURL').then(url => cy.visit(`${url}`)) - cy.findByText('Unpublish').click() + cy.findByRole('button', { name: 'Unpublish' }).click() cy.url().should('match', /\/templates$/) cy.get('@templateURL').then(url => cy.visit(`${url}`, { failOnStatusCode: false, }) ) - cy.findByText('Not found') + cy.findByRole('heading', { name: 'Not found' }) cy.visit('/templates/all') - cy.findByText(name).should('not.exist') + cy.findByRole('heading', { name }).should('not.exist') cy.visit(`/templates/${tagName}`) - cy.findByText(name).should('not.exist') + cy.findByRole('heading', { name }).should('not.exist') // Publish again cy.get('@templateProjectId').then(projectId => @@ -142,12 +134,12 @@ describe('Templates', function () { }) .findByRole('button', { name: 'Menu' }) .click() - cy.findByText('Manage Template').click() - cy.findByText('Publish').click() - cy.findByText('Unpublish', { timeout: 60_000 }) + cy.findByRole('button', { name: 'Manage Template' }).click() + cy.findByRole('button', { name: 'Publish' }).click() + cy.findByRole('button', { name: 'Unpublish', timeout: 60_000 }) // Should assign a new template id - cy.findByText('View it in the template gallery').click() + cy.findByRole('link', { name: 'View it in the template gallery' }).click() cy.url() .should('match', /\/templates\/[a-f0-9]{24}$/) .as('newTemplateURL') @@ -161,31 +153,32 @@ describe('Templates', function () { // Open project from template login(REGULAR_USER) cy.visit('/templates') - cy.findByText(tagName).click() - cy.findByText(name).click() - cy.findByText('Open as Template').click() - cy.url().should('match', /\/project\/[a-f0-9]{24}$/) - cy.get('.project-name').should('contain.text', 'Your Paper') // might have (1) suffix + cy.findByRole('link', { name: tagName }).click() + cy.findByRole('link', { name }).click() + cy.findByRole('link', { name: 'Open as Template' }).click() + cy.findByRole('navigation', { name: 'Project actions' }).findByText( + /Your Paper/i + ) // might have (1) suffix cy.findByRole('navigation', { name: 'Project actions', }) .findByRole('button', { name: 'Menu' }) .click() - cy.findByText('Word Count') // wait for lazy loading - cy.findByText('Manage Template').should('not.exist') + cy.findByRole('button', { name: 'Word Count' }).click() // wait for lazy loading + cy.findByRole('button', { name: 'Manage Template' }).should('not.exist') // Check management as regular user cy.get('@newTemplateURL').then(url => cy.visit(`${url}`)) - cy.findByText('Open as Template') - cy.findByText('Unpublish').should('not.exist') - cy.findByText('Republish').should('not.exist') + cy.findByRole('link', { name: 'Open as Template' }) + cy.findByRole('button', { name: 'Unpublish' }).should('not.exist') + cy.findByRole('button', { name: 'Republish' }).should('not.exist') // Check management as admin user login(ADMIN_USER) cy.get('@newTemplateURL').then(url => cy.visit(`${url}`)) - cy.findByText('Open as Template') - cy.findByText('Unpublish') - cy.findByText('Republish') + cy.findByRole('link', { name: 'Open as Template' }) + cy.findByRole('button', { name: 'Unpublish' }) + cy.findByRole('button', { name: 'Republish' }) cy.get('@templateProjectId').then(projectId => cy.visit(`/project/${projectId}`) ) @@ -194,8 +187,8 @@ describe('Templates', function () { }) .findByRole('button', { name: 'Menu' }) .click() - cy.findByText('Manage Template').click() - cy.findByText('Unpublish') + cy.findByRole('button', { name: 'Manage Template' }).click() + cy.findByRole('button', { name: 'Unpublish' }) // Back to templates user login(TEMPLATES_USER) @@ -209,19 +202,20 @@ describe('Templates', function () { }) .findByRole('button', { name: 'Menu' }) .click() - cy.findByText('Manage Template').click() - cy.findByText('Unpublish').click() - cy.findByText('Publish') + cy.findByRole('button', { name: 'Manage Template' }).click() + cy.findByRole('button', { name: 'Unpublish' }).click() + cy.findByRole('button', { name: 'Publish' }) cy.visit('/templates/all') - cy.findByText(name).should('not.exist') + cy.findByRole('link', { name }).should('not.exist') // check for template links, after creating the first project cy.visit('/') cy.findAllByRole('button', { name: NEW_PROJECT_BUTTON_MATCHER }).click() - cy.findAllByText('All Templates') - .first() - .parent() - .should('have.attr', 'href', '/templates/all') + cy.findByRole('menuitem', { name: /All Templates/ }).should( + 'have.attr', + 'href', + '/templates/all' + ) }) }) @@ -237,25 +231,27 @@ describe('Templates', function () { }) .findByRole('button', { name: 'Menu' }) .click() - cy.findByText('Word Count') // wait for lazy loading - cy.findByText('Manage Template').should('not.exist') + cy.findByRole('button', { name: 'Word Count' }) // wait for lazy loading + cy.findByRole('button', { name: 'Manage Template' }).should('not.exist') cy.visit('/templates', { failOnStatusCode: false }) - cy.findByText('Not found') + cy.findByRole('heading', { name: 'Not found' }) cy.visit('/templates/all', { failOnStatusCode: false }) - cy.findByText('Not found') + cy.findByRole('heading', { name: 'Not found' }) // check for template links, after creating the first project cy.visit('/') cy.findAllByRole('button', { name: NEW_PROJECT_BUTTON_MATCHER }).click() - cy.findAllByText('All Templates').should('not.exist') + cy.findByRole('menuitem', { name: /All Templates/ }).should('not.exist') }) it('should not show templates link on welcome page', function () { login(WITHOUT_PROJECTS_USER) cy.visit('/') - cy.findByText(NEW_PROJECT_BUTTON_MATCHER) // wait for lazy loading - cy.findByText(LABEL_BROWSE_TEMPLATES).should('not.exist') + cy.findByRole('button', { name: NEW_PROJECT_BUTTON_MATCHER }) // wait for lazy loading + cy.findByRole('link', { name: LABEL_BROWSE_TEMPLATES }).should( + 'not.exist' + ) }) } diff --git a/server-ce/test/upgrading.spec.ts b/server-ce/test/upgrading.spec.ts index 333b8c82a2..4a75f15697 100644 --- a/server-ce/test/upgrading.spec.ts +++ b/server-ce/test/upgrading.spec.ts @@ -49,7 +49,7 @@ describe('Upgrading', function () { }) cy.log('Wait for successful compile') - cy.get('.pdf-viewer').should('contain.text', PROJECT_NAME) + cy.findByLabelText(/Page.*1/i).findByText(PROJECT_NAME) cy.log('Increment the doc version three times') for (let i = 0; i < 3; i++) { @@ -66,15 +66,15 @@ describe('Upgrading', function () { }) .findByRole('button', { name: 'Menu' }) .click() - cy.findByText('Source').click() - cy.get('.left-menu-modal-backdrop').click({ force: true }) + cy.findByRole('link', { name: 'Source' }).click() + cy.get('body').type('{esc}') } cy.log('Check compile and history') for (let i = 0; i < 3; i++) { - cy.get('.pdf-viewer').should('contain.text', `Old Section ${i}`) + cy.findByLabelText(/Page.*1/i).findByText(`Old Section ${i}`) } - cy.findByText('History').click() + cy.findByRole('button', { name: 'History' }).click() for (let i = 0; i < 3; i++) { cy.findByText(new RegExp(`\\\\section{Old Section ${i}}`)) } @@ -119,7 +119,7 @@ describe('Upgrading', function () { it('should list the old project', function () { cy.visit('/project') - cy.findByText(PROJECT_NAME) + cy.findByRole('link', { name: PROJECT_NAME }) }) it('should open the old project', function () { @@ -135,8 +135,8 @@ describe('Upgrading', function () { }) 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') + cy.findByLabelText(/Page.*1/i).findByText(PROJECT_NAME) + cy.findByLabelText(/Page.*1/i).findByText('Old Section 2') cy.log('Add more content') const newSection = `New Section ${uuid()}` @@ -145,8 +145,8 @@ describe('Upgrading', function () { cy.log('Check compile and history') recompile() - cy.get('.pdf-viewer').should('contain.text', newSection) - cy.findByText('History').click() + cy.findByLabelText(/Page.*1/i).findByText(newSection) + cy.findByRole('button', { name: 'History' }).click() cy.findByText(/\\section\{Old Section 2}/) cy.findByText(new RegExp(`\\\\section\\{${newSection}}`)) }) @@ -208,10 +208,10 @@ describe('Upgrading', function () { cy.log('Trigger flush') recompile() - cy.get('.pdf-viewer').should('contain.text', 'FiveOOne Section') + cy.findByLabelText(/Page.*1/i).findByText('FiveOOne Section') cy.log('Check for broken history, i.e. not synced with latest edit') - cy.findByText('History').click() + cy.findByRole('button', { name: 'History' }).click() cy.findByText(/\\section\{Old Section 2}/) // wait for lazy loading cy.findByText(/\\section\{FiveOOne Section}/).should('not.exist') }) @@ -246,7 +246,7 @@ describe('Upgrading', function () { cy.log( 'The edit that was made while the history was broken should be there now.' ) - cy.findByText('History').click() + cy.findByRole('button', { name: 'History' }).click() cy.findByText(/\\section\{FiveOOne Section}/) // TODO(das7pad): restore after https://github.com/overleaf/internal/issues/19588 is fixed. diff --git a/services/web/app/views/general/404.pug b/services/web/app/views/general/404.pug index ce92d6d56e..9a9d869cdf 100644 --- a/services/web/app/views/general/404.pug +++ b/services/web/app/views/general/404.pug @@ -5,7 +5,7 @@ block content .container .error-container .error-details - p.error-status Not found + h1.error-status #{translate("not_found")} p.error-description #{translate("cant_find_page")} p.error-actions a.error-btn(href='/') Home diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 1d12577d6b..b6c61b4e1a 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -280,6 +280,7 @@ "clicking_delete_will_remove_sso_config_and_clear_saml_data": "", "clone_with_git": "", "close": "", + "close_dialog": "", "clsi_maintenance": "", "clsi_unavailable": "", "code_check_failed": "", @@ -1272,6 +1273,7 @@ "pdf_unavailable_for_download": "", "pdf_viewer": "", "pdf_viewer_error": "", + "pdf_zoom_level": "", "pending_additional_licenses": "", "pending_addon_cancellation": "", "pending_invite": "", diff --git a/services/web/frontend/js/features/pdf-preview/components/pdf-zoom-dropdown.tsx b/services/web/frontend/js/features/pdf-preview/components/pdf-zoom-dropdown.tsx index 3fbbe0df6e..40120ded5a 100644 --- a/services/web/frontend/js/features/pdf-preview/components/pdf-zoom-dropdown.tsx +++ b/services/web/frontend/js/features/pdf-preview/components/pdf-zoom-dropdown.tsx @@ -75,6 +75,7 @@ function PdfZoomDropdown({ id="pdf-zoom-dropdown" variant="link" className="pdf-toolbar-btn pdfjs-zoom-dropdown-button small" + aria-label={t('pdf_zoom_level')} > {rawScaleToPercentage(rawScale)} diff --git a/services/web/frontend/js/shared/components/ol/ol-modal.tsx b/services/web/frontend/js/shared/components/ol/ol-modal.tsx index 5342946079..35fecd471b 100644 --- a/services/web/frontend/js/shared/components/ol/ol-modal.tsx +++ b/services/web/frontend/js/shared/components/ol/ol-modal.tsx @@ -8,6 +8,7 @@ import { } from 'react-bootstrap' import { ModalBodyProps } from 'react-bootstrap/ModalBody' import type { Options as FocusTrapOptions } from 'focus-trap' +import { useTranslation } from 'react-i18next' type OLModalProps = ModalProps & { size?: 'sm' | 'lg' @@ -52,8 +53,13 @@ export function OLModalHeader({ closeButton = true, ...props }: OLModalHeaderProps) { + const { t } = useTranslation() return ( - + {children} ) diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 5800cb4743..98f651871c 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -357,6 +357,7 @@ "clicking_delete_will_remove_sso_config_and_clear_saml_data": "Clicking <0>Delete will remove your SSO configuration and unlink all users. You can only do this when SSO is disabled in your group settings.", "clone_with_git": "Clone with Git", "close": "Close", + "close_dialog": "Close dialog", "clsi_maintenance": "The compile servers are down for maintenance, and will be back shortly.", "clsi_unavailable": "Sorry, the compile server for your project was temporarily unavailable. Please try again in a few moments.", "cn": "Chinese (Simplified)", @@ -1506,6 +1507,7 @@ "normally_x_price_per_month": "Normally __price__ per month", "normally_x_price_per_year": "Normally __price__ per year", "not_a_student": "Not a student?", + "not_found": "Not found", "not_found_error_from_the_supplied_url": "The link to open this content on Overleaf pointed to a file that could not be found. If this keeps happening for links on a particular site, please report this to them.", "not_managed": "Not managed", "not_now": "Not now", @@ -1659,6 +1661,7 @@ "pdf_unavailable_for_download": "PDF unavailable for download", "pdf_viewer": "PDF Viewer", "pdf_viewer_error": "There was a problem displaying the PDF for this project.", + "pdf_zoom_level": "PDF zoom level", "pending": "Pending", "pending_additional_licenses": "Your subscription is changing to include <0>__pendingAdditionalLicenses__ additional license(s) for a total of <1>__pendingTotalLicenses__ licenses.", "pending_addon_cancellation": "Your subscription will change to remove the __addOnName__ add-on at the end of the current billing period.", diff --git a/services/web/test/frontend/components/editor-left-menu/editor-left-menu.spec.tsx b/services/web/test/frontend/components/editor-left-menu/editor-left-menu.spec.tsx index 18d1d5087c..a33cb38b42 100644 --- a/services/web/test/frontend/components/editor-left-menu/editor-left-menu.spec.tsx +++ b/services/web/test/frontend/components/editor-left-menu/editor-left-menu.spec.tsx @@ -163,7 +163,7 @@ describe('', function () { cy.findByRole('heading', { name: 'Copy project' }) // try closing & re-opening the modal with different methods - cy.findByRole('button', { name: 'Close' }).click() + cy.findByRole('button', { name: 'Close dialog' }).click() cy.findByRole('button', { name: 'Copy project' }).click() cy.findByRole('button', { name: 'Cancel' }).click() cy.findByRole('button', { name: 'Copy project' }).click() diff --git a/services/web/test/frontend/components/shared/modal.spec.tsx b/services/web/test/frontend/components/shared/modal.spec.tsx index 613b711f27..653429de35 100644 --- a/services/web/test/frontend/components/shared/modal.spec.tsx +++ b/services/web/test/frontend/components/shared/modal.spec.tsx @@ -43,7 +43,7 @@ describe('', function () { cy.findByRole('button', { name: 'Open modal' }).click() cy.findByRole('dialog').should('be.visible') cy.findByLabelText(/enter text/i).should('be.visible') - cy.get('body').type('{esc}') + cy.findByRole('button', { name: 'Close dialog' }).click() // Modal should hide with single escape (escapeDeactivates: false means FocusTrap doesn't handle it) cy.findByRole('dialog').should('not.exist') cy.findByRole('button', { name: 'Open modal' }).should('be.visible') @@ -70,13 +70,13 @@ describe('', function () { cy.findByRole('button', { name: 'Open modal' }).click() cy.findByRole('dialog').should('be.visible') - cy.findByRole('button', { name: 'Close' }).should('be.focused') + cy.findByRole('button', { name: 'Close dialog' }).should('be.focused') cy.focused().tab() cy.findByLabelText(/enter text/i).should('be.focused') cy.focused().tab() cy.findByRole('button', { name: 'Close the modal' }).should('be.focused') cy.focused().tab() - cy.findByRole('button', { name: 'Close' }).should('be.focused') + cy.findByRole('button', { name: 'Close dialog' }).should('be.focused') cy.focused().tab({ shift: true }) cy.findByRole('button', { name: 'Close the modal' }).should('be.focused') }) @@ -95,7 +95,7 @@ describe('', function () { cy.mount() cy.findByRole('button', { name: 'Open modal' }).click() cy.findByRole('dialog').should('be.visible') - cy.findByRole('button', { name: 'Close' }).click() + cy.findByRole('button', { name: 'Close dialog' }).click() cy.findByRole('dialog').should('not.exist') }) @@ -103,7 +103,7 @@ describe('', function () { cy.mount() cy.findByRole('button', { name: 'Open modal' }).click() cy.findByRole('dialog').should('be.visible') - cy.get('body').type('{esc}') + cy.findByRole('button', { name: 'Close dialog' }).click() cy.findByRole('dialog').should('not.exist') }) }) diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-dictionary.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-dictionary.test.tsx index e094698d4d..305c21bc5e 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-dictionary.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-dictionary.test.tsx @@ -24,8 +24,8 @@ describe('', function () { within(modal).getByRole('heading', { name: 'Edit Dictionary' }) within(modal).getByText('Your custom dictionary is empty.') - const [, closeButton] = within(modal).getAllByRole('button', { - name: 'Close', + const closeButton = within(modal).getByRole('button', { + name: 'Close dialog', }) fireEvent.click(closeButton) expect(screen.getByTestId('dictionary-modal')).to.not.be.null diff --git a/services/web/test/frontend/features/project-list/components/new-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/new-project-button.test.tsx index 4f9c5e42dc..f7e6d3b3cb 100644 --- a/services/web/test/frontend/features/project-list/components/new-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/new-project-button.test.tsx @@ -62,7 +62,7 @@ describe('', function () { it('close the new project modal when clicking at the top right "x" button', function () { fireEvent.click(screen.getByRole('menuitem', { name: 'Blank project' })) - fireEvent.click(screen.getByRole('button', { name: 'Close' })) + fireEvent.click(screen.getByRole('button', { name: 'Close dialog' })) expect(screen.queryByRole('dialog')).to.be.null }) diff --git a/services/web/test/frontend/features/settings-modal/settings/dictionary-setting.test.tsx b/services/web/test/frontend/features/settings-modal/settings/dictionary-setting.test.tsx index 27949d215a..6d8faa7c84 100644 --- a/services/web/test/frontend/features/settings-modal/settings/dictionary-setting.test.tsx +++ b/services/web/test/frontend/features/settings-modal/settings/dictionary-setting.test.tsx @@ -26,8 +26,8 @@ describe('', function () { within(modal).getByRole('heading', { name: 'Edit Dictionary' }) within(modal).getByText('Your custom dictionary is empty.') - const [, closeButton] = within(modal).getAllByRole('button', { - name: 'Close', + const closeButton = within(modal).getByRole('button', { + name: 'Close dialog', }) fireEvent.click(closeButton) expect(screen.getByTestId('dictionary-modal')).to.not.be.null diff --git a/services/web/test/frontend/features/settings/components/leave-section.test.tsx b/services/web/test/frontend/features/settings/components/leave-section.test.tsx index ddf67ac11f..b36fff9a64 100644 --- a/services/web/test/frontend/features/settings/components/leave-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/leave-section.test.tsx @@ -35,7 +35,7 @@ describe('', function () { ) const cancelButton = screen.getByRole('button', { - name: 'Close', + name: 'Cancel', }) fireEvent.click(cancelButton) diff --git a/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.tsx b/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.tsx index 9cfc6af9bb..e9d5da2abf 100644 --- a/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.tsx +++ b/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.tsx @@ -141,15 +141,10 @@ describe('', function () { createContextProps() ) - const [headerCloseButton, footerCloseButton] = await screen.findAllByRole( - 'button', - { name: 'Close' } - ) + const closeButton = screen.getByRole('button', { name: 'Close dialog' }) + await userEvent.click(closeButton) - await userEvent.click(headerCloseButton) - await userEvent.click(footerCloseButton) - - expect(handleHide.callCount).to.equal(2) + expect(handleHide.callCount).to.equal(1) }) it('handles access level "private"', async function () { @@ -410,7 +405,7 @@ describe('', function () { createContextProps({ publicAccessLevel: 'tokenBased', invites }) ) - const [, closeButton] = screen.getAllByRole('button', { + const closeButton = screen.getByRole('button', { name: 'Close', }) @@ -446,7 +441,7 @@ describe('', function () { createContextProps({ publicAccessLevel: 'tokenBased', invites }) ) - const [, closeButton] = screen.getAllByRole('button', { + const closeButton = screen.getByRole('button', { name: 'Close', }) @@ -481,7 +476,7 @@ describe('', function () { createContextProps({ publicAccessLevel: 'tokenBased', members }) ) - const [, closeButton] = screen.getAllByRole('button', { + const closeButton = screen.getByRole('button', { name: 'Close', })