| | import { fileURLToPath } from 'url' |
| | import path from 'path' |
| |
|
| | import cheerio from 'cheerio' |
| | import { beforeAll, beforeEach, describe, expect, test } from 'vitest' |
| |
|
| | import Page, { FrontmatterErrorsError } from '@/frame/lib/page' |
| | import { allVersions } from '@/versions/lib/all-versions' |
| | import enterpriseServerReleases, { latest } from '@/versions/lib/enterprise-server-releases' |
| | import nonEnterpriseDefaultVersion from '@/versions/lib/non-enterprise-default-version' |
| |
|
| | interface TestContext { |
| | currentVersion: string |
| | currentLanguage: string |
| | currentPath?: string |
| | enterpriseServerVersions?: string[] |
| | [key: string]: any |
| | } |
| |
|
| | const __dirname = path.dirname(fileURLToPath(import.meta.url)) |
| | const enterpriseServerVersions = Object.keys(allVersions).filter((v) => |
| | v.startsWith('enterprise-server@'), |
| | ) |
| |
|
| | |
| | const nonEnterpriseDefaultPlan = nonEnterpriseDefaultVersion.split('@')[0] |
| |
|
| | const opts = { |
| | relativePath: |
| | 'pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches.md', |
| | basePath: path.join(__dirname, '../../../content'), |
| | languageCode: 'en', |
| | } |
| |
|
| | describe('Page class', () => { |
| | test('preserves file path info', async () => { |
| | const page = await Page.init(opts) |
| | expect(page!.relativePath).toBe(opts.relativePath) |
| | expect(page!.fullPath.includes(page!.relativePath)).toBe(true) |
| | }) |
| |
|
| | describe('showMiniToc page property', () => { |
| | let article: Page | undefined |
| | let articleWithFM: Page | undefined |
| | let tocPage: Page | undefined |
| |
|
| | beforeAll(async () => { |
| | article = await Page.init({ |
| | relativePath: 'sample-article.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| |
|
| | articleWithFM = await Page.init({ |
| | showMiniToc: false, |
| | relativePath: article!.relativePath, |
| | basePath: article!.basePath, |
| | languageCode: article!.languageCode, |
| | } as any) |
| |
|
| | tocPage = await Page.init({ |
| | relativePath: 'sample-toc-index.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | }) |
| |
|
| | test('is true by default on articles', () => { |
| | expect(article!.showMiniToc).toBe(true) |
| | }) |
| |
|
| | test('is false on articles when set in frontmatter', () => { |
| | expect(articleWithFM!.showMiniToc).toBe(false) |
| | }) |
| |
|
| | |
| | test('is undefined by default on index.md pages', () => { |
| | expect(tocPage!.showMiniToc).toBeUndefined() |
| | }) |
| | }) |
| |
|
| | describe('page.render(context)', () => { |
| | |
| | |
| | |
| | test('renders the expected Enterprise Server versioned content', async () => { |
| | const page = await Page.init({ |
| | relativePath: 'page-versioned-for-all-enterprise-releases.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | |
| | const context: TestContext = { |
| | currentVersion: `enterprise-server@${enterpriseServerReleases.latest}`, |
| | currentLanguage: 'en', |
| | enterpriseServerVersions, |
| | } |
| | context.currentPath = `/${context.currentLanguage}/${context.currentVersion}/${page!.relativePath}` |
| | let rendered = await page!.render(context) |
| | let $ = cheerio.load(rendered) |
| | expect(($ as any).text()).toBe( |
| | 'This text should render on any actively supported version of Enterprise Server', |
| | ) |
| | expect(($ as any).text()).not.toBe('This text should only render on non-Enterprise') |
| |
|
| | |
| | |
| | context.currentVersion = `enterprise-server@${enterpriseServerReleases.oldestSupported}` |
| | context.currentPath = `/${context.currentLanguage}/${context.currentVersion}/${page!.relativePath}` |
| | rendered = await page!.render(context) |
| | $ = cheerio.load(rendered) |
| | expect(($ as any).text()).toBe( |
| | 'This text should render on any actively supported version of Enterprise Server', |
| | ) |
| | expect(($ as any).text()).not.toBe('This text should only render on non-Enterprise') |
| |
|
| | |
| | |
| | context.currentVersion = nonEnterpriseDefaultVersion |
| | context.currentPath = `/${context.currentLanguage}/${context.currentVersion}/${page!.relativePath}` |
| | rendered = await page!.render(context) |
| | $ = cheerio.load(rendered) |
| | expect(($ as any).text()).not.toBe( |
| | 'This text should render on any actively supported version of Enterprise Server', |
| | ) |
| | expect(($ as any).text()).toBe('This text should only render on non-Enterprise') |
| | }) |
| |
|
| | test('support next to-be-released Enterprise Server version in frontmatter', async () => { |
| | |
| | const page = await Page.init({ |
| | relativePath: 'page-versioned-for-next-enterprise-release.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | |
| | const context: TestContext = { |
| | currentVersion: 'enterprise-server@3.0', |
| | currentLanguage: 'en', |
| | } |
| | await expect(() => { |
| | return page!.render(context) |
| | }).not.toThrow() |
| | }) |
| | }) |
| |
|
| | test('preserves `languageCode`', async () => { |
| | const page = await Page.init(opts) |
| | expect(page!.languageCode).toBe('en') |
| | }) |
| |
|
| | test('parentProductId getter', async () => { |
| | let page = await Page.init({ |
| | relativePath: 'github/some-category/some-article.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures/products'), |
| | languageCode: 'en', |
| | }) |
| | expect(page!.parentProductId).toBe('github') |
| |
|
| | page = await Page.init({ |
| | relativePath: 'actions/some-category/some-article.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures/products'), |
| | languageCode: 'en', |
| | }) |
| | expect(page!.parentProductId).toBe('actions') |
| |
|
| | page = await Page.init({ |
| | relativePath: 'admin/some-category/some-article.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures/products'), |
| | languageCode: 'en', |
| | }) |
| | expect(page!.parentProductId).toBe('admin') |
| | }) |
| |
|
| | describe('permalinks', () => { |
| | test('is an array', async () => { |
| | const page = await Page.init(opts) |
| | expect(Array.isArray(page!.permalinks)).toBe(true) |
| | }) |
| |
|
| | test('has a key for every supported enterprise version (and no deprecated versions)', async () => { |
| | const page = await Page.init(opts) |
| | const pageVersions = page!.permalinks.map((permalink: any) => permalink.pageVersion) |
| | expect( |
| | enterpriseServerReleases.supported.every((version) => |
| | pageVersions.includes(`enterprise-server@${version}`), |
| | ), |
| | ).toBe(true) |
| | expect( |
| | enterpriseServerReleases.deprecated.every( |
| | (version) => !pageVersions.includes(`enterprise-server@${version}`), |
| | ), |
| | ).toBe(true) |
| | }) |
| |
|
| | test('sets versioned values', async () => { |
| | const page = await Page.init(opts) |
| | const expectedPath = |
| | 'pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches' |
| | expect( |
| | page!.permalinks.find( |
| | (permalink: any) => permalink.pageVersion === nonEnterpriseDefaultVersion, |
| | )!.href, |
| | ).toBe(`/en/${expectedPath}`) |
| | expect( |
| | page!.permalinks.find( |
| | (permalink: any) => |
| | permalink.pageVersion === |
| | `enterprise-server@${enterpriseServerReleases.oldestSupported}`, |
| | )!.href, |
| | ).toBe(`/en/enterprise-server@${enterpriseServerReleases.oldestSupported}/${expectedPath}`) |
| | }) |
| |
|
| | test('homepage permalinks', async () => { |
| | const page = await Page.init({ |
| | relativePath: 'index.md', |
| | basePath: path.join(__dirname, '../../../content'), |
| | languageCode: 'en', |
| | }) |
| | expect( |
| | page!.permalinks.find((permalink) => permalink.pageVersion === nonEnterpriseDefaultVersion) |
| | ?.href, |
| | ).toBe('/en') |
| | expect( |
| | page!.permalinks.find( |
| | (permalink) => |
| | permalink.pageVersion === |
| | `enterprise-server@${enterpriseServerReleases.oldestSupported}`, |
| | )?.href, |
| | ).toBe(`/en/enterprise-server@${enterpriseServerReleases.oldestSupported}`) |
| | }) |
| |
|
| | test('permalinks for enterprise-only pages', async () => { |
| | const page = await Page.init({ |
| | relativePath: 'products/admin/some-category/some-article.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | expect( |
| | page!.permalinks.find( |
| | (permalink: any) => permalink.pageVersion === `enterprise-server@${latest}`, |
| | )!.href, |
| | ).toBe( |
| | `/en/enterprise-server@${enterpriseServerReleases.latest}/products/admin/some-category/some-article`, |
| | ) |
| | const pageVersions = page!.permalinks.map((permalink: any) => permalink.pageVersion) |
| | expect(page!.permalinks.length).toBeGreaterThan(0) |
| | expect(pageVersions.includes(nonEnterpriseDefaultVersion)).toBe(false) |
| | }) |
| |
|
| | test('permalinks for non-GitHub.com products without Enterprise versions', async () => { |
| | const page = await Page.init({ |
| | relativePath: 'products/actions/some-category/some-article.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | expect( |
| | page!.permalinks.find( |
| | (permalink: any) => permalink.pageVersion === nonEnterpriseDefaultVersion, |
| | )!.href, |
| | ).toBe('/en/products/actions/some-category/some-article') |
| | expect(page!.permalinks.length).toBe(1) |
| | }) |
| | }) |
| |
|
| | describe('videos', () => { |
| | let page: Page | undefined |
| |
|
| | beforeEach(async () => { |
| | page = await Page.init({ |
| | relativePath: 'article-with-videos.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | }) |
| |
|
| | test('includes videos specified in the featuredLinks frontmatter', async () => { |
| | expect((page as any)!.featuredLinks.videos).toStrictEqual([ |
| | { |
| | title: 'codespaces', |
| | href: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc', |
| | }, |
| | { |
| | title: 'more codespaces', |
| | href: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc', |
| | }, |
| | { |
| | title: 'even more codespaces', |
| | href: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc', |
| | }, |
| | ]) |
| |
|
| | expect((page as any)!.featuredLinks.videosHeading).toBe('Custom Videos heading') |
| | }) |
| | }) |
| |
|
| | describe('introLinks', () => { |
| | test('includes the links specified in the introLinks frontmatter', async () => { |
| | const page = await Page.init({ |
| | relativePath: 'article-with-introLinks.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| |
|
| | expect(page!.introLinks).toStrictEqual({ |
| | overview: 'https://github.com', |
| | 'custom link!': 'https://github.com/features', |
| | }) |
| | }) |
| | }) |
| |
|
| | describe('Page.parseFrontmatter()', () => { |
| | test('throws an error on bad input', () => { |
| | const markdown = null |
| | expect(() => { |
| | ;(Page as any).parseFrontmatter('some/file.md', markdown) |
| | }).toThrow() |
| | }) |
| | }) |
| |
|
| | describe('page.versions frontmatter', () => { |
| | test('pages that use short names in versions frontmatter', async () => { |
| | const page = await Page.init({ |
| | relativePath: 'short-versions.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | expect((page!.versions as any).fpt).toBe('*') |
| | expect((page!.versions as any).ghes).toBe('>3.0') |
| | expect(page!.applicableVersions.includes('free-pro-team@latest')).toBe(true) |
| | expect(page!.applicableVersions.includes(`enterprise-server@${latest}`)).toBe(true) |
| | }) |
| |
|
| | test('index page', async () => { |
| | const page = await Page.init({ |
| | relativePath: 'index.md', |
| | basePath: path.join(__dirname, '../../../content'), |
| | languageCode: 'en', |
| | }) |
| | expect(page!.versions).toEqual({ fpt: '*', ghec: '*', ghes: '*' }) |
| | }) |
| |
|
| | test('enterprise admin index page', async () => { |
| | const page = await Page.init({ |
| | relativePath: 'admin/index.md', |
| | basePath: path.join(__dirname, '../../../content'), |
| | languageCode: 'en', |
| | }) |
| |
|
| | expect(nonEnterpriseDefaultPlan in page!.versions).toBe(false) |
| | expect(page!.versions.ghes).toBe('*') |
| | }) |
| |
|
| | test('feature versions frontmatter', async () => { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const page = await Page.init({ |
| | relativePath: 'feature-versions-frontmatter.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| |
|
| | |
| | expect(page!.versions.fpt).toBe('*') |
| | expect(page!.versions.ghes).toBe('>2.21') |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | expect(page!.applicableVersions.includes('free-pro-team@latest')).toBe(true) |
| | expect(page!.applicableVersions.includes(`enterprise-server@${latest}`)).toBe(true) |
| | expect(page!.applicableVersions.includes('feature')).toBe(false) |
| | expect(page!.applicableVersions.includes('placeholder')).toBe(false) |
| | }) |
| | }) |
| |
|
| | describe('platform specific content', () => { |
| | test('page.defaultPlatform frontmatter', async () => { |
| | const page = await Page.init({ |
| | relativePath: 'actions/some-category/some-article.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures/products'), |
| | languageCode: 'en', |
| | }) |
| | expect((page as any)!.defaultPlatform).toBeDefined() |
| | expect((page as any)!.defaultPlatform).toBe('linux') |
| | }) |
| | }) |
| |
|
| | describe('tool specific content', () => { |
| | test('page.defaultTool frontmatter', async () => { |
| | const page = await Page.init({ |
| | relativePath: 'default-tool.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | expect((page as any)!.defaultTool).toBeDefined() |
| | expect((page as any)!.defaultTool).toBe('cli') |
| | }) |
| | }) |
| | }) |
| |
|
| | describe('catches errors thrown in Page class', () => { |
| | test('frontmatter parsing error', async () => { |
| | async function getPage() { |
| | return await Page.init({ |
| | relativePath: 'page-with-frontmatter-error.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | } |
| |
|
| | await expect(getPage).rejects.toThrow(FrontmatterErrorsError) |
| | }) |
| |
|
| | test('missing versions frontmatter', async () => { |
| | async function getPage() { |
| | return await Page.init({ |
| | relativePath: 'page-with-missing-product-versions.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | } |
| |
|
| | await expect(getPage).rejects.toThrowError('versions') |
| | }) |
| |
|
| | test('English page with a version in frontmatter that its parent product is not available in', async () => { |
| | async function getPage() { |
| | return await Page.init({ |
| | relativePath: 'admin/some-category/some-article-with-mismatched-versions-frontmatter.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures/products'), |
| | languageCode: 'en', |
| | }) |
| | } |
| |
|
| | expect(getPage).rejects.toThrowError(/`versions` frontmatter.*? product is not available in/) |
| | }) |
| |
|
| | describe('versioning optional attributes', () => { |
| | test("re-rendering set appropriate 'product', 'permissions', 'learningTracks'", async () => { |
| | const page = await Page.init({ |
| | relativePath: 'page-with-optional-attributes.md', |
| | basePath: path.join(__dirname, '../../../src/fixtures/fixtures'), |
| | languageCode: 'en', |
| | }) |
| | const context: any = { |
| | page: { version: `enterprise-server@3.2` }, |
| | currentVersion: `enterprise-server@3.2`, |
| | currentVersionObj: {}, |
| | currentProduct: 'snowbird', |
| | currentLanguage: 'en', |
| | currentPath: '/en/enterprise-server@3.2/optional/attributes', |
| | fpt: false, |
| | } |
| |
|
| | await page!.render(context) |
| | expect(page!.product).toBe('') |
| | expect(page!.permissions).toBe('') |
| |
|
| | |
| | context.page.version = nonEnterpriseDefaultVersion |
| | context.version = nonEnterpriseDefaultVersion |
| | context.currentPath = '/en/optional/attributes' |
| | context.fpt = true |
| | await page!.render(context) |
| | expect(page!.product).toContain('FPT rulez!') |
| | expect(page!.permissions).toContain('FPT only!') |
| | }) |
| | }) |
| | }) |
| |
|