Skip to content

Commit

Permalink
Chore: Increase test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
sandypockets committed Dec 17, 2023
1 parent 372fe5f commit 8c1cafc
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 0 deletions.
46 changes: 46 additions & 0 deletions __tests__/addTableOfContents.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import addTableOfContents from '../src/plugins/addTableOfContents.js';

describe("addTableOfContents functionality", () => {
it('generates a table of contents from headings', () => {
const mockTree = {
type: 'root',
children: [
{ type: 'element', tagName: 'h1', properties: {}, children: [{ type: 'text', value: 'Heading 1' }] },
{ type: 'element', tagName: 'h2', properties: {}, children: [{ type: 'text', value: 'Heading 2' }] },
{ type: 'element', tagName: 'h3', properties: {}, children: [{ type: 'text', value: 'Heading 3' }] },
],
};

const tocNode = addTableOfContents(mockTree, false);
expect(tocNode).not.toBeNull();
expect(tocNode.tagName).toBe('ul');
expect(tocNode.children.length).toBe(3);
});

it('inserts the table of contents into the tree', () => {
const mockTree = {
type: 'root',
children: [
{ type: 'element', tagName: 'h1', properties: {}, children: [{ type: 'text', value: 'Heading 1' }] },
{ type: 'element', tagName: 'h2', properties: {}, children: [{ type: 'text', value: 'Heading 2' }] },
],
};

addTableOfContents(mockTree, true);
expect(mockTree.children[0].tagName).toBe('ul');
});

it('does not generate a table of contents for documents without headings', () => {
const mockTree = {
type: 'root',
children: [
{ type: 'element', tagName: 'p', properties: {}, children: [{ type: 'text', value: 'Paragraph text' }] },
],
};

const tocNode = addTableOfContents(mockTree, false);
expect(tocNode).not.toBeNull();
expect(tocNode.children.length).toBe(0);
});

})
73 changes: 73 additions & 0 deletions __tests__/buildExports.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

describe('Build Exports', () => {
it('should export processMarkdown for both CommonJS and ESM builds', async () => {
const cjsBuild = await import(join(__dirname, '../dist/index.cjs'));
const esmBuild = await import(join(__dirname, '../dist/index.esm.js'));

expect(cjsBuild).toBeDefined();
expect(typeof cjsBuild.processMarkdown).toBe('function');

expect(esmBuild).toBeDefined();
expect(typeof esmBuild.processMarkdown).toBe('function');
});

it('should export addHeadingIds for both CommonJS and ESM builds', async () => {
const cjsBuild = await import(join(__dirname, '../dist/index.cjs'));
const esmBuild = await import(join(__dirname, '../dist/index.esm.js'));

expect(cjsBuild).toBeDefined();
expect(typeof cjsBuild.addHeadingIds).toBe('function');

expect(esmBuild).toBeDefined();
expect(typeof esmBuild.addHeadingIds).toBe('function');
});

it('should export addTableOfContents for both CommonJS and ESM builds', async () => {
const cjsBuild = await import(join(__dirname, '../dist/index.cjs'));
const esmBuild = await import(join(__dirname, '../dist/index.esm.js'));

expect(cjsBuild).toBeDefined();
expect(typeof cjsBuild.addTableOfContents).toBe('function');

expect(esmBuild).toBeDefined();
expect(typeof esmBuild.addTableOfContents).toBe('function');
});

it('should export calculateReadingTime for both CommonJS and ESM builds', async () => {
const cjsBuild = await import(join(__dirname, '../dist/index.cjs'));
const esmBuild = await import(join(__dirname, '../dist/index.esm.js'));

expect(cjsBuild).toBeDefined();
expect(typeof cjsBuild.calculateReadingTime).toBe('function');

expect(esmBuild).toBeDefined();
expect(typeof esmBuild.calculateReadingTime).toBe('function');
});

it('should export embed for both CommonJS and ESM builds', async () => {
const cjsBuild = await import(join(__dirname, '../dist/index.cjs'));
const esmBuild = await import(join(__dirname, '../dist/index.esm.js'));

expect(cjsBuild).toBeDefined();
expect(typeof cjsBuild.embed).toBe('function');

expect(esmBuild).toBeDefined();
expect(typeof esmBuild.embed).toBe('function');
});

it('should export wrapElements for both CommonJS and ESM builds', async () => {
const cjsBuild = await import(join(__dirname, '../dist/index.cjs'));
const esmBuild = await import(join(__dirname, '../dist/index.esm.js'));

expect(cjsBuild).toBeDefined();
expect(typeof cjsBuild.wrapElements).toBe('function');

expect(esmBuild).toBeDefined();
expect(typeof esmBuild.wrapElements).toBe('function');
});
});
34 changes: 34 additions & 0 deletions __tests__/calculateReadingTime.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import calculateReadingTime from '../src/plugins/calculateReadingTime';

function generateRandomWord() {
const possibleCharacters = "abcdefghijklmnopqrstuvwxyz";
const randomIndex = Math.floor(Math.random() * possibleCharacters.length);
return possibleCharacters[randomIndex];
}

// Assuming an average word count of 5 characters, this will generate 500 words
const markdownContent = new Array(500).fill(`${generateRandomWord()} `).join("");

describe('calculateReadingTime functionality', () => {
it('calculates reading time with default WPM', () => {
const tree = { type: 'root', children: [{ type: 'text', value: markdownContent }] };
const readingTime = calculateReadingTime()(tree);
// Default WPM is 250, so 500 words should take about 2 minutes, rounded up to 3 minutes
expect(readingTime).toBe(3);
});

it('calculates reading time with custom WPM', () => {
const customWPM = 100;
const tree = { type: 'root', children: [{ type: 'text', value: markdownContent }] };
const readingTime = calculateReadingTime({ wordsPerMinute: customWPM })(tree);
// Custom WPM is 100, so 500 words should take about 5 minutes, rounded up to 6
expect(readingTime).toBe(6);
});

it('handles empty content', () => {
const tree = { type: 'root', children: [{ type: 'text', value: "" }] };
const readingTime = calculateReadingTime()(tree);
// Why would you have an empty document? I don't know, but it gets rounded up to 1 minute.
expect(readingTime).toBe(1);
});
});
82 changes: 82 additions & 0 deletions __tests__/embed.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import embed from "../src/plugins/embed";

describe("embed functionality", () => {
it('embeds a GitHub Gist correctly', () => {
const mockTree = {
type: 'root',
children: [
{
type: 'element',
tagName: 'p',
children: [
{ type: 'text', value: '!embed ' },
{
type: 'element',
tagName: 'a',
properties: { href: 'https://gist.github.com/user/gistid' },
children: [{ type: 'text', value: 'Gist link' }],
},
],
},
],
};
embed()(mockTree);

expect(mockTree.children[0].type).toBe('raw');
expect(mockTree.children[0].value).toContain('https://gist.github.com/user/gistid.pibb');
});


it('embeds a YouTube video correctly', () => {
const mockTree = {
type: 'root',
children: [
{
type: 'element',
tagName: 'p',
children: [
{ type: 'text', value: '!embed ' },
{
type: 'element',
tagName: 'a',
properties: { href: 'https://www.youtube.com/watch?v=videoId' },
children: [{ type: 'text', value: 'YouTube link' }],
},
],
},
],
};

embed()(mockTree);

expect(mockTree.children[0].type).toBe('raw');
expect(mockTree.children[0].value).toContain('https://www.youtube.com/embed/videoId');
});

it('ignores unsupported embed types', () => {
const mockTree = {
type: 'root',
children: [
{
type: 'element',
tagName: 'p',
children: [
{ type: 'text', value: '!embed ' },
{
type: 'element',
tagName: 'a',
properties: { href: 'https://unsupported.com' },
children: [{ type: 'text', value: 'Unsupported link' }],
},
],
},
],
};

embed()(mockTree);

expect(mockTree.children[0].type).not.toBe('raw');
expect(mockTree.children[0].tagName).toBe('p');
});

})
76 changes: 76 additions & 0 deletions __tests__/wrapElements.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import wrapElements from '../src/plugins/wrapElements';

describe('wrapElements', () => {
it('wraps specified elements with a div', () => {
const mockTree = {
type: 'root',
children: [
{ type: 'element', tagName: 'img', properties: {}, children: [] },
{ type: 'element', tagName: 'table', properties: {}, children: [] },
],
};

const options = {
img: 'epic-remark-image',
table: 'epic-remark-table',
};
wrapElements(options)(mockTree);

expect(mockTree.children[0].type).toBe('element');
expect(mockTree.children[0].tagName).toBe('div');
expect(mockTree.children[0].properties.className).toBe('epic-remark-image');
expect(mockTree.children[1].properties.className).toBe('epic-remark-table');
});


it('does not wrap elements if options is empty', () => {
const mockTree = {
type: 'root',
children: [
{ type: 'element', tagName: 'img', properties: {}, children: [] },
{ type: 'element', tagName: 'table', properties: {}, children: [] },
],
};

const emptyOptions = {};
wrapElements(emptyOptions)(mockTree);

expect(mockTree.children[0].tagName).toBe('img');
expect(mockTree.children[1].tagName).toBe('table');
});


it('handles undefined or null node children safely', () => {
const mockTree = {
type: 'root',
children: null,
};

const options = {
img: 'epic-remark-image',
};

expect(() => wrapElements(options)(mockTree)).not.toThrow();
});


it('ignores non-element nodes', () => {
const mockTree = {
type: 'root',
children: [
{ type: 'text', value: 'Just some text' },
{ type: 'element', tagName: 'img', properties: {}, children: [] },
],
};

const options = {
img: 'epic-remark-image',
};

wrapElements(options)(mockTree);

expect(mockTree.children[0].type).toBe('text');
expect(mockTree.children[1].tagName).toBe('div');
expect(mockTree.children[1].properties.className).toBe('epic-remark-image');
});
});

0 comments on commit 8c1cafc

Please sign in to comment.