Files
joplin/packages/editor/CodeMirror/extensions/markdownFrontMatterExtension.test.ts

117 lines
5.2 KiB
TypeScript

import { EditorSelection, EditorState } from '@codemirror/state';
import { frontMatterTagName, frontMatterContentTagName, frontMatterMarkerTagName } from './markdownFrontMatterExtension';
import createTestEditor from '../testing/createTestEditor';
import findNodesWithName from '../testing/findNodesWithName';
// Creates an EditorState with FrontMatter and markdown extensions
const createEditorState = async (initialText: string, expectedTags: string[]): Promise<EditorState> => {
return (await createTestEditor(initialText, EditorSelection.cursor(0), expectedTags)).state;
};
describe('MarkdownFrontMatterExtension', () => {
jest.retryTimes(2);
it('should parse a basic FrontMatter block at the start of the document', async () => {
const documentText = '---\ntitle: Test\n---\n\n# Heading';
const editor = await createEditorState(documentText, [frontMatterTagName, 'ATXHeading1']);
const frontMatterNodes = findNodesWithName(editor, frontMatterTagName);
expect(frontMatterNodes.length).toBe(1);
expect(frontMatterNodes[0].from).toBe(0);
expect(frontMatterNodes[0].to).toBe('---\ntitle: Test\n---'.length);
});
it('should parse FrontMatter with multiple properties', async () => {
const frontMatter = '---\ntitle: Test\ndate: 2024-01-01\ntags: [one, two]\n---';
const documentText = `${frontMatter}\n\nContent here.`;
const editor = await createEditorState(documentText, [frontMatterTagName]);
const frontMatterNodes = findNodesWithName(editor, frontMatterTagName);
expect(frontMatterNodes.length).toBe(1);
expect(frontMatterNodes[0].from).toBe(0);
expect(frontMatterNodes[0].to).toBe(frontMatter.length);
});
it('should not parse FrontMatter if not at document start', async () => {
const documentText = 'Some text\n\n---\ntitle: Test\n---';
const editor = await createEditorState(documentText, ['Paragraph']);
const frontMatterNodes = findNodesWithName(editor, frontMatterTagName);
// Should not be recognized as FrontMatter since it's not at the start
expect(frontMatterNodes.length).toBe(0);
});
it('should not parse FrontMatter without closing delimiter', async () => {
// Test document with --- at start but no closing delimiter
// This should be parsed as a horizontal rule followed by content
const documentText = '# Heading\n\n---\ntitle: Test';
const editor = await createEditorState(documentText, ['ATXHeading1', 'HorizontalRule']);
const frontMatterNodes = findNodesWithName(editor, frontMatterTagName);
// FrontMatter only works at the very start of the document, so this should not be recognized
expect(frontMatterNodes.length).toBe(0);
});
it('should treat the entire document as frontmatter when closing delimiter is missing (issue #14542)', async () => {
const documentText = '---\nsome: frontmatter\n--\n\n# Hey';
const editor = await createEditorState(documentText, [frontMatterTagName]);
const frontMatterNodes = findNodesWithName(editor, frontMatterTagName);
// Frontmatter block must be recognised and span the entire document
expect(frontMatterNodes.length).toBe(1);
expect(frontMatterNodes[0].from).toBe(0);
expect(frontMatterNodes[0].to).toBe(documentText.length);
});
it('should handle empty FrontMatter block', async () => {
const documentText = '---\n---\n\n# Heading';
const editor = await createEditorState(documentText, [frontMatterTagName, 'ATXHeading1']);
const frontMatterNodes = findNodesWithName(editor, frontMatterTagName);
expect(frontMatterNodes.length).toBe(1);
expect(frontMatterNodes[0].from).toBe(0);
expect(frontMatterNodes[0].to).toBe('---\n---'.length);
});
it('should have FrontMatterContent as child node', async () => {
const documentText = '---\nkey: value\n---';
const editor = await createEditorState(documentText, [frontMatterTagName]);
const frontMatterNodes = findNodesWithName(editor, frontMatterTagName);
const contentNodes = findNodesWithName(editor, frontMatterContentTagName);
expect(frontMatterNodes.length).toBe(1);
// Content node may be replaced by YAML parser, but if not, it should exist
// The presence depends on whether YAML language was loaded
expect(contentNodes.length).toBeGreaterThanOrEqual(0);
});
it('should not confuse horizontal rules with FrontMatter', async () => {
const documentText = '# Title\n\n---\n\nSome text';
const editor = await createEditorState(documentText, ['ATXHeading1', 'HorizontalRule']);
const frontMatterNodes = findNodesWithName(editor, frontMatterTagName);
const hrNodes = findNodesWithName(editor, 'HorizontalRule');
expect(frontMatterNodes.length).toBe(0);
expect(hrNodes.length).toBe(1);
});
it('should create FrontMatterMarker nodes for the delimiters', async () => {
const documentText = '---\ntitle: Test\n---\n\n# Heading';
const editor = await createEditorState(documentText, [frontMatterTagName, frontMatterMarkerTagName]);
const markerNodes = findNodesWithName(editor, frontMatterMarkerTagName);
// Should have two markers: opening and closing ---
expect(markerNodes.length).toBe(2);
// Opening marker
expect(markerNodes[0].from).toBe(0);
expect(markerNodes[0].to).toBe(3); // '---'.length
// Closing marker
expect(markerNodes[1].from).toBe('---\ntitle: Test\n'.length);
expect(markerNodes[1].to).toBe('---\ntitle: Test\n---'.length);
});
});