mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
Merge pull request #20140 from overleaf/rd-footer-react
[web] Migrate the footer to React GitOrigin-RevId: 9571d7b3ef9a267fb8250956f821b1ee34ce07c7
This commit is contained in:
@@ -33,6 +33,10 @@ block append meta
|
||||
adminUrl: settings.adminUrl,
|
||||
items: cloneAndTranslateText(nav.header_extras)
|
||||
})
|
||||
meta(name="ol-footer" data-type="json" content={
|
||||
subdomainLang: settings.i18n.subdomainLang,
|
||||
translatedLanguages: settings.translatedLanguages
|
||||
})
|
||||
|
||||
block body
|
||||
if (typeof suppressNavbar === "undefined")
|
||||
@@ -47,7 +51,10 @@ block body
|
||||
if showThinFooter
|
||||
include layout/footer-marketing
|
||||
else
|
||||
include layout/fat-footer
|
||||
if bootstrapVersion === 5
|
||||
include layout/fat-footer-react-bootstrap-5
|
||||
else
|
||||
include layout/fat-footer
|
||||
|
||||
if (typeof suppressCookieBanner === "undefined")
|
||||
include _cookie_banner
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#fat-footer-container
|
||||
@@ -2,8 +2,14 @@
|
||||
"1_2_width": "",
|
||||
"1_4_width": "",
|
||||
"3_4_width": "",
|
||||
"About": "",
|
||||
"Account": "",
|
||||
"Account Settings": "",
|
||||
"Documentation": "",
|
||||
"Get Involved": "",
|
||||
"Help": "",
|
||||
"Learn": "",
|
||||
"Plans and Pricing": "",
|
||||
"a_custom_size_has_been_used_in_the_latex_code": "",
|
||||
"a_fatal_compile_error_that_completely_blocks_compilation": "",
|
||||
"a_file_with_that_name_already_exists_and_will_be_overriden": "",
|
||||
@@ -96,6 +102,7 @@
|
||||
"anonymous": "",
|
||||
"anyone_with_link_can_edit": "",
|
||||
"anyone_with_link_can_view": "",
|
||||
"app_on_x": "",
|
||||
"apply_suggestion": "",
|
||||
"archive": "",
|
||||
"archive_projects": "",
|
||||
@@ -124,6 +131,7 @@
|
||||
"back_to_editor": "",
|
||||
"back_to_subscription": "",
|
||||
"back_to_your_projects": "",
|
||||
"become_an_advisor": "",
|
||||
"before_you_use_the_ai_error_assistant": "",
|
||||
"beta_program_already_participating": "",
|
||||
"beta_program_benefits": "",
|
||||
@@ -132,6 +140,7 @@
|
||||
"binary_history_error": "",
|
||||
"blank_project": "",
|
||||
"blocked_filename": "",
|
||||
"blog": "",
|
||||
"browser": "",
|
||||
"bulk_accept_confirm": "",
|
||||
"bulk_reject_confirm": "",
|
||||
@@ -157,6 +166,7 @@
|
||||
"card_details_are_not_valid": "",
|
||||
"card_must_be_authenticated_by_3dsecure": "",
|
||||
"card_payment": "",
|
||||
"careers": "",
|
||||
"category_arrows": "",
|
||||
"category_greek": "",
|
||||
"category_misc": "",
|
||||
@@ -223,6 +233,7 @@
|
||||
"compile_terminated_by_user": "",
|
||||
"compiler": "",
|
||||
"compiling": "",
|
||||
"compliance": "",
|
||||
"compromised_password": "",
|
||||
"configure_sso": "",
|
||||
"confirm": "",
|
||||
@@ -465,7 +476,14 @@
|
||||
"following_paths_conflict": "",
|
||||
"font_family": "",
|
||||
"font_size": "",
|
||||
"footer_about_us": "",
|
||||
"footer_contact_us": "",
|
||||
"footer_navigation": "",
|
||||
"for_enterprise": "",
|
||||
"for_individuals_and_groups": "",
|
||||
"for_more_information_see_managed_accounts_section": "",
|
||||
"for_students": "",
|
||||
"for_universities": "",
|
||||
"format": "",
|
||||
"found_matching_deleted_users": "",
|
||||
"free_7_day_trial_billed_annually": "",
|
||||
@@ -623,6 +641,8 @@
|
||||
"hotkey_undo": "",
|
||||
"hotkeys": "",
|
||||
"how_it_works": "",
|
||||
"how_to_create_tables": "",
|
||||
"how_to_insert_images": "",
|
||||
"how_we_use_your_data": "",
|
||||
"how_we_use_your_data_explanation": "",
|
||||
"i_want_to_stay": "",
|
||||
@@ -694,6 +714,7 @@
|
||||
"ip_address": "",
|
||||
"is_email_affiliated": "",
|
||||
"issued_on": "",
|
||||
"join_beta_program": "",
|
||||
"join_now": "",
|
||||
"join_overleaf_labs": "",
|
||||
"join_project": "",
|
||||
@@ -723,6 +744,7 @@
|
||||
"last_used": "",
|
||||
"latam_discount_modal_info": "",
|
||||
"latam_discount_modal_title": "",
|
||||
"latex_in_thirty_minutes": "",
|
||||
"latex_places_figures_according_to_a_special_algorithm": "",
|
||||
"latex_places_tables_according_to_a_special_algorithm": "",
|
||||
"layout": "",
|
||||
@@ -742,6 +764,7 @@
|
||||
"length_unit": "",
|
||||
"let_us_know": "",
|
||||
"let_us_know_how_we_can_help": "",
|
||||
"let_us_know_what_you_think": "",
|
||||
"lets_fix_your_errors": "",
|
||||
"library": "",
|
||||
"license_for_educational_purposes": "",
|
||||
@@ -949,6 +972,7 @@
|
||||
"other": "",
|
||||
"other_logs_and_files": "",
|
||||
"other_output_files": "",
|
||||
"our_values": "",
|
||||
"out_of_sync": "",
|
||||
"out_of_sync_detail": "",
|
||||
"output_file": "",
|
||||
@@ -1016,8 +1040,10 @@
|
||||
"plus_more": "",
|
||||
"postal_code": "",
|
||||
"premium_feature": "",
|
||||
"premium_features": "",
|
||||
"premium_plan_label": "",
|
||||
"presentation_mode": "",
|
||||
"press_and_awards": "",
|
||||
"previous_page": "",
|
||||
"price": "",
|
||||
"primarily_work_study_question": "",
|
||||
@@ -1028,6 +1054,7 @@
|
||||
"primarily_work_study_question_university_school": "",
|
||||
"primary_certificate": "",
|
||||
"priority_support": "",
|
||||
"privacy_and_terms": "",
|
||||
"private": "",
|
||||
"problem_talking_to_publishing_service": "",
|
||||
"problem_with_subscription_contact_us": "",
|
||||
@@ -1227,6 +1254,7 @@
|
||||
"select_a_file": "",
|
||||
"select_a_file_figure_modal": "",
|
||||
"select_a_group_optional": "",
|
||||
"select_a_language": "",
|
||||
"select_a_new_owner_for_projects": "",
|
||||
"select_a_payment_method": "",
|
||||
"select_a_project": "",
|
||||
@@ -1567,6 +1595,7 @@
|
||||
"turn_off_link_sharing": "",
|
||||
"turn_on": "",
|
||||
"turn_on_link_sharing": "",
|
||||
"tutorials": "",
|
||||
"unarchive": "",
|
||||
"uncategorized": "",
|
||||
"uncategorized_projects": "",
|
||||
@@ -1675,6 +1704,8 @@
|
||||
"we_do_not_share_personal_information": "",
|
||||
"we_logged_you_in": "",
|
||||
"we_sent_new_code": "",
|
||||
"webinars": "",
|
||||
"website_status": "",
|
||||
"wed_love_you_to_stay": "",
|
||||
"welcome_to_sl": "",
|
||||
"were_making_some_changes_to_project_sharing_this_means_you_will_be_visible": "",
|
||||
@@ -1688,6 +1719,7 @@
|
||||
"what_happens_when_sso_is_enabled": "",
|
||||
"what_should_we_call_you": "",
|
||||
"when_you_tick_the_include_caption_box": "",
|
||||
"why_latex": "",
|
||||
"wide": "",
|
||||
"will_lose_edit_access_on_date": "",
|
||||
"with_premium_subscription_you_also_get": "",
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import ReactDOM from 'react-dom'
|
||||
import DefaultNavbar from '@/features/ui/components/bootstrap-5/navbar/default-navbar'
|
||||
import getMeta from '@/utils/meta'
|
||||
import DefaultNavbar from '@/features/ui/components/bootstrap-5/navbar/default-navbar'
|
||||
import FatFooter from '@/features/ui/components/bootstrap-5/footer/fat-footer'
|
||||
|
||||
const element = document.getElementById('navbar-container')
|
||||
if (element) {
|
||||
const navbarElement = document.getElementById('navbar-container')
|
||||
if (navbarElement) {
|
||||
const navbarProps = getMeta('ol-navbar')
|
||||
ReactDOM.render(<DefaultNavbar {...navbarProps} />, element)
|
||||
ReactDOM.render(<DefaultNavbar {...navbarProps} />, navbarElement)
|
||||
}
|
||||
|
||||
const footerElement = document.getElementById('fat-footer-container')
|
||||
if (footerElement) {
|
||||
const footerProps = getMeta('ol-footer')
|
||||
ReactDOM.render(<FatFooter {...footerProps} />, footerElement)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import LanguagePicker from '../language-picker'
|
||||
import Icon from '@/shared/components/icon'
|
||||
|
||||
type FooterLinkProps = {
|
||||
href: string
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
type SocialMediaLinkProps = {
|
||||
href: string
|
||||
icon: string
|
||||
accessibilityLabel: string
|
||||
}
|
||||
|
||||
function FatFooterBase() {
|
||||
const { t } = useTranslation()
|
||||
const currentYear = new Date().getFullYear()
|
||||
|
||||
return (
|
||||
<footer className="fat-footer-base">
|
||||
<div className="fat-footer-base-section fat-footer-base-meta">
|
||||
<div className="fat-footer-base-item">
|
||||
<div className="fat-footer-base-copyright">
|
||||
© {currentYear} Overleaf
|
||||
</div>
|
||||
<FooterBaseLink href="/legal">
|
||||
{t('privacy_and_terms')}
|
||||
</FooterBaseLink>
|
||||
<FooterBaseLink href="https://www.digital-science.com/security-certifications/">
|
||||
{t('compliance')}
|
||||
</FooterBaseLink>
|
||||
</div>
|
||||
<div className="fat-footer-base-item fat-footer-base-language">
|
||||
<LanguagePicker />
|
||||
</div>
|
||||
</div>
|
||||
<div className="fat-footer-base-section fat-footer-base-social">
|
||||
<div className="fat-footer-base-item">
|
||||
<SocialMediaLink
|
||||
href="https://twitter.com/overleaf"
|
||||
icon="twitter-square"
|
||||
accessibilityLabel={t('app_on_x', { social: 'Twitter' })}
|
||||
/>
|
||||
<SocialMediaLink
|
||||
href="https://www.facebook.com/overleaf.editor"
|
||||
icon="facebook-square"
|
||||
accessibilityLabel={t('app_on_x', { social: 'Facebook' })}
|
||||
/>
|
||||
<SocialMediaLink
|
||||
href="https://www.linkedin.com/company/writelatex-limited"
|
||||
icon="linkedin-square"
|
||||
accessibilityLabel={t('app_on_x', { social: 'LinkedIn' })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
||||
function FooterBaseLink({ href, children }: FooterLinkProps) {
|
||||
return (
|
||||
<a className="fat-footer-link" href={href}>
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
function SocialMediaLink({
|
||||
href,
|
||||
icon,
|
||||
accessibilityLabel,
|
||||
}: SocialMediaLinkProps) {
|
||||
return (
|
||||
<a className="fat-footer-social" href={href}>
|
||||
<Icon
|
||||
type={icon}
|
||||
className="fa"
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
/>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
export default FatFooterBase
|
||||
@@ -0,0 +1,133 @@
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import FatFooterBase from './fat-footer-base'
|
||||
import { FatFooterMetadata } from '../../types/fat-footer-metadata'
|
||||
|
||||
type FooterLinkProps = {
|
||||
href: string
|
||||
label: string
|
||||
}
|
||||
|
||||
type FooterSectionProps = {
|
||||
title: string
|
||||
links: FooterLinkProps[]
|
||||
}
|
||||
|
||||
function FatFooter(props: FatFooterMetadata) {
|
||||
const { t } = useTranslation()
|
||||
const hideFatFooter = false
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: t('About'),
|
||||
links: [
|
||||
{ href: '/about', label: t('footer_about_us') },
|
||||
{ href: '/about/values', label: t('our_values') },
|
||||
{ href: '/about/careers', label: t('careers') },
|
||||
{ href: '/for/press', label: t('press_and_awards') },
|
||||
{ href: '/blog', label: t('blog') },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t('Learn'),
|
||||
links: [
|
||||
{
|
||||
href: '/learn/latex/Learn_LaTeX_in_30_minutes',
|
||||
label: t('latex_in_thirty_minutes'),
|
||||
},
|
||||
{ href: '/latex/templates', label: t('templates') },
|
||||
{ href: '/events/webinars', label: t('webinars') },
|
||||
{ href: '/learn/latex/Tutorials', label: t('tutorials') },
|
||||
{
|
||||
href: '/learn/latex/Inserting_Images',
|
||||
label: t('how_to_insert_images'),
|
||||
},
|
||||
{ href: '/learn/latex/Tables', label: t('how_to_create_tables') },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t('Plans and Pricing'),
|
||||
links: [
|
||||
{
|
||||
href: '/learn/how-to/Overleaf_premium_features',
|
||||
label: t('premium_features'),
|
||||
},
|
||||
{
|
||||
href: '/user/subscription/plans?itm_referrer=footer-for-indv-groups',
|
||||
label: t('for_individuals_and_groups'),
|
||||
},
|
||||
{ href: '/for/enterprises', label: t('for_enterprise') },
|
||||
{ href: '/for/universities', label: t('for_universities') },
|
||||
{
|
||||
href: '/user/subscription/plans?itm_referrer=footer-for-students#student-annual',
|
||||
label: t('for_students'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t('Get Involved'),
|
||||
links: [
|
||||
{ href: '/for/community/advisors', label: t('become_an_advisor') },
|
||||
{
|
||||
href: 'https://forms.gle/67PSpN1bLnjGCmPQ9',
|
||||
label: t('let_us_know_what_you_think'),
|
||||
},
|
||||
{ href: '/beta/participate', label: t('join_beta_program') },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t('Help'),
|
||||
links: [
|
||||
{ href: '/about/why-latex', label: t('why_latex') },
|
||||
{ href: '/learn', label: t('Documentation') },
|
||||
{ href: '/contact', label: t('footer_contact_us') },
|
||||
{ href: 'https://status.overleaf.com/', label: t('website_status') },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<footer className="fat-footer hidden-print">
|
||||
<div
|
||||
role="navigation"
|
||||
aria-label={t('footer_navigation')}
|
||||
className="fat-footer-container"
|
||||
>
|
||||
<div className={`fat-footer-sections ${hideFatFooter ? 'hidden' : ''}`}>
|
||||
<div className="footer-section" id="footer-brand">
|
||||
<a href="/" aria-label={t('overleaf')} className="footer-brand">
|
||||
<span className="visually-hidden">{t('overleaf')}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{sections.map(section => (
|
||||
<div className="footer-section" key={section.title}>
|
||||
<FooterSection title={section.title} links={section.links} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<FatFooterBase />
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
||||
function FooterSection({ title, links }: FooterSectionProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="footer-section-heading">{t(title)}</h2>
|
||||
<ul className="list-unstyled">
|
||||
{links.map(link => (
|
||||
<li key={link.href}>
|
||||
<a href={link.href}>{t(link.label)}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default FatFooter
|
||||
@@ -0,0 +1,60 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownToggle,
|
||||
} from './dropdown-menu'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import getMeta from '@/utils/meta'
|
||||
import Icon from '@/shared/components/icon'
|
||||
|
||||
function LanguagePicker() {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const currentLangCode = getMeta('ol-i18n').currentLangCode
|
||||
const translatedLanguages = getMeta('ol-footer').translatedLanguages
|
||||
const subdomainLang = getMeta('ol-footer').subdomainLang
|
||||
const currentUrlWithQueryParams = window.location.pathname
|
||||
|
||||
return (
|
||||
<Dropdown>
|
||||
<DropdownToggle
|
||||
id="language-picker-toggle"
|
||||
aria-label={t('select_a_language')}
|
||||
data-bs-toggle="dropdown"
|
||||
className="btn-inline-link"
|
||||
variant="link"
|
||||
>
|
||||
<Icon
|
||||
type="language"
|
||||
className="fa fa-fw"
|
||||
accessibilityLabel={t('select_a_language')}
|
||||
/>
|
||||
{translatedLanguages?.[currentLangCode]}
|
||||
</DropdownToggle>
|
||||
|
||||
<DropdownMenu className="sm" aria-labelledby="language-picker-toggle">
|
||||
{subdomainLang &&
|
||||
Object.entries(subdomainLang).map(([subdomain, subdomainDetails]) => {
|
||||
if (!subdomainDetails || !subdomainDetails.lngCode) return null
|
||||
const isActive = subdomainDetails.lngCode === currentLangCode
|
||||
return (
|
||||
<li role="none" key={subdomain}>
|
||||
<DropdownItem
|
||||
href={`${subdomainDetails.url}${currentUrlWithQueryParams}`}
|
||||
active={isActive}
|
||||
aria-current={isActive ? 'true' : false}
|
||||
trailingIcon={isActive ? 'check' : null}
|
||||
>
|
||||
{translatedLanguages?.[subdomainDetails.lngCode]}
|
||||
</DropdownItem>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
|
||||
export default LanguagePicker
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { SubdomainLang } from '@/features/ui/components/types/fat-footer'
|
||||
|
||||
export type FatFooterMetadata = {
|
||||
subdomainLang?: SubdomainLang
|
||||
translatedLanguages: { [key: string]: string }
|
||||
currentLangCode: string
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export interface SubdomainDetails {
|
||||
lngCode: string
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface SubdomainLang {
|
||||
[subdomain: string]: SubdomainDetails
|
||||
}
|
||||
@@ -15,7 +15,7 @@ type SplitButtonItemProps = Pick<
|
||||
|
||||
export type SplitButtonVariants = Extract<
|
||||
ButtonProps['variant'],
|
||||
'primary' | 'secondary' | 'danger'
|
||||
'primary' | 'secondary' | 'danger' | 'link'
|
||||
>
|
||||
|
||||
export type SplitButtonProps = PropsWithChildren<{
|
||||
|
||||
@@ -47,7 +47,7 @@ import { Subscription as ProjectDashboardSubscription } from '../../../types/pro
|
||||
import { ThirdPartyIds } from '../../../types/third-party-ids'
|
||||
import { Publisher } from '../../../types/subscription/dashboard/publisher'
|
||||
import { DefaultNavbarMetadata } from '@/features/ui/components/types/default-navbar-metadata'
|
||||
|
||||
import { FatFooterMetadata } from '@/features/ui/components/types/fat-footer-metadata'
|
||||
export interface Meta {
|
||||
'ol-ExposedSettings': ExposedSettings
|
||||
'ol-allInReconfirmNotificationPeriods': UserEmailData[]
|
||||
@@ -83,6 +83,7 @@ export interface Meta {
|
||||
'ol-error': { name: string } | undefined
|
||||
'ol-expired': boolean
|
||||
'ol-features': Features
|
||||
'ol-footer': FatFooterMetadata
|
||||
'ol-fromPlansPage': boolean
|
||||
'ol-gitBridgeEnabled': boolean
|
||||
'ol-gitBridgePublicBaseUrl': string
|
||||
|
||||
@@ -139,6 +139,12 @@ footer.site-footer {
|
||||
|
||||
#language-picker-toggle {
|
||||
color: var(--content-secondary-dark);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.fat-footer-base-meta a:not(.dropdown-toggle) {
|
||||
|
||||
@@ -1770,6 +1770,7 @@
|
||||
"select_a_file": "Select a File",
|
||||
"select_a_file_figure_modal": "Select a file",
|
||||
"select_a_group_optional": "Select a Group (optional)",
|
||||
"select_a_language": "Select a language",
|
||||
"select_a_new_owner_for_projects": "Select a new owner for this user’s projects",
|
||||
"select_a_payment_method": "Select a payment method",
|
||||
"select_a_project": "Select a Project",
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react'
|
||||
import '../../helpers/bootstrap-5'
|
||||
import LanguagePicker from '../../../../frontend/js/features/ui/components/bootstrap-5/language-picker'
|
||||
import getMeta from '@/utils/meta'
|
||||
import exposedSettings from '../../../../modules/admin-panel/test/frontend/js/features/user/data/exposedSettings'
|
||||
|
||||
describe('LanguagePicker', function () {
|
||||
beforeEach(function () {
|
||||
window.metaAttributesCache.set('ol-i18n', {
|
||||
currentLangCode: 'en',
|
||||
})
|
||||
window.metaAttributesCache.set('ol-footer', {
|
||||
translatedLanguages: {
|
||||
en: 'English',
|
||||
fr: 'Français',
|
||||
es: 'Español',
|
||||
},
|
||||
subdomainLang: {
|
||||
en: { lngCode: 'en', url: 'overleaf.com' },
|
||||
fr: { lngCode: 'fr', url: 'fr.overleaf.com' },
|
||||
es: { lngCode: 'es', url: 'es.overleaf.com' },
|
||||
},
|
||||
})
|
||||
|
||||
Object.assign(getMeta('ol-ExposedSettings'), exposedSettings)
|
||||
})
|
||||
|
||||
it('renders the language picker with the current language', function () {
|
||||
cy.mount(<LanguagePicker />)
|
||||
cy.get('#language-picker-toggle').should('contain', 'English')
|
||||
})
|
||||
|
||||
it('opens the dropdown and lists available languages', function () {
|
||||
cy.mount(<LanguagePicker />)
|
||||
cy.get('#language-picker-toggle').click()
|
||||
|
||||
cy.get('.dropdown-menu').within(() => {
|
||||
cy.contains('English').should('exist')
|
||||
cy.contains('Français').should('exist')
|
||||
cy.contains('Español').should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
it('changes the language and updates the URL when a language is selected', function () {
|
||||
cy.mount(<LanguagePicker />)
|
||||
cy.get('#language-picker-toggle').should('exist').click()
|
||||
cy.contains('Français').click()
|
||||
cy.url().should('include', 'fr.overleaf.com')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user