mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Chore: Mobile: Fix CodeMirror test failures (#7522)
This commit is contained in:
parent
767213cdc1
commit
e7386e6fe3
@ -933,6 +933,9 @@ packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/createEditor.js.ma
|
|||||||
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.d.ts
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.d.ts
|
||||||
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js
|
||||||
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js.map
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js.map
|
||||||
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.d.ts
|
||||||
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.js
|
||||||
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.js.map
|
||||||
packages/app-mobile/components/NoteEditor/CodeMirror/theme.d.ts
|
packages/app-mobile/components/NoteEditor/CodeMirror/theme.d.ts
|
||||||
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js
|
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js
|
||||||
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js.map
|
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js.map
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -921,6 +921,9 @@ packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/createEditor.js.ma
|
|||||||
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.d.ts
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.d.ts
|
||||||
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js
|
||||||
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js.map
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js.map
|
||||||
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.d.ts
|
||||||
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.js
|
||||||
|
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.js.map
|
||||||
packages/app-mobile/components/NoteEditor/CodeMirror/theme.d.ts
|
packages/app-mobile/components/NoteEditor/CodeMirror/theme.d.ts
|
||||||
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js
|
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js
|
||||||
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js.map
|
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js.map
|
||||||
|
@ -7,6 +7,7 @@ import { initCodeMirror } from './CodeMirror';
|
|||||||
import { themeStyle } from '@joplin/lib/theme';
|
import { themeStyle } from '@joplin/lib/theme';
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
import { forceParsing } from '@codemirror/language';
|
import { forceParsing } from '@codemirror/language';
|
||||||
|
import loadLangauges from './testUtil/loadLanguages';
|
||||||
|
|
||||||
|
|
||||||
const createEditorSettings = (themeId: number) => {
|
const createEditorSettings = (themeId: number) => {
|
||||||
@ -27,6 +28,7 @@ describe('CodeMirror', () => {
|
|||||||
const initialText = `${headerLineText}\nThis is a test.`;
|
const initialText = `${headerLineText}\nThis is a test.`;
|
||||||
const editorSettings = createEditorSettings(Setting.THEME_LIGHT);
|
const editorSettings = createEditorSettings(Setting.THEME_LIGHT);
|
||||||
|
|
||||||
|
await loadLangauges();
|
||||||
const editor = initCodeMirror(document.body, initialText, editorSettings);
|
const editor = initCodeMirror(document.body, initialText, editorSettings);
|
||||||
|
|
||||||
// Force the generation of the syntax tree now.
|
// Force the generation of the syntax tree now.
|
||||||
|
@ -10,10 +10,11 @@ describe('markdownCommands.bulletedVsChecklist', () => {
|
|||||||
const bulletedListPart = '- Test\n- This is a test.\n- 3\n- 4\n- 5';
|
const bulletedListPart = '- Test\n- This is a test.\n- 3\n- 4\n- 5';
|
||||||
const checklistPart = '- [ ] This is a checklist\n- [ ] with multiple items.\n- [ ] ☑';
|
const checklistPart = '- [ ] This is a checklist\n- [ ] with multiple items.\n- [ ] ☑';
|
||||||
const initialDocText = `${bulletedListPart}\n\n${checklistPart}`;
|
const initialDocText = `${bulletedListPart}\n\n${checklistPart}`;
|
||||||
|
const expectedTags = ['BulletList', 'Task'];
|
||||||
|
|
||||||
it('should remove a checklist following a bulleted list without modifying the bulleted list', () => {
|
it('should remove a checklist following a bulleted list without modifying the bulleted list', async () => {
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText, EditorSelection.cursor(bulletedListPart.length + 5)
|
initialDocText, EditorSelection.cursor(bulletedListPart.length + 5), expectedTags
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleList(ListType.CheckList)(editor);
|
toggleList(ListType.CheckList)(editor);
|
||||||
@ -22,9 +23,9 @@ describe('markdownCommands.bulletedVsChecklist', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove an unordered list following a checklist without modifying the checklist', () => {
|
it('should remove an unordered list following a checklist without modifying the checklist', async () => {
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText, EditorSelection.cursor(bulletedListPart.length - 5)
|
initialDocText, EditorSelection.cursor(bulletedListPart.length - 5), expectedTags
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleList(ListType.UnorderedList)(editor);
|
toggleList(ListType.UnorderedList)(editor);
|
||||||
@ -33,9 +34,9 @@ describe('markdownCommands.bulletedVsChecklist', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should replace a selection of unordered and task lists with a correctly-numbered list', () => {
|
it('should replace a selection of unordered and task lists with a correctly-numbered list', async () => {
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText, EditorSelection.range(0, initialDocText.length)
|
initialDocText, EditorSelection.range(0, initialDocText.length), expectedTags
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleList(ListType.OrderedList)(editor);
|
toggleList(ListType.OrderedList)(editor);
|
||||||
|
@ -2,36 +2,18 @@
|
|||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { EditorSelection, EditorState, SelectionRange } from '@codemirror/state';
|
import { EditorSelection } from '@codemirror/state';
|
||||||
import { EditorView } from '@codemirror/view';
|
|
||||||
import {
|
import {
|
||||||
toggleBolded, toggleCode, toggleHeaderLevel, toggleItalicized, toggleMath, updateLink,
|
toggleBolded, toggleCode, toggleHeaderLevel, toggleItalicized, toggleMath, updateLink,
|
||||||
} from './markdownCommands';
|
} from './markdownCommands';
|
||||||
import { GFM as GithubFlavoredMarkdownExt } from '@lezer/markdown';
|
import createEditor from './testUtil/createEditor';
|
||||||
import { markdown } from '@codemirror/lang-markdown';
|
import { blockMathTagName } from './markdownMathParser';
|
||||||
import { MarkdownMathExtension } from './markdownMathParser';
|
|
||||||
import { indentUnit } from '@codemirror/language';
|
|
||||||
|
|
||||||
// Creates and returns a minimal editor with markdown extensions
|
|
||||||
const createEditor = (initialText: string, initialSelection: SelectionRange): EditorView => {
|
|
||||||
return new EditorView({
|
|
||||||
doc: initialText,
|
|
||||||
selection: EditorSelection.create([initialSelection]),
|
|
||||||
extensions: [
|
|
||||||
markdown({
|
|
||||||
extensions: [MarkdownMathExtension, GithubFlavoredMarkdownExt],
|
|
||||||
}),
|
|
||||||
indentUnit.of('\t'),
|
|
||||||
EditorState.tabSize.of(4),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('markdownCommands', () => {
|
describe('markdownCommands', () => {
|
||||||
it('should bold/italicize everything selected', () => {
|
it('should bold/italicize everything selected', async () => {
|
||||||
const initialDocText = 'Testing...';
|
const initialDocText = 'Testing...';
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText, EditorSelection.range(0, initialDocText.length)
|
initialDocText, EditorSelection.range(0, initialDocText.length), []
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleBolded(editor);
|
toggleBolded(editor);
|
||||||
@ -55,10 +37,10 @@ describe('markdownCommands', () => {
|
|||||||
expect(editor.state.doc.toString()).toBe('Testing...');
|
expect(editor.state.doc.toString()).toBe('Testing...');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('for a cursor, bolding, then italicizing, should produce a bold-italic region', () => {
|
it('for a cursor, bolding, then italicizing, should produce a bold-italic region', async () => {
|
||||||
const initialDocText = '';
|
const initialDocText = '';
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText, EditorSelection.cursor(0)
|
initialDocText, EditorSelection.cursor(0), []
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleBolded(editor);
|
toggleBolded(editor);
|
||||||
@ -73,9 +55,9 @@ describe('markdownCommands', () => {
|
|||||||
expect(editor.state.doc.toString()).toBe('***Test*** Test');
|
expect(editor.state.doc.toString()).toBe('***Test*** Test');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('toggling math should both create and navigate out of math regions', () => {
|
it('toggling math should both create and navigate out of math regions', async () => {
|
||||||
const initialDocText = 'Testing... ';
|
const initialDocText = 'Testing... ';
|
||||||
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
|
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
|
||||||
|
|
||||||
toggleMath(editor);
|
toggleMath(editor);
|
||||||
expect(editor.state.doc.toString()).toBe('Testing... $$');
|
expect(editor.state.doc.toString()).toBe('Testing... $$');
|
||||||
@ -89,9 +71,9 @@ describe('markdownCommands', () => {
|
|||||||
expect(editor.state.doc.toString()).toBe('Testing... $3 + 3 \\neq 5$...');
|
expect(editor.state.doc.toString()).toBe('Testing... $3 + 3 \\neq 5$...');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('toggling inline code should both create and navigate out of an inline code region', () => {
|
it('toggling inline code should both create and navigate out of an inline code region', async () => {
|
||||||
const initialDocText = 'Testing...\n\n';
|
const initialDocText = 'Testing...\n\n';
|
||||||
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
|
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
|
||||||
|
|
||||||
toggleCode(editor);
|
toggleCode(editor);
|
||||||
editor.dispatch(editor.state.replaceSelection('f(x) = ...'));
|
editor.dispatch(editor.state.replaceSelection('f(x) = ...'));
|
||||||
@ -101,9 +83,9 @@ describe('markdownCommands', () => {
|
|||||||
expect(editor.state.doc.toString()).toBe('Testing...\n\n`f(x) = ...` is a function.');
|
expect(editor.state.doc.toString()).toBe('Testing...\n\n`f(x) = ...` is a function.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set headers to the proper levels (when toggling)', () => {
|
it('should set headers to the proper levels (when toggling)', async () => {
|
||||||
const initialDocText = 'Testing...\nThis is a test.';
|
const initialDocText = 'Testing...\nThis is a test.';
|
||||||
const editor = createEditor(initialDocText, EditorSelection.cursor(3));
|
const editor = await createEditor(initialDocText, EditorSelection.cursor(3), []);
|
||||||
|
|
||||||
toggleHeaderLevel(1)(editor);
|
toggleHeaderLevel(1)(editor);
|
||||||
|
|
||||||
@ -127,11 +109,12 @@ describe('markdownCommands', () => {
|
|||||||
expect(mainSel.from).toBe('Testing...'.length);
|
expect(mainSel.from).toBe('Testing...'.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('headers should toggle properly within block quotes', () => {
|
it('headers should toggle properly within block quotes', async () => {
|
||||||
const initialDocText = 'Testing...\n\n> This is a test.\n> ...a test';
|
const initialDocText = 'Testing...\n\n> This is a test.\n> ...a test';
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText,
|
initialDocText,
|
||||||
EditorSelection.cursor('Testing...\n\n> This'.length)
|
EditorSelection.cursor('Testing...\n\n> This'.length),
|
||||||
|
['Blockquote']
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleHeaderLevel(1)(editor);
|
toggleHeaderLevel(1)(editor);
|
||||||
@ -150,69 +133,48 @@ describe('markdownCommands', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// We need to disable this test because it randomly fails on CI.
|
it('block math should be created correctly within block quotes', async () => {
|
||||||
//
|
const initialDocText = 'Testing...\n\n> This is a test.\n> y = mx + b\n> ...a test';
|
||||||
// ● markdownCommands › block math should properly toggle within block quotes
|
const editor = await createEditor(
|
||||||
//
|
initialDocText,
|
||||||
// expect(received).toEqual(expected) // deep equality
|
EditorSelection.range(
|
||||||
//
|
'Testing...\n\n> This'.length,
|
||||||
// - Expected - 1
|
'Testing...\n\n> This is a test.\n> y = mx + b'.length
|
||||||
// + Received + 3
|
),
|
||||||
//
|
['Blockquote']
|
||||||
// Testing...
|
);
|
||||||
//
|
|
||||||
// - > This is a test.
|
|
||||||
// + > $$
|
|
||||||
// + > This is$$ a test.
|
|
||||||
// > y = mx + b
|
|
||||||
// + > $$
|
|
||||||
// > ...a test
|
|
||||||
//
|
|
||||||
// 179 | toggleMath(editor);
|
|
||||||
// 180 | mainSel = editor.state.selection.main;
|
|
||||||
// > 181 | expect(editor.state.doc.toString()).toEqual(initialDocText);
|
|
||||||
// | ^
|
|
||||||
// 182 | expect(mainSel.from).toBe('Testing...\n\n'.length);
|
|
||||||
// 183 | expect(mainSel.to).toBe('Testing...\n\n> This is a test.\n> y = mx + b'.length);
|
|
||||||
// 184 | });
|
|
||||||
|
|
||||||
|
toggleMath(editor);
|
||||||
|
|
||||||
// it('block math should properly toggle within block quotes', () => {
|
// Toggling math should surround the content in '$$'s
|
||||||
// const initialDocText = 'Testing...\n\n> This is a test.\n> y = mx + b\n> ...a test';
|
const mainSel = editor.state.selection.main;
|
||||||
// const editor = createEditor(
|
expect(editor.state.doc.toString()).toEqual(
|
||||||
// initialDocText,
|
'Testing...\n\n> $$\n> This is a test.\n> y = mx + b\n> $$\n> ...a test'
|
||||||
// EditorSelection.range(
|
);
|
||||||
// 'Testing...\n\n> This'.length,
|
expect(mainSel.from).toBe('Testing...\n\n'.length);
|
||||||
// 'Testing...\n\n> This is a test.\n> y = mx + b'.length
|
expect(mainSel.to).toBe('Testing...\n\n> $$\n> This is a test.\n> y = mx + b\n> $$'.length);
|
||||||
// )
|
});
|
||||||
// );
|
|
||||||
|
|
||||||
// toggleMath(editor);
|
it('block math should be correctly removed within block quotes', async () => {
|
||||||
|
const initialDocText = 'Testing...\n\n> $$\n> This is a test.\n> y = mx + b\n> $$\n> ...a test';
|
||||||
|
|
||||||
// // Toggling math should surround the content in '$$'s
|
const editor = await createEditor(
|
||||||
// let mainSel = editor.state.selection.main;
|
initialDocText,
|
||||||
// expect(editor.state.doc.toString()).toEqual(
|
EditorSelection.cursor('Testing...\n\n> $$\n> This is'.length),
|
||||||
// 'Testing...\n\n> $$\n> This is a test.\n> y = mx + b\n> $$\n> ...a test'
|
['Blockquote', blockMathTagName]
|
||||||
// );
|
);
|
||||||
// expect(mainSel.from).toBe('Testing...\n\n'.length);
|
|
||||||
// expect(mainSel.to).toBe('Testing...\n\n> $$\n> This is a test.\n> y = mx + b\n> $$'.length);
|
|
||||||
|
|
||||||
// // Change to a cursor --- test cursor expansion
|
// Toggling math should remove the '$$'s
|
||||||
// editor.dispatch({
|
toggleMath(editor);
|
||||||
// selection: EditorSelection.cursor('Testing...\n\n> $$\n> This is'.length),
|
const mainSel = editor.state.selection.main;
|
||||||
// });
|
expect(editor.state.doc.toString()).toEqual('Testing...\n\n> This is a test.\n> y = mx + b\n> ...a test');
|
||||||
|
expect(mainSel.from).toBe('Testing...\n\n'.length);
|
||||||
|
expect(mainSel.to).toBe('Testing...\n\n> This is a test.\n> y = mx + b'.length);
|
||||||
|
});
|
||||||
|
|
||||||
// // Toggling math again should remove the '$$'s
|
it('updateLink should replace link titles and isolate URLs if no title is given', async () => {
|
||||||
// toggleMath(editor);
|
|
||||||
// mainSel = editor.state.selection.main;
|
|
||||||
// expect(editor.state.doc.toString()).toEqual(initialDocText);
|
|
||||||
// expect(mainSel.from).toBe('Testing...\n\n'.length);
|
|
||||||
// expect(mainSel.to).toBe('Testing...\n\n> This is a test.\n> y = mx + b'.length);
|
|
||||||
// });
|
|
||||||
|
|
||||||
it('updateLink should replace link titles and isolate URLs if no title is given', () => {
|
|
||||||
const initialDocText = '[foo](http://example.com/)';
|
const initialDocText = '[foo](http://example.com/)';
|
||||||
const editor = createEditor(initialDocText, EditorSelection.cursor('[f'.length));
|
const editor = await createEditor(initialDocText, EditorSelection.cursor('[f'.length), ['Link']);
|
||||||
|
|
||||||
updateLink('bar', 'https://example.com/')(editor);
|
updateLink('bar', 'https://example.com/')(editor);
|
||||||
expect(editor.state.doc.toString()).toBe(
|
expect(editor.state.doc.toString()).toBe(
|
||||||
@ -225,9 +187,9 @@ describe('markdownCommands', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('toggling math twice, starting on a line with content, should a math block', () => {
|
it('toggling math twice, starting on a line with content, should a math block', async () => {
|
||||||
const initialDocText = 'Testing... ';
|
const initialDocText = 'Testing... ';
|
||||||
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
|
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
|
||||||
|
|
||||||
toggleMath(editor);
|
toggleMath(editor);
|
||||||
toggleMath(editor);
|
toggleMath(editor);
|
||||||
@ -235,9 +197,9 @@ describe('markdownCommands', () => {
|
|||||||
expect(editor.state.doc.toString()).toBe('Testing... \n$$\nf(x) = ...\n$$');
|
expect(editor.state.doc.toString()).toBe('Testing... \n$$\nf(x) = ...\n$$');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('toggling math twice on an empty line should create an empty math block', () => {
|
it('toggling math twice on an empty line should create an empty math block', async () => {
|
||||||
const initialDocText = 'Testing...\n\n';
|
const initialDocText = 'Testing...\n\n';
|
||||||
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
|
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
|
||||||
|
|
||||||
toggleMath(editor);
|
toggleMath(editor);
|
||||||
toggleMath(editor);
|
toggleMath(editor);
|
||||||
@ -245,9 +207,9 @@ describe('markdownCommands', () => {
|
|||||||
expect(editor.state.doc.toString()).toBe('Testing...\n\n$$\nf(x) = ...\n$$');
|
expect(editor.state.doc.toString()).toBe('Testing...\n\n$$\nf(x) = ...\n$$');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('toggling code twice on an empty line should create an empty code block', () => {
|
it('toggling code twice on an empty line should create an empty code block', async () => {
|
||||||
const initialDocText = 'Testing...\n\n';
|
const initialDocText = 'Testing...\n\n';
|
||||||
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
|
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
|
||||||
|
|
||||||
// Toggling code twice should create a block code region
|
// Toggling code twice should create a block code region
|
||||||
toggleCode(editor);
|
toggleCode(editor);
|
||||||
@ -259,9 +221,9 @@ describe('markdownCommands', () => {
|
|||||||
expect(editor.state.doc.toString()).toBe('Testing...\n\nf(x) = ...\n');
|
expect(editor.state.doc.toString()).toBe('Testing...\n\nf(x) = ...\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('toggling math twice inside a block quote should produce an empty math block', () => {
|
it('toggling math twice inside a block quote should produce an empty math block', async () => {
|
||||||
const initialDocText = '> Testing...> \n> ';
|
const initialDocText = '> Testing...> \n> ';
|
||||||
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
|
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), ['Blockquote']);
|
||||||
|
|
||||||
toggleMath(editor);
|
toggleMath(editor);
|
||||||
toggleMath(editor);
|
toggleMath(editor);
|
||||||
@ -278,9 +240,9 @@ describe('markdownCommands', () => {
|
|||||||
expect(sel.to).toBe(editor.state.doc.length);
|
expect(sel.to).toBe(editor.state.doc.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('toggling inline code should both create and navigate out of an inline code region', () => {
|
it('toggling inline code should both create and navigate out of an inline code region', async () => {
|
||||||
const initialDocText = 'Testing...\n\n';
|
const initialDocText = 'Testing...\n\n';
|
||||||
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
|
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
|
||||||
|
|
||||||
toggleCode(editor);
|
toggleCode(editor);
|
||||||
editor.dispatch(editor.state.replaceSelection('f(x) = ...'));
|
editor.dispatch(editor.state.replaceSelection('f(x) = ...'));
|
||||||
|
@ -10,25 +10,27 @@ import { ListType } from '../types';
|
|||||||
import createEditor from './testUtil/createEditor';
|
import createEditor from './testUtil/createEditor';
|
||||||
|
|
||||||
describe('markdownCommands.toggleList', () => {
|
describe('markdownCommands.toggleList', () => {
|
||||||
it('should remove the same type of list', () => {
|
it('should remove the same type of list', async () => {
|
||||||
const initialDocText = '- testing\n- this is a test';
|
const initialDocText = '- testing\n- this is a `test`\n';
|
||||||
|
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText,
|
initialDocText,
|
||||||
EditorSelection.cursor(5)
|
EditorSelection.cursor(5),
|
||||||
|
['BulletList', 'InlineCode']
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleList(ListType.UnorderedList)(editor);
|
toggleList(ListType.UnorderedList)(editor);
|
||||||
expect(editor.state.doc.toString()).toBe(
|
expect(editor.state.doc.toString()).toBe(
|
||||||
'testing\nthis is a test'
|
'testing\nthis is a `test`\n'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should insert a numbered list with correct numbering', () => {
|
it('should insert a numbered list with correct numbering', async () => {
|
||||||
const initialDocText = 'Testing...\nThis is a test\nof list toggling...';
|
const initialDocText = 'Testing...\nThis is a test\nof list toggling...';
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText,
|
initialDocText,
|
||||||
EditorSelection.cursor('Testing...\nThis is a'.length)
|
EditorSelection.cursor('Testing...\nThis is a'.length),
|
||||||
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleList(ListType.OrderedList)(editor);
|
toggleList(ListType.OrderedList)(editor);
|
||||||
@ -47,12 +49,13 @@ describe('markdownCommands.toggleList', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const numberedListText = '- 1\n- 2\n- 3\n- 4\n- 5\n- 6\n- 7';
|
const unorderedListText = '- 1\n- 2\n- 3\n- 4\n- 5\n- 6\n- 7';
|
||||||
|
|
||||||
it('should correctly replace an unordered list with a numbered list', () => {
|
it('should correctly replace an unordered list with a numbered list', async () => {
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
numberedListText,
|
unorderedListText,
|
||||||
EditorSelection.cursor(numberedListText.length)
|
EditorSelection.cursor(unorderedListText.length),
|
||||||
|
['BulletList']
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleList(ListType.OrderedList)(editor);
|
toggleList(ListType.OrderedList)(editor);
|
||||||
@ -62,10 +65,11 @@ describe('markdownCommands.toggleList', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should correctly replace an unordered list with a checklist', () => {
|
it('should correctly replace an unordered list with a checklist', async () => {
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
numberedListText,
|
unorderedListText,
|
||||||
EditorSelection.cursor(numberedListText.length)
|
EditorSelection.cursor(unorderedListText.length),
|
||||||
|
['BulletList']
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleList(ListType.CheckList)(editor);
|
toggleList(ListType.CheckList)(editor);
|
||||||
@ -74,13 +78,14 @@ describe('markdownCommands.toggleList', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should properly toggle a sublist of a bulleted list', () => {
|
it('should properly toggle a sublist of a bulleted list', async () => {
|
||||||
const preSubListText = '# List test\n * This\n * is\n';
|
const preSubListText = '# List test\n * This\n * is\n';
|
||||||
const initialDocText = `${preSubListText}\t* a\n\t* test\n * of list toggling`;
|
const initialDocText = `${preSubListText}\t* a\n\t* test\n * of list toggling`;
|
||||||
|
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText,
|
initialDocText,
|
||||||
EditorSelection.cursor(preSubListText.length + '\t* a'.length)
|
EditorSelection.cursor(preSubListText.length + '\t* a'.length),
|
||||||
|
['BulletList', 'ATXHeading1']
|
||||||
);
|
);
|
||||||
|
|
||||||
// Indentation should be preserved when changing list types
|
// Indentation should be preserved when changing list types
|
||||||
@ -94,6 +99,17 @@ describe('markdownCommands.toggleList', () => {
|
|||||||
expect(editor.state.selection.main.to).toBe(
|
expect(editor.state.selection.main.to).toBe(
|
||||||
`${preSubListText}\t1. a\n\t2. test`.length
|
`${preSubListText}\t1. a\n\t2. test`.length
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not preserve indentation when removing sublists', async () => {
|
||||||
|
const preSubListText = '# List test\n * This\n * is\n';
|
||||||
|
const initialDocText = `${preSubListText}\t1. a\n\t2. test\n * of list toggling`;
|
||||||
|
|
||||||
|
const editor = await createEditor(
|
||||||
|
initialDocText,
|
||||||
|
EditorSelection.range(preSubListText.length, `${preSubListText}\t1. a\n\t2. test`.length),
|
||||||
|
['ATXHeading1', 'BulletList', 'OrderedList']
|
||||||
|
);
|
||||||
|
|
||||||
// Indentation should not be preserved when removing lists
|
// Indentation should not be preserved when removing lists
|
||||||
toggleList(ListType.OrderedList)(editor);
|
toggleList(ListType.OrderedList)(editor);
|
||||||
@ -102,51 +118,47 @@ describe('markdownCommands.toggleList', () => {
|
|||||||
'# List test\n * This\n * is\na\ntest\n * of list toggling'
|
'# List test\n * This\n * is\na\ntest\n * of list toggling'
|
||||||
);
|
);
|
||||||
|
|
||||||
// The below test:
|
// Put the cursor in the middle of the list
|
||||||
// `expect(editor.state.doc.toString()).toBe(expectedChecklistPart)`
|
editor.dispatch({ selection: EditorSelection.cursor(preSubListText.length) });
|
||||||
// randomly fails on CI, so disabling it for now.
|
|
||||||
|
|
||||||
|
// Sublists should be changed
|
||||||
|
toggleList(ListType.CheckList)(editor);
|
||||||
|
const expectedChecklistPart =
|
||||||
|
'# List test\n - [ ] This\n - [ ] is\n - [ ] a\n - [ ] test\n - [ ] of list toggling';
|
||||||
|
expect(editor.state.doc.toString()).toBe(
|
||||||
|
expectedChecklistPart
|
||||||
|
);
|
||||||
|
|
||||||
// // Put the cursor in the middle of the list
|
editor.dispatch({ selection: EditorSelection.cursor(editor.state.doc.length) });
|
||||||
// editor.dispatch({ selection: EditorSelection.cursor(preSubListText.length) });
|
editor.dispatch(editor.state.replaceSelection('\n\n\n'));
|
||||||
|
|
||||||
// // Sublists should be changed
|
// toggleList should also create a new list if the cursor is on an empty line.
|
||||||
// toggleList(ListType.CheckList)(editor);
|
toggleList(ListType.OrderedList)(editor);
|
||||||
// const expectedChecklistPart =
|
editor.dispatch(editor.state.replaceSelection('Test.\n2. Test2\n3. Test3'));
|
||||||
// '# List test\n - [ ] This\n - [ ] is\n - [ ] a\n - [ ] test\n - [ ] of list toggling';
|
|
||||||
// expect(editor.state.doc.toString()).toBe(
|
|
||||||
// expectedChecklistPart
|
|
||||||
// );
|
|
||||||
|
|
||||||
// editor.dispatch({ selection: EditorSelection.cursor(editor.state.doc.length) });
|
expect(editor.state.doc.toString()).toBe(
|
||||||
// editor.dispatch(editor.state.replaceSelection('\n\n\n'));
|
`${expectedChecklistPart}\n\n\n1. Test.\n2. Test2\n3. Test3`
|
||||||
|
);
|
||||||
|
|
||||||
// // toggleList should also create a new list if the cursor is on an empty line.
|
toggleList(ListType.CheckList)(editor);
|
||||||
// toggleList(ListType.OrderedList)(editor);
|
expect(editor.state.doc.toString()).toBe(
|
||||||
// editor.dispatch(editor.state.replaceSelection('Test.\n2. Test2\n3. Test3'));
|
`${expectedChecklistPart}\n\n\n- [ ] Test.\n- [ ] Test2\n- [ ] Test3`
|
||||||
|
);
|
||||||
|
|
||||||
// expect(editor.state.doc.toString()).toBe(
|
// The entire checklist should have been selected (and thus will now be indented)
|
||||||
// `${expectedChecklistPart}\n\n\n1. Test.\n2. Test2\n3. Test3`
|
increaseIndent(editor);
|
||||||
// );
|
expect(editor.state.doc.toString()).toBe(
|
||||||
|
`${expectedChecklistPart}\n\n\n\t- [ ] Test.\n\t- [ ] Test2\n\t- [ ] Test3`
|
||||||
// toggleList(ListType.CheckList)(editor);
|
);
|
||||||
// expect(editor.state.doc.toString()).toBe(
|
|
||||||
// `${expectedChecklistPart}\n\n\n- [ ] Test.\n- [ ] Test2\n- [ ] Test3`
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // The entire checklist should have been selected (and thus will now be indented)
|
|
||||||
// increaseIndent(editor);
|
|
||||||
// expect(editor.state.doc.toString()).toBe(
|
|
||||||
// `${expectedChecklistPart}\n\n\n\t- [ ] Test.\n\t- [ ] Test2\n\t- [ ] Test3`
|
|
||||||
// );
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should toggle a numbered list without changing its sublists', () => {
|
it('should toggle a numbered list without changing its sublists', async () => {
|
||||||
const initialDocText = '1. Foo\n2. Bar\n3. Baz\n\t- Test\n\t- of\n\t- sublists\n4. Foo';
|
const initialDocText = '1. Foo\n2. Bar\n3. Baz\n\t- Test\n\t- of\n\t- sublists\n4. Foo';
|
||||||
|
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText,
|
initialDocText,
|
||||||
EditorSelection.cursor(0)
|
EditorSelection.cursor(0),
|
||||||
|
['OrderedList', 'BulletList']
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleList(ListType.CheckList)(editor);
|
toggleList(ListType.CheckList)(editor);
|
||||||
@ -155,12 +167,13 @@ describe('markdownCommands.toggleList', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should toggle a sublist without changing the parent list', () => {
|
it('should toggle a sublist without changing the parent list', async () => {
|
||||||
const initialDocText = '1. This\n2. is\n3. ';
|
const initialDocText = '1. This\n2. is\n3. ';
|
||||||
|
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText,
|
initialDocText,
|
||||||
EditorSelection.cursor(initialDocText.length)
|
EditorSelection.cursor(initialDocText.length),
|
||||||
|
['OrderedList']
|
||||||
);
|
);
|
||||||
|
|
||||||
increaseIndent(editor);
|
increaseIndent(editor);
|
||||||
@ -177,11 +190,12 @@ describe('markdownCommands.toggleList', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should toggle lists properly within block quotes', () => {
|
it('should toggle lists properly within block quotes', async () => {
|
||||||
const preSubListText = '> # List test\n> * This\n> * is\n';
|
const preSubListText = '> # List test\n> * This\n> * is\n';
|
||||||
const initialDocText = `${preSubListText}> \t* a\n> \t* test\n> * of list toggling`;
|
const initialDocText = `${preSubListText}> \t* a\n> \t* test\n> * of list toggling`;
|
||||||
const editor = createEditor(
|
const editor = await createEditor(
|
||||||
initialDocText, EditorSelection.cursor(preSubListText.length + 3)
|
initialDocText, EditorSelection.cursor(preSubListText.length + 3),
|
||||||
|
['BlockQuote', 'BulletList']
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleList(ListType.OrderedList)(editor);
|
toggleList(ListType.OrderedList)(editor);
|
||||||
|
@ -1,24 +1,17 @@
|
|||||||
import { markdown } from '@codemirror/lang-markdown';
|
/**
|
||||||
|
* @jest-environment jsdom
|
||||||
|
*/
|
||||||
|
|
||||||
import { syntaxTree } from '@codemirror/language';
|
import { syntaxTree } from '@codemirror/language';
|
||||||
import { SyntaxNode } from '@lezer/common';
|
import { SyntaxNode } from '@lezer/common';
|
||||||
import { EditorState } from '@codemirror/state';
|
import { EditorSelection, EditorState } from '@codemirror/state';
|
||||||
import { blockMathTagName, inlineMathTagName, MarkdownMathExtension } from './markdownMathParser';
|
import { blockMathTagName, inlineMathContentTagName, inlineMathTagName } from './markdownMathParser';
|
||||||
import { GFM as GithubFlavoredMarkdownExt } from '@lezer/markdown';
|
|
||||||
import forceFullParse from './testUtil/forceFullParse';
|
import createEditor from './testUtil/createEditor';
|
||||||
|
|
||||||
// Creates an EditorState with math and markdown extensions
|
// Creates an EditorState with math and markdown extensions
|
||||||
const createEditorState = (initialText: string): EditorState => {
|
const createEditorState = async (initialText: string, expectedTags: string[]): Promise<EditorState> => {
|
||||||
const editorState = EditorState.create({
|
return (await createEditor(initialText, EditorSelection.cursor(0), expectedTags)).state;
|
||||||
doc: initialText,
|
|
||||||
extensions: [
|
|
||||||
markdown({
|
|
||||||
extensions: [MarkdownMathExtension, GithubFlavoredMarkdownExt],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
forceFullParse(editorState);
|
|
||||||
|
|
||||||
return editorState;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a list of all nodes with the given name in the given editor's syntax tree.
|
// Returns a list of all nodes with the given name in the given editor's syntax tree.
|
||||||
@ -38,31 +31,29 @@ const findNodesWithName = (editor: EditorState, nodeName: string) => {
|
|||||||
|
|
||||||
describe('markdownMathParser', () => {
|
describe('markdownMathParser', () => {
|
||||||
|
|
||||||
// Disable flaky test - randomly fails on line `expect(inlineMathContentNodes.length).toBe(0);`
|
it('should parse inline math that contains space characters, numbers, and symbols', async () => {
|
||||||
|
const documentText = '$3 + 3$';
|
||||||
|
const editor = await createEditorState(documentText, [inlineMathTagName, 'number']);
|
||||||
|
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
|
||||||
|
const inlineMathContentNodes = findNodesWithName(editor, inlineMathContentTagName);
|
||||||
|
|
||||||
// it('should parse inline math that contains space characters, numbers, and symbols', () => {
|
// There should only be one inline node
|
||||||
// const documentText = '$3 + 3$';
|
expect(inlineMathNodes.length).toBe(1);
|
||||||
// const editor = createEditorState(documentText);
|
|
||||||
// const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
|
|
||||||
// const inlineMathContentNodes = findNodesWithName(editor, inlineMathContentTagName);
|
|
||||||
|
|
||||||
// // There should only be one inline node
|
expect(inlineMathNodes[0].from).toBe(0);
|
||||||
// expect(inlineMathNodes.length).toBe(1);
|
expect(inlineMathNodes[0].to).toBe(documentText.length);
|
||||||
|
|
||||||
// expect(inlineMathNodes[0].from).toBe(0);
|
// The content tag should be replaced by the internal sTeX parser
|
||||||
// expect(inlineMathNodes[0].to).toBe(documentText.length);
|
expect(inlineMathContentNodes.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
// // The content tag should be replaced by the internal sTeX parser
|
it('should parse comment within multi-word inline math', async () => {
|
||||||
// expect(inlineMathContentNodes.length).toBe(0);
|
|
||||||
// });
|
|
||||||
|
|
||||||
it('should parse comment within multi-word inline math', () => {
|
|
||||||
const beforeMath = '# Testing!\n\nThis is a test of ';
|
const beforeMath = '# Testing!\n\nThis is a test of ';
|
||||||
const mathRegion = '$\\TeX % TeX Comment!$';
|
const mathRegion = '$\\TeX % TeX Comment!$';
|
||||||
const afterMath = ' formatting.';
|
const afterMath = ' formatting.';
|
||||||
const documentText = `${beforeMath}${mathRegion}${afterMath}`;
|
const documentText = `${beforeMath}${mathRegion}${afterMath}`;
|
||||||
|
|
||||||
const editor = createEditorState(documentText);
|
const editor = await createEditorState(documentText, [inlineMathTagName, 'comment']);
|
||||||
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
|
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
|
||||||
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
|
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
|
||||||
const commentNodes = findNodesWithName(editor, 'comment');
|
const commentNodes = findNodesWithName(editor, 'comment');
|
||||||
@ -75,30 +66,30 @@ describe('markdownMathParser', () => {
|
|||||||
expect(inlineMathNodes[0].to).toBe(beforeMath.length + mathRegion.length);
|
expect(inlineMathNodes[0].to).toBe(beforeMath.length + mathRegion.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shouldn\'t start inline math if there is no ending $', () => {
|
it('shouldn\'t start inline math if there is no ending $', async () => {
|
||||||
const documentText = 'This is a $test\n\nof inline math$...';
|
const documentText = '*This* is a $test\n\nof inline math$...';
|
||||||
const editor = createEditorState(documentText);
|
const editor = await createEditorState(documentText, ['Emphasis']);
|
||||||
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
|
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
|
||||||
|
|
||||||
// Math should end if there is no matching '$'.
|
// Math should end if there is no matching '$'.
|
||||||
expect(inlineMathNodes.length).toBe(0);
|
expect(inlineMathNodes.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shouldn\'t start if math would have a space just after the $', () => {
|
it('shouldn\'t start if math would have a space just after the $', async () => {
|
||||||
const documentText = 'This is a $ test of inline math$...\n\n$Testing... $...';
|
const documentText = 'This *is* a $ test of inline math$...\n\n$Testing... $...';
|
||||||
const editor = createEditorState(documentText);
|
const editor = await createEditorState(documentText, ['Emphasis']);
|
||||||
expect(findNodesWithName(editor, inlineMathTagName).length).toBe(0);
|
expect(findNodesWithName(editor, inlineMathTagName).length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shouldn\'t start inline math if $ is escaped', () => {
|
it('shouldn\'t start inline math if $ is escaped', async () => {
|
||||||
const documentText = 'This is a \\$test of inline math$...';
|
const documentText = 'This is a \\$test of inline math$... **Testing...**';
|
||||||
const editor = createEditorState(documentText);
|
const editor = await createEditorState(documentText, ['StrongEmphasis']);
|
||||||
expect(findNodesWithName(editor, inlineMathTagName).length).toBe(0);
|
expect(findNodesWithName(editor, inlineMathTagName).length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly parse document containing just block math', () => {
|
it('should correctly parse document containing just block math', async () => {
|
||||||
const documentText = '$$\n\t\\{ 1, 1, 2, 3, 5, ... \\}\n$$';
|
const documentText = '$$\n\t\\{ 1, 1, 2, 3, 5, ... \\} % Comment\n$$';
|
||||||
const editor = createEditorState(documentText);
|
const editor = await createEditorState(documentText, [blockMathTagName, 'comment']);
|
||||||
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
|
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
|
||||||
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
|
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
|
||||||
|
|
||||||
@ -109,10 +100,10 @@ describe('markdownMathParser', () => {
|
|||||||
expect(blockMathNodes[0].to).toBe(documentText.length);
|
expect(blockMathNodes[0].to).toBe(documentText.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly parse comment in block math', () => {
|
it('should correctly parse comment in block math', async () => {
|
||||||
const startingText = '$$ % Testing...\n\t\\text{Test.}\n$$';
|
const startingText = '$$ % Testing...\n\t\\text{Test.}\n$$';
|
||||||
const afterMath = '\nTest.';
|
const afterMath = '\nTest.';
|
||||||
const editor = createEditorState(startingText + afterMath);
|
const editor = await createEditorState(startingText + afterMath, ['comment', blockMathTagName]);
|
||||||
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
|
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
|
||||||
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
|
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
|
||||||
const texParserComments = findNodesWithName(editor, 'comment');
|
const texParserComments = findNodesWithName(editor, 'comment');
|
||||||
@ -130,10 +121,10 @@ describe('markdownMathParser', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should extend block math without ending tag to end of document', () => {
|
it('should extend block math without ending tag to end of document', async () => {
|
||||||
const beforeMath = '# Testing...\n\n';
|
const beforeMath = '# Testing...\n\n';
|
||||||
const documentText = `${beforeMath}$$\n\t\\text{Testing...}\n\n\t3 + 3 = 6`;
|
const documentText = `${beforeMath}$$\n\t\\text{Testing...}\n\n\t3 + 3 = 6 % Comment`;
|
||||||
const editor = createEditorState(documentText);
|
const editor = await createEditorState(documentText, ['ATXHeading1', blockMathTagName, 'comment']);
|
||||||
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
|
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
|
||||||
|
|
||||||
expect(blockMathNodes.length).toBe(1);
|
expect(blockMathNodes.length).toBe(1);
|
||||||
@ -141,9 +132,9 @@ describe('markdownMathParser', () => {
|
|||||||
expect(blockMathNodes[0].to).toBe(documentText.length);
|
expect(blockMathNodes[0].to).toBe(documentText.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse block math declared on a single line', () => {
|
it('should parse block math declared on a single line', async () => {
|
||||||
const documentText = '$$ Test. $$';
|
const documentText = '$$ Test. $$';
|
||||||
const editor = createEditorState(documentText);
|
const editor = await createEditorState(documentText, [blockMathTagName]);
|
||||||
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
|
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
|
||||||
|
|
||||||
expect(blockMathNodes.length).toBe(1);
|
expect(blockMathNodes.length).toBe(1);
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
import { markdown } from '@codemirror/lang-markdown';
|
import { markdown } from '@codemirror/lang-markdown';
|
||||||
import { GFM as GithubFlavoredMarkdownExt } from '@lezer/markdown';
|
import { GFM as GithubFlavoredMarkdownExt } from '@lezer/markdown';
|
||||||
import { indentUnit } from '@codemirror/language';
|
import { indentUnit, syntaxTree } from '@codemirror/language';
|
||||||
import { SelectionRange, EditorSelection, EditorState } from '@codemirror/state';
|
import { SelectionRange, EditorSelection, EditorState } from '@codemirror/state';
|
||||||
import { EditorView } from '@codemirror/view';
|
import { EditorView } from '@codemirror/view';
|
||||||
import { MarkdownMathExtension } from '../markdownMathParser';
|
import { MarkdownMathExtension } from '../markdownMathParser';
|
||||||
import forceFullParse from './forceFullParse';
|
import forceFullParse from './forceFullParse';
|
||||||
|
import loadLangauges from './loadLanguages';
|
||||||
|
|
||||||
|
// Creates and returns a minimal editor with markdown extensions. Waits to return the editor
|
||||||
|
// until all syntax tree tags in `expectedSyntaxTreeTags` exist.
|
||||||
|
const createEditor = async (
|
||||||
|
initialText: string, initialSelection: SelectionRange, expectedSyntaxTreeTags: string[]
|
||||||
|
): Promise<EditorView> => {
|
||||||
|
await loadLangauges();
|
||||||
|
|
||||||
// Creates and returns a minimal editor with markdown extensions
|
|
||||||
const createEditor = (initialText: string, initialSelection: SelectionRange): EditorView => {
|
|
||||||
const editor = new EditorView({
|
const editor = new EditorView({
|
||||||
doc: initialText,
|
doc: initialText,
|
||||||
selection: EditorSelection.create([initialSelection]),
|
selection: EditorSelection.create([initialSelection]),
|
||||||
@ -20,7 +26,39 @@ const createEditor = (initialText: string, initialSelection: SelectionRange): Ed
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
forceFullParse(editor.state);
|
let sawExpectedTagCount = 0;
|
||||||
|
while (sawExpectedTagCount < expectedSyntaxTreeTags.length) {
|
||||||
|
forceFullParse(editor.state);
|
||||||
|
|
||||||
|
sawExpectedTagCount = 0;
|
||||||
|
const seenTags = new Set<string>();
|
||||||
|
|
||||||
|
syntaxTree(editor.state).iterate({
|
||||||
|
from: 0,
|
||||||
|
to: editor.state.doc.length,
|
||||||
|
enter: (node) => {
|
||||||
|
for (const expectedTag of expectedSyntaxTreeTags) {
|
||||||
|
if (node.name === expectedTag) {
|
||||||
|
seenTags.add(node.name);
|
||||||
|
sawExpectedTagCount ++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sawExpectedTagCount < expectedSyntaxTreeTags.length) {
|
||||||
|
const missingTags = expectedSyntaxTreeTags.filter(tagName => {
|
||||||
|
return !seenTags.has(tagName);
|
||||||
|
});
|
||||||
|
console.warn(`Didn't find all expected tags. Missing ${missingTags}. Retrying...`);
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
setTimeout(resolve, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return editor;
|
return editor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
import syntaxHighlightingLanguages from '../syntaxHighlightingLanguages';
|
||||||
|
|
||||||
|
// Ensure languages we use are loaded. Without this, tests may randomly fail (LanguageDescriptions
|
||||||
|
// are loaded asyncronously, in the background).
|
||||||
|
const loadLangauges = async () => {
|
||||||
|
const allLanguages = syntaxHighlightingLanguages;
|
||||||
|
|
||||||
|
for (const lang of allLanguages) {
|
||||||
|
await lang.load();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export default loadLangauges;
|
@ -81,11 +81,11 @@
|
|||||||
"@codemirror/lang-markdown": "6.0.5",
|
"@codemirror/lang-markdown": "6.0.5",
|
||||||
"@codemirror/lang-php": "6.0.1",
|
"@codemirror/lang-php": "6.0.1",
|
||||||
"@codemirror/lang-rust": "6.0.1",
|
"@codemirror/lang-rust": "6.0.1",
|
||||||
"@codemirror/language": "6.3.1",
|
"@codemirror/language": "6.3.2",
|
||||||
"@codemirror/legacy-modes": "6.3.1",
|
"@codemirror/legacy-modes": "6.3.1",
|
||||||
"@codemirror/search": "6.2.3",
|
"@codemirror/search": "6.2.3",
|
||||||
"@codemirror/state": "6.1.4",
|
"@codemirror/state": "6.1.4",
|
||||||
"@codemirror/view": "6.6.0",
|
"@codemirror/view": "6.7.1",
|
||||||
"@joplin/tools": "~2.10",
|
"@joplin/tools": "~2.10",
|
||||||
"@lezer/highlight": "1.1.3",
|
"@lezer/highlight": "1.1.3",
|
||||||
"@types/fs-extra": "9.0.13",
|
"@types/fs-extra": "9.0.13",
|
||||||
|
61
yarn.lock
61
yarn.lock
@ -3173,8 +3173,8 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@codemirror/autocomplete@npm:^6.0.0":
|
"@codemirror/autocomplete@npm:^6.0.0":
|
||||||
version: 6.3.4
|
version: 6.4.0
|
||||||
resolution: "@codemirror/autocomplete@npm:6.3.4"
|
resolution: "@codemirror/autocomplete@npm:6.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@codemirror/language": ^6.0.0
|
"@codemirror/language": ^6.0.0
|
||||||
"@codemirror/state": ^6.0.0
|
"@codemirror/state": ^6.0.0
|
||||||
@ -3185,7 +3185,7 @@ __metadata:
|
|||||||
"@codemirror/state": ^6.0.0
|
"@codemirror/state": ^6.0.0
|
||||||
"@codemirror/view": ^6.0.0
|
"@codemirror/view": ^6.0.0
|
||||||
"@lezer/common": ^1.0.0
|
"@lezer/common": ^1.0.0
|
||||||
checksum: dafb6b3dee11551ed7a2ec1d20fa05641abefe2e0b5da045d4a3383146bb04f0b9650448a378a5921cc183944d626482a608b71f3da5a036a881a873006b8dbf
|
checksum: 3470fee01da60d3d71b8b4f8728629c0f0441e704b8b828592f98c000d75fdb2c9077727e82685626cf45b95cadbc0c1a03968261df2f0cfb4162418b5f4dd1f
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -3250,7 +3250,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@codemirror/lang-javascript@npm:6.1.1, @codemirror/lang-javascript@npm:^6.0.0":
|
"@codemirror/lang-javascript@npm:6.1.1":
|
||||||
version: 6.1.1
|
version: 6.1.1
|
||||||
resolution: "@codemirror/lang-javascript@npm:6.1.1"
|
resolution: "@codemirror/lang-javascript@npm:6.1.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3265,6 +3265,21 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@codemirror/lang-javascript@npm:^6.0.0":
|
||||||
|
version: 6.1.2
|
||||||
|
resolution: "@codemirror/lang-javascript@npm:6.1.2"
|
||||||
|
dependencies:
|
||||||
|
"@codemirror/autocomplete": ^6.0.0
|
||||||
|
"@codemirror/language": ^6.0.0
|
||||||
|
"@codemirror/lint": ^6.0.0
|
||||||
|
"@codemirror/state": ^6.0.0
|
||||||
|
"@codemirror/view": ^6.0.0
|
||||||
|
"@lezer/common": ^1.0.0
|
||||||
|
"@lezer/javascript": ^1.0.0
|
||||||
|
checksum: f4336b7efd44e4158b9979f0c23918184c897d0fe3e40b5414bd9243a9899ecdba4dfe13970fe5024a1894579af80cb4c5dd574c6c2b7bd7ff06d8c8cb88616b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@codemirror/lang-markdown@npm:6.0.5":
|
"@codemirror/lang-markdown@npm:6.0.5":
|
||||||
version: 6.0.5
|
version: 6.0.5
|
||||||
resolution: "@codemirror/lang-markdown@npm:6.0.5"
|
resolution: "@codemirror/lang-markdown@npm:6.0.5"
|
||||||
@ -3302,9 +3317,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@codemirror/language@npm:6.3.1, @codemirror/language@npm:^6.0.0, @codemirror/language@npm:^6.3.0":
|
"@codemirror/language@npm:6.3.2, @codemirror/language@npm:^6.0.0, @codemirror/language@npm:^6.3.0":
|
||||||
version: 6.3.1
|
version: 6.3.2
|
||||||
resolution: "@codemirror/language@npm:6.3.1"
|
resolution: "@codemirror/language@npm:6.3.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@codemirror/state": ^6.0.0
|
"@codemirror/state": ^6.0.0
|
||||||
"@codemirror/view": ^6.0.0
|
"@codemirror/view": ^6.0.0
|
||||||
@ -3312,7 +3327,7 @@ __metadata:
|
|||||||
"@lezer/highlight": ^1.0.0
|
"@lezer/highlight": ^1.0.0
|
||||||
"@lezer/lr": ^1.0.0
|
"@lezer/lr": ^1.0.0
|
||||||
style-mod: ^4.0.0
|
style-mod: ^4.0.0
|
||||||
checksum: 349b9806e1e2ce5d99ba1f5815cc4772e6032f68c95718594e8335196ef0686bc6378db7cdd5f0fda57ba068eebf0ee413bb336e32cc1ff958a743190a0266da
|
checksum: b70ed9b85d0bea79181c86e88a1f5c0bada30680ee1fe6a68efc01bc037c3d14f94a83602fc46cc4b4393589605ef7e986ed5174443502f3365dd61f883894fa
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -3354,14 +3369,14 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@codemirror/view@npm:6.6.0, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.2.2, @codemirror/view@npm:^6.6.0":
|
"@codemirror/view@npm:6.7.1, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.2.2, @codemirror/view@npm:^6.6.0":
|
||||||
version: 6.6.0
|
version: 6.7.1
|
||||||
resolution: "@codemirror/view@npm:6.6.0"
|
resolution: "@codemirror/view@npm:6.7.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@codemirror/state": ^6.1.4
|
"@codemirror/state": ^6.1.4
|
||||||
style-mod: ^4.0.0
|
style-mod: ^4.0.0
|
||||||
w3c-keyname: ^2.2.4
|
w3c-keyname: ^2.2.4
|
||||||
checksum: 9b007eedcf13e94ec7d9c30ee302e1a1fcd382bef2481bd9afa3a116458652983e745b40494eb29d80df1dca8f99e91dcb1e4eba37670c2553ffc90bef0933e7
|
checksum: 75a5846d61e63027e9bf1dfd0b507932934cb7650b7959c1191e68b161eb1756e9773f964c4331970b51864aef8f7954bc5cc8fdb51b0f6533de6c20568833ed
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -4662,11 +4677,11 @@ __metadata:
|
|||||||
"@codemirror/lang-markdown": 6.0.5
|
"@codemirror/lang-markdown": 6.0.5
|
||||||
"@codemirror/lang-php": 6.0.1
|
"@codemirror/lang-php": 6.0.1
|
||||||
"@codemirror/lang-rust": 6.0.1
|
"@codemirror/lang-rust": 6.0.1
|
||||||
"@codemirror/language": 6.3.1
|
"@codemirror/language": 6.3.2
|
||||||
"@codemirror/legacy-modes": 6.3.1
|
"@codemirror/legacy-modes": 6.3.1
|
||||||
"@codemirror/search": 6.2.3
|
"@codemirror/search": 6.2.3
|
||||||
"@codemirror/state": 6.1.4
|
"@codemirror/state": 6.1.4
|
||||||
"@codemirror/view": 6.6.0
|
"@codemirror/view": 6.7.1
|
||||||
"@joplin/lib": ~2.10
|
"@joplin/lib": ~2.10
|
||||||
"@joplin/react-native-saf-x": ~2.10
|
"@joplin/react-native-saf-x": ~2.10
|
||||||
"@joplin/renderer": ~2.10
|
"@joplin/renderer": ~2.10
|
||||||
@ -6023,12 +6038,12 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@lezer/css@npm:^1.0.0, @lezer/css@npm:^1.1.0":
|
"@lezer/css@npm:^1.0.0, @lezer/css@npm:^1.1.0":
|
||||||
version: 1.1.0
|
version: 1.1.1
|
||||||
resolution: "@lezer/css@npm:1.1.0"
|
resolution: "@lezer/css@npm:1.1.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@lezer/highlight": ^1.0.0
|
"@lezer/highlight": ^1.0.0
|
||||||
"@lezer/lr": ^1.0.0
|
"@lezer/lr": ^1.0.0
|
||||||
checksum: 5d2a176d7f4cf5076d8841af9b7bcafcbad5dd1b8f46fa1ad56c0fbf76f4bd4cd4ee0b1c4f1f1c9f8dba4fffb88908e64b5d7919c8706b35f575ddff8512ef31
|
checksum: a7e4893aacaa7f26d5679c77a640f401b37d14155cb54863aa91b59dfd220b280360a341c0fedafc65d31101de13a5ae33cf3876c352f2da528344dafdc9b3d7
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -6042,13 +6057,13 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@lezer/html@npm:^1.1.0":
|
"@lezer/html@npm:^1.1.0":
|
||||||
version: 1.2.0
|
version: 1.3.0
|
||||||
resolution: "@lezer/html@npm:1.2.0"
|
resolution: "@lezer/html@npm:1.3.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@lezer/common": ^1.0.0
|
"@lezer/common": ^1.0.0
|
||||||
"@lezer/highlight": ^1.0.0
|
"@lezer/highlight": ^1.0.0
|
||||||
"@lezer/lr": ^1.0.0
|
"@lezer/lr": ^1.0.0
|
||||||
checksum: 737f6884328845100575c3bb9b0add622d00233d9d75f6bd201d37e31b990af371984b7ab91681bfe258234b77d486bc97f61a8ebdb4bd70a942f06a22b1aac1
|
checksum: e6efde94614a5b7ebf2713b244a110ef9025369561c7bf42fe6dd8f5877d2ee0c71f894b8b43d1284d23bf429fd3688ec3b6b0c2b8702df366c2b5e5cedc4c19
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -6063,12 +6078,12 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@lezer/javascript@npm:^1.0.0":
|
"@lezer/javascript@npm:^1.0.0":
|
||||||
version: 1.3.1
|
version: 1.4.0
|
||||||
resolution: "@lezer/javascript@npm:1.3.1"
|
resolution: "@lezer/javascript@npm:1.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@lezer/highlight": ^1.0.0
|
"@lezer/highlight": ^1.0.0
|
||||||
"@lezer/lr": ^1.0.0
|
"@lezer/lr": ^1.0.0
|
||||||
checksum: bcf1a2ac84198f7caedf320d5222b6f4d39ece62d939ebe02b461bb175027c9b66d7be7feba51d3d8317bdd972c4fbdde3d9edbd60fa342b9e97db8ca1b63922
|
checksum: 36c64e8530feef9b937cf75f8833aa8c0f5c8c0812c55c53a133d1af5deb491dd80084397d5773e873db90ff717aede25b45fa827eead66400cb81b097567c42
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user