import { describe, expect, test } from 'vitest'
import cheerio from 'cheerio'
import { getDataByLanguage } from '@/data-directory/lib/get-data'
import { getDOM } from '@/tests/helpers/e2etest'
import { supported } from '@/versions/lib/enterprise-server-releases'
describe('spotlight', () => {
test('renders styled warnings', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/warnings')
const nodes = $('.ghd-spotlight-attention')
expect(nodes.length).toBe(1)
expect(nodes.text().includes('This is inside the warning.')).toBe(true)
})
test('renders styled danger', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/danger')
const nodes = $('.ghd-spotlight-danger')
expect(nodes.length).toBe(1)
expect(nodes.text().includes('Danger, Will Robinson.')).toBe(true)
})
test('renders styled tips', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/tips')
const nodes = $('.ghd-spotlight-success')
expect(nodes.length).toBe(1)
expect(nodes.text().includes('This is inside the tip.')).toBe(true)
})
test('renders styled notes', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/notes')
const nodes = $('.ghd-spotlight-accent')
expect(nodes.length).toBe(1)
expect(nodes.text().includes('This is inside the note.')).toBe(true)
})
})
describe('raw', () => {
test('renders raw', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/raw')
const lead = $('[data-testid="lead"]').html()
expect(lead).toMatch('{% raw %}')
const code = $('pre code').html()
expect(code).toMatch('{% data foo.bar.buzz %}')
expect(code).toMatch('{{ page.title }}')
})
})
describe('tool', () => {
test('renders platform-specific content', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/platform-specific')
expect($('.ghd-tool.mac p').length).toBe(1)
expect($('.ghd-tool.mac p').text().includes('mac specific content')).toBe(true)
expect($('.ghd-tool.windows p').length).toBe(1)
expect($('.ghd-tool.windows p').text().includes('windows specific content')).toBe(true)
expect($('.ghd-tool.linux p').length).toBe(1)
expect($('.ghd-tool.linux p').text().includes('linux specific content')).toBe(true)
})
test('renders expected mini TOC headings in platform-specific content', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/platform-specific')
expect($('h2#in-this-article').length).toBe(1)
expect($('h2#in-this-article + nav ul .ghd-tool.mac').length).toBe(1)
expect($('h2#in-this-article + nav ul .ghd-tool.windows').length).toBe(1)
expect($('h2#in-this-article + nav ul .ghd-tool.linux').length).toBe(1)
})
})
describe('post', () => {
test('whitespace control', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/whitespace')
const html = $('#article-contents').html()
expect(html).toMatch('
HubGit
')
expect(html).toMatch('Text before. HubGit Text after.
')
expect(html).toMatch('HubGit')
expect(html).toMatch('CramFPTped')
// Test what happens to `Cram{% ifversion fpt %}FPT{% endif %}ped.`
// when it's not free-pro-team.
{
const $inner: cheerio.Root = await getDOM(
'/enterprise-server@latest/get-started/liquid/whitespace',
)
const innerHtml = $inner('#article-contents').html()
// Assures that there's not whitespace left when the `{% ifversion %}`
// yields an empty string.
expect(innerHtml).toMatch('Cramped')
}
})
})
describe('rowheaders', () => {
test('rowheaders', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/table-row-headers')
const tables = $('#article-contents table')
expect(tables.length).toBe(2)
// The first table should have this structure:
//
// table
// tbody
// tr
// th
// td
// td
// td
//
// (and there are 2 of these rows)
//
// That's because a Liquid + Markdown solution rewrites the
// *first* `tbody td` to become a `th` instead.
const firstTable = tables.filter((i: number) => i === 0)
expect($('tbody tr th', firstTable).length).toBe(2)
expect($('tbody tr td', firstTable).length).toBe(2 * 3)
// The second table should have this structure:
//
// table
// tbody
// tr
// td
// td
// td
//
// (and there are 3 of these
rows)
const secondTable = tables.filter((i: number) => i === 1)
expect($('tbody tr th', secondTable).length).toBe(0)
expect($('tbody tr td', secondTable).length).toBe(3 * 3)
// More specifically, the | tags should have the appropriate
// `scope` attribute.
// See "Scope attribute should be used correctly on tables"
// https://dequeuniversity.com/rules/axe/4.1/scope-attr-valid?application=RuleDescription
$('thead th', firstTable).each((i: number, element: any) => {
expect($(element).attr('scope')).toBe('col')
})
$('tbody th', firstTable).each((i: number, element: any) => {
expect($(element).attr('scope')).toBe('row')
})
// The 5 here is the other `expect(...)` that happens before these
// two, just above, `expect(...)` inside the `.each(...)` loops.
let totalAssertions = 5
totalAssertions += $('thead th', firstTable).length
totalAssertions += $('tbody th', firstTable).length
expect.assertions(totalAssertions)
})
})
describe('ifversion', () => {
// the matchesPerVersion object contains a list of conditions that
// should match per version tested, but we also operate against it
// to find out versions that shouldn't match
const ghesLast = `enterprise-server@${supported[supported.length - 1]}`
const ghesPenultimate = `enterprise-server@${supported[supported.length - 2]}`
const matchesPerVersion: Record = {
'free-pro-team@latest': [
'condition-a',
'condition-b',
'condition-d',
'condition-i',
'condition-j',
'condition-l',
],
'enterprise-cloud@latest': ['condition-c', 'condition-j', 'condition-l'],
[ghesLast]: [
'condition-c',
'condition-e',
'condition-f',
'condition-g',
'condition-h',
'condition-i',
'condition-k',
'condition-m',
'condition-n',
'condition-o',
],
[ghesPenultimate]: [
'condition-c',
'condition-e',
'condition-f',
'condition-i',
'condition-j',
'condition-m',
'condition-o',
],
}
test.each(Object.keys(matchesPerVersion))(
'ifversion using rendered version %p',
async (version: string) => {
const $: cheerio.Root = await getDOM(`/${version}/get-started/liquid/ifversion`)
const html = $('#article-contents').html()
const allConditions = Object.values(matchesPerVersion).flat()
// this is all conditions that should match for this rendered version
const wantedConditions = allConditions.filter((condition: string) => {
return matchesPerVersion[version].includes(condition)
})
// this is the inverse of the above, conditions that shouldn't match for this rendered version
const unwantedConditions = allConditions.filter((condition: string) => {
return !matchesPerVersion[version].includes(condition)
})
for (const condition of wantedConditions as string[]) {
expect(html).toMatch(condition)
}
for (const condition of unwantedConditions as string[]) {
expect(html).not.toMatch(condition)
}
},
)
})
describe('misc Liquid', () => {
test('links with liquid from data', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/links-with-liquid')
// The URL comes from variables.product.pricing_url
const url = getDataByLanguage('variables.product.pricing_url', 'en')
if (!url) throw new Error('variable could not be found')
const links = $(`#article-contents a[href="${url}"]`)
expect(links.length).toBe(2)
const texts = links
.map((i: number, element: any) => {
return $(element).text()
})
.get()
expect(texts[0]).toBe(url)
expect(texts[1]).toBe('Pricing')
})
test('page with tool Liquid tag followed by Markdown', async () => {
// This test tests Markdown being correctly rendered when the
// Markdown directly follows a tool tag like `{% linux %}...{% endlinux %}`.
// The next line immediately after the `{% endlinux %}` should not
// leave the Markdown unrendered
const $: cheerio.Root = await getDOM('/get-started/liquid/tool-platform-switcher')
const innerHTML = $('#article-contents').html()
expect(innerHTML).not.toMatch('On *this* line is `Markdown` too.')
expect(innerHTML).toMatch(' On this line is Markdown too. ')
})
})
describe('data tag', () => {
test('injects data reusables with the right whitespace', async () => {
const $: cheerio.Root = await getDOM('/get-started/liquid/data')
// This proves that the two injected reusables tables work.
// CommonMark is finicky if the indentation isn't perfect, so
// if you don't get exactly 2 tables, something is wrong, and if it's
// wrong it's most likely because of the leading whitespaces.
expect($('#article-contents table').length).toBe(2)
// To truly understand this test, you have to see
// http://localhost:4000/en/get-started/liquid/data to understand it.
// The page uses `{% data ... %}` within the bodies of bullet points.
// If the whitespace isn't correct and working, the bullet points
// would get confused and think the bullet point "body" is a new
// bullet point on its own.
expect($('#article-contents ol').length).toBe(3)
expect($('#article-contents ol li').length).toBe(2 + 1 + 2)
// In the very first bullet point we inject something that multiple
// linebreaks in it. The source looks like this:
//
// 1. Bullet point
//
// {% data reusables.injectables.multiple_numbers %}
//
// (The code comment itself here has 3 spaces of manual indentation)
// What's important is that all the expected lines of that reusables
// stick inside this `ul li` block.
const liText = $('#article-contents ol li').first().text()
expect(liText).toMatch(/Bullet point\nOne\nTwo\nThree\nFour/)
// The code block uses `{% data ... %}` and it should be indented
// so that it aligns perfectly with the code block itself.
// One of the injected data reusables contains multiple lines.
// It's important that each line from that starts at the far
// left. No more or less whitespace.
const codeBlock = $('#article-contents li pre').text()
expect(codeBlock).toMatch(/^One\n/)
expect(codeBlock).toMatch(/^One\nTwo\n/)
expect(codeBlock).toMatch(/^One\nTwo\nThree\n/)
// The code block also a reusables that is just one line.
expect(codeBlock).toMatch(/One Two Three Four\n/)
// On its own, if you look at
// src/fixtures/fixtures/data/reusables/injectables/paragraphs.md, you'll
// see each line is NOT prefixed with whitespace indentation.
// But because `{% data reusables.injectables.paragraphs %}` is
// inserted with some indentation, that's replicated on every line.
const li = $('#article-contents li')
.filter((_: number, element: any) => {
return $(element).text().trim().startsWith('Point 1')
})
.eq(0)
// You can't really test the exact whitespace with cheerio,
// of the original HTML, but it doesn't actually matter. What
// matters is that within the bullet point, that starts with "Point 1",
// it *contains* all the paragraphs
// from src/fixtures/fixtures/data/reusables/injectables/paragraphs.md.
expect(li.text()).toMatch(/Paragraph one/)
expect(li.text()).toMatch(/Paragraph two/)
expect(li.text()).toMatch(/Paragraph three/)
})
})
|