import cheerio from 'cheerio' import renderContent from '../../lib/render-content/renderContent.js' import { EOL } from 'os' // Use platform-specific line endings for realistic tests when templates have // been loaded from disk const nl = (str) => str.replace(/\n/g, EOL) describe('renderContent', () => { test('takes a template and a context and returns a string (async)', async () => { const template = 'my favorite color is {{ color }}.' const context = { color: 'orange' } const output = await renderContent(template, context) expect(output, '

my favorite color is orange.

') }) test('preserves content within {% raw %} tags', async () => { const template = nl('For example: {% raw %}{% include cool_header.html %}{% endraw %}.') const expected = '

For example: {% include cool_header.html %}.

' const output = await renderContent(template) expect(output).toBe(expected) }) test('removes extra newlines to prevent lists from breaking', async () => { const template = nl(` 1. item one 1. item two 1. item three`) const html = await renderContent(template) const $ = cheerio.load(html, { xmlMode: true }) expect($('ol').length).toBe(1) expect($('ol > li').length).toBe(3) }) test('removes extra newlines from lists of links', async () => { const template = nl(`- item - item`) const html = await renderContent(template) const $ = cheerio.load(html, { xmlMode: true }) expect($('ul p').length, 0) }) test('renders text only', async () => { const template = 'my favorite color is {{ color }}.' const context = { color: 'orange' } const output = await renderContent(template, context, { textOnly: true }) expect(output, 'my favorite color is orange.') }) test('throws on rendering errors', async () => { const template = 1 const context = {} let err try { await renderContent(template, context) } catch (_err) { err = _err } expect(err).toBeTruthy() }) test('warns and throws on rendering errors when the file name is passed', async () => { const template = 1 const context = {} let err let warned = false const error = console.error console.error = (message) => { expect(message, 'renderContent failed on file: name') console.error = error warned = true } try { await renderContent(template, context, { filename: 'name' }) } catch (_err) { err = _err } expect(err).toBeTruthy() expect(warned).toBeTruthy() }) test('renders empty templates', async () => { const template = '' const context = {} const output = await renderContent(template, context) expect(output).toBe('') }) test('encodes entities', async () => { const template = '' const context = {} const output = await renderContent(template, context, { encodeEntities: true, }) expect(output).toBe('<p><beep></beep></p>') }) test('does not render newlines around links in tables', async () => { const template = nl(` | Keyboard shortcut | Description |-----------|------------ |g c | Go to the **Code** tab |g i | Go to the **Issues** tab. For more information, see "[About issues](/articles/about-issues)." `) const html = await renderContent(template) const $ = cheerio.load(html, { xmlMode: true }) expect( $.html().includes('"About issues."') ).toBeTruthy() }) test('does not render newlines around inline code in tables', async () => { const template = nl(` | Package manager | formats | | --- | --- | | Python | \`requirements.txt\`, \`pipfile.lock\` `) const html = await renderContent(template) const $ = cheerio.load(html, { xmlMode: true }) expect( $.html().includes('requirements.txt, pipfile.lock') ).toBeTruthy() }) test('does not render newlines around emphasis in code', async () => { const template = nl(` | Qualifier | Example | ------------- | ------------- | user:USERNAME | [**user:defunkt ubuntu**](https://github.com/search?q=user%3Adefunkt+ubuntu&type=Issues) matches issues with the word "ubuntu" from repositories owned by @defunkt. `) const html = await renderContent(template) const $ = cheerio.load(html, { xmlMode: true }) expect($.html().includes('user:USERNAME')).toBeTruthy() }) test('renders code blocks with # comments', async () => { const template = nl(` 1. This is a list item with code containing a comment: \`\`\`shell $ foo the bar # some comment here \`\`\` 1. This is another list item. `) const html = await renderContent(template) const $ = cheerio.load(html, { xmlMode: true }) expect($('ol').length).toBe(1) expect($.html().includes('# some comment here')).toBeTruthy() expect($.html().includes('

')).toBeFalsy() expect($.html().includes('')).toBeFalsy() }) test('renders headings at the right level', async () => { const template = nl(` # This is a level 1 ## This is a level 2 ### This is a level 3 #### This is a level 4 ##### This is a level 5 `) const html = await renderContent(template) const $ = cheerio.load(html, { xmlMode: true }) ;[1, 2, 3, 4, 5].forEach((level) => { expect( $(`h${level}#this-is-a-level-${level} a[href="#this-is-a-level-${level}"]`).length ).toBe(1) }) }) test('does syntax highlighting', async () => { let template = nl(` \`\`\`js const example = true \`\`\`\` `) let html = await renderContent(template) let $ = cheerio.load(html, { xmlMode: true }) expect($.html().includes('
')).toBeTruthy()
    expect($.html().includes('const')).toBeTruthy()

    template = nl(`
\`\`\`erb
<% @articles.each do |article| %>
\`\`\`\`
    `)
    html = await renderContent(template)
    $ = cheerio.load(html, { xmlMode: true })
    expect($.html().includes('
')).toBeTruthy()
    expect($.html().includes('@articles')).toBeTruthy()

    template = nl(`
\`\`\`http
POST / HTTP/2
\`\`\`\`
    `)
    html = await renderContent(template)
    $ = cheerio.load(html, { xmlMode: true })
    expect($.html().includes('
')).toBeTruthy()
    expect($.html().includes('POST')).toBeTruthy()

    template = nl(`
\`\`\`groovy
plugins {
  ...
  id 'maven-publish'
}
\`\`\`\`
    `)
    html = await renderContent(template)
    $ = cheerio.load(html, { xmlMode: true })
    expect($.html().includes('
')).toBeTruthy()
    expect(
      $.html().includes(''maven-publish'')
    ).toBeTruthy()

    template = nl(`
\`\`\`Dockerfile
FROM alpine:3.10
\`\`\`\`
    `)
    html = await renderContent(template)
    $ = cheerio.load(html, { xmlMode: true })
    expect($.html().includes('
')).toBeTruthy()
    expect($.html().includes('FROM')).toBeTruthy()

    template = nl(`
\`\`\`Powershell
$resourceGroupName = "octocat-testgroup"
\`\`\`\`
    `)
    html = await renderContent(template)
    $ = cheerio.load(html, { xmlMode: true })
    expect($.html().includes('
')).toBeTruthy()
    expect($.html().includes('$resourceGroupName')).toBeTruthy()
  })

  test('does not autoguess code block language', async () => {
    const template = nl(`
\`\`\`
some code
\`\`\`\
    `)
    const html = await renderContent(template)
    const $ = cheerio.load(html, { xmlMode: true })
    expect($.html().includes('
some code\n
')).toBeTruthy() }) test('renders a line break in a table', async () => { const content = `| Webhook event payload | Activity types | | --------------------- | -------------- | | [\`issues\`](/webhooks/event-payloads/#issues) | - \`opened\`
- \`edited\`
- \`other\` |` const file = await renderContent(content) expect(file).toBe( '
Webhook event payloadActivity types
issues- opened
- edited
- other
' ) }) test('renders a copy button for code blocks with {:copy} annotation', async () => { const template = nl(` \`\`\`js{:copy} some code \`\`\`\ `) const html = await renderContent(template) const $ = cheerio.load(html) const el = $('button.js-btn-copy') expect(el.data('clipboard-text')).toBe('some code') }) })