From c2da12939e12f4e6fc9ad64953beb94d37c2161b Mon Sep 17 00:00:00 2001 From: Tim Down <158919+timdown@users.noreply.github.com> Date: Wed, 19 Mar 2025 11:48:41 +0000 Subject: [PATCH] Merge pull request #24313 from overleaf/td-ac-bs5-frontend-tests Update front-end tests to use Bootstrap 5 GitOrigin-RevId: abaa09f8c0639d64d6ade97468ab16204e5de97b --- .../web/frontend/extracted-translations.json | 1 + .../components/dictionary-modal.tsx | 1 + .../notifications/groups/common.tsx | 1 + .../emails/institution-and-role.tsx | 1 + .../settings/components/password-section.tsx | 1 + .../dashboard/leave-group-modal.tsx | 3 +- ...rsonal-subscription-recurly-sync-email.tsx | 1 + .../cancel-plan/cancel-subscription.tsx | 1 + .../cancel-plan/downgrade-plan-button.tsx | 1 + .../cancel-plan/extend-trial-button.tsx | 1 + .../modals/cancel-ai-add-on-modal.tsx | 1 + .../modals/change-to-group-modal.tsx | 1 + .../modals/confirm-change-plan-modal.tsx | 1 + .../modals/keep-current-plan-modal.tsx | 1 + .../js/shared/components/loading-spinner.tsx | 6 + .../settings/settings-dictionary.test.tsx | 4 +- .../components/online-users-widget.test.jsx | 4 +- .../components/current-plan-widget.test.tsx | 34 ++-- .../components/new-project-button.test.tsx | 12 -- .../components/notifications.test.tsx | 6 +- .../components/project-list-root.test.tsx | 68 +++++-- .../components/project-list-title.tsx | 3 + .../sidebar/add-affiliation.test.tsx | 2 +- .../components/survey-widget.test.tsx | 8 +- .../archive-project-button.test.tsx | 8 +- ...e-and-download-project-pdf-button.test.tsx | 4 +- .../copy-project-button.test.tsx | 10 +- .../delete-project-button.test.tsx | 8 +- .../download-project-button.test.tsx | 4 +- .../leave-project-button.test.tsx | 8 +- .../rename-project-button.test.tsx | 4 +- .../trash-project-button.test.tsx | 8 +- .../unarchive-project-button.test.tsx | 4 +- .../untrash-project-button.test.tsx | 4 +- .../buttons/archive-projects.button.test.tsx | 4 +- .../buttons/download-projects-button.test.tsx | 4 +- .../buttons/trash-projects.button.test.tsx | 4 +- .../rename-project-modal.test.tsx | 8 +- .../table/projects-action-modal.test.tsx | 4 +- .../components/account-info-section.test.tsx | 2 +- .../emails/emails-section-actions.test.tsx | 13 +- .../emails-section-add-new-email.test.tsx | 4 +- .../components/emails/emails-section.test.tsx | 2 +- .../components/emails/sso-alert.test.tsx | 10 +- .../components/linking-section.test.tsx | 2 +- .../linking/integration-widget.test.tsx | 15 +- .../components/linking/sso-widget.test.tsx | 23 ++- .../components/password-section.test.tsx | 2 +- .../components/security-section.test.tsx | 2 +- .../group-subscription-memberships.test.tsx | 12 +- .../dashboard/personal-subscription.test.tsx | 2 +- .../dashboard/states/active/active.test.tsx | 10 +- .../active/change-plan/change-plan.test.tsx | 34 ++-- .../group-invite/accepted-invite.test.tsx | 60 +++--- .../group-invite/group-invite.test.tsx | 179 +++++++++--------- .../web/test/frontend/helpers/reset-meta.ts | 1 + 56 files changed, 358 insertions(+), 264 deletions(-) diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 5a4e7d818d..b00674e5aa 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -836,6 +836,7 @@ "join_project": "", "join_team_explanation": "", "joined_team": "", + "joining": "", "justify": "", "kb_suggestions_enquiry": "", "keep_current_plan": "", diff --git a/services/web/frontend/js/features/dictionary/components/dictionary-modal.tsx b/services/web/frontend/js/features/dictionary/components/dictionary-modal.tsx index ad450f65a1..dc5415a403 100644 --- a/services/web/frontend/js/features/dictionary/components/dictionary-modal.tsx +++ b/services/web/frontend/js/features/dictionary/components/dictionary-modal.tsx @@ -15,6 +15,7 @@ function DictionaryModal({ show, handleHide }: DictionaryModalProps) { show={show} onHide={handleHide} id="dictionary-modal" + data-testid="dictionary-modal" size="sm" > diff --git a/services/web/frontend/js/features/project-list/components/notifications/groups/common.tsx b/services/web/frontend/js/features/project-list/components/notifications/groups/common.tsx index 96bbd1a840..3a383a0064 100644 --- a/services/web/frontend/js/features/project-list/components/notifications/groups/common.tsx +++ b/services/web/frontend/js/features/project-list/components/notifications/groups/common.tsx @@ -96,6 +96,7 @@ function CommonNotification({ notification }: CommonNotificationProps) { handleAcceptInvite(notification)} > diff --git a/services/web/frontend/js/features/settings/components/emails/institution-and-role.tsx b/services/web/frontend/js/features/settings/components/emails/institution-and-role.tsx index ea96920e3d..5506b4e27a 100644 --- a/services/web/frontend/js/features/settings/components/emails/institution-and-role.tsx +++ b/services/web/frontend/js/features/settings/components/emails/institution-and-role.tsx @@ -145,6 +145,7 @@ function InstitutionAndRole({ userEmailData }: InstitutionAndRoleProps) { type="submit" disabled={!role || !department} isLoading={isLoading} + loadingLabel={t('saving')} bs3Props={{ loading: isLoading ? `${t('saving')}…` diff --git a/services/web/frontend/js/features/settings/components/password-section.tsx b/services/web/frontend/js/features/settings/components/password-section.tsx index 63a8cbcae2..06c7e099d1 100644 --- a/services/web/frontend/js/features/settings/components/password-section.tsx +++ b/services/web/frontend/js/features/settings/components/password-section.tsx @@ -203,6 +203,7 @@ function PasswordForm() { variant="primary" disabled={!isFormValid} isLoading={isLoading} + loadingLabel={`${t('saving')}…`} bs3Props={{ loading: isLoading ? `${t('saving')}…` : t('change'), }} diff --git a/services/web/frontend/js/features/subscription/components/dashboard/leave-group-modal.tsx b/services/web/frontend/js/features/subscription/components/dashboard/leave-group-modal.tsx index 6214f3b46f..d56b0c80b8 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/leave-group-modal.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/leave-group-modal.tsx @@ -70,13 +70,14 @@ export default function LeaveGroupModal() { onClick={handleConfirmLeaveGroup} disabled={inflight} isLoading={inflight} + loadingLabel={t('processing_uppercase') + '…'} bs3Props={{ loading: inflight ? t('processing_uppercase') + '…' : t('leave_now'), }} > - {t('processing_uppercase')} + {t('leave_now')} diff --git a/services/web/frontend/js/features/subscription/components/dashboard/personal-subscription-recurly-sync-email.tsx b/services/web/frontend/js/features/subscription/components/dashboard/personal-subscription-recurly-sync-email.tsx index 6fc965a9be..1425609264 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/personal-subscription-recurly-sync-email.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/personal-subscription-recurly-sync-email.tsx @@ -50,6 +50,7 @@ function PersonalSubscriptionRecurlySyncEmail() { type="submit" disabled={isLoading} isLoading={isLoading} + loadingLabel={t('updating')} bs3Props={{ loading: isLoading ? t('updating') + '…' : t('update'), }} diff --git a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx index 504891cabb..eddb4baafc 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/cancel-subscription.tsx @@ -34,6 +34,7 @@ function ConfirmCancelSubscriptionButton({ return ( { + // Ensure that spinner is displayed immediately if delay is 0 + if (delay === 0) { + setShow(true) + return + } + const timer = setTimeout(() => { setShow(true) }, delay) 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 4b0fe63391..e094698d4d 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 @@ -19,7 +19,7 @@ describe('', function () { const button = screen.getByText('Edit') fireEvent.click(button) - const modal = screen.getAllByRole('dialog')[0] + const modal = screen.getByTestId('dictionary-modal') within(modal).getByRole('heading', { name: 'Edit Dictionary' }) within(modal).getByText('Your custom dictionary is empty.') @@ -28,6 +28,6 @@ describe('', function () { name: 'Close', }) fireEvent.click(closeButton) - expect(screen.queryByRole('dialog')).to.be.null + expect(screen.getByTestId('dictionary-modal')).to.not.be.null }) }) diff --git a/services/web/test/frontend/features/editor-navigation-toolbar/components/online-users-widget.test.jsx b/services/web/test/frontend/features/editor-navigation-toolbar/components/online-users-widget.test.jsx index 6292891b4d..96a8abe0aa 100644 --- a/services/web/test/frontend/features/editor-navigation-toolbar/components/online-users-widget.test.jsx +++ b/services/web/test/frontend/features/editor-navigation-toolbar/components/online-users-widget.test.jsx @@ -26,11 +26,11 @@ describe('', function () { screen.getByText('a') }) - it('displays user name in a tooltip', function () { + it('displays user name in a tooltip', async function () { render() const icon = screen.getByText('t') fireEvent.mouseOver(icon) - screen.getByRole('tooltip', { name: 'test_user' }) + await screen.findByRole('tooltip', { name: 'test_user' }) }) it('calls "goToUser" when the user initial is clicked', function () { diff --git a/services/web/test/frontend/features/project-list/components/current-plan-widget.test.tsx b/services/web/test/frontend/features/project-list/components/current-plan-widget.test.tsx index c4f67ce472..0ec6db3c9f 100644 --- a/services/web/test/frontend/features/project-list/components/current-plan-widget.test.tsx +++ b/services/web/test/frontend/features/project-list/components/current-plan-widget.test.tsx @@ -41,13 +41,13 @@ describe('', function () { render() }) - it('shows text and tooltip on mouseover', function () { + it('shows text and tooltip on mouseover', async function () { const link = screen.getByRole('link', { name: /plan is paused/i, }) fireEvent.mouseOver(link) - screen.getByRole('tooltip', { name: pausedTooltipMessage }) + await screen.findByRole('tooltip', { name: pausedTooltipMessage }) }) }) @@ -60,17 +60,17 @@ describe('', function () { render() }) - it('shows text and tooltip on mouseover', function () { + it('shows text and tooltip on mouseover', async function () { const link = screen.getByRole('link', { name: /you’re on the free plan/i, }) fireEvent.mouseOver(link) - screen.getByRole('tooltip', { name: freePlanTooltipMessage }) + await screen.findByRole('tooltip', { name: freePlanTooltipMessage }) }) it('clicks on upgrade button', function () { - const upgradeLink = screen.getByRole('link', { name: /upgrade/i }) + const upgradeLink = screen.getByRole('button', { name: /upgrade/i }) fireEvent.click(upgradeLink) expect(sendMBSpy).to.be.calledOnce expect(sendMBSpy).calledWith('upgrade-button-click', { @@ -156,7 +156,7 @@ describe('', function () { }) }) - it('shows text and tooltip on mouseover', function () { + it('shows text and tooltip on mouseover', async function () { render() const link = screen.getByRole('link', { @@ -164,10 +164,10 @@ describe('', function () { }) fireEvent.mouseOver(link) - screen.getByRole('tooltip', { + await screen.findByRole('tooltip', { name: new RegExp(`on the ${subscription.plan.name}`, 'i'), }) - screen.getByRole('tooltip', { name: paidPlanTooltipMessage }) + await screen.findByRole('tooltip', { name: paidPlanTooltipMessage }) }) }) @@ -189,7 +189,7 @@ describe('', function () { }) }) - it('shows text and tooltip on mouseover (without subscription team name)', function () { + it('shows text and tooltip on mouseover (without subscription team name)', async function () { render() const link = screen.getByRole('link', { @@ -198,16 +198,16 @@ describe('', function () { fireEvent.mouseOver(link) expect(subscription.subscription.teamName).to.be.undefined - screen.getByRole('tooltip', { + await screen.findByRole('tooltip', { name: new RegExp( `on the ${subscription.plan.name} plan as a member of a group subscription`, 'i' ), }) - screen.getByRole('tooltip', { name: paidPlanTooltipMessage }) + await screen.findByRole('tooltip', { name: paidPlanTooltipMessage }) }) - it('shows text and tooltip on mouseover (with subscription team name)', function () { + it('shows text and tooltip on mouseover (with subscription team name)', async function () { const newSubscription = { ...subscription, subscription: { @@ -227,18 +227,18 @@ describe('', function () { }) fireEvent.mouseOver(link) - screen.getByRole('tooltip', { + await screen.findByRole('tooltip', { name: new RegExp( `on the ${newSubscription.plan.name} plan as a member of a group subscription, ${newSubscription.subscription.teamName}`, 'i' ), }) - screen.getByRole('tooltip', { name: paidPlanTooltipMessage }) + await screen.findByRole('tooltip', { name: paidPlanTooltipMessage }) }) }) describe('commons', function () { - it('shows text and tooltip on mouseover', function () { + it('shows text and tooltip on mouseover', async function () { const subscription = { type: 'commons', plan: { @@ -260,13 +260,13 @@ describe('', function () { }) fireEvent.mouseOver(link) - screen.getByRole('tooltip', { + await screen.findByRole('tooltip', { name: new RegExp( `on the ${subscription.plan.name} plan because of your affiliation with ${subscription.subscription.name}`, 'i' ), }) - screen.getByRole('tooltip', { name: paidPlanTooltipMessage }) + await screen.findByRole('tooltip', { name: paidPlanTooltipMessage }) }) }) }) 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 d3c465434e..93c7a68e3a 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 @@ -4,20 +4,8 @@ import fetchMock from 'fetch-mock' import NewProjectButton from '../../../../../frontend/js/features/project-list/components/new-project-button' import { renderWithProjectListContext } from '../helpers/render-with-context' import getMeta from '@/utils/meta' -import * as bootstrapUtils from '@/features/utils/bootstrap-5' -import sinon, { type SinonStub } from 'sinon' describe('', function () { - let isBootstrap5Stub: SinonStub - - before(function () { - isBootstrap5Stub = sinon.stub(bootstrapUtils, 'isBootstrap5').returns(true) - }) - - after(function () { - isBootstrap5Stub.restore() - }) - beforeEach(function () { fetchMock.reset() }) diff --git a/services/web/test/frontend/features/project-list/components/notifications.test.tsx b/services/web/test/frontend/features/project-list/components/notifications.test.tsx index 43a3791197..771c9da37e 100644 --- a/services/web/test/frontend/features/project-list/components/notifications.test.tsx +++ b/services/web/test/frontend/features/project-list/components/notifications.test.tsx @@ -141,7 +141,9 @@ describe('', function () { expect(joinBtn.disabled).to.be.true - await waitForElementToBeRemoved(() => screen.getByText('Loading')) + await waitForElementToBeRemoved(() => + screen.getByRole('button', { name: /joining/i }) + ) expect(acceptMock.called()).to.be.true screen.getByText(/joined/i) @@ -185,7 +187,7 @@ describe('', function () { fireEvent.click(joinBtn) await waitForElementToBeRemoved(() => - screen.getByRole('button', { name: /loading/i }) + screen.getByRole('button', { name: /joining/i }) ) expect(fetchMock.called()).to.be.true diff --git a/services/web/test/frontend/features/project-list/components/project-list-root.test.tsx b/services/web/test/frontend/features/project-list/components/project-list-root.test.tsx index 09b186cece..3145280f63 100644 --- a/services/web/test/frontend/features/project-list/components/project-list-root.test.tsx +++ b/services/web/test/frontend/features/project-list/components/project-list-root.test.tsx @@ -1,4 +1,10 @@ -import { fireEvent, screen, waitFor, within } from '@testing-library/react' +import { + fireEvent, + screen, + waitFor, + waitForElementToBeRemoved, + within, +} from '@testing-library/react' import { expect } from 'chai' import fetchMock from 'fetch-mock' import sinon from 'sinon' @@ -157,7 +163,9 @@ describe('', function () { const archiveButton = within(actionsToolbar).getByLabelText('Archive') fireEvent.click(archiveButton) - const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement + const confirmBtn = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmBtn) expect(confirmBtn.disabled).to.be.true @@ -187,7 +195,9 @@ describe('', function () { const archiveButton = within(actionsToolbar).getByLabelText('Trash') fireEvent.click(archiveButton) - const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement + const confirmBtn = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmBtn) expect(confirmBtn.disabled).to.be.true @@ -266,14 +276,15 @@ describe('', function () { status: 200, }) - const unarchiveButton = - within(actionsToolbar).getByText('Restore') + const unarchiveButton = within(actionsToolbar).getByRole('button', { + name: 'Restore', + }) fireEvent.click(unarchiveButton) await fetchMock.flush(true) expect(fetchMock.done()).to.be.true - screen.getByText('No projects') + await screen.findByText('No projects') }) it('only unarchive the selected projects', async function () { @@ -340,7 +351,7 @@ describe('', function () { await fetchMock.flush(true) expect(fetchMock.done()).to.be.true - screen.getByText('No projects') + await screen.findByText('No projects') }) it('only untrashes the selected projects', async function () { @@ -369,7 +380,9 @@ describe('', function () { within(actionsToolbar).getByLabelText('Archive') fireEvent.click(archiveButton) - const confirmButton = screen.getByText('Confirm') + const confirmButton = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmButton) expect(confirmButton.disabled).to.be.true @@ -427,7 +440,9 @@ describe('', function () { }) fireEvent.click(leaveButton) - const confirmButton = screen.getByText('Confirm') + const confirmButton = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmButton) expect(confirmButton.disabled).to.be.true @@ -484,7 +499,9 @@ describe('', function () { }) fireEvent.click(deleteButton) - const confirmButton = screen.getByText('Confirm') + const confirmButton = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmButton) expect(confirmButton.disabled).to.be.true @@ -550,7 +567,9 @@ describe('', function () { }) fireEvent.click(deleteLeaveButton) - const confirmButton = screen.getByText('Confirm') + const confirmButton = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmButton) expect(confirmButton.disabled).to.be.true @@ -616,7 +635,11 @@ describe('', function () { const trashBtns = screen.getAllByRole('button', { name: 'Trash' }) for (const [index, trashBtn] of trashBtns.entries()) { fireEvent.click(trashBtn) - fireEvent.click(screen.getByText('Confirm')) + fireEvent.click( + screen.getByRole('button', { + name: 'Confirm', + }) + ) await waitFor(() => { expect( trashProjectMock.called( @@ -843,8 +866,9 @@ describe('', function () { ) // same name - let confirmButton = - within(modal).getByText('Rename') + let confirmButton = within(modal).getByRole('button', { + name: 'Rename', + }) as HTMLButtonElement expect(confirmButton.disabled).to.be.true // no name @@ -852,7 +876,9 @@ describe('', function () { fireEvent.change(input, { target: { value: '' }, }) - confirmButton = within(modal).getByText('Rename') + confirmButton = within(modal).getByRole('button', { + name: 'Rename', + }) as HTMLButtonElement expect(confirmButton.disabled).to.be.true }) @@ -887,8 +913,9 @@ describe('', function () { target: { value: newProjectName }, }) - const confirmButton = - within(modal).getByText('Rename') + const confirmButton = within(modal).getByRole('button', { + name: 'Rename', + }) as HTMLButtonElement expect(confirmButton.disabled).to.be.false fireEvent.click(confirmButton) @@ -1033,7 +1060,7 @@ describe('', function () { selectedMatchesDisplayed(2) }) - it('shows correct list after closing modal, changing selecting, and reopening modal', async function () { + it('shows correct list after closing modal, changing selection, and reopening modal', async function () { selectedMatchesDisplayed(2) const modal = screen.getAllByRole('dialog', { hidden: false })[0] @@ -1041,7 +1068,10 @@ describe('', function () { name: 'Cancel', }) fireEvent.click(cancelButton) - expect(screen.queryByRole('dialog', { hidden: false })).to.be.null + + await waitForElementToBeRemoved( + screen.getByRole('dialog', { hidden: false }) + ) await screen.findAllByRole('checkbox') fireEvent.click(allCheckboxes[3]) diff --git a/services/web/test/frontend/features/project-list/components/project-list-title.tsx b/services/web/test/frontend/features/project-list/components/project-list-title.tsx index 8e34c6ca0e..e69cea0151 100644 --- a/services/web/test/frontend/features/project-list/components/project-list-title.tsx +++ b/services/web/test/frontend/features/project-list/components/project-list-title.tsx @@ -4,6 +4,9 @@ import { Tag } from '../../../../../app/src/Features/Tags/types' import ProjectListTitle from '../../../../../frontend/js/features/project-list/components/title/project-list-title' describe('', function () { + beforeEach(function () { + window.metaAttributesCache.set('ol-bootstrapVersion', 5) + }) type TestCase = { filter: Filter selectedTag: Tag | undefined diff --git a/services/web/test/frontend/features/project-list/components/sidebar/add-affiliation.test.tsx b/services/web/test/frontend/features/project-list/components/sidebar/add-affiliation.test.tsx index 0ae2654e0c..cfedf93978 100644 --- a/services/web/test/frontend/features/project-list/components/sidebar/add-affiliation.test.tsx +++ b/services/web/test/frontend/features/project-list/components/sidebar/add-affiliation.test.tsx @@ -31,7 +31,7 @@ describe('Add affiliation widget', function () { await waitFor(() => expect(fetchMock.called('/api/project'))) screen.getByText(/are you affiliated with an institution/i) - const addAffiliationLink = screen.getByRole('link', { + const addAffiliationLink = screen.getByRole('button', { name: /add affiliation/i, }) expect(addAffiliationLink.getAttribute('href')).to.equal('/user/settings') diff --git a/services/web/test/frontend/features/project-list/components/survey-widget.test.tsx b/services/web/test/frontend/features/project-list/components/survey-widget.test.tsx index 798703d0af..bd6aeb683c 100644 --- a/services/web/test/frontend/features/project-list/components/survey-widget.test.tsx +++ b/services/web/test/frontend/features/project-list/components/survey-widget.test.tsx @@ -36,7 +36,7 @@ describe('', function () { screen.getByText(this.preText) screen.getByText(this.linkText) - const link = screen.getByRole('link', { + const link = screen.getByRole('button', { name: 'Take survey', }) as HTMLAnchorElement expect(link.href).to.equal(this.url) @@ -51,7 +51,7 @@ describe('', function () { const text = screen.queryByText(this.preText) expect(text).to.be.null - const link = screen.queryByRole('link') + const link = screen.queryByRole('button') expect(link).to.be.null const dismissed = localStorage.getItem('dismissed-my-survey') @@ -80,7 +80,7 @@ describe('', function () { const text = screen.queryByText(this.preText) expect(text).to.be.null - const link = screen.queryByRole('link') + const link = screen.queryByRole('button') expect(link).to.be.null }) }) @@ -98,7 +98,7 @@ describe('', function () { const text = screen.queryByText(this.preText) expect(text).to.be.null - const link = screen.queryByRole('link') + const link = screen.queryByRole('button') expect(link).to.be.null }) }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/archive-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/archive-project-button.test.tsx index 34381de117..6a4eee370f 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/archive-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/archive-project-button.test.tsx @@ -16,13 +16,13 @@ describe('', function () { resetProjectListContextFetch() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { renderWithProjectListContext( ) const btn = screen.getByRole('button', { name: 'Archive' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Archive' }) + await screen.findByRole('tooltip', { name: 'Archive' }) }) it('opens the modal when clicked', function () { @@ -59,7 +59,9 @@ describe('', function () { screen.getByText('Archive Projects') screen.getByText('You are about to archive the following projects:') screen.getByText('Archiving projects won’t affect your collaborators.') - const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement + const confirmBtn = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmBtn) expect(confirmBtn.disabled).to.be.true diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/compile-and-download-project-pdf-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/compile-and-download-project-pdf-button.test.tsx index 0f1ac903ed..ba0b3fd3b9 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/compile-and-download-project-pdf-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/compile-and-download-project-pdf-button.test.tsx @@ -32,10 +32,10 @@ describe('', function () { sendMBSpy.restore() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { const btn = screen.getByRole('button', { name: 'Download PDF' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Download PDF' }) + await screen.findByRole('tooltip', { name: 'Download PDF' }) }) it('downloads the project PDF when clicked', async function () { diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/copy-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/copy-project-button.test.tsx index 3dbf028c29..d50a8cff0a 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/copy-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/copy-project-button.test.tsx @@ -17,13 +17,13 @@ describe('', function () { resetProjectListContextFetch() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { renderWithProjectListContext( ) const btn = screen.getByRole('button', { name: 'Copy' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Copy' }) + await screen.findByRole('tooltip', { name: 'Copy' }) }) it('does not render the button when project is archived', function () { @@ -51,14 +51,16 @@ describe('', function () { renderWithProjectListContext( ) + const btn = screen.getByRole('button', { name: 'Copy' }) + fireEvent.click(btn) screen.getByText('Copy Project') screen.getByLabelText('New Name') screen.getByDisplayValue(`${copyableProject.name} (Copy)`) - const copyBtn = screen.getByRole('button', { + const copyBtn = screen.getAllByRole('button', { name: 'Copy', - }) + })[1] fireEvent.click(copyBtn) expect(copyBtn.disabled).to.be.true diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/delete-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/delete-project-button.test.tsx index c02d197db4..15555728c9 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/delete-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/delete-project-button.test.tsx @@ -17,14 +17,14 @@ describe('', function () { resetProjectListContextFetch() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { window.metaAttributesCache.set('ol-user_id', trashedProject.owner?.id) renderWithProjectListContext( ) const btn = screen.getByRole('button', { name: 'Delete' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Delete' }) + await screen.findByRole('tooltip', { name: 'Delete' }) }) it('does not render button when trashed and not owner', function () { @@ -61,7 +61,9 @@ describe('', function () { screen.getByText('Delete Projects') screen.getByText('You are about to delete the following projects:') screen.getByText('This action cannot be undone.') - const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement + const confirmBtn = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmBtn) expect(confirmBtn.disabled).to.be.true diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/download-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/download-project-button.test.tsx index 28b3e8c4a2..89e215c082 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/download-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/download-project-button.test.tsx @@ -23,10 +23,10 @@ describe('', function () { this.locationStub.restore() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { const btn = screen.getByRole('button', { name: 'Download .zip file' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Download .zip file' }) + await screen.findByRole('tooltip', { name: 'Download .zip file' }) }) it('downloads the project when clicked', async function () { diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/leave-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/leave-project-button.test.tsx index 12dc8d736a..fcbea5a22c 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/leave-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/leave-project-button.test.tsx @@ -18,13 +18,13 @@ describe('', function () { resetProjectListContextFetch() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { renderWithProjectListContext( ) const btn = screen.getByRole('button', { name: 'Leave' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Leave' }) + await screen.findByRole('tooltip', { name: 'Leave' }) }) it('does not render button when owner', function () { @@ -67,7 +67,9 @@ describe('', function () { screen.getByText('Leave Projects') screen.getByText('You are about to leave the following projects:') screen.getByText('This action cannot be undone.') - const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement + const confirmBtn = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmBtn) expect(confirmBtn.disabled).to.be.true diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/rename-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/rename-project-button.test.tsx index bf7773b56c..e5a8e051b7 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/rename-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/rename-project-button.test.tsx @@ -51,7 +51,9 @@ describe('', function () { const btn = screen.getByRole('button') fireEvent.click(btn) screen.getByText('Rename Project') - const confirmBtn = screen.getByText('Rename') as HTMLButtonElement + const confirmBtn = screen.getByRole('button', { + name: 'Rename', + }) as HTMLButtonElement expect(confirmBtn.disabled).to.be.true const nameInput = screen.getByDisplayValue(ownedProject.name) fireEvent.change(nameInput, { target: { value: 'new name' } }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/trash-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/trash-project-button.test.tsx index a62627226e..960d506b2b 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/trash-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/trash-project-button.test.tsx @@ -16,13 +16,13 @@ describe('', function () { resetProjectListContextFetch() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { renderWithProjectListContext( ) const btn = screen.getByRole('button', { name: 'Trash' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Trash' }) + await screen.findByRole('tooltip', { name: 'Trash' }) }) it('does not render the button when project is trashed', function () { @@ -49,7 +49,9 @@ describe('', function () { screen.getByText('Trash Projects') screen.getByText('You are about to trash the following projects:') screen.getByText('Trashing projects won’t affect your collaborators.') - const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement + const confirmBtn = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmBtn) expect(confirmBtn.disabled).to.be.true diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/unarchive-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/unarchive-project-button.test.tsx index 3bbfa57085..f4541de3f8 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/unarchive-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/unarchive-project-button.test.tsx @@ -17,13 +17,13 @@ describe('', function () { resetProjectListContextFetch() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { renderWithProjectListContext( ) const btn = screen.getByRole('button', { name: 'Restore' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Restore' }) + await screen.findByRole('tooltip', { name: 'Restore' }) }) it('does not render the button when project is trashed', function () { diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/untrash-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/untrash-project-button.test.tsx index 2aff62529c..d72b7f9344 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/untrash-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/untrash-project-button.test.tsx @@ -16,13 +16,13 @@ describe('', function () { resetProjectListContextFetch() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { renderWithProjectListContext( ) const btn = screen.getByRole('button', { name: 'Restore' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Restore' }) + await screen.findByRole('tooltip', { name: 'Restore' }) }) it('does not render the button when project is current', function () { diff --git a/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/archive-projects.button.test.tsx b/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/archive-projects.button.test.tsx index a88ac41620..2963592164 100644 --- a/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/archive-projects.button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/archive-projects.button.test.tsx @@ -10,11 +10,11 @@ describe('', function () { resetProjectListContextFetch() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { renderWithProjectListContext() const btn = screen.getByRole('button', { name: 'Archive' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Archive' }) + await screen.findByRole('tooltip', { name: 'Archive' }) }) it('opens the modal when clicked', function () { diff --git a/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/download-projects-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/download-projects-button.test.tsx index 62ad38efbf..17d28ef3be 100644 --- a/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/download-projects-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/download-projects-button.test.tsx @@ -10,10 +10,10 @@ describe('', function () { resetProjectListContextFetch() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { renderWithProjectListContext() const btn = screen.getByRole('button', { name: 'Download' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Download' }) + await screen.findByRole('tooltip', { name: 'Download' }) }) }) diff --git a/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/trash-projects.button.test.tsx b/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/trash-projects.button.test.tsx index 17da41f29f..3e20d0aa5e 100644 --- a/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/trash-projects.button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/project-tools/buttons/trash-projects.button.test.tsx @@ -10,11 +10,11 @@ describe('', function () { resetProjectListContextFetch() }) - it('renders tooltip for button', function () { + it('renders tooltip for button', async function () { renderWithProjectListContext() const btn = screen.getByRole('button', { name: 'Trash' }) fireEvent.mouseOver(btn) - screen.getByRole('tooltip', { name: 'Trash' }) + await screen.findByRole('tooltip', { name: 'Trash' }) }) it('opens the modal when clicked', function () { diff --git a/services/web/test/frontend/features/project-list/components/table/project-tools/rename-project-modal.test.tsx b/services/web/test/frontend/features/project-list/components/table/project-tools/rename-project-modal.test.tsx index 2843b29ac1..607aa32e74 100644 --- a/services/web/test/frontend/features/project-list/components/table/project-tools/rename-project-modal.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/project-tools/rename-project-modal.test.tsx @@ -32,10 +32,14 @@ describe('', function () { /> ) screen.getByText('Rename Project') - const input = screen.getByLabelText('New Name') as HTMLButtonElement + const input = screen.getByRole('textbox', { + name: 'New Name', + }) as HTMLInputElement expect(input.value).to.equal(currentProjects[0].name) - const submitButton = screen.getByText('Rename') as HTMLButtonElement + const submitButton = screen.getByRole('button', { + name: 'Rename', + }) as HTMLButtonElement expect(submitButton.disabled).to.be.true fireEvent.change(input, { diff --git a/services/web/test/frontend/features/project-list/components/table/projects-action-modal.test.tsx b/services/web/test/frontend/features/project-list/components/table/projects-action-modal.test.tsx index 66b350eaab..e0a4b9d406 100644 --- a/services/web/test/frontend/features/project-list/components/table/projects-action-modal.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/projects-action-modal.test.tsx @@ -32,7 +32,9 @@ describe('', function () { showModal /> ) - const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement + const confirmBtn = screen.getByRole('button', { + name: 'Confirm', + }) as HTMLButtonElement fireEvent.click(confirmBtn) expect(confirmBtn.disabled).to.be.true // verify action handled diff --git a/services/web/test/frontend/features/settings/components/account-info-section.test.tsx b/services/web/test/frontend/features/settings/components/account-info-section.test.tsx index 50a1924dd0..607c8ea552 100644 --- a/services/web/test/frontend/features/settings/components/account-info-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/account-info-section.test.tsx @@ -90,7 +90,7 @@ describe('', function () { name: 'Update', }) ) - await screen.findByText('Saving…') + await screen.findByRole('button', { name: 'Loading' }) finishUpdateCall(200) await screen.findByRole('button', { diff --git a/services/web/test/frontend/features/settings/components/emails/emails-section-actions.test.tsx b/services/web/test/frontend/features/settings/components/emails/emails-section-actions.test.tsx index f770155ba9..c1b83b3421 100644 --- a/services/web/test/frontend/features/settings/components/emails/emails-section-actions.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/emails-section-actions.test.tsx @@ -172,11 +172,7 @@ describe('email actions - make primary', function () { fireEvent.click( withinModal.getByRole('button', { name: 'Change primary email' }) ) - expect(screen.queryByRole('dialog')).to.be.null - - await waitForElementToBeRemoved(() => - screen.getByRole('button', { name: /Processing/i, hidden: true }) - ) + await waitForElementToBeRemoved(() => screen.getByRole('dialog')) } it('shows confirmation modal and closes it', async function () { @@ -201,13 +197,14 @@ describe('email actions - make primary', function () { withinModal.getByRole('button', { name: 'Change primary email' }) fireEvent.click(withinModal.getByRole('button', { name: /cancel/i })) - expect(screen.queryByRole('dialog')).to.be.null + + await waitForElementToBeRemoved(screen.getByRole('dialog')) }) it('shows loader and removes button', async function () { fetchMock .get('/user/emails?ensureAffiliation=true', [userEmailData]) - .post('/user/emails/default?delete-primary-unconfirmed', 200) + .post('/user/emails/default?delete-unconfirmed-primary', 200) render() await confirmPrimaryEmail() @@ -223,7 +220,7 @@ describe('email actions - make primary', function () { it('shows error', async function () { fetchMock .get('/user/emails?ensureAffiliation=true', [userEmailData]) - .post('/user/emails/default?delete-primary-unconfirmed', 503) + .post('/user/emails/default?delete-unconfirmed-primary', 503) render() await confirmPrimaryEmail() diff --git a/services/web/test/frontend/features/settings/components/emails/emails-section-add-new-email.test.tsx b/services/web/test/frontend/features/settings/components/emails/emails-section-add-new-email.test.tsx index cf7d305aea..720dd31fdd 100644 --- a/services/web/test/frontend/features/settings/components/emails/emails-section-add-new-email.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/emails-section-add-new-email.test.tsx @@ -69,7 +69,7 @@ async function confirmCodeForEmail(email: string) { }) fireEvent.click(submitCodeBtn) await waitForElementToBeRemoved(() => - screen.getByRole('button', { name: /confirming/i }) + screen.getByRole('button', { name: /Loading/i }) ) } @@ -216,7 +216,7 @@ describe('', function () { await waitForElementToBeRemoved(() => screen.getByRole('button', { - name: /add new email/i, + name: /Loading/i, }) ) diff --git a/services/web/test/frontend/features/settings/components/emails/emails-section.test.tsx b/services/web/test/frontend/features/settings/components/emails/emails-section.test.tsx index ec05d1e90d..e4183e6e3f 100644 --- a/services/web/test/frontend/features/settings/components/emails/emails-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/emails-section.test.tsx @@ -134,7 +134,7 @@ describe('', function () { screen.queryByText(/an error has occurred while performing your request/i) ).to.be.null - await screen.findByRole('button', { + await screen.findAllByRole('button', { name: /resend confirmation code/i, }) }) diff --git a/services/web/test/frontend/features/settings/components/emails/sso-alert.test.tsx b/services/web/test/frontend/features/settings/components/emails/sso-alert.test.tsx index f9a53f86b7..1bce35d8e4 100644 --- a/services/web/test/frontend/features/settings/components/emails/sso-alert.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/sso-alert.test.tsx @@ -3,7 +3,7 @@ import { expect } from 'chai' import { SSOAlert } from '../../../../../../frontend/js/features/settings/components/emails/sso-alert' describe('', function () { - describe('when thereis no institutional linking information', function () { + describe('when there is no institutional linking information', function () { it('should be empty', function () { render() expect(screen.queryByRole('alert')).to.be.null @@ -49,11 +49,11 @@ describe('', function () { ) render() const closeButtons = screen.getAllByRole('button', { - name: 'Close alert', + name: 'Close', }) fireEvent.click(closeButtons[0]) fireEvent.click(closeButtons[1]) - expect(screen.queryByRole('button', { name: 'Close alert' })).to.be.null + expect(screen.queryByRole('button', { name: 'Close' })).to.be.null }) }) @@ -87,10 +87,10 @@ describe('', function () { it('the alert should be closeable', function () { render() const closeButton = screen.getByRole('button', { - name: 'Close alert', + name: 'Close', }) fireEvent.click(closeButton) - expect(screen.queryByRole('button', { name: 'Close alert' })).to.be.null + expect(screen.queryByRole('button', { name: 'Close' })).to.be.null }) }) }) diff --git a/services/web/test/frontend/features/settings/components/linking-section.test.tsx b/services/web/test/frontend/features/settings/components/linking-section.test.tsx index f693529abc..8567769fc4 100644 --- a/services/web/test/frontend/features/settings/components/linking-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/linking-section.test.tsx @@ -78,7 +78,7 @@ describe('', function () { ) const helpLink = screen.getByRole('link', { name: 'Learn more' }) expect(helpLink.getAttribute('href')).to.equal('/blog/434') - const linkButton = screen.getByRole('link', { name: 'Link' }) + const linkButton = screen.getByRole('button', { name: 'Link' }) expect(linkButton.getAttribute('href')).to.equal('/auth/orcid?intent=link') }) diff --git a/services/web/test/frontend/features/settings/components/linking/integration-widget.test.tsx b/services/web/test/frontend/features/settings/components/linking/integration-widget.test.tsx index 54c1fc54f3..ed656056e3 100644 --- a/services/web/test/frontend/features/settings/components/linking/integration-widget.test.tsx +++ b/services/web/test/frontend/features/settings/components/linking/integration-widget.test.tsx @@ -1,6 +1,6 @@ import { expect } from 'chai' import sinon from 'sinon' -import { screen, fireEvent, render } from '@testing-library/react' +import { screen, fireEvent, render, within } from '@testing-library/react' import { IntegrationLinkingWidget } from '../../../../../../frontend/js/features/settings/components/linking/integration-widget' import * as eventTracking from '@/infrastructure/event-tracking' @@ -32,7 +32,7 @@ describe('', function () { }) it('should render an upgrade link and track clicks', function () { - const upgradeLink = screen.getByRole('link', { name: 'Upgrade' }) + const upgradeLink = screen.getByRole('button', { name: 'Upgrade' }) expect(upgradeLink.getAttribute('href')).to.equal( '/user/subscription/plans' ) @@ -51,7 +51,7 @@ describe('', function () { it('should render a link to initiate integration linking', function () { expect( - screen.getByRole('link', { name: 'Link' }).getAttribute('href') + screen.getByRole('button', { name: 'Link' }).getAttribute('href') ).to.equal('/link') }) @@ -90,10 +90,11 @@ describe('', function () { it('should open a modal with a link to confirm integration unlinking', function () { fireEvent.click(screen.getByRole('button', { name: 'Unlink' })) - screen.getByText('confirm unlink') - screen.getByText('you will be unlinked') - screen.getByRole('button', { name: 'Cancel' }) - screen.getByRole('button', { name: 'Unlink' }) + const withinModal = within(screen.getByRole('dialog')) + withinModal.getByText('confirm unlink') + withinModal.getByText('you will be unlinked') + withinModal.getByRole('button', { name: 'Cancel' }) + withinModal.getByRole('button', { name: 'Unlink' }) }) it('should cancel unlinking when clicking "cancel" in the confirmation modal', async function () { diff --git a/services/web/test/frontend/features/settings/components/linking/sso-widget.test.tsx b/services/web/test/frontend/features/settings/components/linking/sso-widget.test.tsx index 5a0705b0a7..d78de73ebc 100644 --- a/services/web/test/frontend/features/settings/components/linking/sso-widget.test.tsx +++ b/services/web/test/frontend/features/settings/components/linking/sso-widget.test.tsx @@ -1,6 +1,12 @@ import { expect } from 'chai' import sinon from 'sinon' -import { screen, fireEvent, render, waitFor } from '@testing-library/react' +import { + screen, + fireEvent, + render, + waitFor, + within, +} from '@testing-library/react' import { FetchError } from '../../../../../../frontend/js/infrastructure/fetch-json' import { SSOLinkingWidget } from '../../../../../../frontend/js/features/settings/components/linking/sso-widget' @@ -27,7 +33,7 @@ describe('', function () { it('should render a link to `linkPath`', function () { render() expect( - screen.getByRole('link', { name: 'Link' }).getAttribute('href') + screen.getByRole('button', { name: 'Link' }).getAttribute('href') ).to.equal('/integration/link?intent=link') }) }) @@ -75,7 +81,7 @@ describe('', function () { ) fireEvent.click(screen.getByRole('button', { name: 'Unlink' })) - confirmBtn = screen.getByRole('button', { + confirmBtn = within(screen.getByRole('dialog')).getByRole('button', { name: 'Unlink', hidden: false, }) @@ -109,10 +115,13 @@ describe('', function () { ) fireEvent.click(screen.getByRole('button', { name: 'Unlink' })) - const confirmBtn = screen.getByRole('button', { - name: 'Unlink', - hidden: false, - }) + const confirmBtn = within(screen.getByRole('dialog')).getByRole( + 'button', + { + name: 'Unlink', + hidden: false, + } + ) fireEvent.click(confirmBtn) }) diff --git a/services/web/test/frontend/features/settings/components/password-section.test.tsx b/services/web/test/frontend/features/settings/components/password-section.test.tsx index bd245fc539..ae6a620f1f 100644 --- a/services/web/test/frontend/features/settings/components/password-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/password-section.test.tsx @@ -145,7 +145,7 @@ describe('', function () { render() submitValidForm() - await screen.findByText('Saving…') + await screen.findByRole('button', { name: 'Saving…' }) finishUpdateCall({ status: 200, diff --git a/services/web/test/frontend/features/settings/components/security-section.test.tsx b/services/web/test/frontend/features/settings/components/security-section.test.tsx index b10c303069..48146e82cf 100644 --- a/services/web/test/frontend/features/settings/components/security-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/security-section.test.tsx @@ -22,7 +22,7 @@ describe('', function () { render() expect(screen.getAllByText('Single Sign-On (SSO)').length).to.equal(2) - const link = screen.getByRole('link', { + const link = screen.getByRole('button', { name: /Set up SSO/i, }) expect(link).to.exist diff --git a/services/web/test/frontend/features/subscription/components/dashboard/group-subscription-memberships.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/group-subscription-memberships.test.tsx index 45a83b36c6..830787afc1 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/group-subscription-memberships.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/group-subscription-memberships.test.tsx @@ -92,7 +92,9 @@ describe('', function () { ) - const leaveGroupButton = screen.getByText('Leave group') + const leaveGroupButton = screen.getByRole('button', { + name: 'Leave group', + }) fireEvent.click(leaveGroupButton) this.confirmModal = screen.getByRole('dialog') @@ -100,8 +102,12 @@ describe('', function () { 'Are you sure you want to leave this group?' ) - this.cancelButton = within(this.confirmModal).getByText('Cancel') - this.leaveNowButton = within(this.confirmModal).getByText('Leave now') + this.cancelButton = within(this.confirmModal).getByRole('button', { + name: 'Cancel', + }) + this.leaveNowButton = within(this.confirmModal).getByRole('button', { + name: 'Leave now', + }) }) afterEach(function () { diff --git a/services/web/test/frontend/features/subscription/components/dashboard/personal-subscription.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/personal-subscription.test.tsx index a977f678fc..884f528466 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/personal-subscription.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/personal-subscription.test.tsx @@ -89,7 +89,7 @@ describe('', function () { screen.getByText('No further payments will be taken.', { exact: false }) - screen.getByRole('link', { name: 'View your invoices' }) + screen.getByRole('button', { name: 'View your invoices' }) screen.getByRole('button', { name: 'Reactivate your subscription' }) }) diff --git a/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx index 4ae339bf9d..406d6d3710 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx @@ -323,7 +323,7 @@ describe('', function () { fireEvent.click(button) const cancelButton = screen.getByRole('button', { - name: 'Loading', + name: 'Processing…', }) as HTMLButtonElement expect(cancelButton.disabled).to.be.true @@ -368,7 +368,7 @@ describe('', function () { name: cancelButtonText, }) screen.getByRole('button', { - name: 'Loading', + name: 'Processing…', }) }) @@ -385,7 +385,7 @@ describe('', function () { expect(buttons[0].getAttribute('disabled')).to.equal('') expect(buttons[1].getAttribute('disabled')).to.equal('') screen.getByRole('button', { - name: 'Loading', + name: 'Processing…', }) screen.getByRole('button', { name: extendTrialButtonText, @@ -456,7 +456,7 @@ describe('', function () { name: cancelButtonText, }) screen.getByRole('button', { - name: 'Loading', + name: 'Processing…', }) }) @@ -473,7 +473,7 @@ describe('', function () { expect(buttons[0].getAttribute('disabled')).to.equal('') expect(buttons[1].getAttribute('disabled')).to.equal('') screen.getByRole('button', { - name: 'Loading', + name: 'Processing…', }) screen.getByRole('button', { name: downgradeButtonText, diff --git a/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx index e2bc6fecc7..6c75d77583 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx @@ -118,10 +118,14 @@ describe('', function () { }) fireEvent.click(buttons[0]) - await screen.findByText('Are you sure you want to change plan to', { - exact: false, - }) - screen.getByRole('button', { name: 'Change plan' }) + const confirmModal = screen.getByRole('dialog') + await within(confirmModal).findByText( + 'Are you sure you want to change plan to', + { + exact: false, + } + ) + within(confirmModal).getByRole('button', { name: 'Change plan' }) expect( screen.queryByText( @@ -197,10 +201,13 @@ describe('', function () { await screen.findByText('Are you sure you want to change plan to', { exact: false, }) - const buttonConfirm = screen.getByRole('button', { name: 'Change plan' }) + const buttonConfirm = within(screen.getByRole('dialog')).getByRole( + 'button', + { name: 'Change plan' } + ) fireEvent.click(buttonConfirm) - screen.getByText('processing', { exact: false }) + screen.getByRole('button', { name: 'Processing…' }) // page is reloaded on success await waitFor(() => { @@ -230,10 +237,13 @@ describe('', function () { await screen.findByText('Are you sure you want to change plan to', { exact: false, }) - const buttonConfirm = screen.getByRole('button', { name: 'Change plan' }) + const buttonConfirm = within(screen.getByRole('dialog')).getByRole( + 'button', + { name: 'Change plan' } + ) fireEvent.click(buttonConfirm) - screen.getByText('processing', { exact: false }) + screen.getByRole('button', { name: 'Processing…' }) await screen.findByText('Sorry, something went wrong. ', { exact: false }) await screen.findByText('Please try again. ', { exact: false }) @@ -286,7 +296,7 @@ describe('', function () { }) fireEvent.click(buttonConfirm) - screen.getByText('processing', { exact: false }) + screen.getByRole('button', { name: 'Processing…' }) // page is reloaded on success await waitFor(() => { @@ -304,7 +314,7 @@ describe('', function () { }) fireEvent.click(buttonConfirm) - screen.getByText('processing', { exact: false }) + screen.getByRole('button', { name: 'Processing…' }) await screen.findByText('Sorry, something went wrong. ', { exact: false }) await screen.findByText('Please try again. ', { exact: false }) await screen.findByText('If the problem continues please contact us.', { @@ -518,7 +528,7 @@ describe('', function () { const buttonConfirm = screen.getByRole('button', { name: 'Upgrade now' }) fireEvent.click(buttonConfirm) - screen.getByText('processing', { exact: false }) + screen.getByRole('button', { name: 'Processing…' }) // // page is reloaded on success await waitFor(() => { @@ -539,7 +549,7 @@ describe('', function () { const buttonConfirm = screen.getByRole('button', { name: 'Upgrade now' }) fireEvent.click(buttonConfirm) - screen.getByText('processing', { exact: false }) + screen.getByRole('button', { name: 'Processing…' }) await screen.findByText('Sorry, something went wrong. ', { exact: false }) await screen.findByText('Please try again. ', { exact: false }) diff --git a/services/web/test/frontend/features/subscription/components/group-invite/accepted-invite.test.tsx b/services/web/test/frontend/features/subscription/components/group-invite/accepted-invite.test.tsx index a3d0a4419d..54222e7fb3 100644 --- a/services/web/test/frontend/features/subscription/components/group-invite/accepted-invite.test.tsx +++ b/services/web/test/frontend/features/subscription/components/group-invite/accepted-invite.test.tsx @@ -2,34 +2,38 @@ import { render, screen } from '@testing-library/react' import AcceptedInvite from '../../../../../../frontend/js/features/subscription/components/group-invite/accepted-invite' import { expect } from 'chai' -describe('accepted group invite', function () { - it('renders', async function () { - window.metaAttributesCache.set('ol-inviterName', 'example@overleaf.com') - render() - await screen.findByText( - 'You have joined the group subscription managed by example@overleaf.com' - ) - }) +for (const bsVersion of [3, 5]) + describe('accepted group invite' + ` bs${bsVersion}`, function () { + beforeEach(function () { + window.metaAttributesCache.set('ol-bootstrapVersion', bsVersion) + }) + it('renders', async function () { + window.metaAttributesCache.set('ol-inviterName', 'example@overleaf.com') + render() + await screen.findByText( + 'You have joined the group subscription managed by example@overleaf.com' + ) + }) - it('links to SSO enrollment page for SSO groups', async function () { - window.metaAttributesCache.set('ol-inviterName', 'example@overleaf.com') - window.metaAttributesCache.set('ol-groupSSOActive', true) - window.metaAttributesCache.set('ol-subscriptionId', 'group123') - render() - const linkBtn = (await screen.findByRole('link', { - name: 'Done', - })) as HTMLLinkElement - expect(linkBtn.href).to.equal( - 'https://www.test-overleaf.com/subscription/group123/sso_enrollment' - ) - }) + it('links to SSO enrollment page for SSO groups', async function () { + window.metaAttributesCache.set('ol-inviterName', 'example@overleaf.com') + window.metaAttributesCache.set('ol-groupSSOActive', true) + window.metaAttributesCache.set('ol-subscriptionId', 'group123') + render() + const linkBtn = (await screen.findByRole('link', { + name: 'Done', + })) as HTMLLinkElement + expect(linkBtn.href).to.equal( + 'https://www.test-overleaf.com/subscription/group123/sso_enrollment' + ) + }) - it('links to dash for non-SSO groups', async function () { - window.metaAttributesCache.set('ol-inviterName', 'example@overleaf.com') - render() - const linkBtn = (await screen.findByRole('link', { - name: 'Done', - })) as HTMLLinkElement - expect(linkBtn.href).to.equal('https://www.test-overleaf.com/project') + it('links to dash for non-SSO groups', async function () { + window.metaAttributesCache.set('ol-inviterName', 'example@overleaf.com') + render() + const linkBtn = (await screen.findByRole('link', { + name: 'Done', + })) as HTMLLinkElement + expect(linkBtn.href).to.equal('https://www.test-overleaf.com/project') + }) }) -}) diff --git a/services/web/test/frontend/features/subscription/components/group-invite/group-invite.test.tsx b/services/web/test/frontend/features/subscription/components/group-invite/group-invite.test.tsx index cc70eff90d..1c03302364 100644 --- a/services/web/test/frontend/features/subscription/components/group-invite/group-invite.test.tsx +++ b/services/web/test/frontend/features/subscription/components/group-invite/group-invite.test.tsx @@ -2,37 +2,80 @@ import { render, screen } from '@testing-library/react' import { expect } from 'chai' import GroupInvite from '../../../../../../frontend/js/features/subscription/components/group-invite/group-invite' -describe('group invite', function () { - const inviterName = 'example@overleaf.com' - beforeEach(function () { - window.metaAttributesCache.set('ol-inviterName', inviterName) - }) - - it('renders header', async function () { - render() - await screen.findByText(inviterName) - screen.getByText(`has invited you to join a group subscription on Overleaf`) - expect(screen.queryByText('Email link expired, please request a new one.')) - .to.be.null - }) - - describe('when user has personal subscription', function () { +for (const bsVersion of [3, 5]) + describe('group invite' + ` bs${bsVersion}`, function () { + window.metaAttributesCache.set('ol-bootstrapVersion', bsVersion) + const inviterName = 'example@overleaf.com' beforeEach(function () { - window.metaAttributesCache.set( - 'ol-hasIndividualRecurlySubscription', - true - ) + window.metaAttributesCache.set('ol-inviterName', inviterName) }) - it('renders cancel personal subscription view', async function () { + it('renders header', async function () { render() - await screen.findByText( - 'You already have an individual subscription, would you like us to cancel this first before joining the group licence?' + await screen.findByText(inviterName) + screen.getByText( + `has invited you to join a group subscription on Overleaf` ) + expect( + screen.queryByText('Email link expired, please request a new one.') + ).to.be.null }) - describe('and in a managed group', function () { - // note: this should not be possible but managed user view takes priority over all + describe('when user has personal subscription', function () { + beforeEach(function () { + window.metaAttributesCache.set( + 'ol-hasIndividualRecurlySubscription', + true + ) + }) + + it('renders cancel personal subscription view', async function () { + render() + await screen.findByText( + 'You already have an individual subscription, would you like us to cancel this first before joining the group licence?' + ) + }) + + describe('and in a managed group', function () { + // note: this should not be possible but managed user view takes priority over all + beforeEach(function () { + window.metaAttributesCache.set( + 'ol-currentManagedUserAdminEmail', + 'example@overleaf.com' + ) + window.metaAttributesCache.set('ol-cannot-join-subscription', true) + }) + + it('renders managed user cannot join view', async function () { + render() + await screen.findByText('You can’t join this group subscription') + screen.getByText( + 'Your Overleaf account is managed by your current group admin (example@overleaf.com). This means you can’t join additional group subscriptions', + { exact: false } + ) + screen.getByRole('link', { name: 'Read more about Managed Users.' }) + }) + }) + }) + + describe('when user does not have a personal subscription', function () { + beforeEach(function () { + window.metaAttributesCache.set( + 'ol-hasIndividualRecurlySubscription', + false + ) + window.metaAttributesCache.set('ol-inviteToken', 'token123') + }) + + it('does not render cancel personal subscription view', async function () { + render() + await screen.findByText( + 'Please click the button below to join the group subscription and enjoy the benefits of an upgraded Overleaf account' + ) + }) + }) + + describe('when the user is already a managed user in another group', function () { beforeEach(function () { window.metaAttributesCache.set( 'ol-currentManagedUserAdminEmail', @@ -43,7 +86,11 @@ describe('group invite', function () { it('renders managed user cannot join view', async function () { render() - await screen.findByText('You can’t join this group subscription') + await screen.findByText(inviterName) + screen.getByText( + `has invited you to join a group subscription on Overleaf` + ) + screen.getByText('You can’t join this group subscription') screen.getByText( 'Your Overleaf account is managed by your current group admin (example@overleaf.com). This means you can’t join additional group subscriptions', { exact: false } @@ -51,70 +98,28 @@ describe('group invite', function () { screen.getByRole('link', { name: 'Read more about Managed Users.' }) }) }) - }) - describe('when user does not have a personal subscription', function () { - beforeEach(function () { - window.metaAttributesCache.set( - 'ol-hasIndividualRecurlySubscription', - false - ) - window.metaAttributesCache.set('ol-inviteToken', 'token123') + describe('expired', function () { + beforeEach(function () { + window.metaAttributesCache.set('ol-expired', true) + }) + + it('shows error notification when expired', async function () { + render() + await screen.findByText('Email link expired, please request a new one.') + }) }) - it('does not render cancel personal subscription view', async function () { - render() - await screen.findByText( - 'Please click the button below to join the group subscription and enjoy the benefits of an upgraded Overleaf account' - ) + describe('join view', function () { + beforeEach(function () { + window.metaAttributesCache.set('ol-inviteToken', 'token123') + }) + + it('shows view to join group', async function () { + render() + await screen.findByText( + 'Please click the button below to join the group subscription and enjoy the benefits of an upgraded Overleaf account' + ) + }) }) }) - - describe('when the user is already a managed user in another group', function () { - beforeEach(function () { - window.metaAttributesCache.set( - 'ol-currentManagedUserAdminEmail', - 'example@overleaf.com' - ) - window.metaAttributesCache.set('ol-cannot-join-subscription', true) - }) - - it('renders managed user cannot join view', async function () { - render() - await screen.findByText(inviterName) - screen.getByText( - `has invited you to join a group subscription on Overleaf` - ) - screen.getByText('You can’t join this group subscription') - screen.getByText( - 'Your Overleaf account is managed by your current group admin (example@overleaf.com). This means you can’t join additional group subscriptions', - { exact: false } - ) - screen.getByRole('link', { name: 'Read more about Managed Users.' }) - }) - }) - - describe('expired', function () { - beforeEach(function () { - window.metaAttributesCache.set('ol-expired', true) - }) - - it('shows error notification when expired', async function () { - render() - await screen.findByText('Email link expired, please request a new one.') - }) - }) - - describe('join view', function () { - beforeEach(function () { - window.metaAttributesCache.set('ol-inviteToken', 'token123') - }) - - it('shows view to join group', async function () { - render() - await screen.findByText( - 'Please click the button below to join the group subscription and enjoy the benefits of an upgraded Overleaf account' - ) - }) - }) -}) diff --git a/services/web/test/frontend/helpers/reset-meta.ts b/services/web/test/frontend/helpers/reset-meta.ts index f5a979828a..f5b00b332b 100644 --- a/services/web/test/frontend/helpers/reset-meta.ts +++ b/services/web/test/frontend/helpers/reset-meta.ts @@ -2,6 +2,7 @@ export function resetMeta() { window.metaAttributesCache = new Map() window.metaAttributesCache.set('ol-projectHistoryBlobsEnabled', true) window.metaAttributesCache.set('ol-i18n', { currentLangCode: 'en' }) + window.metaAttributesCache.set('ol-bootstrapVersion', 5) window.metaAttributesCache.set('ol-ExposedSettings', { appName: 'Overleaf', maxEntitiesPerProject: 10,