diff --git a/.github/actions/get-docs-early-access/action.yml b/.github/actions/get-docs-early-access/action.yml new file mode 100644 index 000000000000..85a61a2ba2c3 --- /dev/null +++ b/.github/actions/get-docs-early-access/action.yml @@ -0,0 +1,33 @@ +name: Clone and add docs-early-access + +description: Clone docs-early-access and copy its content into the repo + +inputs: + token: + description: PAT + required: true + +runs: + using: 'composite' + steps: + - name: Figure out which branch to checkout + id: check-early-access + env: + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + GITHUB_TOKEN: ${{ inputs.token }} + shell: bash + run: node .github/actions-scripts/what-docs-early-access-branch.js + + - name: Clone + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + with: + repository: github/docs-early-access + token: ${{ inputs.token }} + path: docs-early-access + ref: ${{ steps.check-early-access.outputs.branch }} + + - name: Merge docs-early-access repo's folders + shell: bash + run: | + .github/actions-scripts/merge-early-access.sh + rm -fr docs-early-access diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 492c27ee658f..a4a072b54884 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -88,28 +88,10 @@ jobs: - uses: ./.github/actions/node-npm-setup - - name: Figure out which docs-early-access branch to checkout, if internal repo + - uses: ./.github/actions/get-docs-early-access if: ${{ github.repository == 'github/docs-internal' }} - id: check-early-access - env: - BRANCH_NAME: ${{ github.head_ref || github.ref_name }} - GITHUB_TOKEN: ${{ secrets.DOCUBOT_REPO_PAT }} - run: node .github/actions-scripts/what-docs-early-access-branch.js - - - name: Check out docs-early-access too, if internal repo - if: ${{ github.repository == 'github/docs-internal' }} - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 with: - repository: github/docs-early-access token: ${{ secrets.DOCUBOT_REPO_PAT }} - path: docs-early-access - ref: ${{ steps.check-early-access.outputs.branch }} - - - name: Merge docs-early-access repo's folders - if: ${{ github.repository == 'github/docs-internal' }} - run: | - .github/actions-scripts/merge-early-access.sh - rm -fr docs-early-access - name: Check the test fixture data (if applicable) if: ${{ matrix.test-group == 'rendering-fixtures' }} diff --git a/tests/fixtures/content/early-access/index.md b/tests/fixtures/content/early-access/index.md new file mode 100644 index 000000000000..21a549b103c0 --- /dev/null +++ b/tests/fixtures/content/early-access/index.md @@ -0,0 +1,13 @@ +--- +title: Early Access documentation +hidden: true +versions: '*' +children: + - /secrets +--- + +👋 Hello, local test developer! This page is not visible on production. + +These are the Early Access pages for {{ allVersions[currentVersion].versionTitle }}: + +{{ earlyAccessPageLinks }} diff --git a/tests/fixtures/content/early-access/secrets/deeper/index.md b/tests/fixtures/content/early-access/secrets/deeper/index.md new file mode 100644 index 000000000000..767020a471bb --- /dev/null +++ b/tests/fixtures/content/early-access/secrets/deeper/index.md @@ -0,0 +1,7 @@ +--- +title: Deeper secrets +versions: '*' +hidden: true +children: + - /mariana-trench +--- diff --git a/tests/fixtures/content/early-access/secrets/deeper/mariana-trench.md b/tests/fixtures/content/early-access/secrets/deeper/mariana-trench.md new file mode 100644 index 000000000000..0f8ff8c531f1 --- /dev/null +++ b/tests/fixtures/content/early-access/secrets/deeper/mariana-trench.md @@ -0,0 +1,9 @@ +--- +title: Mariana Trench +versions: '*' +hidden: true +--- + +## This is a deep early-access article + +Exists to test stuff like breadcrumbs. diff --git a/tests/fixtures/content/early-access/secrets/early-days.md b/tests/fixtures/content/early-access/secrets/early-days.md new file mode 100644 index 000000000000..46047547c731 --- /dev/null +++ b/tests/fixtures/content/early-access/secrets/early-days.md @@ -0,0 +1,8 @@ +--- +title: Early days +hidden: true +versions: + fpt: '*' +--- + +This page is only available in **free, pro, & team**. diff --git a/tests/fixtures/content/early-access/secrets/index.md b/tests/fixtures/content/early-access/secrets/index.md new file mode 100644 index 000000000000..f0b3eb3dda8b --- /dev/null +++ b/tests/fixtures/content/early-access/secrets/index.md @@ -0,0 +1,8 @@ +--- +title: GitHub Secrets +versions: '*' +hidden: true +children: + - /early-days + - /deeper +--- diff --git a/tests/fixtures/content/get-started/quickstart/dynamic-title.md b/tests/fixtures/content/get-started/quickstart/dynamic-title.md new file mode 100644 index 000000000000..a68de8def879 --- /dev/null +++ b/tests/fixtures/content/get-started/quickstart/dynamic-title.md @@ -0,0 +1,14 @@ +--- +title: '{% ifversion fpt %}Hello{% else %}Greetings{% endif %} {% data variables.product.product_name %}' +versions: + fpt: '*' + ghes: '*' + ghae: '*' + ghec: '*' +type: quick_start +--- + +## Introduction + +This page has a single `title` and it uses Liquid that depends on +`ifversion` and `data variables...`. diff --git a/tests/fixtures/content/get-started/quickstart/index.md b/tests/fixtures/content/get-started/quickstart/index.md index 6600b7c498c8..0e113ac57d59 100644 --- a/tests/fixtures/content/get-started/quickstart/index.md +++ b/tests/fixtures/content/get-started/quickstart/index.md @@ -9,4 +9,5 @@ versions: children: - /hello-world - /link-rewriting + - /dynamic-title --- diff --git a/tests/fixtures/content/index.md b/tests/fixtures/content/index.md index 6580cd67039f..8759ab07a461 100644 --- a/tests/fixtures/content/index.md +++ b/tests/fixtures/content/index.md @@ -17,6 +17,7 @@ children: # as if the URL had been `/en/free-pro-team@latest/get-started/anything`. - search - get-started + - early-access # - account-and-profile # - authentication # - repositories @@ -42,7 +43,6 @@ children: # - pages # - education # - desktop - # - early-access # - support childGroups: - name: Get started diff --git a/tests/rendering-fixtures/breadcrumbs.js b/tests/rendering-fixtures/breadcrumbs.js new file mode 100644 index 000000000000..86c0c0180b8a --- /dev/null +++ b/tests/rendering-fixtures/breadcrumbs.js @@ -0,0 +1,83 @@ +import { getDOM } from '../helpers/e2etest.js' + +describe('breadcrumbs', () => { + test('top-level product pages have breadcrumbs and breadcrumbs should exist regardless of header or in-article', async () => { + const $ = await getDOM('/get-started') + const links = $('[data-testid=breadcrumbs-in-article] a') + expect(links.attr('class').includes('d-none')).toBe(false) + }) + + test('links always prefixed with language', async () => { + const $ = await getDOM('/get-started/quickstart/hello-world') + const links = $('[data-testid=breadcrumbs-in-article] a') + links.each((i, element) => { + expect($(element).attr('href').startsWith('/en/')).toBe(true) + }) + expect.assertions(3) + }) + + test('top-level hidden /search page has no breadcrumbs', async () => { + const $ = await getDOM('/search') + const links = $('[data-testid=breadcrumbs-in-article] a') + expect(links.length).toBe(0) + const headers = $('[data-testid=breadcrumbs-header]') + expect(headers.length).toBe(0) + }) + + test('short titles are preferred', async () => { + const $ = await getDOM('/get-started/foo/bar') + const links = $('[data-testid=breadcrumbs-in-article] a:last-child') + expect(links.text()).toBe('Bar') + }) + + test('article pages have breadcrumbs in article with product, category, maptopic, and article and last breadcrumb is not viewable', async () => { + const $ = await getDOM('/get-started/quickstart/hello-world') + const links = $('[data-testid=breadcrumbs-in-article] a') + expect(links.length).toBe(3) + expect($(links[0]).text()).toBe('Get started') + expect($(links[0]).attr('class').includes('d-none')).toBe(false) + expect($(links[1]).text()).toBe('Quickstart') + expect($(links[1]).attr('class').includes('d-none')).toBe(false) + expect($(links[2]).text()).toBe('Hello World') + expect($(links[2]).attr('class').includes('d-none')).toBe(true) + }) + + test('works for enterprise-server articles too', async () => { + const $ = await getDOM('/enterprise-server@latest/get-started/quickstart/hello-world') + const links = $('[data-testid=breadcrumbs-in-article] a') + expect(links.length).toBe(3) + expect($(links[0]).text()).toBe('Get started') + expect($(links[1]).text()).toBe('Quickstart') + expect($(links[2]).text()).toBe('Hello World') + }) + + test('works for titles that depend on Liquid', async () => { + const $fpt = await getDOM('/get-started/quickstart/dynamic-title') + const fptLinks = $fpt('[data-testid=breadcrumbs-in-article] a') + expect($fpt(fptLinks[2]).text()).toBe('Hello GitHub') + + const $ghec = await getDOM('/enterprise-cloud@latest/get-started/quickstart/dynamic-title') + const ghecLinks = $ghec('[data-testid=breadcrumbs-in-article] a') + expect($ghec(ghecLinks[2]).text()).toBe('Greetings GitHub Enterprise Cloud') + }) + + // Note, early access always work for fixture content + test('top-level product pages have breadcrumbs', async () => { + const $ = await getDOM('/early-access/secrets/deeper/mariana-trench') + expect($('[data-testid=breadcrumbs-in-article]').length).toBe(1) + expect($('[data-testid=breadcrumbs-header]').length).toBe(1) + }) + + test('early access article pages have breadcrumbs with product, category, and article', async () => { + const $ = await getDOM('/early-access/secrets/deeper/mariana-trench') + const $breadcrumbTitles = $( + '[data-testid=breadcrumbs-in-article] [data-testid=breadcrumb-title]' + ) + const $breadcrumbLinks = $('[data-testid=breadcrumbs-in-article] a') + + expect($breadcrumbTitles.length).toBe(0) + expect($breadcrumbLinks.length).toBe(2) + expect($breadcrumbLinks[0].attribs.title).toBe('Deeper secrets') + expect($breadcrumbLinks[1].attribs.title).toBe('Mariana Trench') + }) +}) diff --git a/tests/rendering/breadcrumbs.js b/tests/rendering/breadcrumbs.js deleted file mode 100644 index e249056a091e..000000000000 --- a/tests/rendering/breadcrumbs.js +++ /dev/null @@ -1,242 +0,0 @@ -import { jest } from '@jest/globals' - -import { getDOM, getJSON } from '../helpers/e2etest.js' -import { describeIfDocsEarlyAccess } from '../helpers/conditional-runs.js' - -describe('breadcrumbs', () => { - jest.setTimeout(300 * 1000) - - describe('rendering', () => { - 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-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 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 $breadcrumbsInArticle = $('[data-testid=breadcrumbs-in-article] a') - - 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) - - const $breadcrumbsInHeader = $('[data-testid=breadcrumbs-header] a') - - 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 $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 $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 () => { - const $ = await getDOM( - // article path has overlap with `/en/github` - '/en/github-cli/github-cli/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 $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 $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-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-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') - }) - }) - - describe('breadcrumbs object', () => { - test('works on product index pages', async () => { - const breadcrumbs = await getJSON('/en/repositories?json=breadcrumbs') - const expected = [ - { - href: '/en/repositories', - title: 'Repositories', - }, - ] - expect(breadcrumbs).toEqual(expected) - }) - - test('works on category index pages', async () => { - const breadcrumbs = await getJSON( - '/en/issues/tracking-your-work-with-issues/quickstart?json=breadcrumbs' - ) - const expected = [ - { - href: '/en/issues', - title: 'GitHub Issues', - }, - { - href: '/en/issues/tracking-your-work-with-issues', - title: 'Issues', - }, - { - href: '/en/issues/tracking-your-work-with-issues/quickstart', - title: 'Quickstart for GitHub Issues', - }, - ] - expect(breadcrumbs).toEqual(expected) - }) - - test('works on maptopic pages', async () => { - const breadcrumbs = await getJSON( - '/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-personal-account-settings?json=breadcrumbs' - ) - const expected = [ - { - href: '/en/account-and-profile', - title: 'Account and profile', - }, - { - href: '/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github', - title: 'Personal accounts', - }, - { - href: '/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-personal-account-settings', - title: 'Personal account settings', - }, - ] - expect(breadcrumbs).toEqual(expected) - }) - - test('works on articles that DO have maptopics ', async () => { - const breadcrumbs = await getJSON( - '/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-personal-account-settings/about-your-personal-dashboard?json=breadcrumbs' - ) - const expected = [ - { - href: '/en/account-and-profile', - title: 'Account and profile', - }, - { - href: '/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github', - title: 'Personal accounts', - }, - { - href: '/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-personal-account-settings', - title: 'Personal account settings', - }, - { - href: '/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-personal-account-settings/about-your-personal-dashboard', - title: 'Your personal dashboard', - }, - ] - expect(breadcrumbs).toEqual(expected) - }) - - test('works on articles that DO NOT have maptopics ', async () => { - const breadcrumbs = await getJSON( - '/site-policy/privacy-policies/github-privacy-statement?json=breadcrumbs' - ) - const expected = [ - { - href: '/en/site-policy', - title: 'Site policy', - }, - { - href: '/en/site-policy/privacy-policies', - title: 'Privacy Policies', - }, - { - href: '/en/site-policy/privacy-policies/github-privacy-statement', - title: 'GitHub Privacy Statement', - }, - ] - expect(breadcrumbs).toEqual(expected) - }) - - test('returns an empty array on the landing page', async () => { - const breadcrumbs = await getJSON('/en?json=breadcrumbs') - expect(breadcrumbs).toEqual([]) - }) - }) -})