From e5370a599017ddc355193a776576b7f088100861 Mon Sep 17 00:00:00 2001 From: Robert Sese <734194+rsese@users.noreply.github.com> Date: Mon, 13 Feb 2023 11:37:47 -0600 Subject: [PATCH] Feature Branch: Global Nav Phase 2 (#34359) Co-authored-by: Grace Park Co-authored-by: Joe Oak <41307427+joeoak@users.noreply.github.com> --- components/DefaultLayout.tsx | 2 +- components/article/ArticleGridLayout.tsx | 6 +- components/article/ArticlePage.tsx | 2 +- components/landing/ProductLanding.tsx | 2 +- components/landing/TocLanding.tsx | 2 +- components/page-header/Breadcrumbs.tsx | 34 ++--- components/page-header/Header.tsx | 121 ++++++++++++++++-- .../page-header/HeaderNotifications.tsx | 2 +- components/page-header/LanguagePicker.tsx | 2 +- components/page-header/VersionPicker.tsx | 2 +- components/rest/RestCodeSamples.module.scss | 2 + components/sidebar/AllProductsLink.tsx | 6 +- components/sidebar/ApiVersionPicker.tsx | 27 +--- components/sidebar/SidebarNav.tsx | 62 +++++++-- components/sidebar/SidebarProduct.module.scss | 29 ----- components/sidebar/SidebarProduct.tsx | 47 +------ tests/browser/browser.js | 60 ++++++++- tests/rendering/breadcrumbs.js | 111 ++++++++++------ tests/rendering/sidebar.js | 18 ++- tests/translations/frame.js | 2 +- 20 files changed, 340 insertions(+), 199 deletions(-) diff --git a/components/DefaultLayout.tsx b/components/DefaultLayout.tsx index 798ea58e2b2c..1af82c476940 100644 --- a/components/DefaultLayout.tsx +++ b/components/DefaultLayout.tsx @@ -42,7 +42,7 @@ export const DefaultLayout = (props: Props) => { {/* For local site search indexing */} -
+
diff --git a/components/article/ArticleGridLayout.tsx b/components/article/ArticleGridLayout.tsx index a5352fc0af63..2d821df12088 100644 --- a/components/article/ArticleGridLayout.tsx +++ b/components/article/ArticleGridLayout.tsx @@ -17,7 +17,7 @@ export const ArticleGridLayout = ({ intro, topper, toc, children, className }: P {toc} @@ -44,7 +44,7 @@ const Container = styled(Box)` row-gap: ${themeGet('space.2')}; - @media (min-width: ${themeGet('breakpoints.3')}) { + @media (min-width: ${themeGet('breakpoints.2')}) { max-width: none; padding-top: ${themeGet('space.4')}; grid-template-rows: auto 1fr; @@ -59,7 +59,7 @@ const Container = styled(Box)` ` const SidebarContent = styled(Box)` - @media (min-width: ${themeGet('breakpoints.3')}) { + @media (min-width: ${themeGet('breakpoints.2')}) { position: sticky; padding-top: ${themeGet('space.4')}; top: 5em; diff --git a/components/article/ArticlePage.tsx b/components/article/ArticlePage.tsx index 7e2b5844650c..a0630a2b500f 100644 --- a/components/article/ArticlePage.tsx +++ b/components/article/ArticlePage.tsx @@ -53,7 +53,7 @@ export const ArticlePage = () => { {router.pathname.includes('/rest/') && }
-
+
{
{router.query.productId === 'rest' && } -
+
diff --git a/components/landing/TocLanding.tsx b/components/landing/TocLanding.tsx index 6d386c72ee0c..b5ceb88209af 100644 --- a/components/landing/TocLanding.tsx +++ b/components/landing/TocLanding.tsx @@ -38,7 +38,7 @@ export const TocLanding = () => {
-
+
diff --git a/components/page-header/Breadcrumbs.tsx b/components/page-header/Breadcrumbs.tsx index c84155f95ccf..3f0b6c1f1234 100644 --- a/components/page-header/Breadcrumbs.tsx +++ b/components/page-header/Breadcrumbs.tsx @@ -1,18 +1,20 @@ import cx from 'classnames' -import { useRouter } from 'next/router' + import { useMainContext } from '../context/MainContext' import { Link } from 'components/Link' + import styles from './Breadcrumbs.module.scss' +type Props = { + inHeader?: boolean +} + export type BreadcrumbT = { title: string href?: string } -export const Breadcrumbs = () => { - const router = useRouter() - // remove query string and hash - const pathWithLocale = `/${router.locale}${router.asPath.split('?')[0].split('#')[0]}` +export const Breadcrumbs = ({ inHeader }: Props) => { const { breadcrumbs } = useMainContext() return ( @@ -23,7 +25,7 @@ export const Breadcrumbs = () => { updating script/search/parse-page-sections-into-records.js. */
diff --git a/components/page-header/HeaderNotifications.tsx b/components/page-header/HeaderNotifications.tsx index 0b3cee73ae96..d55e51462648 100644 --- a/components/page-header/HeaderNotifications.tsx +++ b/components/page-header/HeaderNotifications.tsx @@ -98,7 +98,7 @@ export const HeaderNotifications = () => { className={cx( 'flash flash-banner', styles.container, - 'text-center f5 color-fg-default py-4 px-6', + 'text-center f5 color-fg-default py-4 px-6 z-1', type === NotificationType.TRANSLATION && 'color-bg-accent', type === NotificationType.RELEASE && 'color-bg-accent', type === NotificationType.EARLY_ACCESS && 'color-bg-danger', diff --git a/components/page-header/LanguagePicker.tsx b/components/page-header/LanguagePicker.tsx index 2a10f22b52d8..dc85a184d432 100644 --- a/components/page-header/LanguagePicker.tsx +++ b/components/page-header/LanguagePicker.tsx @@ -81,7 +81,7 @@ export const LanguagePicker = ({ mediumOrLower }: Props) => { }} buttonBorder={mediumOrLower} dataTestId="default-language" - ariaLabel="Select language" + ariaLabel={`Select language: current language is ${selectedLang.name}`} alignment={mediumOrLower ? 'start' : 'end'} />
diff --git a/components/page-header/VersionPicker.tsx b/components/page-header/VersionPicker.tsx index 43ba4c6efb61..ed36bf1ea711 100644 --- a/components/page-header/VersionPicker.tsx +++ b/components/page-header/VersionPicker.tsx @@ -90,7 +90,7 @@ export const VersionPicker = ({ mediumOrLower }: Props) => { pickerLabel="Version" dataTestId="field" buttonBorder={mediumOrLower} - ariaLabel="Select GitHub product version" + ariaLabel={`Select GitHub product version: current version is ${currentVersion}`} renderItem={(item) => { return (
diff --git a/components/rest/RestCodeSamples.module.scss b/components/rest/RestCodeSamples.module.scss index 63b84f1503b6..342dac6b7940 100644 --- a/components/rest/RestCodeSamples.module.scss +++ b/components/rest/RestCodeSamples.module.scss @@ -11,6 +11,8 @@ background-color: transparent; padding: 8px 8px 16px; white-space: pre; + max-width: 90vw; + @include breakpoint(lg) { max-width: 40vw; } diff --git a/components/sidebar/AllProductsLink.tsx b/components/sidebar/AllProductsLink.tsx index a7af6084fc50..a330f80f684f 100644 --- a/components/sidebar/AllProductsLink.tsx +++ b/components/sidebar/AllProductsLink.tsx @@ -9,14 +9,14 @@ export const AllProductsLink = () => { const currentVersionPathSegment = currentVersion === DEFAULT_VERSION ? '' : `/${currentVersion}` return ( -
  • +
    All products -
  • +
    ) } diff --git a/components/sidebar/ApiVersionPicker.tsx b/components/sidebar/ApiVersionPicker.tsx index ba0d5cbdf5f3..586278c6d740 100644 --- a/components/sidebar/ApiVersionPicker.tsx +++ b/components/sidebar/ApiVersionPicker.tsx @@ -1,5 +1,4 @@ import { useRouter } from 'next/router' -import cx from 'classnames' import Cookies from 'js-cookie' import { InfoIcon } from '@primer/octicons-react' @@ -9,15 +8,8 @@ import { Picker } from 'components/ui/Picker' import { useTranslation } from 'components/hooks/useTranslation' import { API_VERSION_COOKIE_NAME } from 'components/RestRedirect' -import styles from './SidebarProduct.module.scss' - const API_VERSION_SUFFIX = ' (latest)' -type Props = { - mediumOrLower?: boolean - width?: number -} - function rememberApiVersion(apiVersion: string) { try { // We use this cookie to remember which API Version a user chooses @@ -37,7 +29,7 @@ function rememberApiVersion(apiVersion: string) { } } -export const ApiVersionPicker = ({ mediumOrLower, width }: Props) => { +export const ApiVersionPicker = () => { const router = useRouter() const { currentVersion } = useVersion() const { allVersions } = useMainContext() @@ -89,18 +81,7 @@ export const ApiVersionPicker = ({ mediumOrLower, width }: Props) => { // This only shows the REST Version picker if it's calendar date versioned return allVersions[currentVersion].apiVersions.length > 0 ? ( -
    +
    { />
    - ) : ( -
    - ) + ) : null } diff --git a/components/sidebar/SidebarNav.tsx b/components/sidebar/SidebarNav.tsx index e462df96c175..c7597b6feb36 100644 --- a/components/sidebar/SidebarNav.tsx +++ b/components/sidebar/SidebarNav.tsx @@ -1,23 +1,63 @@ +import cx from 'classnames' + import { useMainContext } from 'components/context/MainContext' import { SidebarProduct } from './SidebarProduct' import { SidebarHomepage } from './SidebarHomepage' +import { AllProductsLink } from './AllProductsLink' +import { ApiVersionPicker } from './ApiVersionPicker' +import { Link } from 'components/Link' + +type Props = { + variant?: 'full' | 'overlay' +} -export const SidebarNav = () => { - const { error, currentProduct } = useMainContext() +export const SidebarNav = ({ variant = 'full' }: Props) => { + const { error, currentProduct, currentProductTree } = useMainContext() + const isRestPage = currentProduct && currentProduct.id === 'rest' + const productTitle = currentProductTree?.shortTitle || currentProductTree?.title + // we need to roughly account for the site header height plus the height of + // the side nav header (which is taller when we show the API version picker) + // so we don't cut off the bottom of the sidebar + const sidebarPaddingBottom = isRestPage ? '250px' : '185px' return (
    -
    ) } diff --git a/components/sidebar/SidebarProduct.module.scss b/components/sidebar/SidebarProduct.module.scss index 0b1245c765fd..5696dd25683a 100644 --- a/components/sidebar/SidebarProduct.module.scss +++ b/components/sidebar/SidebarProduct.module.scss @@ -11,32 +11,3 @@ .sidebarArticleActive::before { border-left-width: 2px; } - -.apiFixedHeader { - position: fixed; - left: 0; - right: 0; - background-color: var(--color-canvas-default); - z-index: 1; -} - -.apiAllProductsLink { - top: 64px; -} - -.apiTitle { - padding-top: 10px; - top: 100px; -} - -.apiVersionPicker { - top: 128px; - - svg { - float: right; - } -} - -.noApiVersion { - margin: -5em; -} diff --git a/components/sidebar/SidebarProduct.tsx b/components/sidebar/SidebarProduct.tsx index e025d286231d..d4daac4f93e0 100644 --- a/components/sidebar/SidebarProduct.tsx +++ b/components/sidebar/SidebarProduct.tsx @@ -1,36 +1,20 @@ import { useRouter } from 'next/router' -import { useEffect, useRef, useState } from 'react' +import { useEffect, useRef } from 'react' import cx from 'classnames' import { useMainContext } from 'components/context/MainContext' import { useTranslation } from 'components/hooks/useTranslation' import { Link } from 'components/Link' -import { AllProductsLink } from 'components/sidebar/AllProductsLink' import { RestCollapsibleSection } from './RestCollapsibleSection' import { ProductCollapsibleSection } from './ProductCollapsibleSection' -import { ApiVersionPicker } from './ApiVersionPicker' - -import styles from './SidebarProduct.module.scss' export const SidebarProduct = () => { const router = useRouter() - const [sidebarWidth, setSidebarWidth] = useState(0) const sidebarRef = useRef(null) const { currentProduct, currentProductTree } = useMainContext() const { t } = useTranslation(['products']) const isRestPage = currentProduct && currentProduct.id === 'rest' - useEffect(() => { - function updateSize() { - if (sidebarRef.current) { - setSidebarWidth(sidebarRef.current.offsetWidth) - } - } - window.addEventListener('resize', updateSize) - updateSize() - return () => window.removeEventListener('resize', updateSize) - }, []) - useEffect(() => { const activeArticle = document.querySelector('[data-is-current-page=true]') // Setting to the top doesn't give enough context of surrounding categories @@ -52,10 +36,8 @@ export const SidebarProduct = () => { routePath.includes(href) ) - const productTitle = currentProductTree.shortTitle || currentProductTree.title - const productSection = () => ( -
  • +
    • {currentProductTree && currentProductTree.childPages.map((childPage, i) => { @@ -109,8 +91,7 @@ export const SidebarProduct = () => { ) return ( <> - -
    • +
      • {conceptualPages.map((childPage, i) => { const isStandaloneCategory = childPage.documentType === 'article' @@ -191,27 +172,7 @@ export const SidebarProduct = () => { } return ( -
          -
          - -
          - -
        • - - {productTitle} - -
        • +
            {isRestPage ? restSection() : productSection()}
          ) diff --git a/tests/browser/browser.js b/tests/browser/browser.js index 953390b2fbf9..1e11062487d0 100644 --- a/tests/browser/browser.js +++ b/tests/browser/browser.js @@ -136,9 +136,25 @@ describe('browser search', () => { }) }) +describe('x-large viewports - 1280+', () => { + jest.setTimeout(60 * 1000) + it('in article breadcrumbs at xl viewport should remove last breadcrumb', async () => { + await page.setViewport({ width: 1300, height: 700 }) + await page.goto( + 'http://localhost:4000/en/enterprise-cloud@latest/admin/identity-and-access-management/managing-iam-for-your-enterprise/about-authentication-for-your-enterprise' + ) + const breadcrumbsElement = await page.$$('[data-testid=breadcrumbs-in-article] ul li') + const breadcrumbsMissingElement = await page.$$( + '[data-testid=breadcrumbs-in-article] ul li .d-none' + ) + expect(breadcrumbsMissingElement.length).toBe(1) + expect(breadcrumbsElement.length).toBe(4) + }) +}) + describe('large -> x-large viewports - 1012+', () => { jest.setTimeout(60 * 1000) - it('version picker is visible', async () => { + it('version picker is visible in header', async () => { await page.setViewport({ width: 1013, height: 700 }) await page.goto('http://localhost:4000/en/actions') await page.click('[data-testid=version-picker]') @@ -146,19 +162,43 @@ describe('large -> x-large viewports - 1012+', () => { expect(versionItems.length).toBeGreaterThan(0) }) - it('language picker is visible', async () => { + it('language picker is visible in header', async () => { await page.goto('http://localhost:4000/en/actions') const languagePickerElement = await page.$$('[data-testid=language-picker]') expect(languagePickerElement.length).toBe(1) }) - it('sign up button is visible', async () => { + it('sign up button is visible in header', async () => { const signUpElement = await page.$('[data-testid=header-signup]') const signUpValue = await signUpElement.evaluate((el) => el.textContent) expect(signUpValue).toBe('Sign up') }) }) +describe('large viewports - 1012-1279', () => { + jest.setTimeout(60 * 1000) + it('hamburger button for sidebar overlay is visible', async () => { + await page.setViewport({ width: 1013, height: 700 }) + await page.goto('http://localhost:4000/en/actions') + await page.click('[data-testid=sidebar-hamburger]') + const sidebarElement = await page.$('[data-testid=sidebar-product-dialog]') + const sideBarValue = await sidebarElement.evaluate((el) => el.textContent) + expect(sideBarValue).toBe('GitHub Actions') + }) + + it('breadcrumbs show up in the header', async () => { + await page.goto( + 'http://localhost:4000/en/enterprise-cloud@latest/admin/identity-and-access-management/managing-iam-for-your-enterprise/about-authentication-for-your-enterprise' + ) + const breadcrumbsElement = await page.$$('[data-testid=breadcrumbs-header] ul li') + const breadcrumbsMissingElement = await page.$$( + '[data-testid=breadcrumbs-header] ul li .d-none' + ) + expect(breadcrumbsMissingElement.length).toBe(0) + expect(breadcrumbsElement.length).toBe(4) + }) +}) + describe('medium viewports - 768-1011', () => { jest.setTimeout(60 * 1000) it('version picker is visible', async () => { @@ -183,6 +223,13 @@ describe('medium viewports - 768-1011', () => { const signUpValue = await signUpElement.evaluate((el) => el.textContent) expect(signUpValue).toBe('Sign up') }) + + it('hamburger button for sidebar overlay is visible', async () => { + await page.click('[data-testid=sidebar-hamburger]') + const sidebarElement = await page.$('[data-testid=sidebar-product-dialog]') + const sideBarValue = await sidebarElement.evaluate((el) => el.textContent) + expect(sideBarValue).toBe('GitHub Actions') + }) }) describe('small -> x-small viewports - under 544 -> 767', () => { @@ -233,6 +280,13 @@ describe('small -> x-small viewports - under 544 -> 767', () => { const signUpValue = await signUpElement.evaluate((el) => el.textContent) expect(signUpValue).toBe('Sign up') }) + + it('hamburger button for sidebar overlay is visible', async () => { + await page.click('[data-testid=sidebar-hamburger]') + const sidebarElement = await page.$('[data-testid=sidebar-product-dialog]') + const sideBarValue = await sidebarElement.evaluate((el) => el.textContent) + expect(sideBarValue).toBe('GitHub Actions') + }) }) describe('survey', () => { diff --git a/tests/rendering/breadcrumbs.js b/tests/rendering/breadcrumbs.js index 06132a70140e..e249056a091e 100644 --- a/tests/rendering/breadcrumbs.js +++ b/tests/rendering/breadcrumbs.js @@ -7,53 +7,65 @@ describe('breadcrumbs', () => { jest.setTimeout(300 * 1000) describe('rendering', () => { - test('top-level product pages have breadcrumbs', async () => { + test('top-level product pages have breadcrumbs and breadcrumbs should exist regardles of header or in-article', async () => { const $ = await getDOM('/repositories') - expect($('[data-testid=breadcrumbs]')).toHaveLength(1) + expect($('[data-testid=breadcrumbs-in-article] a')).toHaveLength(1) + expect($('[data-testid=breadcrumbs-in-article] a')[0].attribs.class.includes('d-none')).toBe( + false + ) + expect($('[data-testid=breadcrumbs-header] a')).toHaveLength(1) + expect($('[data-testid=breadcrumbs-header] a')[0].attribs.class.includes('d-none')).toBe( + false + ) }) - test('article pages have breadcrumbs with product, category, maptopic, and article', async () => { + test('article pages in xl viewports have breadcrumbs in article with product, category, maptopic, and article and last breadcrumb is not viewable', async () => { const $ = await getDOM( '/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/adding-an-email-address-to-your-github-account' ) - const $breadcrumbs = $('[data-testid=breadcrumbs] a') + const $breadcrumbsInArticle = $('[data-testid=breadcrumbs-in-article] a') - expect($breadcrumbs).toHaveLength(4) - expect($breadcrumbs[0].attribs.title).toBe('Account and profile') - expect($breadcrumbs[1].attribs.title).toBe('Personal accounts') - expect($breadcrumbs[2].attribs.title).toBe('Manage email preferences') - expect($breadcrumbs[3].attribs.title).toBe('Add an email address') - }) + expect($breadcrumbsInArticle).toHaveLength(4) + expect($breadcrumbsInArticle[0].attribs.title).toBe('Account and profile') + expect($breadcrumbsInArticle[1].attribs.title).toBe('Personal accounts') + expect($breadcrumbsInArticle[2].attribs.title).toBe('Manage email preferences') + expect($breadcrumbsInArticle[3].attribs.title).toBe('Add an email address') + expect($breadcrumbsInArticle[3].attribs.class.includes('d-none')).toBe(true) - test('maptopic pages include their own grayed-out breadcrumb', async () => { - const $ = await getDOM( - '/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences' - ) - const $breadcrumbs = $('[data-testid=breadcrumbs] a') + const $breadcrumbsInHeader = $('[data-testid=breadcrumbs-header] a') - expect($breadcrumbs).toHaveLength(3) - expect($breadcrumbs[0].attribs.title).toBe('Account and profile') - expect($breadcrumbs[1].attribs.title).toBe('Personal accounts') - expect($breadcrumbs[2].attribs.title).toBe('Manage email preferences') - expect($breadcrumbs[2].attribs.class.includes('color-fg-muted')).toBe(true) + expect($breadcrumbsInHeader).toHaveLength(4) + expect($breadcrumbsInHeader[0].attribs.title).toBe('Account and profile') + expect($breadcrumbsInHeader[1].attribs.title).toBe('Personal accounts') + expect($breadcrumbsInHeader[2].attribs.title).toBe('Manage email preferences') + expect($breadcrumbsInHeader[3].attribs.title).toBe('Add an email address') + expect($breadcrumbsInHeader[3].attribs.class.includes('d-none')).toBe(false) }) test('works for enterprise user pages', async () => { const $ = await getDOM( '/en/enterprise-server/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/adding-an-email-address-to-your-github-account' ) - const $breadcrumbs = $('[data-testid=breadcrumbs] a') - expect($breadcrumbs).toHaveLength(4) - expect($breadcrumbs[0].attribs.title).toBe('Account and profile') + const $breadcrumbsInArticle = $('[data-testid=breadcrumbs-in-article] a') + expect($breadcrumbsInArticle).toHaveLength(4) + expect($breadcrumbsInArticle[0].attribs.title).toBe('Account and profile') + + const $breadcrumbsInHeader = $('[data-testid=breadcrumbs-header] a') + expect($breadcrumbsInHeader).toHaveLength(4) + expect($breadcrumbsInHeader[0].attribs.title).toBe('Account and profile') }) test('works for ghec billing page', async () => { const $ = await getDOM( '/enterprise-cloud@latest/billing/managing-billing-for-your-github-account/about-billing-for-your-enterprise' ) - const $breadcrumbs = $('[data-testid=breadcrumbs] a') - expect($breadcrumbs).toHaveLength(3) - expect($breadcrumbs[0].attribs.title).toBe('Billing and payments') + const $breadcrumbsInArticle = $('[data-testid=breadcrumbs-in-article] a') + expect($breadcrumbsInArticle).toHaveLength(3) + expect($breadcrumbsInArticle[0].attribs.title).toBe('Billing and payments') + + const $breadcrumbsInHeader = $('[data-testid=breadcrumbs-header] a') + expect($breadcrumbsInHeader).toHaveLength(3) + expect($breadcrumbsInHeader[0].attribs.title).toBe('Billing and payments') }) test('works for pages that have overlapping product names', async () => { @@ -61,45 +73,64 @@ describe('breadcrumbs', () => { // article path has overlap with `/en/github` '/en/github-cli/github-cli/about-github-cli' ) - const $breadcrumbs = $('[data-testid=breadcrumbs] a') - expect($breadcrumbs).toHaveLength(3) - expect($breadcrumbs[0].attribs.title).toBe('GitHub CLI') - expect($breadcrumbs[1].attribs.title).toBe('GitHub CLI') - expect($breadcrumbs[2].attribs.title).toBe('About GitHub CLI') + const $breadcrumbsInArticle = $('[data-testid=breadcrumbs-in-article] a') + expect($breadcrumbsInArticle).toHaveLength(3) + expect($breadcrumbsInArticle[0].attribs.title).toBe('GitHub CLI') + expect($breadcrumbsInArticle[1].attribs.title).toBe('GitHub CLI') + expect($breadcrumbsInArticle[2].attribs.title).toBe('About GitHub CLI') + expect($breadcrumbsInArticle[2].attribs.class.includes('d-none')).toBe(true) + + const $breadcrumbsInHeader = $('[data-testid=breadcrumbs-header] a') + expect($breadcrumbsInHeader).toHaveLength(3) + expect($breadcrumbsInHeader[0].attribs.title).toBe('GitHub CLI') + expect($breadcrumbsInHeader[1].attribs.title).toBe('GitHub CLI') + expect($breadcrumbsInHeader[2].attribs.title).toBe('About GitHub CLI') + expect($breadcrumbsInHeader[2].attribs.class.includes('d-none')).toBe(false) }) test('parses Liquid variables inside titles', async () => { const $ = await getDOM('/en/education/manage-coursework-with-github-classroom') - const $breadcrumbs = $('[data-testid=breadcrumbs] a') - expect($breadcrumbs).toHaveLength(2) - expect($breadcrumbs[1].attribs.title).toBe('GitHub Classroom') + const $breadcrumbsInArticle = $('[data-testid=breadcrumbs-in-article] a') + expect($breadcrumbsInArticle).toHaveLength(2) + expect($breadcrumbsInArticle[1].attribs.title).toBe('GitHub Classroom') + expect($breadcrumbsInArticle[1].attribs.class.includes('d-none')).toBe(true) + + const $breadcrumbsInHeader = $('[data-testid=breadcrumbs-header] a') + expect($breadcrumbsInHeader).toHaveLength(2) + expect($breadcrumbsInHeader[1].attribs.title).toBe('GitHub Classroom') + expect($breadcrumbsInHeader[1].attribs.class.includes('d-none')).toBe(false) }) test('English breadcrumbs link to English pages', async () => { const $ = await getDOM('/en/get-started/learning-about-github') - const $breadcrumbs = $('[data-testid=breadcrumbs] a') - expect($breadcrumbs[0].attribs.href).toBe('/en/get-started') + const $breadcrumbsInArticle = $('[data-testid=breadcrumbs-in-article] a') + expect($breadcrumbsInArticle[0].attribs.href).toBe('/en/get-started') + + const $breadcrumbsInHeader = $('[data-testid=breadcrumbs-in-article] a') + expect($breadcrumbsInHeader[0].attribs.href).toBe('/en/get-started') }) }) describeIfDocsEarlyAccess('early access rendering', () => { test('top-level product pages have breadcrumbs', async () => { const $ = await getDOM('/early-access/github/articles/using-gist-playground') - expect($('[data-testid=breadcrumbs]')).toHaveLength(1) + expect($('[data-testid=breadcrumbs-in-article]')).toHaveLength(1) + expect($('[data-testid=breadcrumbs-header]')).toHaveLength(1) }) test('early access article pages have breadcrumbs with product, category, and article', async () => { const $ = await getDOM( '/early-access/enterprise-importer/understanding-github-enterprise-importer' ) - const $breadcrumbTitles = $('[data-testid=breadcrumbs] [data-testid=breadcrumb-title]') - const $breadcrumbLinks = $('[data-testid=breadcrumbs] a') + const $breadcrumbTitles = $( + '[data-testid=breadcrumbs-in-article] [data-testid=breadcrumb-title]' + ) + const $breadcrumbLinks = $('[data-testid=breadcrumbs-in-article] a') expect($breadcrumbTitles).toHaveLength(0) expect($breadcrumbLinks).toHaveLength(2) expect($breadcrumbLinks[0].attribs.title).toBe('GitHub Enterprise Importer') expect($breadcrumbLinks[1].attribs.title).toBe('Understand the Importer') - expect($breadcrumbLinks[1].attribs.class.includes('color-fg-muted')).toBe(true) }) }) diff --git a/tests/rendering/sidebar.js b/tests/rendering/sidebar.js index 4b01adfd9d43..34e2416a0778 100644 --- a/tests/rendering/sidebar.js +++ b/tests/rendering/sidebar.js @@ -27,18 +27,16 @@ describe('sidebar', () => { ]) }) - test('highlights active product on Enterprise pages', async () => { - expect($enterprisePage('[data-testid=sidebar] [data-testid=sidebar-product]').length).toBe(1) - expect( - $enterprisePage('[data-testid=sidebar] [data-testid=sidebar-product] > a').text().trim() - ).toBe('Enterprise administrators') + test('highlights active product on Enterprise pages on xl viewport', async () => { + expect($enterprisePage('[data-testid=sidebar-product-xl]').length).toBe(1) + expect($enterprisePage('[data-testid=sidebar-product-xl]').text().trim()).toBe( + 'Enterprise administrators' + ) }) - test('highlights active product on GitHub pages', async () => { - expect($githubPage('[data-testid=sidebar] [data-testid=sidebar-product]').length).toBe(1) - expect( - $githubPage('[data-testid=sidebar] [data-testid=sidebar-product] > a').text().trim() - ).toBe('Get started') + test('highlights active product on GitHub pages on xl viewport', async () => { + expect($githubPage('[data-testid=sidebar-product-xl]').length).toBe(1) + expect($githubPage('[data-testid=sidebar-product-xl]').text().trim()).toBe('Get started') }) test('includes links to external products like Electron and CodeQL', async () => { diff --git a/tests/translations/frame.js b/tests/translations/frame.js index c1bdff768127..1f567da8b0e1 100644 --- a/tests/translations/frame.js +++ b/tests/translations/frame.js @@ -15,7 +15,7 @@ describe('frame', () => { test.each(langs)('breadcrumbs link to %s pages', async (lang) => { const $ = await getDOM(`/${lang}/get-started/learning-about-github`) - const $breadcrumbs = $('[data-testid=breadcrumbs] a') + const $breadcrumbs = $('[data-testid=breadcrumbs-in-article] a') expect($breadcrumbs[0].attribs.href).toBe(`/${lang}/get-started`) })