summaryrefslogtreecommitdiff
path: root/packages/integrations/mdx/test
diff options
context:
space:
mode:
authorGravatar Ben Holmes <hey@bholmes.dev> 2022-08-01 16:23:56 -0500
committerGravatar GitHub <noreply@github.com> 2022-08-01 17:23:56 -0400
commit40ef43a59b08a1a8fbcd9f4a53745a9636a4fbb9 (patch)
tree8de04dac9061ee3febc6daea482e34ec08f9295a /packages/integrations/mdx/test
parentf62f05f181502dba1d8e705b6c33e6cdcca7340a (diff)
downloadastro-40ef43a59b08a1a8fbcd9f4a53745a9636a4fbb9.tar.gz
astro-40ef43a59b08a1a8fbcd9f4a53745a9636a4fbb9.tar.zst
astro-40ef43a59b08a1a8fbcd9f4a53745a9636a4fbb9.zip
[MDX] Add `getHeadings` + generate anchor links (#4095)
* deps: mdx github-slugger * feat: add getHeadings via rehype plugin * chore: stray console.log * test: getHeadings w/ & w/0 JSX expressions * docs: add generated exports * refactor: pass headings using vfile.data * deps: vfile * test: heading anchor IDs * docs: add collect-headings to default rehype plugins * chore: changeset * deps: estree-util-value-to-estree * refactor: inject getHeadings export the right way! * deps: switch to acorn * refactor: just use acorn * docs: `getHeadings` info structuring Co-authored-by: Chris Swithinbank <swithinbank@gmail.com> * docs: clarify `url` example Co-authored-by: Chris Swithinbank <swithinbank@gmail.com> * fix: move slugger inside plugin call * refactor: cleanup code reassignment * chore: lint * deps: mdast-util-mdx, test utils * refactor: add jsToTreeNode util * feat: expose utils for lib authors * test: rehype plugins w/ and w/o extends * test: fixture * refactor: remove utils from package exports Co-authored-by: Chris Swithinbank <swithinbank@gmail.com>
Diffstat (limited to 'packages/integrations/mdx/test')
-rw-r--r--packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/pages.json.js11
-rw-r--r--packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/test-with-jsx-expressions.mdx8
-rw-r--r--packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/test.mdx9
-rw-r--r--packages/integrations/mdx/test/fixtures/mdx-rehype-plugins/src/pages/reading-time.json.js7
-rw-r--r--packages/integrations/mdx/test/fixtures/mdx-rehype-plugins/src/pages/space-ipsum.mdx25
-rw-r--r--packages/integrations/mdx/test/mdx-get-headings.test.js56
-rw-r--r--packages/integrations/mdx/test/mdx-rehype-plugins.test.js81
7 files changed, 197 insertions, 0 deletions
diff --git a/packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/pages.json.js b/packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/pages.json.js
new file mode 100644
index 000000000..940e5c141
--- /dev/null
+++ b/packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/pages.json.js
@@ -0,0 +1,11 @@
+export async function get() {
+ const mdxPages = await import.meta.glob('./*.mdx', { eager: true });
+
+ return {
+ body: JSON.stringify({
+ headingsByPage: Object.fromEntries(
+ Object.entries(mdxPages ?? {}).map(([k, v]) => [k, v?.getHeadings()])
+ ),
+ }),
+ }
+}
diff --git a/packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/test-with-jsx-expressions.mdx b/packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/test-with-jsx-expressions.mdx
new file mode 100644
index 000000000..2ec7b1686
--- /dev/null
+++ b/packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/test-with-jsx-expressions.mdx
@@ -0,0 +1,8 @@
+export const h2Title = "Section 1"
+export const h3Title = "Subsection 1"
+
+# Heading test with JSX expressions
+
+## {h2Title}
+
+### {h3Title}
diff --git a/packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/test.mdx b/packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/test.mdx
new file mode 100644
index 000000000..2bf3677cf
--- /dev/null
+++ b/packages/integrations/mdx/test/fixtures/mdx-get-headings/src/pages/test.mdx
@@ -0,0 +1,9 @@
+# Heading test
+
+## Section 1
+
+### Subsection 1
+
+### Subsection 2
+
+## Section 2
diff --git a/packages/integrations/mdx/test/fixtures/mdx-rehype-plugins/src/pages/reading-time.json.js b/packages/integrations/mdx/test/fixtures/mdx-rehype-plugins/src/pages/reading-time.json.js
new file mode 100644
index 000000000..60f7cb1be
--- /dev/null
+++ b/packages/integrations/mdx/test/fixtures/mdx-rehype-plugins/src/pages/reading-time.json.js
@@ -0,0 +1,7 @@
+import { readingTime } from './space-ipsum.mdx';
+
+export function get() {
+ return {
+ body: JSON.stringify(readingTime),
+ }
+}
diff --git a/packages/integrations/mdx/test/fixtures/mdx-rehype-plugins/src/pages/space-ipsum.mdx b/packages/integrations/mdx/test/fixtures/mdx-rehype-plugins/src/pages/space-ipsum.mdx
new file mode 100644
index 000000000..ad8ae7daa
--- /dev/null
+++ b/packages/integrations/mdx/test/fixtures/mdx-rehype-plugins/src/pages/space-ipsum.mdx
@@ -0,0 +1,25 @@
+# Space ipsum
+
+For those who have seen the Earth from space, and for the hundreds and perhaps thousands more who will, the experience most certainly changes your perspective. The things that we share in our world are far more valuable than those which divide us.
+
+It suddenly struck me that that tiny pea, pretty and blue, was the Earth. I put up my thumb and shut one eye, and my thumb blotted out the planet Earth. I didn’t feel like a giant. I felt very, very small.
+
+Science has not yet mastered prophecy. We predict too much for the next year and yet far too little for the next 10.
+
+## Section 2
+
+We choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard, because that goal will serve to organize and measure the best of our energies and skills, because that challenge is one that we are willing to accept, one we are unwilling to postpone, and one which we intend to win.
+
+There can be no thought of finishing for ‘aiming for the stars.’ Both figuratively and literally, it is a task to occupy the generations. And no matter how much progress one makes, there is always the thrill of just beginning.
+
+As I stand out here in the wonders of the unknown at Hadley, I sort of realize there’s a fundamental truth to our nature, Man must explore . . . and this is exploration at its greatest.
+
+## Section 3
+
+Never in all their history have men been able truly to conceive of the world as one: a single sphere, a globe, having the qualities of a globe, a round earth in which all the directions eventually meet, in which there is no center because every point, or none, is center — an equal earth which all men occupy as equals. The airman’s earth, if free men make it, will be truly round: a globe in practice, not in theory.
+
+To be the first to enter the cosmos, to engage, single-handed, in an unprecedented duel with nature—could one dream of anything more?
+
+There can be no thought of finishing for ‘aiming for the stars.’ Both figuratively and literally, it is a task to occupy the generations. And no matter how much progress one makes, there is always the thrill of just beginning.
+
+We are all connected; To each other, biologically. To the earth, chemically. To the rest of the universe atomically.
diff --git a/packages/integrations/mdx/test/mdx-get-headings.test.js b/packages/integrations/mdx/test/mdx-get-headings.test.js
new file mode 100644
index 000000000..247ffedb4
--- /dev/null
+++ b/packages/integrations/mdx/test/mdx-get-headings.test.js
@@ -0,0 +1,56 @@
+import mdx from '@astrojs/mdx';
+
+import { expect } from 'chai';
+import { parseHTML } from 'linkedom';
+import { loadFixture } from '../../../astro/test/test-utils.js';
+
+describe('MDX getHeadings', () => {
+ let fixture;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: new URL('./fixtures/mdx-get-headings/', import.meta.url),
+ integrations: [mdx()],
+ });
+
+ await fixture.build();
+ });
+
+ it('adds anchor IDs to headings', async () => {
+ const html = await fixture.readFile('/test/index.html');
+ const { document } = parseHTML(html);
+
+ const h2Ids = document.querySelectorAll('h2').map(el => el?.id);
+ const h3Ids = document.querySelectorAll('h3').map(el => el?.id);
+ expect(document.querySelector('h1').id).to.equal('heading-test');
+ expect(h2Ids).to.contain('section-1');
+ expect(h2Ids).to.contain('section-2');
+ expect(h3Ids).to.contain('subsection-1');
+ expect(h3Ids).to.contain('subsection-2');
+ });
+
+ it('generates correct getHeadings() export', async () => {
+ const { headingsByPage } = JSON.parse(await fixture.readFile('/pages.json'));
+ // TODO: make this a snapshot test :)
+ expect(JSON.stringify(headingsByPage['./test.mdx'])).to.equal(JSON.stringify([
+ { depth: 1, slug: 'heading-test', text: 'Heading test' },
+ { depth: 2, slug: 'section-1', text: 'Section 1' },
+ { depth: 3, slug: 'subsection-1', text: 'Subsection 1' },
+ { depth: 3, slug: 'subsection-2', text: 'Subsection 2' },
+ { depth: 2, slug: 'section-2', text: 'Section 2' }
+ ]));
+ });
+
+ it('generates correct getHeadings() export for JSX expressions', async () => {
+ const { headingsByPage } = JSON.parse(await fixture.readFile('/pages.json'));
+ expect(JSON.stringify(headingsByPage['./test-with-jsx-expressions.mdx'])).to.equal(JSON.stringify([
+ {
+ depth: 1,
+ slug: 'heading-test-with-jsx-expressions',
+ text: 'Heading test with JSX expressions'
+ },
+ { depth: 2, slug: 'h2title', text: 'h2Title' },
+ { depth: 3, slug: 'h3title', text: 'h3Title' }
+ ]));
+ });
+});
diff --git a/packages/integrations/mdx/test/mdx-rehype-plugins.test.js b/packages/integrations/mdx/test/mdx-rehype-plugins.test.js
new file mode 100644
index 000000000..bb0c6eb63
--- /dev/null
+++ b/packages/integrations/mdx/test/mdx-rehype-plugins.test.js
@@ -0,0 +1,81 @@
+import mdx from '@astrojs/mdx';
+import { jsToTreeNode } from '../dist/utils.js';
+
+import { expect } from 'chai';
+import { parseHTML } from 'linkedom';
+import getReadingTime from 'reading-time';
+import { toString } from 'mdast-util-to-string';
+
+import { loadFixture } from '../../../astro/test/test-utils.js';
+
+export function rehypeReadingTime() {
+ return function (tree) {
+ const readingTime = getReadingTime(toString(tree))
+ tree.children.unshift(
+ jsToTreeNode(`export const readingTime = ${JSON.stringify(readingTime)}`)
+ )
+ };
+}
+
+const FIXTURE_ROOT = new URL('./fixtures/mdx-rehype-plugins/', import.meta.url);
+
+describe('MDX rehype plugins', () => {
+ describe('without "extends"', () => {
+ let fixture;
+ before(async () => {
+ fixture = await loadFixture({
+ root: FIXTURE_ROOT,
+ integrations: [
+ mdx({
+ rehypePlugins: [rehypeReadingTime],
+ }),
+ ],
+ });
+ await fixture.build();
+ });
+
+ it('removes default getHeadings', async () => {
+ const html = await fixture.readFile('/space-ipsum/index.html');
+ const { document } = parseHTML(html);
+
+ const headings = [...document.querySelectorAll('h1, h2')];
+ expect(headings.length).to.be.greaterThan(0);
+ for (const heading of headings) {
+ expect(heading.id).to.be.empty;
+ }
+ });
+
+ it('supports custom rehype plugins - reading time', async () => {
+ const readingTime = JSON.parse(await fixture.readFile('/reading-time.json'));
+
+ expect(readingTime).to.not.be.null;
+ expect(readingTime.text).to.match(/^\d+ min read/);
+ });
+ });
+
+ describe('with "extends"', () => {
+ let fixture;
+ before(async () => {
+ fixture = await loadFixture({
+ root: FIXTURE_ROOT,
+ integrations: [
+ mdx({
+ rehypePlugins: { extends: [rehypeReadingTime] },
+ }),
+ ],
+ });
+ await fixture.build();
+ });
+
+ it('preserves default getHeadings', async () => {
+ const html = await fixture.readFile('/space-ipsum/index.html');
+ const { document } = parseHTML(html);
+
+ const headings = [...document.querySelectorAll('h1, h2')];
+ expect(headings.length).to.be.greaterThan(0);
+ for (const heading of headings) {
+ expect(heading.id).to.not.be.empty;
+ }
+ });
+ });
+});