diff --git a/server-ce/test/git-bridge.spec.ts b/server-ce/test/git-bridge.spec.ts index 071091bdfd..67a09b3409 100644 --- a/server-ce/test/git-bridge.spec.ts +++ b/server-ce/test/git-bridge.spec.ts @@ -93,7 +93,7 @@ describe('git-bridge', function () { cy.get('code').contains(`git clone ${gitURL(id.toString())}`) }) cy.findByRole('button', { - name: 'Generate token', + name: /generate token/i, }).click() cy.get('code').contains(/olp_[a-zA-Z0-9]{16}/) }) @@ -196,7 +196,7 @@ describe('git-bridge', function () { cy.get('code').contains(`git clone ${gitURL(projectId.toString())}`) }) cy.findByRole('button', { - name: 'Generate token', + name: /generate token/i, }).click() cy.get('code') .contains(/olp_[a-zA-Z0-9]{16}/) diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 207da71688..df46529ffe 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -895,10 +895,12 @@ "layout_options": "", "layout_processing": "", "learn_more": "", + "learn_more_about": "", "learn_more_about_account": "", "learn_more_about_compile_timeouts": "", "learn_more_about_link_sharing": "", "learn_more_about_managed_users": "", + "learn_more_about_managing_email": "", "learn_more_about_other_causes_of_compile_timeouts": "", "leave": "", "leave_any_group_subscriptions": "", @@ -1144,6 +1146,7 @@ "other_causes_of_compile_timeouts": "", "other_logs_and_files": "", "other_output_files": "", + "our_help_page": "", "our_team_will_get_back_to_you_shortly": "", "our_values": "", "out_of_sync": "", diff --git a/services/web/frontend/js/features/settings/components/account-info-section.tsx b/services/web/frontend/js/features/settings/components/account-info-section.tsx index 4fd410d89f..1ff865e757 100644 --- a/services/web/frontend/js/features/settings/components/account-info-section.tsx +++ b/services/web/frontend/js/features/settings/components/account-info-section.tsx @@ -70,7 +70,7 @@ function AccountInfoSection() { return ( <> -

{t('update_account_info')}

+

{t('update_account_info')}

{hasAffiliationsFeature ? null : ( {t('update')} diff --git a/services/web/frontend/js/features/settings/components/emails-section.tsx b/services/web/frontend/js/features/settings/components/emails-section.tsx index a8bc54b017..30d52fbf9e 100644 --- a/services/web/frontend/js/features/settings/components/emails-section.tsx +++ b/services/web/frontend/js/features/settings/components/emails-section.tsx @@ -40,6 +40,7 @@ function EmailsSectionContent() { , ]} /> diff --git a/services/web/frontend/js/features/settings/components/linking/integration-widget.tsx b/services/web/frontend/js/features/settings/components/linking/integration-widget.tsx index def60625a2..0ef67446b6 100644 --- a/services/web/frontend/js/features/settings/components/linking/integration-widget.tsx +++ b/services/web/frontend/js/features/settings/components/linking/integration-widget.tsx @@ -20,6 +20,7 @@ function trackLinkingClick(integration: string) { } type IntegrationLinkingWidgetProps = { + id: string logo: ReactNode title: string description: string @@ -35,6 +36,7 @@ type IntegrationLinkingWidgetProps = { } export function IntegrationLinkingWidget({ + id, logo, title, description, @@ -65,12 +67,17 @@ export function IntegrationLinkingWidget({
{logo}
-

{title}

+

{title}

{!hasFeature && {t('premium_feature')}}

{description}{' '} - + {t('learn_more')}

@@ -78,6 +85,7 @@ export function IntegrationLinkingWidget({
void linkPath: string disabled?: boolean + titleId: string } function ActionButton({ @@ -114,16 +123,22 @@ function ActionButton({ linkPath, disabled, integration, + titleId, }: ActionButtonProps) { const { t } = useTranslation() + const linkTextId = `${titleId}-link` + if (!hasFeature) { return ( trackUpgradeClick(integration)} + aria-labelledby={`${titleId} ${linkTextId}`} > - {t('upgrade')} + + {t('upgrade')} + ) } else if (linked) { diff --git a/services/web/frontend/js/features/settings/components/linking/sso-widget.tsx b/services/web/frontend/js/features/settings/components/linking/sso-widget.tsx index 8d5bc169d1..bea87e7979 100644 --- a/services/web/frontend/js/features/settings/components/linking/sso-widget.tsx +++ b/services/web/frontend/js/features/settings/components/linking/sso-widget.tsx @@ -69,12 +69,17 @@ export function SSOLinkingWidget({
{providerLogos[providerId]}
-

{title}

+

{title}

{description?.replace(/<[^>]+>/g, '')}{' '} {helpPath ? ( - + {t('learn_more')} ) : null} @@ -85,6 +90,7 @@ export function SSOLinkingWidget({

void + titleId: string } function ActionButton({ @@ -113,8 +120,11 @@ function ActionButton({ accountIsLinked, linkPath, onUnlinkClick, + titleId, }: ActionButtonProps) { const { t } = useTranslation() + const linkTextId = `${titleId}-link` + if (unlinkRequestInflight) { return ( @@ -123,13 +133,24 @@ function ActionButton({ ) } else if (accountIsLinked) { return ( - + {t('unlink')} ) } else { return ( - + {t('link')} ) diff --git a/services/web/locales/en.json b/services/web/locales/en.json index d9daebdd6a..2735e04205 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -1174,11 +1174,13 @@ "ldap_create_admin_instructions": "Choose an email address for the first __appName__ admin account. This should correspond to an account in the LDAP system. You will then be asked to log in with this account.", "learn": "Learn", "learn_more": "Learn more", + "learn_more_about": "Learn more about __integrationName__", "learn_more_about_account": "<0>Learn more about managing your __appName__ account.", "learn_more_about_compile_timeouts": "<0>Learn more about compile timeouts.", "learn_more_about_emails": "<0>Learn more about managing your __appName__ emails.", "learn_more_about_link_sharing": "Learn more about Link Sharing", "learn_more_about_managed_users": "Learn more about Managed Users.", + "learn_more_about_managing_email": "Learn more about managing your __appName__ emails.", "learn_more_about_other_causes_of_compile_timeouts": "<0>Learn more about other causes of compile timeouts and how to fix them.", "leave": "Leave", "leave_any_group_subscriptions": "Leave any group subscriptions other than the one that will be managing your account. <0>Leave them from the Subscription page.", @@ -1511,6 +1513,7 @@ "other_output_files": "Download other output files", "other_sessions": "Other Sessions", "other_ways_to_log_in": "Other ways to log in", + "our_help_page": "Our help page", "our_team_will_get_back_to_you_shortly": "Our team will get back to you shortly.", "our_values": "Our values", "out_of_sync": "Out of sync", 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 112e7d90e7..e41cfe643f 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 @@ -47,7 +47,7 @@ describe('', function () { }) fireEvent.click( screen.getByRole('button', { - name: 'Update', + name: /update/i, }) ) expect(updateMock.callHistory.called()).to.be.true @@ -68,7 +68,7 @@ describe('', function () { target: { value: 'john' }, }) const button = screen.getByRole('button', { - name: 'Update', + name: /update/i, }) as HTMLButtonElement expect(button.disabled).to.be.true @@ -87,14 +87,14 @@ describe('', function () { fireEvent.click( screen.getByRole('button', { - name: 'Update', + name: /update/i, }) ) await screen.findByRole('button', { name: /saving/i }) finishUpdateCall(200) await screen.findByRole('button', { - name: 'Update', + name: /update/i, }) screen.getByText('Thanks, your settings have been updated.') }) @@ -105,7 +105,7 @@ describe('', function () { fireEvent.click( screen.getByRole('button', { - name: 'Update', + name: /update/i, }) ) await screen.findByText('Something went wrong. Please try again.') @@ -117,7 +117,7 @@ describe('', function () { fireEvent.click( screen.getByRole('button', { - name: 'Update', + name: /update/i, }) ) await screen.findByText( @@ -136,7 +136,7 @@ describe('', function () { fireEvent.click( screen.getByRole('button', { - name: 'Update', + name: /update/i, }) ) await screen.findByText('This email is already registered') @@ -153,7 +153,7 @@ describe('', function () { fireEvent.click( screen.getByRole('button', { - name: 'Update', + name: /update/i, }) ) expect( @@ -184,7 +184,7 @@ describe('', function () { fireEvent.click( screen.getByRole('button', { - name: 'Update', + name: /update account info/i, }) ) expect( @@ -212,7 +212,7 @@ describe('', function () { fireEvent.click( screen.getByRole('button', { - name: 'Update', + name: /update/i, }) ) expect( 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 c556ac83a7..105e52f0aa 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 @@ -106,7 +106,7 @@ describe('', function () { }) fireEvent.click(button) - await screen.findByLabelText(/email/i) + await screen.findByLabelText(/email/i, { selector: 'input' }) }) it('renders "Start adding your address" until a valid email is typed', async function () { @@ -121,7 +121,7 @@ describe('', function () { }) fireEvent.click(button) - const input = screen.getByLabelText(/email/i) + const input = screen.getByLabelText(/email/i, { selector: 'input' }) // initially the text is displayed and the "add email" button disabled screen.getByText('Start by adding your email address.') @@ -200,7 +200,7 @@ describe('', function () { .post('/user/emails/confirm-secondary', 200) fireEvent.click(addAnotherEmailBtn) - const input = screen.getByLabelText(/email/i) + const input = screen.getByLabelText(/email/i, { selector: 'input' }) fireEvent.change(input, { target: { value: userEmailData.email }, @@ -242,7 +242,7 @@ describe('', function () { .post('/user/emails/secondary', 400) fireEvent.click(addAnotherEmailBtn) - const input = screen.getByLabelText(/email/i) + const input = screen.getByLabelText(/email/i, { selector: 'input' }) fireEvent.change(input, { target: { value: userEmailData.email }, @@ -279,7 +279,7 @@ describe('', function () { await userEvent.click(button) - const input = screen.getByLabelText(/email/i) + const input = screen.getByLabelText(/email/i, { selector: 'input' }) fireEvent.change(input, { target: { value: 'user@autocomplete.edu' }, }) @@ -302,7 +302,10 @@ describe('', function () { await userEvent.click(button) - await userEvent.type(screen.getByLabelText(/email/i), userEmailData.email) + await userEvent.type( + screen.getByLabelText(/email/i, { selector: 'input' }), + userEmailData.email + ) await userEvent.click(screen.getByRole('button', { name: /let us know/i })) @@ -415,7 +418,10 @@ describe('', function () { // open "add new email" section and click "let us know" to open the Country/University form await userEvent.click(button) - await userEvent.type(screen.getByLabelText(/email/i), userEmailData.email) + await userEvent.type( + screen.getByLabelText(/email/i, { selector: 'input' }), + userEmailData.email + ) await userEvent.click(screen.getByRole('button', { name: /let us know/i })) // select a country @@ -457,7 +463,10 @@ describe('', function () { await userEvent.click(button) - await userEvent.type(screen.getByLabelText(/email/i), userEmailData.email) + await userEvent.type( + screen.getByLabelText(/email/i, { selector: 'input' }), + userEmailData.email + ) await userEvent.click(screen.getByRole('button', { name: /let us know/i })) @@ -574,7 +583,7 @@ describe('', function () { await userEvent.click(button) await userEvent.type( - screen.getByLabelText(/email/i), + screen.getByLabelText(/email/i, { selector: 'input' }), `user@${hostnameFirstChar}` ) @@ -647,7 +656,7 @@ describe('', function () { await userEvent.click(button) await userEvent.type( - screen.getByLabelText(/email/i), + screen.getByLabelText(/email/i, { selector: 'input' }), `user@${hostnameFirstChar}` ) 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 451a510855..13d3a0f9ff 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 @@ -40,6 +40,7 @@ describe('', function () { screen.getByText(/add additional email addresses/i) screen.getByText(/to change your primary email/i) + screen.getByLabelText('Learn more about managing your Overleaf emails.') }) it('renders a loading message when loading', async function () { 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 d134ffeae6..887ada15de 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 @@ -69,16 +69,19 @@ describe('', function () { screen.getByText('linked accounts') screen.getByText('Google') + screen.getByRole('button', { name: /link google/i }) screen.getByText('Log in with Google.') - screen.getByRole('button', { name: 'Unlink' }) + screen.getByRole('button', { name: /unlink/i }) screen.getByText('ORCID') screen.getByText( /Securely establish your identity by linking your ORCID iD/ ) - const helpLink = screen.getByRole('link', { name: 'Learn more' }) + const helpLink = screen.getByRole('link', { + name: /learn more about orcid/i, + }) expect(helpLink.getAttribute('href')).to.equal('/blog/434') - const linkButton = screen.getByRole('button', { name: 'Link' }) + const linkButton = screen.getByRole('button', { name: /link orcid/i }) 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 ed656056e3..435dbba0fa 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 @@ -6,6 +6,7 @@ import * as eventTracking from '@/infrastructure/event-tracking' describe('', function () { const defaultProps = { + id: 'integration-widget-id', logo:
, title: 'Integration', description: 'paragraph1', @@ -32,7 +33,7 @@ describe('', function () { }) it('should render an upgrade link and track clicks', function () { - const upgradeLink = screen.getByRole('button', { name: 'Upgrade' }) + const upgradeLink = screen.getByRole('button', { name: /upgrade/i }) expect(upgradeLink.getAttribute('href')).to.equal( '/user/subscription/plans' ) 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 d78de73ebc..5d29176c17 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 @@ -25,7 +25,7 @@ describe('', function () { screen.getByText('integration') screen.getByText('integration description') expect( - screen.getByRole('link', { name: 'Learn more' }).getAttribute('href') + screen.getByRole('link', { name: /learn more/i }).getAttribute('href') ).to.equal('/help/integration') }) @@ -33,7 +33,7 @@ describe('', function () { it('should render a link to `linkPath`', function () { render() expect( - screen.getByRole('button', { name: 'Link' }).getAttribute('href') + screen.getByRole('button', { name: /link/i }).getAttribute('href') ).to.equal('/integration/link?intent=link') }) }) @@ -49,11 +49,11 @@ describe('', function () { }) it('should display an `unlink` button', function () { - screen.getByRole('button', { name: 'Unlink' }) + screen.getByRole('button', { name: /unlink/i }) }) it('should open a modal to confirm integration unlinking', function () { - fireEvent.click(screen.getByRole('button', { name: 'Unlink' })) + fireEvent.click(screen.getByRole('button', { name: /unlink/i })) screen.getByText('Unlink integration Account') screen.getByText( 'Warning: When you unlink your account from integration you will not be able to sign in using integration anymore.' @@ -61,7 +61,7 @@ describe('', function () { }) it('should cancel unlinking when clicking cancel in the confirmation modal', async function () { - fireEvent.click(screen.getByRole('button', { name: 'Unlink' })) + fireEvent.click(screen.getByRole('button', { name: /unlink/i })) const cancelBtn = screen.getByRole('button', { name: 'Cancel', hidden: false, @@ -80,9 +80,9 @@ describe('', function () { render( ) - fireEvent.click(screen.getByRole('button', { name: 'Unlink' })) + fireEvent.click(screen.getByRole('button', { name: /unlink/i })) confirmBtn = within(screen.getByRole('dialog')).getByRole('button', { - name: 'Unlink', + name: /unlink/i, hidden: false, }) }) @@ -114,11 +114,11 @@ describe('', function () { render( ) - fireEvent.click(screen.getByRole('button', { name: 'Unlink' })) + fireEvent.click(screen.getByRole('button', { name: /unlink/i })) const confirmBtn = within(screen.getByRole('dialog')).getByRole( 'button', { - name: 'Unlink', + name: /unlink/i, hidden: false, } ) @@ -130,7 +130,7 @@ describe('', function () { }) it('should display the unlink button ', async function () { - await screen.findByRole('button', { name: 'Unlink' }) + await screen.findByRole('button', { name: /unlink/i }) }) }) })