aboutsummaryrefslogtreecommitdiff
path: root/packages/integrations/mdx/test/mdx-plugins.test.js
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/mdx/test/mdx-plugins.test.js')
-rw-r--r--packages/integrations/mdx/test/mdx-plugins.test.js315
1 files changed, 315 insertions, 0 deletions
diff --git a/packages/integrations/mdx/test/mdx-plugins.test.js b/packages/integrations/mdx/test/mdx-plugins.test.js
new file mode 100644
index 000000000..68ce1e22e
--- /dev/null
+++ b/packages/integrations/mdx/test/mdx-plugins.test.js
@@ -0,0 +1,315 @@
+import mdx from '@astrojs/mdx';
+
+import * as assert from 'node:assert/strict';
+import { before, describe, it } from 'node:test';
+import { visit as estreeVisit } from 'estree-util-visit';
+import { parseHTML } from 'linkedom';
+import remarkToc from 'remark-toc';
+import { loadFixture } from '../../../astro/test/test-utils.js';
+
+const FIXTURE_ROOT = new URL('./fixtures/mdx-plugins/', import.meta.url);
+const FILE = '/with-plugins/index.html';
+
+describe('MDX plugins', () => {
+ it('supports custom remark plugins - TOC', async () => {
+ const fixture = await buildFixture({
+ integrations: [
+ mdx({
+ remarkPlugins: [remarkToc],
+ }),
+ ],
+ });
+
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ assert.notEqual(selectTocLink(document), null);
+ });
+
+ it('Applies GFM by default', async () => {
+ const fixture = await buildFixture({
+ integrations: [mdx()],
+ });
+
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ assert.notEqual(selectGfmLink(document), null);
+ });
+
+ it('Applies SmartyPants by default', async () => {
+ const fixture = await buildFixture({
+ integrations: [mdx()],
+ });
+
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ const quote = selectSmartypantsQuote(document);
+ assert.notEqual(quote, null);
+ assert.equal(quote.textContent.includes('“Smartypants” is — awesome'), true);
+ });
+
+ it('supports custom rehype plugins', async () => {
+ const fixture = await buildFixture({
+ integrations: [
+ mdx({
+ rehypePlugins: [rehypeExamplePlugin],
+ }),
+ ],
+ });
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ assert.notEqual(selectRehypeExample(document), null);
+ });
+
+ it('supports custom rehype plugins from integrations', async () => {
+ const fixture = await buildFixture({
+ integrations: [
+ mdx(),
+ {
+ name: 'test',
+ hooks: {
+ 'astro:config:setup': ({ updateConfig }) => {
+ updateConfig({
+ markdown: {
+ rehypePlugins: [rehypeExamplePlugin],
+ },
+ });
+ },
+ },
+ },
+ ],
+ });
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ assert.notEqual(selectRehypeExample(document), null);
+ });
+
+ it('supports custom rehype plugins with namespaced attributes', async () => {
+ const fixture = await buildFixture({
+ integrations: [
+ mdx({
+ rehypePlugins: [rehypeSvgPlugin],
+ }),
+ ],
+ });
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ assert.notEqual(selectRehypeSvg(document), null);
+ });
+
+ it('extends markdown config by default', async () => {
+ const fixture = await buildFixture({
+ markdown: {
+ remarkPlugins: [remarkExamplePlugin],
+ rehypePlugins: [rehypeExamplePlugin],
+ },
+ integrations: [mdx()],
+ });
+
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ assert.notEqual(selectRemarkExample(document), null);
+ assert.notEqual(selectRehypeExample(document), null);
+ });
+
+ it('ignores string-based plugins in markdown config', async () => {
+ const fixture = await buildFixture({
+ markdown: {
+ remarkPlugins: [['remark-toc', {}]],
+ },
+ integrations: [mdx()],
+ });
+
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ assert.equal(selectTocLink(document), null);
+ });
+
+ for (const extendMarkdownConfig of [true, false]) {
+ describe(`extendMarkdownConfig = ${extendMarkdownConfig}`, () => {
+ let fixture;
+ before(async () => {
+ fixture = await buildFixture({
+ markdown: {
+ remarkPlugins: [remarkToc],
+ gfm: false,
+ smartypants: false,
+ },
+ integrations: [
+ mdx({
+ extendMarkdownConfig,
+ remarkPlugins: [remarkExamplePlugin],
+ rehypePlugins: [rehypeExamplePlugin],
+ }),
+ ],
+ });
+ });
+
+ it('Handles MDX plugins', async () => {
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ assert.notEqual(selectRemarkExample(document, 'MDX remark plugins not applied.'), null);
+ assert.notEqual(selectRehypeExample(document, 'MDX rehype plugins not applied.'), null);
+ });
+
+ it('Handles Markdown plugins', async () => {
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ assert.equal(
+ selectTocLink(
+ document,
+ '`remarkToc` plugin applied unexpectedly. Should override Markdown config.',
+ ),
+ null,
+ );
+ });
+
+ it('Handles gfm', async () => {
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ if (extendMarkdownConfig === true) {
+ assert.equal(selectGfmLink(document), null, 'Does not respect `markdown.gfm` option.');
+ } else {
+ assert.notEqual(selectGfmLink(document), null, 'Respects `markdown.gfm` unexpectedly.');
+ }
+ });
+
+ it('Handles smartypants', async () => {
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ const quote = selectSmartypantsQuote(document);
+
+ if (extendMarkdownConfig === true) {
+ assert.equal(
+ quote.textContent.includes('"Smartypants" is -- awesome'),
+ true,
+ 'Does not respect `markdown.smartypants` option.',
+ );
+ } else {
+ assert.equal(
+ quote.textContent.includes('“Smartypants” is — awesome'),
+ true,
+ 'Respects `markdown.smartypants` unexpectedly.',
+ );
+ }
+ });
+ });
+ }
+
+ it('supports custom recma plugins', async () => {
+ const fixture = await buildFixture({
+ integrations: [
+ mdx({
+ recmaPlugins: [recmaExamplePlugin],
+ }),
+ ],
+ });
+
+ const html = await fixture.readFile(FILE);
+ const { document } = parseHTML(html);
+
+ assert.notEqual(selectRecmaExample(document), null);
+ });
+});
+
+async function buildFixture(config) {
+ const fixture = await loadFixture({
+ root: FIXTURE_ROOT,
+ ...config,
+ });
+ await fixture.build();
+ return fixture;
+}
+
+function remarkExamplePlugin() {
+ return (tree) => {
+ tree.children.push({
+ type: 'html',
+ value: '<div data-remark-plugin-works="true"></div>',
+ });
+ };
+}
+
+function rehypeExamplePlugin() {
+ return (tree) => {
+ tree.children.push({
+ type: 'element',
+ tagName: 'div',
+ properties: { 'data-rehype-plugin-works': 'true' },
+ });
+ };
+}
+
+function rehypeSvgPlugin() {
+ return (tree) => {
+ tree.children.push({
+ type: 'element',
+ tagName: 'svg',
+ properties: { xmlns: 'http://www.w3.org/2000/svg' },
+ children: [
+ {
+ type: 'element',
+ tagName: 'use',
+ properties: { xLinkHref: '#icon' },
+ },
+ ],
+ });
+ };
+}
+
+function recmaExamplePlugin() {
+ return (tree) => {
+ estreeVisit(tree, (node) => {
+ if (
+ node.type === 'VariableDeclarator' &&
+ node.id.name === 'recmaPluginWorking' &&
+ node.init?.type === 'Literal'
+ ) {
+ node.init = {
+ ...(node.init ?? {}),
+ value: true,
+ raw: 'true',
+ };
+ }
+ });
+ };
+}
+
+function selectTocLink(document) {
+ return document.querySelector('ul a[href="#section-1"]');
+}
+
+function selectGfmLink(document) {
+ return document.querySelector('a[href="https://handle-me-gfm.com"]');
+}
+
+function selectSmartypantsQuote(document) {
+ return document.querySelector('blockquote');
+}
+
+function selectRemarkExample(document) {
+ return document.querySelector('div[data-remark-plugin-works]');
+}
+
+function selectRehypeExample(document) {
+ return document.querySelector('div[data-rehype-plugin-works]');
+}
+
+function selectRehypeSvg(document) {
+ return document.querySelector('svg > use[xlink\\:href]');
+}
+
+function selectRecmaExample(document) {
+ return document.querySelector('div[data-recma-plugin-works]');
+}