summaryrefslogtreecommitdiff
path: root/packages/astro/test/astro-markdown.test.js
diff options
context:
space:
mode:
authorGravatar Ben Holmes <hey@bholmes.dev> 2022-08-05 14:43:50 -0500
committerGravatar GitHub <noreply@github.com> 2022-08-05 15:43:50 -0400
commit471c6f784e21399676c8b2002665ffdf83a1c59e (patch)
treeb39134eb9b53b3a9ef9b987286061215a2af3531 /packages/astro/test/astro-markdown.test.js
parent838eb3e5cc523d20aa5fb6b136ed5f6701568b1d (diff)
downloadastro-471c6f784e21399676c8b2002665ffdf83a1c59e.tar.gz
astro-471c6f784e21399676c8b2002665ffdf83a1c59e.tar.zst
astro-471c6f784e21399676c8b2002665ffdf83a1c59e.zip
[markdown] Harder, better, faster, stronger `vite-plugin-markdown` (#4137)
* refactor: vite-plugin-md -> vite-plugin-md-legacy * wip: add vite-plugin-md * feat: always apply jsx renderer * fix: markHTMLString on VNode result * feat: apply new vite-plugin-markdown! * fix: add meta export to md * fix: remove needless $$metadata export * fix: toggle to legacy plugin on flag * fix: pass fileId to renderMarkdown * test: raw and compiled content on plain md * fix: escape vite env refs * refactor: astro-md -> legacy-astro-flavored-md, astro-md-mode -> astro-markdown * fix: import.meta.env refs with tests * fix: add pkg.json to clientAddress * fix: prefer JSX integration over Astro runtime * Revert "fix: prefer JSX integration over Astro runtime" This reverts commit 3e5fa49344be9c857393da9af095faab152e92e1. * fix: remove .mdx check on importSource * chore: changeset * chore: remove TODO * fix: add back getHeadings * fix: add pkg.json to astro-head fixture * fix: default to Astro renderer for MDX and MD * feat: add "headings" and "frontmatter" to md layouts * refactor: remove legacy flag conditionals from legacy plugin * fix: add back MDX warning when legacy is off * test: getHeadings() glob * fix: add error on "astro.headings" access * feat: update docs example astro.headings => headings * refactor: readFile as string w/ utf-8 * chore: remove astro metadata TODO * refactor: stringify HTML once * fix: add pkg.json to glob-pages-css
Diffstat (limited to '')
-rw-r--r--packages/astro/test/astro-markdown.test.js239
1 files changed, 85 insertions, 154 deletions
diff --git a/packages/astro/test/astro-markdown.test.js b/packages/astro/test/astro-markdown.test.js
index 92b78121a..eb1b43bcc 100644
--- a/packages/astro/test/astro-markdown.test.js
+++ b/packages/astro/test/astro-markdown.test.js
@@ -2,199 +2,130 @@ import { expect } from 'chai';
import * as cheerio from 'cheerio';
import { loadFixture, fixLineEndings } from './test-utils.js';
+const FIXTURE_ROOT = './fixtures/astro-markdown/';
+
describe('Astro Markdown', () => {
let fixture;
before(async () => {
fixture = await loadFixture({
- root: './fixtures/astro-markdown/',
+ root: FIXTURE_ROOT,
});
await fixture.build();
});
- it('Can parse JSX expressions in markdown pages', async () => {
+ it('Leaves JSX expressions unprocessed', async () => {
const html = await fixture.readFile('/jsx-expressions/index.html');
const $ = cheerio.load(html);
- expect($('h2').html()).to.equal('Blog Post with JSX expressions');
-
- expect(html).to.contain('JSX at the start of the line!');
- for (let listItem of ['test-1', 'test-2', 'test-3']) {
- expect($(`#${listItem}`).html()).to.equal(`${listItem}`);
- }
- });
-
- it('Can handle slugs with JSX expressions in markdown pages', async () => {
- const html = await fixture.readFile('/slug/index.html');
- const $ = cheerio.load(html);
-
- expect($('h1').attr('id')).to.equal('my-blog-post');
- });
-
- it('Can handle code elements without extra spacing', async () => {
- const html = await fixture.readFile('/code-element/index.html');
- const $ = cheerio.load(html);
-
- $('code').each((_, el) => {
- expect($(el).html()).to.equal($(el).html().trim());
- });
- });
-
- it('Can handle namespaced components in markdown', async () => {
- const html = await fixture.readFile('/namespace/index.html');
- const $ = cheerio.load(html);
-
- expect($('h1').text()).to.equal('Hello Namespace!');
- expect($('button').length).to.equal(1);
- });
-
- it('Correctly handles component children in markdown pages (#3319)', async () => {
- const html = await fixture.readFile('/children/index.html');
-
- expect(html).not.to.contain('<p></p>');
- });
-
- it('Can handle HTML comments in markdown pages', async () => {
- const html = await fixture.readFile('/comment/index.html');
- const $ = cheerio.load(html);
-
- expect($('h1').text()).to.equal('It works!');
+ expect($('h2').html()).to.equal('{frontmatter.title}');
});
- it('Prevents `*/` sequences from breaking HTML comments (#3476)', async () => {
- const html = await fixture.readFile('/comment-with-js/index.html');
- const $ = cheerio.load(html);
+ it('Leaves JSX components un-transformed', async () => {
+ const html = await fixture.readFile('/components/index.html');
- expect($('h1').text()).to.equal('It still works!');
- });
-
- it('Can handle HTML comments in inline code', async () => {
- const html = await fixture.readFile('/comment-with-js/index.html');
- const $ = cheerio.load(html);
-
- expect($('p code').text()).to.equal('<!-- HTML comments in code -->');
- });
-
- it('Can handle HTML comments in code fences', async () => {
- const html = await fixture.readFile('/comment-with-js/index.html');
- const $ = cheerio.load(html);
-
- expect($('pre > code').text()).to.equal('<!-- HTML comments in code fence -->');
- });
-
- // https://github.com/withastro/astro/issues/3254
- it('Can handle scripts in markdown pages', async () => {
- const html = await fixture.readFile('/script/index.html');
- expect(html).not.to.match(new RegExp('/src/scripts/test.js'));
- });
-
- it('Empty code blocks do not fail', async () => {
- const html = await fixture.readFile('/empty-code/index.html');
- const $ = cheerio.load(html);
-
- // test 1: There is not a `<code>` in the codeblock
- expect($('pre')[0].children).to.have.lengthOf(1);
-
- // test 2: The empty `<pre>` failed to render
- expect($('pre')[1].children).to.have.lengthOf(0);
- });
-
- it('Can render markdown with --- for horizontal rule', async () => {
- const html = await fixture.readFile('/dash/index.html');
- expect(!!html).to.equal(true);
+ expect(html).to.include('<counter client:load="" count="{0}">');
});
+
it('Exposes raw markdown content', async () => {
const { raw } = JSON.parse(await fixture.readFile('/raw-content.json'));
- expect(fixLineEndings(raw)).to.equal(
- `\n## With components\n\n### Non-hydrated\n\n<Hello name="Astro Naut" />\n\n### Hydrated\n\n<Counter client:load />\n<SvelteButton client:load />\n`
+ expect(fixLineEndings(raw).trim()).to.equal(
+ `# Basic page\n\nLets make sure raw and compiled content look right!`
);
});
- it('Exposes HTML parser for raw markdown content', async () => {
+ it('Exposes compiled HTML content', async () => {
const { compiled } = JSON.parse(await fixture.readFile('/raw-content.json'));
- expect(fixLineEndings(compiled)).to.equal(
- `<h2 id="with-components">With components</h2>\n<h3 id="non-hydrated">Non-hydrated</h3>\n<Hello name="Astro Naut" />\n<h3 id="hydrated">Hydrated</h3>\n<Counter client:load />\n<SvelteButton client:load />`
+ expect(fixLineEndings(compiled).trim()).to.equal(
+ `<h1 id="basic-page">Basic page</h1>\n<p>Lets make sure raw and compiled content look right!</p>`
);
});
- it('Allows referencing Vite env var names in markdown (#3412)', async () => {
- const html = await fixture.readFile('/vite-env-vars/index.html');
- const $ = cheerio.load(html);
+ describe('syntax highlighting', async () => {
+ it('handles Shiki', async () => {
+ const html = await fixture.readFile('/code-in-md/index.html');
+ const $ = cheerio.load(html);
- // test 1: referencing an existing var name
- expect($('code').eq(0).text()).to.equal('import.meta.env.SITE');
- expect($('li').eq(0).text()).to.equal('import.meta.env.SITE');
- expect($('code').eq(3).text()).to.contain('site: import.meta.env.SITE');
- expect($('blockquote').text()).to.contain('import.meta.env.SITE');
-
- // test 2: referencing a non-existing var name
- expect($('code').eq(1).text()).to.equal('import.meta.env.TITLE');
- expect($('li').eq(1).text()).to.equal('import.meta.env.TITLE');
- expect($('code').eq(3).text()).to.contain('title: import.meta.env.TITLE');
- expect($('blockquote').text()).to.contain('import.meta.env.TITLE');
-
- // test 3: referencing `import.meta.env` itself (without any var name)
- expect($('code').eq(2).text()).to.equal('import.meta.env');
- expect($('li').eq(2).text()).to.equal('import.meta.env');
- expect($('code').eq(3).text()).to.contain('// Use Vite env vars with import.meta.env');
- expect($('blockquote').text()).to.match(/import\.meta\.env\s*$/);
- });
+ expect($('pre.astro-code').length).to.not.equal(0);
+ });
- it('Escapes HTML tags in code blocks', async () => {
- const html = await fixture.readFile('/code-in-md/index.html');
- const $ = cheerio.load(html);
+ it('handles Prism', async () => {
+ const prismFixture = await loadFixture({
+ root: FIXTURE_ROOT,
+ markdown: {
+ syntaxHighlight: 'prism',
+ },
+ });
+ await prismFixture.build();
- expect($('code').eq(0).html()).to.equal('&lt;script&gt;');
- expect($('blockquote').length).to.equal(1);
- expect($('code').eq(1).html()).to.equal('&lt;/script&gt;');
- expect($('pre').html()).to.contain('&gt;This should also work without any problems.&lt;');
- });
+ const html = await prismFixture.readFile('/code-in-md/index.html');
+ const $ = cheerio.load(html);
- it('Allows defining slot contents in component children', async () => {
- const html = await fixture.readFile('/slots/index.html');
- const $ = cheerio.load(html);
+ expect($('pre.language-html').length).to.not.equal(0);
+ });
+ });
- const slots = $('article').eq(0);
- expect(slots.find('> .fragmentSlot > div').text()).to.contain('1:');
- expect(slots.find('> .fragmentSlot > div + p').text()).to.contain('2:');
- expect(slots.find('> .pSlot > p[title="hello"]').text()).to.contain('3:');
- expect(slots.find('> .defaultSlot').html()).to.match(
- new RegExp(
- `<div>4: Div in default slot</div>` +
- // Optional extra paragraph due to the line breaks between components
- `(<p></p>)?` +
- `<p>5: Paragraph in fragment in default slot</p>` +
- // Optional whitespace due to the line breaks between components
- `[\s\n]*` +
- `6: Regular text in default slot`
- )
- );
- const nestedSlots = $('article').eq(1);
- expect(nestedSlots.find('> .fragmentSlot').html()).to.contain('1:');
- expect(nestedSlots.find('> .pSlot > p').text()).to.contain('2:');
- expect(nestedSlots.find('> .defaultSlot > article').text().replace(/\s+/g, ' ')).to.equal(
- `
- 3: nested fragmentSlot
- 4: nested pSlot
- 5: nested text in default slot
- `.replace(/\s+/g, ' ')
- );
+ it('Passes frontmatter to layout via "content" and "frontmatter" props', async () => {
+ const html = await fixture.readFile('/with-layout/index.html');
+ const $ = cheerio.load(html);
- expect($('article').eq(3).text().replace(/[^❌]/g, '')).to.equal('❌❌❌');
+ const contentTitle = $('[data-content-title]');
+ const frontmatterTitle = $('[data-frontmatter-title]');
- expect($('article').eq(4).text().replace(/[^❌]/g, '')).to.equal('❌❌❌');
+ expect(contentTitle.text()).to.equal('With layout');
+ expect(frontmatterTitle.text()).to.equal('With layout');
});
- it('Generate the right props for the layout', async () => {
- const html = await fixture.readFile('/layout-props/index.html');
+ it('Passes headings to layout via "headings" prop', async () => {
+ const html = await fixture.readFile('/with-layout/index.html');
const $ = cheerio.load(html);
- expect($('#title').text()).to.equal('Hello world!');
- expect($('#url').text()).to.equal('/layout-props');
- expect($('#file').text()).to.match(/.*\/layout-props.md$/);
+ const headingSlugs = [...$('body').find('[data-headings] > li')].map(
+ (el) => $(el).text()
+ );
+
+ expect(headingSlugs.length).to.be.greaterThan(0);
+ expect(headingSlugs).to.contain('section-1');
+ expect(headingSlugs).to.contain('section-2');
+ });
+
+ it('Exposes getHeadings() on glob imports', async () => {
+ const { headings } = JSON.parse(await fixture.readFile('/headings-glob.json'));
+
+ const headingSlugs = headings.map(heading => heading?.slug);
+
+ expect(headingSlugs).to.contain('section-1');
+ expect(headingSlugs).to.contain('section-2');
+ });
+
+ describe('Vite env vars (#3412)', () => {
+ it('Allows referencing import.meta.env in content', async () => {
+ const html = await fixture.readFile('/vite-env-vars/index.html');
+ const $ = cheerio.load(html);
+
+ // test 1: referencing an existing var name
+ expect($('code').eq(0).text()).to.equal('import.meta.env.SITE');
+ expect($('li').eq(0).text()).to.equal('import.meta.env.SITE');
+ expect($('code').eq(3).text()).to.contain('site: import.meta.env.SITE');
+
+ // // test 2: referencing a non-existing var name
+ expect($('code').eq(1).text()).to.equal('import.meta.env.TITLE');
+ expect($('li').eq(1).text()).to.equal('import.meta.env.TITLE');
+ expect($('code').eq(3).text()).to.contain('title: import.meta.env.TITLE');
+
+ // // test 3: referencing `import.meta.env` itself (without any var name)
+ expect($('code').eq(2).text()).to.equal('import.meta.env');
+ expect($('li').eq(2).text()).to.equal('import.meta.env');
+ expect($('code').eq(3).text()).to.contain('// Use Vite env vars with import.meta.env');
+ });
+ it('Allows referencing import.meta.env in frontmatter', async () => {
+ const { title = '' } = JSON.parse(await fixture.readFile('/vite-env-vars-glob.json'));
+ expect(title).to.contain('import.meta.env.SITE');
+ expect(title).to.contain('import.meta.env.TITLE');
+ });
});
});