From fd32a3c96f5a13f4b8dcac0de3998503faba5303 Mon Sep 17 00:00:00 2001 From: Jannik Stehle Date: Fri, 9 Oct 2026 10:59:49 +0200 Subject: [PATCH 1/6] refactor(web-pkg): register markdown tokenizers on a Marked instance --- .../web-pkg/src/editor/composables/strategies/markdown.ts | 7 ++++--- packages/web-pkg/src/editor/extensions/frontmatter.ts | 4 ++-- packages/web-pkg/src/editor/extensions/markdownLists.ts | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/web-pkg/src/editor/composables/strategies/markdown.ts b/packages/web-pkg/src/editor/composables/strategies/markdown.ts index 59e26d21d4d..ad3e2753a35 100644 --- a/packages/web-pkg/src/editor/composables/strategies/markdown.ts +++ b/packages/web-pkg/src/editor/composables/strategies/markdown.ts @@ -36,12 +36,13 @@ export const useStrategyMarkdown = (editorState: TextEditorState): ContentTypeSt // process wide singleton which grows with every editor opened and keeps each // manager it ever saw alive. Holding our own instance bounds both to the // lifetime of this strategy. + const instance = new Marked() + registerFrontmatterTokenizer(instance) + registerMarkdownListTokenizer(instance) // Cast because tiptap types the option as the default export, which carries a // `getDefaults` helper a plain instance lacks. The manager never calls it: it // only touches `use`, `setOptions`, `Lexer`, `lexer` and `defaults`. - const marked = new Marked() as unknown as typeof markedDefault - registerFrontmatterTokenizer(marked) - registerMarkdownListTokenizer(marked) + const marked = instance as unknown as typeof markedDefault const editorContentType = () => { return 'markdown' diff --git a/packages/web-pkg/src/editor/extensions/frontmatter.ts b/packages/web-pkg/src/editor/extensions/frontmatter.ts index 4e9f9224eb2..52b618647a2 100644 --- a/packages/web-pkg/src/editor/extensions/frontmatter.ts +++ b/packages/web-pkg/src/editor/extensions/frontmatter.ts @@ -1,6 +1,6 @@ import { commands as coreCommands, Node, mergeAttributes } from '@tiptap/core' import type { CommandProps, JSONContent, MarkdownToken } from '@tiptap/core' -import type { marked } from 'marked' +import type { Marked } from 'marked' import { TextSelection } from '@tiptap/pm/state' import { VueNodeViewRenderer } from '@tiptap/vue-3' import FrontmatterComponent from '../components/FrontmatterComponent.vue' @@ -45,7 +45,7 @@ const frontmatterPattern = /^---[ \t]*\r?\n([\s\S]*?)(?:\r?\n)?---[ \t]*(?:\r?\n * given and never removes them, so the singleton would grow for as long as the * tab is open and hold on to every manager it ever saw. */ -export function registerFrontmatterTokenizer(instance: typeof marked): void { +export function registerFrontmatterTokenizer(instance: Marked): void { instance.use({ extensions: [ { diff --git a/packages/web-pkg/src/editor/extensions/markdownLists.ts b/packages/web-pkg/src/editor/extensions/markdownLists.ts index e6d94e5dc90..e68a8b6c7bf 100644 --- a/packages/web-pkg/src/editor/extensions/markdownLists.ts +++ b/packages/web-pkg/src/editor/extensions/markdownLists.ts @@ -1,7 +1,7 @@ import type { JSONContent, MarkdownToken } from '@tiptap/core' import { ListItem, OrderedList } from '@tiptap/extension-list' import { Tokenizer } from 'marked' -import type { marked } from 'marked' +import type { Marked } from 'marked' function isEmptySubItemUnderline(token?: MarkdownToken): boolean { // `- text` followed by ` -` lexes as a setext heading, not as an empty sub item @@ -118,7 +118,7 @@ const emptyFirstItemPattern = /^( {0,3}(?:[-+*]|\d{1,9}[.)]))[ \t]+(?=\n|$)/ * * Takes the instance as an argument for the same reason as `registerFrontmatterTokenizer`. */ -export function registerMarkdownListTokenizer(instance: typeof marked): void { +export function registerMarkdownListTokenizer(instance: Marked): void { instance.use({ tokenizer: { list(src) { From c3103378cc4c8034a981a7a0c6bc2e8ebdbe692c Mon Sep 17 00:00:00 2001 From: Jannik Stehle Date: Fri, 9 Oct 2026 10:27:15 +0200 Subject: [PATCH 2/6] test(web-pkg): add fixture based markdown round trip tests --- .prettierignore | 3 + .../strategies/fixtures/markdown/basics.md | 45 ++++++ .../fixtures/markdown/blockquote-alert.md | 2 + .../blockquote-escaped-alert-marker.md | 3 + .../code-block-fence-indented-1-space.md | 3 + .../code-block-fence-indented-2-spaces.md | 4 + .../code-block-indented-fence-after-list.md | 4 + .../markdown/list-asterisk-markers.md | 2 + .../markdown/list-blockquote-in-item.md | 2 + .../list-empty-first-ordered-sub-item.md | 3 + .../markdown/list-empty-item-in-blockquote.md | 1 + .../markdown/list-empty-item-with-sub-list.md | 2 + .../fixtures/markdown/list-empty-item.md | 1 + .../fixtures/markdown/list-empty-items.md | 6 + .../markdown/list-empty-last-sub-item.md | 3 + .../list-empty-sub-item-with-children.md | 8 ++ .../fixtures/markdown/list-empty-sub-items.md | 9 ++ .../markdown/list-escaped-lines-in-item.md | 3 + .../list-heading-below-empty-marker.md | 3 + .../fixtures/markdown/list-heading-in-item.md | 2 + .../markdown/list-heading-in-letter-item.md | 3 + .../markdown/list-heading-in-ordered-item.md | 2 + .../markdown/list-image-after-text.md | 3 + .../fixtures/markdown/list-image-item.md | 6 + .../markdown/list-letters-empty-item.md | 3 + .../fixtures/markdown/list-literal-nbsp.md | 5 + .../markdown/list-lowercase-letters.md | 2 + .../markdown/list-lowercase-roman-numerals.md | 2 + .../list-ordered-content-indented-2-spaces.md | 3 + .../list-ordered-continuation-line.md | 2 + .../list-ordered-item-escaped-line.md | 2 + .../list-ordered-right-aligned-nested.md | 12 ++ .../markdown/list-ordered-right-aligned.md | 10 ++ .../markdown/list-ordered-start-number.md | 2 + .../markdown/list-text-after-code-block.md | 4 + .../markdown/list-text-after-heading.md | 2 + .../markdown/list-uppercase-letters.md | 2 + .../markdown/list-uppercase-roman-numerals.md | 2 + .../paragraph-escaped-block-syntax.md | 20 +++ .../markdown/paragraph-indented-lines.md | 7 + .../markdown/paragraph-soft-line-breaks.md | 4 + .../paragraph-text-like-block-syntax.md | 7 + .../markdown/table-block-syntax-in-cells.md | 3 + .../task-list-code-block-in-bullet-item.md | 6 + .../task-list-code-block-in-ordered-item.md | 6 + ...ask-list-code-block-nested-tab-indented.md | 6 + ...ode-block-tab-indented-after-blank-line.md | 8 ++ .../task-list-code-block-tab-indented.md | 4 + ...block-tilde-with-tabs-after-nested-item.md | 6 + ...t-code-block-with-tabs-after-blank-line.md | 6 + ...-code-block-with-tabs-after-nested-item.md | 5 + ...-list-code-block-with-tabs-three-levels.md | 7 + .../task-list-code-block-with-tabs.md | 5 + .../task-list-code-block-with-task-syntax.md | 7 + ...t-indented-code-block-after-nested-item.md | 4 + ...list-indented-code-block-tab-and-spaces.md | 3 + ...task-list-indented-code-block-with-tabs.md | 3 + .../task-list-nested-item-tab-indented.md | 2 + .../strategies/markdownFixtures.spec.ts | 132 ++++++++++++++++++ 59 files changed, 427 insertions(+) create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/basics.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/blockquote-alert.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/blockquote-escaped-alert-marker.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-1-space.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-2-spaces.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-indented-fence-after-list.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-asterisk-markers.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-blockquote-in-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-ordered-sub-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-in-blockquote.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-with-sub-list.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-items.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-sub-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-item-with-children.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-items.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-escaped-lines-in-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-below-empty-marker.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-letter-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-ordered-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-image-after-text.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-image-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-letters-empty-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-literal-nbsp.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-lowercase-letters.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-lowercase-roman-numerals.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-content-indented-2-spaces.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-continuation-line.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned-nested.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-start-number.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-code-block.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-heading.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-uppercase-letters.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-uppercase-roman-numerals.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-escaped-block-syntax.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-indented-lines.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-soft-line-breaks.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-text-like-block-syntax.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/table-block-syntax-in-cells.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-bullet-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-ordered-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-nested-tab-indented.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented-after-blank-line.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tilde-with-tabs-after-nested-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-blank-line.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-nested-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-three-levels.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-task-syntax.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-after-nested-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-tab-and-spaces.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-with-tabs.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-nested-item-tab-indented.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts diff --git a/.prettierignore b/.prettierignore index 0cec5fa211d..598a5ca1889 100644 --- a/.prettierignore +++ b/.prettierignore @@ -9,3 +9,6 @@ pnpm-lock.yaml **/translations.json /CHANGELOG.md + +# markdown round trip fixtures, formatting is part of the test +packages/web-pkg/tests/unit/editor/strategies/fixtures/ diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/basics.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/basics.md new file mode 100644 index 00000000000..f0700b5a63b --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/basics.md @@ -0,0 +1,45 @@ +--- +title: Fixtures +tags: [a, b] +--- + +# Heading 1 + +## Heading 2 + +Setext heading +============== + +Text with *emphasis*, __strong__, ~~strike~~, `code` and a [link](https://opencloud.eu "title"). +A second line with a hard break +after it. + +![image](https://opencloud.eu/logo.png) + +> A quote +> with two lines +> +> > nested + +*** + +* bullet +* list + + nested + +1. ordered +2. list + +- [ ] open task +- [x] done task + +| left | center | right | +|:-----|:------:|------:| +| a | b | c | +| `d` | **e** | [f](#f) | + +```js +const x = 1 +``` + + indented code diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/blockquote-alert.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/blockquote-alert.md new file mode 100644 index 00000000000..d1adbf20db6 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/blockquote-alert.md @@ -0,0 +1,2 @@ +> [!NOTE] +> hint diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/blockquote-escaped-alert-marker.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/blockquote-escaped-alert-marker.md new file mode 100644 index 00000000000..19572458657 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/blockquote-escaped-alert-marker.md @@ -0,0 +1,3 @@ +> \[!NOTE\](x) text + +> \[!NOTE\] text diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-1-space.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-1-space.md new file mode 100644 index 00000000000..411b8e433ed --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-1-space.md @@ -0,0 +1,3 @@ + ``` + code + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-2-spaces.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-2-spaces.md new file mode 100644 index 00000000000..5e60169b8dd --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-2-spaces.md @@ -0,0 +1,4 @@ + ``` + code + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-indented-fence-after-list.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-indented-fence-after-list.md new file mode 100644 index 00000000000..5f313633e6e --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-indented-fence-after-list.md @@ -0,0 +1,4 @@ +- a + ``` + code + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-asterisk-markers.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-asterisk-markers.md new file mode 100644 index 00000000000..6e62dbbbd71 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-asterisk-markers.md @@ -0,0 +1,2 @@ +* a +* b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-blockquote-in-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-blockquote-in-item.md new file mode 100644 index 00000000000..e849f382df5 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-blockquote-in-item.md @@ -0,0 +1,2 @@ +- > quote +- b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-ordered-sub-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-ordered-sub-item.md new file mode 100644 index 00000000000..89f20ffefdb --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-ordered-sub-item.md @@ -0,0 +1,3 @@ +- a + 1. + 2. b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-in-blockquote.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-in-blockquote.md new file mode 100644 index 00000000000..a2737f15f5b --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-in-blockquote.md @@ -0,0 +1 @@ +> - diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-with-sub-list.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-with-sub-list.md new file mode 100644 index 00000000000..e3fa9edf40e --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-with-sub-list.md @@ -0,0 +1,2 @@ +- + - x diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item.md new file mode 100644 index 00000000000..277cc02ff38 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item.md @@ -0,0 +1 @@ +- diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-items.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-items.md new file mode 100644 index 00000000000..5f6fb46afc1 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-items.md @@ -0,0 +1,6 @@ +- a +- +- b + +1. +2. b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-sub-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-sub-item.md new file mode 100644 index 00000000000..97166cee15d --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-sub-item.md @@ -0,0 +1,3 @@ +- a + - b + - diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-item-with-children.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-item-with-children.md new file mode 100644 index 00000000000..42fc0293dc8 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-item-with-children.md @@ -0,0 +1,8 @@ +- Parent + -   + - x + - c + +- a + -   + - x diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-items.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-items.md new file mode 100644 index 00000000000..52848f45658 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-items.md @@ -0,0 +1,9 @@ +- Parent + -   + - c +- Next + +1. Parent + -   + - c +2. Next diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-escaped-lines-in-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-escaped-lines-in-item.md new file mode 100644 index 00000000000..07111fc775b --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-escaped-lines-in-item.md @@ -0,0 +1,3 @@ +- a + 2\. b + Dr\. Smith diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-below-empty-marker.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-below-empty-marker.md new file mode 100644 index 00000000000..b4002e586ad --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-below-empty-marker.md @@ -0,0 +1,3 @@ +- + # Title +- b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-item.md new file mode 100644 index 00000000000..f8828005764 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-item.md @@ -0,0 +1,2 @@ +- # Title +- b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-letter-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-letter-item.md new file mode 100644 index 00000000000..e3f695da801 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-letter-item.md @@ -0,0 +1,3 @@ +a. + # Title +b. y diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-ordered-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-ordered-item.md new file mode 100644 index 00000000000..999d5473b68 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-ordered-item.md @@ -0,0 +1,2 @@ +1. # Title +2. b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-image-after-text.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-image-after-text.md new file mode 100644 index 00000000000..54505d88a26 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-image-after-text.md @@ -0,0 +1,3 @@ +- a + + ![a](http://x/a.png) diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-image-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-image-item.md new file mode 100644 index 00000000000..de5a22e343d --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-image-item.md @@ -0,0 +1,6 @@ +- ![a](http://x/a.png) + - sub +- a +- ![b](http://x/b.png) + +1. ![c](http://x/c.png) diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-letters-empty-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-letters-empty-item.md new file mode 100644 index 00000000000..32b023b4387 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-letters-empty-item.md @@ -0,0 +1,3 @@ +a. one +b. +c. three diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-literal-nbsp.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-literal-nbsp.md new file mode 100644 index 00000000000..dd5e7126b32 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-literal-nbsp.md @@ -0,0 +1,5 @@ +- &nbsp; + - x + +a. &nbsp; +b. two diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-lowercase-letters.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-lowercase-letters.md new file mode 100644 index 00000000000..dfe6e687154 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-lowercase-letters.md @@ -0,0 +1,2 @@ +a. one +b. two diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-lowercase-roman-numerals.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-lowercase-roman-numerals.md new file mode 100644 index 00000000000..f76c059dc72 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-lowercase-roman-numerals.md @@ -0,0 +1,2 @@ +i. one +ii. two diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-content-indented-2-spaces.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-content-indented-2-spaces.md new file mode 100644 index 00000000000..12e4ed6d881 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-content-indented-2-spaces.md @@ -0,0 +1,3 @@ +1. a + + more diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-continuation-line.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-continuation-line.md new file mode 100644 index 00000000000..b19caf123f8 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-continuation-line.md @@ -0,0 +1,2 @@ +1. a + b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.md new file mode 100644 index 00000000000..97ac8afb947 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.md @@ -0,0 +1,2 @@ +1. a + 12345678901\. b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned-nested.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned-nested.md new file mode 100644 index 00000000000..0ac87d87dab --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned-nested.md @@ -0,0 +1,12 @@ +1. parent + 1. item 1 + 2. item 2 + 3. item 3 + 4. item 4 + 5. item 5 + 6. item 6 + 7. item 7 + 8. item 8 + 9. item 9 + 10. item 10 +2. next diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned.md new file mode 100644 index 00000000000..ff75b2278ad --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned.md @@ -0,0 +1,10 @@ + 1. item 1 + 2. item 2 + 3. item 3 + 4. item 4 + 5. item 5 + 6. item 6 + 7. item 7 + 8. item 8 + 9. item 9 +10. item 10 diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-start-number.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-start-number.md new file mode 100644 index 00000000000..b2df56582c9 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-start-number.md @@ -0,0 +1,2 @@ +3. a +4. b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-code-block.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-code-block.md new file mode 100644 index 00000000000..63ad90fe3fe --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-code-block.md @@ -0,0 +1,4 @@ +1. ``` + x + ``` + *em* [l](http://x) diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-heading.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-heading.md new file mode 100644 index 00000000000..8feaba1b2aa --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-heading.md @@ -0,0 +1,2 @@ +- # Title + [l](http://x) **b** y diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-uppercase-letters.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-uppercase-letters.md new file mode 100644 index 00000000000..266a343b194 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-uppercase-letters.md @@ -0,0 +1,2 @@ +A. one +B. two diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-uppercase-roman-numerals.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-uppercase-roman-numerals.md new file mode 100644 index 00000000000..d5c0838e470 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-uppercase-roman-numerals.md @@ -0,0 +1,2 @@ +I. one +II. two diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-escaped-block-syntax.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-escaped-block-syntax.md new file mode 100644 index 00000000000..921af594ea6 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-escaped-block-syntax.md @@ -0,0 +1,20 @@ +1\. May + +1\) May + +\- not a list + +\+ not a list + +\# not a heading + +2026\. was a year + +A\. Müller + +I\. Introduction + +i\. e. something + +Title +\=== diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-indented-lines.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-indented-lines.md new file mode 100644 index 00000000000..9b68f00a5a0 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-indented-lines.md @@ -0,0 +1,7 @@ + x paragraph + +a + b + +a + b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-soft-line-breaks.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-soft-line-breaks.md new file mode 100644 index 00000000000..5bd61f9695a --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-soft-line-breaks.md @@ -0,0 +1,4 @@ +Hi +Mr. Smith +2. Liga +1\. one diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-text-like-block-syntax.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-text-like-block-syntax.md new file mode 100644 index 00000000000..a6ab441aa4f --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-text-like-block-syntax.md @@ -0,0 +1,7 @@ +#hashtag + ++1 + +-5 degrees + +1.5 liters diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/table-block-syntax-in-cells.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/table-block-syntax-in-cells.md new file mode 100644 index 00000000000..64c69347766 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/table-block-syntax-in-cells.md @@ -0,0 +1,3 @@ +| a | b | +|---|---| +| - | 1. x | diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-bullet-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-bullet-item.md new file mode 100644 index 00000000000..73515bd2339 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-bullet-item.md @@ -0,0 +1,6 @@ +- [ ] a + - b + + ``` + code + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-ordered-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-ordered-item.md new file mode 100644 index 00000000000..2c4f273200c --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-ordered-item.md @@ -0,0 +1,6 @@ +- [ ] a + 1. b + + ```js + code + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-nested-tab-indented.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-nested-tab-indented.md new file mode 100644 index 00000000000..1fbd5aa881c --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-nested-tab-indented.md @@ -0,0 +1,6 @@ +- [ ] a + - [ ] b + ``` + code + indented + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented-after-blank-line.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented-after-blank-line.md new file mode 100644 index 00000000000..7cedc26debe --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented-after-blank-line.md @@ -0,0 +1,8 @@ +- [ ] a + + ``` + code + ``` +- [ ] b + +after diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented.md new file mode 100644 index 00000000000..cefe8c110eb --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented.md @@ -0,0 +1,4 @@ +- [ ] a + ```js + const x = 1 + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tilde-with-tabs-after-nested-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tilde-with-tabs-after-nested-item.md new file mode 100644 index 00000000000..2feb5f79552 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tilde-with-tabs-after-nested-item.md @@ -0,0 +1,6 @@ +- [ ] a + - [ ] b + + ~~~ + x + ~~~ diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-blank-line.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-blank-line.md new file mode 100644 index 00000000000..a1256759439 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-blank-line.md @@ -0,0 +1,6 @@ +- [ ] run + + ```make + build: + go build + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-nested-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-nested-item.md new file mode 100644 index 00000000000..52ba58278c8 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-nested-item.md @@ -0,0 +1,5 @@ +- [ ] a + - [ ] b + ``` + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-three-levels.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-three-levels.md new file mode 100644 index 00000000000..eee6a5b731b --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-three-levels.md @@ -0,0 +1,7 @@ +- [ ] a + - [ ] b + - [ ] c + + ``` + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs.md new file mode 100644 index 00000000000..28ffea5a22b --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs.md @@ -0,0 +1,5 @@ +- [ ] run + ```make + build: + go build + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-task-syntax.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-task-syntax.md new file mode 100644 index 00000000000..6dcfb04c3a4 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-task-syntax.md @@ -0,0 +1,7 @@ +- [ ] a + ```md + - [ ] example + more text + - [ ] nested example + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-after-nested-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-after-nested-item.md new file mode 100644 index 00000000000..b84382c3aaa --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-after-nested-item.md @@ -0,0 +1,4 @@ +- [ ] a + - [ ] b + + x diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-tab-and-spaces.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-tab-and-spaces.md new file mode 100644 index 00000000000..7dc0886fb42 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-tab-and-spaces.md @@ -0,0 +1,3 @@ +- [ ] a + + x diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-with-tabs.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-with-tabs.md new file mode 100644 index 00000000000..579a088e11f --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-with-tabs.md @@ -0,0 +1,3 @@ +- [ ] a + + x diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-nested-item-tab-indented.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-nested-item-tab-indented.md new file mode 100644 index 00000000000..3d7df7b81bf --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-nested-item-tab-indented.md @@ -0,0 +1,2 @@ +- [ ] a + - [ ] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts new file mode 100644 index 00000000000..76e6ed4c17e --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts @@ -0,0 +1,132 @@ +import { readdirSync, readFileSync } from 'node:fs' +import { join } from 'node:path' +import { ref } from 'vue' +import { Editor } from '@tiptap/vue-3' +import { Marked } from 'marked' +import { createTestingPinia } from '@opencloud-eu/web-test-helpers' +import { useStrategyMarkdown } from '../../../../src/editor/composables/strategies/markdown' +import { registerMarkdownListTokenizer } from '../../../../src/editor/extensions' +import type { TextEditorLinkPanelRequest, TextEditorState } from '../../../../src/editor/types' + +vi.mock('vue3-gettext', () => ({ + useGettext: () => ({ $gettext: (text: string) => text }) +})) + +const fixturesDir = join(import.meta.dirname, 'fixtures', 'markdown') + +function loadFixtures(dir: string): [string, string][] { + return readdirSync(dir) + .filter((name) => name.endsWith('.md')) + .sort() + .map((name) => { + const markdown = readFileSync(join(dir, name), 'utf8') + // an empty fixture would pass silently + if (!markdown.trim()) { + throw new Error(`Empty fixture ${name}`) + } + return [name, markdown] + }) +} + +function save(markdown: string): string { + const state: TextEditorState = { + sourceMode: ref(false), + linkPanel: ref(null), + editorZoom: ref(100) + } + const strategy = useStrategyMarkdown(state) + const editor = new Editor({ + extensions: strategy.extensions(), + content: strategy.deserialize(markdown), + contentType: 'markdown' + }) + expect(() => editor.state.doc.check()).not.toThrow() + const saved = strategy.serialize(editor.state.doc) + editor.destroy() + return saved +} + +// Reference renderer for both the original and the saved markdown. The list tokenizer +// makes marked read a lone `- ` as an empty item, as CommonMark does. Since the editor +// uses the same tokenizer, empty items need inline tests with exact output. +// The render check is weak where marked differs from the editor, which needs inline +// tests as well: marked reads letter or roman lists and frontmatter as paragraphs, +// expands tabs in list items to spaces, and normalize() folds nbsp into a space. +const marked = new Marked() +registerMarkdownListTokenizer(marked) + +const blockTagPattern = /^(BLOCKQUOTE|H[1-6]|HR|OL|P|PRE|TABLE|UL)$/ + +/** + * Wraps the inline content of tight list items into paragraphs, since the editor + * does not keep lists tight or loose. + */ +function wrapListItemContent(item: Element) { + let paragraph: HTMLParagraphElement | null = null + for (const child of Array.from(item.childNodes)) { + if (child instanceof Element && blockTagPattern.test(child.tagName)) { + paragraph = null + continue + } + if (!paragraph) { + paragraph = document.createElement('p') + item.insertBefore(paragraph, child) + } + paragraph.appendChild(child) + } +} + +/** + * Removes differences that do not change what a reader sees: whitespace, tight or + * loose lists, and the " " the editor writes into empty list items. + */ +function normalize(html: string): string { + const template = document.createElement('template') + template.innerHTML = html + const root = template.content + + root + .querySelectorAll('li > input[type="checkbox"], li > p:first-child > input') + .forEach((input) => { + const checkbox = input as HTMLInputElement + checkbox.closest('li').dataset.task = checkbox.checked ? 'done' : 'open' + checkbox.remove() + }) + root.querySelectorAll('li').forEach(wrapListItemContent) + + const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT) + for (let node = walker.nextNode(); node; node = walker.nextNode()) { + if (!node.parentElement?.closest('code, pre')) { + node.textContent = node.textContent.replace(/\s+/g, ' ') + } + } + + // one tag per line for readable diffs + return template.innerHTML + .replace( + /\s*(<\/?(?:blockquote|br|h[1-6]|hr|li|ol|p|pre|table|thead|tbody|tr|td|th|ul)\b[^>]*>)\s*/g, + '$1\n' + ) + .replace(/

\n<\/p>\n/g, '') +} + +function render(markdown: string): string { + return normalize(marked.parse(markdown) as string) +} + +function expectRoundtrip(markdown: string) { + const saved = save(markdown) + + expect(render(saved), saved).toBe(render(markdown)) + expect(save(saved)).toBe(saved) +} + +describe('markdown fixture roundtrip', () => { + beforeEach(() => { + createTestingPinia() + }) + + it.each(loadFixtures(fixturesDir))('keeps %s', (_, markdown) => { + expectRoundtrip(markdown) + }) +}) From 289fbbbc77eecfd4144a1c78560379cca1e9bb8c Mon Sep 17 00:00:00 2001 From: Jannik Stehle Date: Fri, 9 Oct 2026 10:30:33 +0200 Subject: [PATCH 3/6] test(web-pkg): drop inline markdown round trip tests covered by fixtures --- .../markdown/list-item-escaped-marker.md | 1 + .../fixtures/markdown/list-literal-nbsp.md | 4 + .../list-ordered-item-escaped-line.md | 8 ++ .../strategies/markdownListRoundtrip.spec.ts | 87 ----------------- .../markdownParagraphRoundtrip.spec.ts | 18 ---- .../markdownTaskListRoundtrip.spec.ts | 93 ++++++++----------- 6 files changed, 50 insertions(+), 161 deletions(-) create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-item-escaped-marker.md diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-item-escaped-marker.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-item-escaped-marker.md new file mode 100644 index 00000000000..0aa893e59ad --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-item-escaped-marker.md @@ -0,0 +1 @@ +1. \- diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-literal-nbsp.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-literal-nbsp.md index dd5e7126b32..527d43f20ff 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-literal-nbsp.md +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-literal-nbsp.md @@ -1,3 +1,7 @@ +- &nbsp; + +text + - &nbsp; - x diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.md index 97ac8afb947..3de17495c2d 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.md +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.md @@ -1,2 +1,10 @@ 1. a 12345678901\. b +2. a + B\. b +3. a + 2\. b +4. a + \- b +5. a + \# b diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts index 4324414ebac..a5a40795ae0 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts @@ -135,46 +135,6 @@ describe('markdown list roundtrip', () => { } ) - it.each([ - '- # Title\n [l](http://x) **b** y\n', - '1. ```\n x\n ```\n *em* [l](http://x)\n' - ])('keeps the inline formatting of text after a block in %j', (markdown) => { - const { editor, serialized } = expectStableRoundtrip(markdown) - - expect(serialized).not.toContain('\\') - const marks = toJSON(editor) - .content[0].content[0].content.at(-1) - .content.flatMap(({ marks = [] }) => marks.map(({ type }) => type)) - expect(marks).toContain('link') - }) - - it.each(['- &nbsp;\n', '- &nbsp;\n - x\n', 'a. &nbsp;\nb. two\n'])( - 'keeps the literal text " " in %j', - (markdown) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(toJSON(editor).content[0].content[0].content[0]).toEqual({ - type: 'paragraph', - content: [{ type: 'text', text: ' ' }] - }) - } - ) - - it.each([ - ['- ![a](http://x/a.png)\n', '- ![a](http://x/a.png)'], - ['- a\n- ![a](http://x/a.png)\n', '- a\n- ![a](http://x/a.png)'], - ['1. ![a](http://x/a.png)\n', '1. ![a](http://x/a.png)'], - ['- ![a](http://x/a.png)\n - sub\n', '- ![a](http://x/a.png)\n - sub'], - ['- a\n\n ![a](http://x/a.png)\n', '- a\n\n ![a](http://x/a.png)'] - ])('keeps the image in %j', (markdown, expected) => { - const { editor, serialized } = expectStableRoundtrip(markdown) - - expect(serialized).toBe(expected) - expect(toJSON(editor).content[0].content.at(-1).content).toContainEqual( - expect.objectContaining({ type: 'image' }) - ) - }) - it.each([ ['- \n', '-'], ['- \n- b\n', '-\n- b'], @@ -224,32 +184,12 @@ describe('markdown list roundtrip', () => { expect(editor.getText()).toContain('[x] b') }) - const rightAligned = Array.from( - { length: 10 }, - (_, index) => `${String(index + 1).padStart(2)}. item ${index + 1}` - ).join('\n') - - it('keeps every item of a right aligned list', () => { - const { editor } = expectStableRoundtrip(`${rightAligned}\n`) - - const [list] = toJSON(editor).content - expect(list.type).toBe('orderedList') - expect(list.content).toHaveLength(10) - expect(list.content[9].content[0].content[0].text).toBe('item 10') - }) - it('starts a list numbered from 0 at 1', () => { const { editor } = expectStableRoundtrip('0. a\n1. b\n') expect(toJSON(editor).content[0].attrs.start).toBe(1) }) - it('keeps the start number', () => { - const { editor } = expectStableRoundtrip('3. a\n4. b\n') - - expect(toJSON(editor).content[0]).toMatchObject({ type: 'orderedList', attrs: { start: 3 } }) - }) - it.each([ ['a', 'a. one\nb. two'], ['A', 'A. one\nB. two'], @@ -279,32 +219,5 @@ describe('markdown list roundtrip', () => { ] }) }) - - it('keeps every item of a right aligned nested list', () => { - const nested = rightAligned - .split('\n') - .map((line) => ` ${line}`) - .join('\n') - const { editor } = expectStableRoundtrip(`1. parent\n${nested}\n2. next\n`) - - const [list] = toJSON(editor).content - expect(list.content).toHaveLength(2) - expect(list.content[0].content[1].type).toBe('orderedList') - expect(list.content[0].content[1].content).toHaveLength(10) - }) - }) - - describe('task lists', () => { - it.each([ - ['a bullet', '- [ ] a\n - b\n\n ```\n code\n ```\n', 'bulletList'], - ['an ordered', '- [ ] a\n 1. b\n\n ```js\n code\n ```\n', 'orderedList'] - ])('keeps a code block in %s list item in a task item', (_, markdown, type) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(toJSON(editor).content[0].content[0].content[1]).toMatchObject({ - type, - content: [{ type: 'listItem', content: [{ type: 'paragraph' }, { type: 'codeBlock' }] }] - }) - }) }) }) diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts index 875135c0904..e49bc5641fc 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts @@ -121,16 +121,6 @@ describe('markdown paragraph roundtrip', () => { expect(serialized).toContain('| - | 1. x |') }) - it('keeps escaped list markers as text', () => { - const { editor } = expectStableRoundtrip('\\- dash\n\n1\\. text\n\n1. \\-\n') - - expect(toJSON(editor).content.map(({ type }) => type)).toEqual([ - 'paragraph', - 'paragraph', - 'orderedList' - ]) - }) - it('keeps an alert marker in a blockquote', () => { const { serialized } = expectStableRoundtrip('> [!NOTE]\n> hint\n') @@ -176,15 +166,7 @@ describe('markdown paragraph roundtrip', () => { ]) }) - it('escapes ordered list markers after a soft line break', () => { - const { editor, serialized } = expectStableRoundtrip('- a\n 2\\. b\n Dr\\. Smith\n') - - expect(serialized).toBe('- a\n2\\. b\nDr\\. Smith') - expect(toJSON(editor).content[0].content).toHaveLength(1) - }) - it.each([ - ['12345678901. b', '12345678901\\. b'], ['B.\u00a0b', 'B\\.\u00a0b'], ['2.\u00a0b', '2\\.\u00a0b'], ['-\u00a0b', '\\-\u00a0b'], diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts index 514ab86413f..2a441baa139 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts @@ -61,14 +61,11 @@ describe('markdown task list and code block roundtrip', () => { }) describe('code blocks', () => { - it.each([ - [' ```\n code\n ```\n', 'code'], - [' ~~~\n code\n x\n ~~~\n', ' code\n x'], - ['- a\n ```\n code\n ```\n', 'code'] - ])('keeps the indented code block %j', (markdown, code) => { - const { editor } = expectStableRoundtrip(markdown) + // marked keeps the indentation of tilde fenced code, so no fixture + it('keeps the code of an indented tilde fence', () => { + const { editor } = expectStableRoundtrip(' ~~~\n code\n x\n ~~~\n') - expect(codeBlockTexts(toJSON(editor))).toEqual([code]) + expect(codeBlockTexts(toJSON(editor))).toEqual([' code\n x']) }) }) @@ -110,16 +107,14 @@ describe('markdown task list and code block roundtrip', () => { }) }) - it.each([ - ['a paragraph', '- [ ] a\n\tb\n', 'paragraph'], - ['a task item', '- [ ] a\n\t- [ ] b\n', 'taskList'] - ])('keeps a tab indented line as %s in the task item', (_, markdown, type) => { - const { editor } = expectStableRoundtrip(markdown) + it('keeps a tab indented line as a paragraph in the task item', () => { + const { editor } = expectStableRoundtrip('- [ ] a\n\tb\n') expect(toJSON(editor).content).toHaveLength(1) - expect(toJSON(editor).content[0].content[0].content[1]).toMatchObject({ type }) + expect(toJSON(editor).content[0].content[0].content[1]).toMatchObject({ type: 'paragraph' }) }) + // The fixtures cannot guard these: marked expands tabs in list items to spaces it.each([ ['directly below the item', '- [ ] run\n ```make\n build:\n \tgo build\n ```\n'], ['after a blank line', '- [ ] run\n\n ```make\n build:\n \tgo build\n ```\n'] @@ -134,49 +129,35 @@ describe('markdown task list and code block roundtrip', () => { }) it.each([ - ['without a blank line', '- [ ] a\n - [ ] b\n ```\n \tx\n ```\n'], - ['with a tilde fence', '- [ ] a\n - [ ] b\n\n ~~~\n \tx\n ~~~\n'], - ['three levels deep', '- [ ] a\n - [ ] b\n - [ ] c\n\n ```\n \tx\n ```\n'] - ])('keeps tabs in a code block after a nested task item %s', (_, markdown) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(codeBlockTexts(toJSON(editor))).toEqual(['\tx']) - }) - - it('keeps a code block after a nested task item in the outer item', () => { - const { editor } = expectStableRoundtrip('- [ ] a\n - [ ] b\n ```\n x\n ```\n') - - expect(toJSON(editor).content[0].content[0].content.map(({ type }) => type)).toEqual([ - 'paragraph', - 'taskList', - 'codeBlock' - ]) - }) - - it.each([ - ['- [ ] a\n ```md\n - [ ] example\n more text\n ```\n', '- [ ] example\nmore text'], - ['- [ ] a\n ```md\n - [ ] nested example\n \tx\n ```\n', ' - [ ] nested example\n\tx'] - ])('keeps task item syntax in a code block %j as code', (markdown, code) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(codeBlockTexts(toJSON(editor))).toEqual([code]) - }) - - it.each([ - ['- [ ] a\n\t```js\n\tconst x = 1\n\t```\n', 'const x = 1'], - ['- [ ] a\n\n\t```\n\tcode\n\t```\n- [ ] b\n\nafter\n', 'code'], - ['- [ ] a\n\t- [ ] b\n\t\t```\n\t\tcode\n\t\t\tindented\n\t\t```\n', 'code\n\tindented'] - ])('keeps a tab indented code block %j in a task item', (markdown, code) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(codeBlockTexts(toJSON(editor))).toEqual([code]) - }) - - it.each([ - ['- [ ] a\n\n \tx\n', '\tx'], - ['- [ ] a\n\n \t\tx\n', '\tx'], - ['- [ ] a\n - [ ] b\n\n \tx\n', '\tx'] - ])('keeps tabs in the indented code block %j in a task item', (markdown, code) => { + ['after a nested item', '- [ ] a\n - [ ] b\n ```\n \tx\n ```\n', '\tx'], + [ + 'in a tilde fence after a nested item', + '- [ ] a\n - [ ] b\n\n ~~~\n \tx\n ~~~\n', + '\tx' + ], + [ + 'three levels deep', + '- [ ] a\n - [ ] b\n - [ ] c\n\n ```\n \tx\n ```\n', + '\tx' + ], + [ + 'with task item syntax', + '- [ ] a\n ```md\n - [ ] nested example\n \tx\n ```\n', + ' - [ ] nested example\n\tx' + ], + [ + 'with a tab indented fence', + '- [ ] a\n\t- [ ] b\n\t\t```\n\t\tcode\n\t\t\tindented\n\t\t```\n', + 'code\n\tindented' + ], + ['in an indented code block', '- [ ] a\n\n \tx\n', '\tx'], + ['in a tab indented code block', '- [ ] a\n\n \t\tx\n', '\tx'], + [ + 'in an indented code block after a nested item', + '- [ ] a\n - [ ] b\n\n \tx\n', + '\tx' + ] + ])('keeps tabs in a code block in a task item %s', (_, markdown, code) => { const { editor } = expectStableRoundtrip(markdown) expect(codeBlockTexts(toJSON(editor))).toEqual([code]) From 6088030047fa9216d7e4e42df7be2f2d8b9a3fbb Mon Sep 17 00:00:00 2001 From: Jannik Stehle Date: Fri, 9 Oct 2026 10:43:53 +0200 Subject: [PATCH 4/6] test(web-pkg): share markdown round trip test helpers --- .../tests/unit/editor/strategies/helpers.ts | 58 +++++++++++++++++++ .../strategies/markdownFixtures.spec.ts | 25 ++------ .../strategies/markdownListRoundtrip.spec.ts | 49 ++-------------- .../strategies/markdownMarkedInstance.spec.ts | 13 +---- .../markdownParagraphRoundtrip.spec.ts | 56 ++++-------------- .../markdownTaskListRoundtrip.spec.ts | 48 ++------------- 6 files changed, 87 insertions(+), 162 deletions(-) create mode 100644 packages/web-pkg/tests/unit/editor/strategies/helpers.ts diff --git a/packages/web-pkg/tests/unit/editor/strategies/helpers.ts b/packages/web-pkg/tests/unit/editor/strategies/helpers.ts new file mode 100644 index 00000000000..86d4459a20c --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/helpers.ts @@ -0,0 +1,58 @@ +import { expect } from 'vitest' +import { ref } from 'vue' +import { Editor } from '@tiptap/vue-3' +import type { JSONContent } from '@tiptap/core' +import { useStrategyMarkdown } from '../../../../src/editor/composables/strategies/markdown' +import type { TextEditorLinkPanelRequest, TextEditorState } from '../../../../src/editor/types' +import type { ContentTypeStrategy } from '../../../../src/editor/composables/strategies/types' + +export function createStrategy(): ContentTypeStrategy { + const state: TextEditorState = { + sourceMode: ref(false), + linkPanel: ref(null), + editorZoom: ref(100) + } + return useStrategyMarkdown(state) +} + +const editors: Editor[] = [] + +export function createEditor(strategy: ContentTypeStrategy, content: string): Editor { + const editor = new Editor({ + extensions: strategy.extensions(), + content: strategy.deserialize(content), + contentType: 'markdown' + }) + editors.push(editor) + return editor +} + +export function destroyEditors(): void { + editors.splice(0).forEach((editor) => editor.destroy()) +} + +export function toJSON(editor: Editor): JSONContent { + return editor.getJSON() as JSONContent +} + +export interface LoadedMarkdown { + editor: Editor + serialized: string +} + +export function load(markdown: string): LoadedMarkdown { + const strategy = createStrategy() + const editor = createEditor(strategy, markdown) + return { editor, serialized: strategy.serialize(editor.state.doc) } +} + +export function expectStableRoundtrip(markdown: string): LoadedMarkdown { + const { editor, serialized } = load(markdown) + expect(() => editor.state.doc.check()).not.toThrow() + + const reloaded = load(serialized) + expect(() => reloaded.editor.state.doc.check()).not.toThrow() + expect(toJSON(reloaded.editor)).toEqual(toJSON(editor)) + + return { editor, serialized } +} diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts index 76e6ed4c17e..82e33984044 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts @@ -1,12 +1,9 @@ import { readdirSync, readFileSync } from 'node:fs' import { join } from 'node:path' -import { ref } from 'vue' -import { Editor } from '@tiptap/vue-3' import { Marked } from 'marked' import { createTestingPinia } from '@opencloud-eu/web-test-helpers' -import { useStrategyMarkdown } from '../../../../src/editor/composables/strategies/markdown' import { registerMarkdownListTokenizer } from '../../../../src/editor/extensions' -import type { TextEditorLinkPanelRequest, TextEditorState } from '../../../../src/editor/types' +import { destroyEditors, expectStableRoundtrip } from './helpers' vi.mock('vue3-gettext', () => ({ useGettext: () => ({ $gettext: (text: string) => text }) @@ -29,21 +26,7 @@ function loadFixtures(dir: string): [string, string][] { } function save(markdown: string): string { - const state: TextEditorState = { - sourceMode: ref(false), - linkPanel: ref(null), - editorZoom: ref(100) - } - const strategy = useStrategyMarkdown(state) - const editor = new Editor({ - extensions: strategy.extensions(), - content: strategy.deserialize(markdown), - contentType: 'markdown' - }) - expect(() => editor.state.doc.check()).not.toThrow() - const saved = strategy.serialize(editor.state.doc) - editor.destroy() - return saved + return expectStableRoundtrip(markdown).serialized } // Reference renderer for both the original and the saved markdown. The list tokenizer @@ -126,6 +109,10 @@ describe('markdown fixture roundtrip', () => { createTestingPinia() }) + afterEach(() => { + destroyEditors() + }) + it.each(loadFixtures(fixturesDir))('keeps %s', (_, markdown) => { expectRoundtrip(markdown) }) diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts index a5a40795ae0..e4762032c54 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts @@ -1,58 +1,19 @@ -import { ref } from 'vue' -import { Editor } from '@tiptap/vue-3' -import type { JSONContent } from '@tiptap/core' import { createTestingPinia } from '@opencloud-eu/web-test-helpers' -import { useStrategyMarkdown } from '../../../../src/editor/composables/strategies/markdown' -import type { TextEditorLinkPanelRequest, TextEditorState } from '../../../../src/editor/types' -import type { ContentTypeStrategy } from '../../../../src/editor/composables/strategies/types' +import { toJSON, load, expectStableRoundtrip, destroyEditors } from './helpers' vi.mock('vue3-gettext', () => ({ useGettext: () => ({ $gettext: (text: string) => text }) })) -function createStrategy(): ContentTypeStrategy { - const state: TextEditorState = { - sourceMode: ref(false), - linkPanel: ref(null), - editorZoom: ref(100) - } - return useStrategyMarkdown(state) -} - -function createEditor(strategy: ContentTypeStrategy, content: string): Editor { - return new Editor({ - extensions: strategy.extensions(), - content: strategy.deserialize(content), - contentType: 'markdown' - }) -} - -function toJSON(editor: Editor): JSONContent { - return editor.getJSON() as JSONContent -} - -function load(markdown: string) { - const strategy = createStrategy() - const editor = createEditor(strategy, markdown) - return { editor, serialized: strategy.serialize(editor.state.doc) } -} - -function expectStableRoundtrip(markdown: string) { - const { editor, serialized } = load(markdown) - expect(() => editor.state.doc.check()).not.toThrow() - - const reloaded = load(serialized) - expect(() => reloaded.editor.state.doc.check()).not.toThrow() - expect(toJSON(reloaded.editor)).toEqual(toJSON(editor)) - - return { editor, serialized } -} - describe('markdown list roundtrip', () => { beforeEach(() => { createTestingPinia() }) + afterEach(() => { + destroyEditors() + }) + describe('list items', () => { it('keeps the parent of an empty sub item', () => { const { editor, serialized } = expectStableRoundtrip('- Parent\n - \n- Next\n') diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownMarkedInstance.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownMarkedInstance.spec.ts index 2e283acdb1e..bc71fd8dbce 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownMarkedInstance.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownMarkedInstance.spec.ts @@ -1,23 +1,12 @@ -import { ref } from 'vue' import { Editor } from '@tiptap/vue-3' import { MarkdownManager } from '@tiptap/markdown' import { createTestingPinia } from '@opencloud-eu/web-test-helpers' -import { useStrategyMarkdown } from '../../../../src/editor/composables/strategies/markdown' -import type { TextEditorLinkPanelRequest, TextEditorState } from '../../../../src/editor/types' +import { createStrategy } from './helpers' vi.mock('vue3-gettext', () => ({ useGettext: () => ({ $gettext: (text: string) => text }) })) -function createStrategy() { - const state: TextEditorState = { - sourceMode: ref(false), - linkPanel: ref(null), - editorZoom: ref(100) - } - return useStrategyMarkdown(state) -} - /** * How many block tokenizers marked's process wide singleton carries. Every * `MarkdownManager` appends its extensions' tokenizers to whichever instance it diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts index e49bc5641fc..8bee1aba0f5 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts @@ -1,53 +1,17 @@ -import { ref } from 'vue' -import { Editor } from '@tiptap/vue-3' -import type { JSONContent } from '@tiptap/core' import { createTestingPinia } from '@opencloud-eu/web-test-helpers' -import { useStrategyMarkdown } from '../../../../src/editor/composables/strategies/markdown' -import type { TextEditorLinkPanelRequest, TextEditorState } from '../../../../src/editor/types' -import type { ContentTypeStrategy } from '../../../../src/editor/composables/strategies/types' +import { + createStrategy, + createEditor, + toJSON, + load, + expectStableRoundtrip, + destroyEditors +} from './helpers' vi.mock('vue3-gettext', () => ({ useGettext: () => ({ $gettext: (text: string) => text }) })) -function createStrategy(): ContentTypeStrategy { - const state: TextEditorState = { - sourceMode: ref(false), - linkPanel: ref(null), - editorZoom: ref(100) - } - return useStrategyMarkdown(state) -} - -function createEditor(strategy: ContentTypeStrategy, content: string): Editor { - return new Editor({ - extensions: strategy.extensions(), - content: strategy.deserialize(content), - contentType: 'markdown' - }) -} - -function toJSON(editor: Editor): JSONContent { - return editor.getJSON() as JSONContent -} - -function load(markdown: string) { - const strategy = createStrategy() - const editor = createEditor(strategy, markdown) - return { editor, serialized: strategy.serialize(editor.state.doc) } -} - -function expectStableRoundtrip(markdown: string) { - const { editor, serialized } = load(markdown) - expect(() => editor.state.doc.check()).not.toThrow() - - const reloaded = load(serialized) - expect(() => reloaded.editor.state.doc.check()).not.toThrow() - expect(toJSON(reloaded.editor)).toEqual(toJSON(editor)) - - return { editor, serialized } -} - function serializeParagraph(text: string): string { const strategy = createStrategy() const editor = createEditor(strategy, '') @@ -63,6 +27,10 @@ describe('markdown paragraph roundtrip', () => { createTestingPinia() }) + afterEach(() => { + destroyEditors() + }) + describe('paragraphs', () => { it.each([ ['- not a list', '\\- not a list'], diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts index 2a441baa139..0fe7c9ed558 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts @@ -1,53 +1,11 @@ -import { ref } from 'vue' -import { Editor } from '@tiptap/vue-3' import type { JSONContent } from '@tiptap/core' import { createTestingPinia } from '@opencloud-eu/web-test-helpers' -import { useStrategyMarkdown } from '../../../../src/editor/composables/strategies/markdown' -import type { TextEditorLinkPanelRequest, TextEditorState } from '../../../../src/editor/types' -import type { ContentTypeStrategy } from '../../../../src/editor/composables/strategies/types' +import { toJSON, expectStableRoundtrip, destroyEditors } from './helpers' vi.mock('vue3-gettext', () => ({ useGettext: () => ({ $gettext: (text: string) => text }) })) -function createStrategy(): ContentTypeStrategy { - const state: TextEditorState = { - sourceMode: ref(false), - linkPanel: ref(null), - editorZoom: ref(100) - } - return useStrategyMarkdown(state) -} - -function createEditor(strategy: ContentTypeStrategy, content: string): Editor { - return new Editor({ - extensions: strategy.extensions(), - content: strategy.deserialize(content), - contentType: 'markdown' - }) -} - -function toJSON(editor: Editor): JSONContent { - return editor.getJSON() as JSONContent -} - -function load(markdown: string) { - const strategy = createStrategy() - const editor = createEditor(strategy, markdown) - return { editor, serialized: strategy.serialize(editor.state.doc) } -} - -function expectStableRoundtrip(markdown: string) { - const { editor, serialized } = load(markdown) - expect(() => editor.state.doc.check()).not.toThrow() - - const reloaded = load(serialized) - expect(() => reloaded.editor.state.doc.check()).not.toThrow() - expect(toJSON(reloaded.editor)).toEqual(toJSON(editor)) - - return { editor, serialized } -} - function codeBlockTexts(node: JSONContent): string[] { if (node.type === 'codeBlock') { return [node.content?.map(({ text }) => text).join('') ?? ''] @@ -60,6 +18,10 @@ describe('markdown task list and code block roundtrip', () => { createTestingPinia() }) + afterEach(() => { + destroyEditors() + }) + describe('code blocks', () => { // marked keeps the indentation of tilde fenced code, so no fixture it('keeps the code of an indented tilde fence', () => { From 39301bb446e9b86c6d759b10f72981d209e0b85f Mon Sep 17 00:00:00 2001 From: Jannik Stehle Date: Fri, 9 Oct 2026 11:21:04 +0200 Subject: [PATCH 5/6] test(web-pkg): check exact output of markdown fixtures --- .../fixtures/markdown/basics.out.md | 48 ++++++++++++ .../code-block-fence-indented-1-space.out.md | 3 + .../code-block-fence-indented-2-spaces.out.md | 4 + ...ode-block-indented-fence-after-list.out.md | 5 ++ .../markdown/list-asterisk-markers.out.md | 2 + .../markdown/list-blockquote-in-item.out.md | 3 + .../list-empty-first-ordered-sub-item.out.md | 3 + .../list-empty-item-in-blockquote.out.md | 1 + .../list-empty-item-with-sub-list.out.md | 2 + .../fixtures/markdown/list-empty-item.out.md | 1 + .../fixtures/markdown/list-empty-items.out.md | 6 ++ .../markdown/list-empty-last-sub-item.out.md | 3 + .../list-empty-sub-item-with-children.out.md | 7 ++ .../list-escaped-lines-in-item.out.md | 3 + .../list-heading-below-empty-marker.out.md | 3 + .../markdown/list-heading-in-item.out.md | 3 + .../list-heading-in-letter-item.out.md | 3 + .../list-heading-in-ordered-item.out.md | 3 + .../markdown/list-letters-empty-item.out.md | 3 + ...t-ordered-content-indented-2-spaces.out.md | 3 + .../list-ordered-continuation-line.out.md | 2 + .../list-ordered-item-escaped-line.out.md | 10 +++ .../list-ordered-right-aligned-nested.out.md | 12 +++ .../list-ordered-right-aligned.out.md | 10 +++ .../list-text-after-code-block.out.md | 6 ++ .../markdown/list-text-after-heading.out.md | 4 + .../markdown/paragraph-indented-lines.out.md | 7 ++ .../table-block-syntax-in-cells.out.md | 4 + ...task-list-code-block-in-bullet-item.out.md | 5 ++ ...ask-list-code-block-in-ordered-item.out.md | 5 ++ ...list-code-block-nested-tab-indented.out.md | 6 ++ ...block-tab-indented-after-blank-line.out.md | 7 ++ .../task-list-code-block-tab-indented.out.md | 4 + ...k-tilde-with-tabs-after-nested-item.out.md | 5 ++ ...de-block-with-tabs-after-blank-line.out.md | 5 ++ ...t-code-block-with-tabs-three-levels.out.md | 6 ++ ...dented-code-block-after-nested-item.out.md | 5 ++ ...-indented-code-block-tab-and-spaces.out.md | 4 + ...-list-indented-code-block-with-tabs.out.md | 4 + .../task-list-nested-item-tab-indented.out.md | 2 + .../tests/unit/editor/strategies/helpers.ts | 8 +- .../strategies/markdownFixtures.spec.ts | 78 +++++++++++++------ 42 files changed, 282 insertions(+), 26 deletions(-) create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/basics.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-1-space.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-2-spaces.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-indented-fence-after-list.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-asterisk-markers.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-blockquote-in-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-ordered-sub-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-in-blockquote.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-with-sub-list.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-items.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-sub-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-item-with-children.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-escaped-lines-in-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-below-empty-marker.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-letter-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-ordered-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-letters-empty-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-content-indented-2-spaces.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-continuation-line.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned-nested.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-code-block.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-heading.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-indented-lines.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/table-block-syntax-in-cells.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-bullet-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-ordered-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-nested-tab-indented.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented-after-blank-line.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tilde-with-tabs-after-nested-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-blank-line.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-three-levels.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-after-nested-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-tab-and-spaces.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-with-tabs.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-nested-item-tab-indented.out.md diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/basics.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/basics.out.md new file mode 100644 index 00000000000..112bc98509e --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/basics.out.md @@ -0,0 +1,48 @@ +--- +title: Fixtures +tags: [a, b] +--- + +# Heading 1 + +## Heading 2 + +# Setext heading + +Text with *emphasis*, **strong**, ~~strike~~, `code` and a [link](https://opencloud.eu "title"). +A second line with a hard break +after it. + +![image](https://opencloud.eu/logo.png) + +> A quote +> with two lines +> +> > nested + +--- + +- bullet +- list + - nested + +1. ordered +2. list + +- [ ] open task +- [x] done task + + +| left | center | right | +| :---- | :------: | -------: | +| a | b | c | +| `d` | **e** | [f](#f) | + + +```js +const x = 1 +``` + +``` +indented code +``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-1-space.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-1-space.out.md new file mode 100644 index 00000000000..7bec66de82d --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-1-space.out.md @@ -0,0 +1,3 @@ +``` +code +``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-2-spaces.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-2-spaces.out.md new file mode 100644 index 00000000000..d60492e9769 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-fence-indented-2-spaces.out.md @@ -0,0 +1,4 @@ +``` + code + x +``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-indented-fence-after-list.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-indented-fence-after-list.out.md new file mode 100644 index 00000000000..b9da48e978b --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/code-block-indented-fence-after-list.out.md @@ -0,0 +1,5 @@ +- a + +``` +code +``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-asterisk-markers.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-asterisk-markers.out.md new file mode 100644 index 00000000000..4068906cb53 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-asterisk-markers.out.md @@ -0,0 +1,2 @@ +- a +- b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-blockquote-in-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-blockquote-in-item.out.md new file mode 100644 index 00000000000..76407b623f1 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-blockquote-in-item.out.md @@ -0,0 +1,3 @@ +-   + > quote +- b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-ordered-sub-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-ordered-sub-item.out.md new file mode 100644 index 00000000000..e18c2945708 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-ordered-sub-item.out.md @@ -0,0 +1,3 @@ +- a + 1.   + 2. b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-in-blockquote.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-in-blockquote.out.md new file mode 100644 index 00000000000..62e6b27082a --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-in-blockquote.out.md @@ -0,0 +1 @@ +> - diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-with-sub-list.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-with-sub-list.out.md new file mode 100644 index 00000000000..7e52fbe3b0d --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item-with-sub-list.out.md @@ -0,0 +1,2 @@ +-   + - x diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item.out.md new file mode 100644 index 00000000000..39cdd0ded6d --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-item.out.md @@ -0,0 +1 @@ +- diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-items.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-items.out.md new file mode 100644 index 00000000000..da313df8ccb --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-items.out.md @@ -0,0 +1,6 @@ +- a +- +- b + +1. +2. b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-sub-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-sub-item.out.md new file mode 100644 index 00000000000..17221884813 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-sub-item.out.md @@ -0,0 +1,3 @@ +- a + - b + - diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-item-with-children.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-item-with-children.out.md new file mode 100644 index 00000000000..118d4a9f876 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-sub-item-with-children.out.md @@ -0,0 +1,7 @@ +- Parent + -   + - x + - c +- a + -   + - x diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-escaped-lines-in-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-escaped-lines-in-item.out.md new file mode 100644 index 00000000000..afa5a02a9a9 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-escaped-lines-in-item.out.md @@ -0,0 +1,3 @@ +- a +2\. b +Dr\. Smith diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-below-empty-marker.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-below-empty-marker.out.md new file mode 100644 index 00000000000..f06888e9dc5 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-below-empty-marker.out.md @@ -0,0 +1,3 @@ +-   + # Title +- b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-item.out.md new file mode 100644 index 00000000000..f06888e9dc5 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-item.out.md @@ -0,0 +1,3 @@ +-   + # Title +- b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-letter-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-letter-item.out.md new file mode 100644 index 00000000000..b16ae370c6b --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-letter-item.out.md @@ -0,0 +1,3 @@ +a.   + # Title +b. y diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-ordered-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-ordered-item.out.md new file mode 100644 index 00000000000..13d317d78db --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-heading-in-ordered-item.out.md @@ -0,0 +1,3 @@ +1.   + # Title +2. b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-letters-empty-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-letters-empty-item.out.md new file mode 100644 index 00000000000..ec31729bb14 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-letters-empty-item.out.md @@ -0,0 +1,3 @@ +a. one +b.   +c. three diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-content-indented-2-spaces.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-content-indented-2-spaces.out.md new file mode 100644 index 00000000000..21906a2a23e --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-content-indented-2-spaces.out.md @@ -0,0 +1,3 @@ +1. a + +more diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-continuation-line.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-continuation-line.out.md new file mode 100644 index 00000000000..e0e7526d4ae --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-continuation-line.out.md @@ -0,0 +1,2 @@ +1. a +b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.out.md new file mode 100644 index 00000000000..37bc041235b --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-item-escaped-line.out.md @@ -0,0 +1,10 @@ +1. a +12345678901\. b +2. a +B\. b +3. a +2\. b +4. a +\- b +5. a +\# b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned-nested.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned-nested.out.md new file mode 100644 index 00000000000..ee97c32ebad --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned-nested.out.md @@ -0,0 +1,12 @@ +1. parent + 1. item 1 + 2. item 2 + 3. item 3 + 4. item 4 + 5. item 5 + 6. item 6 + 7. item 7 + 8. item 8 + 9. item 9 + 10. item 10 +2. next diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned.out.md new file mode 100644 index 00000000000..c09c9467280 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-ordered-right-aligned.out.md @@ -0,0 +1,10 @@ +1. item 1 +2. item 2 +3. item 3 +4. item 4 +5. item 5 +6. item 6 +7. item 7 +8. item 8 +9. item 9 +10. item 10 diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-code-block.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-code-block.out.md new file mode 100644 index 00000000000..6293aa282c4 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-code-block.out.md @@ -0,0 +1,6 @@ +1.   + ``` + x + ``` + + *em* [l](http://x) diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-heading.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-heading.out.md new file mode 100644 index 00000000000..61161aa9d95 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-text-after-heading.out.md @@ -0,0 +1,4 @@ +-   + # Title + + [l](http://x) **b** y diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-indented-lines.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-indented-lines.out.md new file mode 100644 index 00000000000..b1a42791129 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/paragraph-indented-lines.out.md @@ -0,0 +1,7 @@ +x paragraph + +a +b + +a +b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/table-block-syntax-in-cells.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/table-block-syntax-in-cells.out.md new file mode 100644 index 00000000000..d9da4146c39 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/table-block-syntax-in-cells.out.md @@ -0,0 +1,4 @@ + +| a | b | +| --- | ---- | +| - | 1. x | diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-bullet-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-bullet-item.out.md new file mode 100644 index 00000000000..31d16043c54 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-bullet-item.out.md @@ -0,0 +1,5 @@ +- [ ] a + - b + ``` + code + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-ordered-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-ordered-item.out.md new file mode 100644 index 00000000000..a62e17590fd --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-in-ordered-item.out.md @@ -0,0 +1,5 @@ +- [ ] a + 1. b + ```js + code + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-nested-tab-indented.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-nested-tab-indented.out.md new file mode 100644 index 00000000000..5c84ea9374a --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-nested-tab-indented.out.md @@ -0,0 +1,6 @@ +- [ ] a + - [ ] b + ``` + code + indented + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented-after-blank-line.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented-after-blank-line.out.md new file mode 100644 index 00000000000..b463652a062 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented-after-blank-line.out.md @@ -0,0 +1,7 @@ +- [ ] a + ``` + code + ``` +- [ ] b + +after diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented.out.md new file mode 100644 index 00000000000..746bc6fae2c --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tab-indented.out.md @@ -0,0 +1,4 @@ +- [ ] a + ```js + const x = 1 + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tilde-with-tabs-after-nested-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tilde-with-tabs-after-nested-item.out.md new file mode 100644 index 00000000000..52ba58278c8 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-tilde-with-tabs-after-nested-item.out.md @@ -0,0 +1,5 @@ +- [ ] a + - [ ] b + ``` + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-blank-line.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-blank-line.out.md new file mode 100644 index 00000000000..28ffea5a22b --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-after-blank-line.out.md @@ -0,0 +1,5 @@ +- [ ] run + ```make + build: + go build + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-three-levels.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-three-levels.out.md new file mode 100644 index 00000000000..4792f00f7e1 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-code-block-with-tabs-three-levels.out.md @@ -0,0 +1,6 @@ +- [ ] a + - [ ] b + - [ ] c + ``` + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-after-nested-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-after-nested-item.out.md new file mode 100644 index 00000000000..c558fe39286 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-after-nested-item.out.md @@ -0,0 +1,5 @@ +- [ ] a + - [ ] b + ``` + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-tab-and-spaces.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-tab-and-spaces.out.md new file mode 100644 index 00000000000..a4dad886d78 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-tab-and-spaces.out.md @@ -0,0 +1,4 @@ +- [ ] a + ``` + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-with-tabs.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-with-tabs.out.md new file mode 100644 index 00000000000..a4dad886d78 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-indented-code-block-with-tabs.out.md @@ -0,0 +1,4 @@ +- [ ] a + ``` + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-nested-item-tab-indented.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-nested-item-tab-indented.out.md new file mode 100644 index 00000000000..b5c0717d885 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/task-list-nested-item-tab-indented.out.md @@ -0,0 +1,2 @@ +- [ ] a + - [ ] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/helpers.ts b/packages/web-pkg/tests/unit/editor/strategies/helpers.ts index 86d4459a20c..79c1e058966 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/helpers.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/helpers.ts @@ -46,7 +46,11 @@ export function load(markdown: string): LoadedMarkdown { return { editor, serialized: strategy.serialize(editor.state.doc) } } -export function expectStableRoundtrip(markdown: string): LoadedMarkdown { +export interface StableRoundtrip extends LoadedMarkdown { + reserialized: string +} + +export function expectStableRoundtrip(markdown: string): StableRoundtrip { const { editor, serialized } = load(markdown) expect(() => editor.state.doc.check()).not.toThrow() @@ -54,5 +58,5 @@ export function expectStableRoundtrip(markdown: string): LoadedMarkdown { expect(() => reloaded.editor.state.doc.check()).not.toThrow() expect(toJSON(reloaded.editor)).toEqual(toJSON(editor)) - return { editor, serialized } + return { editor, serialized, reserialized: reloaded.serialized } } diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts index 82e33984044..18e95b7109a 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts @@ -11,30 +11,57 @@ vi.mock('vue3-gettext', () => ({ const fixturesDir = join(import.meta.dirname, 'fixtures', 'markdown') -function loadFixtures(dir: string): [string, string][] { - return readdirSync(dir) - .filter((name) => name.endsWith('.md')) - .sort() - .map((name) => { - const markdown = readFileSync(join(dir, name), 'utf8') - // an empty fixture would pass silently - if (!markdown.trim()) { - throw new Error(`Empty fixture ${name}`) +interface Fixture { + name: string + markdown: string + expected: string +} + +const outputSuffix = '.out.md' + +function readFixture(dir: string, name: string): string { + const content = readFileSync(join(dir, name), 'utf8') + // an empty fixture would pass silently + if (!content.trim()) { + throw new Error(`Empty fixture ${name}`) + } + return content +} + +function trimFinalNewline(markdown: string): string { + return markdown.endsWith('\n') ? markdown.slice(0, -1) : markdown +} + +/** + * Loads the `.md` fixtures. The editor must save a fixture unchanged, or as + * `.out.md` where that exists. A single final newline is ignored. + */ +function loadFixtures(dir: string): Fixture[] { + const names = readdirSync(dir).sort() + names + .filter((name) => name.endsWith(outputSuffix)) + .forEach((name) => { + if (!names.includes(name.replace(outputSuffix, '.md'))) { + throw new Error(`Output ${name} without fixture`) } - return [name, markdown] }) -} -function save(markdown: string): string { - return expectStableRoundtrip(markdown).serialized + return names + .filter((name) => name.endsWith('.md') && !name.endsWith(outputSuffix)) + .map((name) => { + const markdown = readFixture(dir, name) + const output = name.replace(/\.md$/, outputSuffix) + const expected = names.includes(output) ? readFixture(dir, output) : markdown + return { name, markdown, expected } + }) } // Reference renderer for both the original and the saved markdown. The list tokenizer -// makes marked read a lone `- ` as an empty item, as CommonMark does. Since the editor -// uses the same tokenizer, empty items need inline tests with exact output. -// The render check is weak where marked differs from the editor, which needs inline -// tests as well: marked reads letter or roman lists and frontmatter as paragraphs, -// expands tabs in list items to spaces, and normalize() folds nbsp into a space. +// makes marked read a lone `- ` as an empty item, as CommonMark does. +// The render check is weak where marked differs from the editor, which the exact +// output check covers: marked reads letter or roman lists and frontmatter as +// paragraphs, expands tabs in list items to spaces, and normalize() folds nbsp into +// a space. const marked = new Marked() registerMarkdownListTokenizer(marked) @@ -97,11 +124,12 @@ function render(markdown: string): string { return normalize(marked.parse(markdown) as string) } -function expectRoundtrip(markdown: string) { - const saved = save(markdown) +function expectSaved({ markdown, expected }: Fixture): string { + const { serialized, reserialized } = expectStableRoundtrip(markdown) - expect(render(saved), saved).toBe(render(markdown)) - expect(save(saved)).toBe(saved) + expect(trimFinalNewline(serialized)).toBe(trimFinalNewline(expected)) + expect(reserialized).toBe(serialized) + return serialized } describe('markdown fixture roundtrip', () => { @@ -113,7 +141,9 @@ describe('markdown fixture roundtrip', () => { destroyEditors() }) - it.each(loadFixtures(fixturesDir))('keeps %s', (_, markdown) => { - expectRoundtrip(markdown) + it.each(loadFixtures(fixturesDir))('keeps $name', (fixture) => { + const saved = expectSaved(fixture) + + expect(render(saved), saved).toBe(render(fixture.markdown)) }) }) From 81aee3a350186175898e6a0315a53f8739b857cf Mon Sep 17 00:00:00 2001 From: Jannik Stehle Date: Fri, 9 Oct 2026 11:21:23 +0200 Subject: [PATCH 6/6] test(web-pkg): move inline markdown round trip tests to fixtures --- .../markdown/list-empty-first-item.md | 2 + .../markdown/list-empty-first-item.out.md | 2 + .../markdown/list-empty-last-ordered-item.md | 2 + .../list-empty-last-ordered-item.out.md | 2 + .../code-block-tilde-fence-indented.md | 4 + .../code-block-tilde-fence-indented.out.md | 4 + ...mpty-sub-item-bare-marker-with-children.md | 4 + ...-sub-item-bare-marker-with-children.out.md | 4 + .../list-empty-sub-item-with-siblings.md | 9 + .../list-empty-sub-item-with-siblings.out.md | 9 + .../list-empty-sub-item-with-sub-list.md | 3 + .../list-empty-sub-item-with-sub-list.out.md | 3 + .../unlike-marked/list-empty-sub-item.md | 3 + .../unlike-marked/list-empty-sub-item.out.md | 3 + .../list-ordered-start-number-0.md | 2 + .../list-ordered-start-number-0.out.md | 2 + .../list-ordered-task-syntax-loose.md | 3 + .../list-ordered-task-syntax-loose.out.md | 2 + ...d-task-syntax-multi-paragraph-last-item.md | 4 + ...sk-syntax-multi-paragraph-last-item.out.md | 4 + ...ist-ordered-task-syntax-multi-paragraph.md | 4 + ...ordered-task-syntax-multi-paragraph.out.md | 4 + .../list-ordered-task-syntax-nested.md | 3 + .../list-ordered-task-syntax-nested.out.md | 3 + .../list-ordered-task-syntax-sub-list.md | 5 + .../list-ordered-task-syntax-sub-list.out.md | 5 + .../list-ordered-task-syntax-tight.md | 2 + .../list-ordered-task-syntax-tight.out.md | 2 + ...e-block-under-indented-after-blank-line.md | 5 + ...ock-under-indented-after-blank-line.out.md | 4 + ...-block-under-indented-after-nested-item.md | 5 + ...ck-under-indented-after-nested-item.out.md | 5 + .../task-list-code-block-under-indented.md | 5 + ...task-list-code-block-under-indented.out.md | 5 + .../task-list-heading-under-indented.md | 2 + .../task-list-heading-under-indented.out.md | 2 + .../task-list-line-tab-indented.md | 2 + .../task-list-line-tab-indented.out.md | 3 + .../task-list-lines-under-indented.md | 3 + .../task-list-lines-under-indented.out.md | 4 + ...t-paragraph-tab-indented-in-nested-item.md | 4 + ...ragraph-tab-indented-in-nested-item.out.md | 5 + ...agraph-under-indented-after-nested-item.md | 5 + ...ph-under-indented-after-nested-item.out.md | 5 + .../task-list-paragraph-under-indented.md | 3 + .../task-list-paragraph-under-indented.out.md | 3 + .../strategies/markdownFixtures.spec.ts | 9 + .../strategies/markdownListRoundtrip.spec.ts | 161 +----------------- .../markdownParagraphRoundtrip.spec.ts | 77 --------- .../markdownTaskListRoundtrip.spec.ts | 145 ---------------- 50 files changed, 179 insertions(+), 382 deletions(-) create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-ordered-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-ordered-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/code-block-tilde-fence-indented.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/code-block-tilde-fence-indented.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-bare-marker-with-children.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-bare-marker-with-children.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-siblings.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-siblings.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-sub-list.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-sub-list.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-start-number-0.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-start-number-0.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-loose.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-loose.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph-last-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph-last-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-nested.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-nested.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-sub-list.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-sub-list.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-tight.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-tight.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-blank-line.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-blank-line.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-nested-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-nested-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-heading-under-indented.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-heading-under-indented.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-line-tab-indented.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-line-tab-indented.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-lines-under-indented.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-lines-under-indented.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-tab-indented-in-nested-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-tab-indented-in-nested-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented-after-nested-item.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented-after-nested-item.out.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented.md create mode 100644 packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented.out.md delete mode 100644 packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-item.md new file mode 100644 index 00000000000..49e6a9c6cef --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-item.md @@ -0,0 +1,2 @@ +- +- b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-item.out.md new file mode 100644 index 00000000000..1e21e4778f4 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-first-item.out.md @@ -0,0 +1,2 @@ +- +- b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-ordered-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-ordered-item.md new file mode 100644 index 00000000000..5c2840a8aeb --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-ordered-item.md @@ -0,0 +1,2 @@ +1. a +2. diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-ordered-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-ordered-item.out.md new file mode 100644 index 00000000000..a0b37d69276 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/list-empty-last-ordered-item.out.md @@ -0,0 +1,2 @@ +1. a +2. diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/code-block-tilde-fence-indented.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/code-block-tilde-fence-indented.md new file mode 100644 index 00000000000..2a5c11e10d0 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/code-block-tilde-fence-indented.md @@ -0,0 +1,4 @@ + ~~~ + code + x + ~~~ diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/code-block-tilde-fence-indented.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/code-block-tilde-fence-indented.out.md new file mode 100644 index 00000000000..d60492e9769 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/code-block-tilde-fence-indented.out.md @@ -0,0 +1,4 @@ +``` + code + x +``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-bare-marker-with-children.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-bare-marker-with-children.md new file mode 100644 index 00000000000..5cc7ed929e1 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-bare-marker-with-children.md @@ -0,0 +1,4 @@ +- Parent + - + - x + - c diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-bare-marker-with-children.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-bare-marker-with-children.out.md new file mode 100644 index 00000000000..69880165d31 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-bare-marker-with-children.out.md @@ -0,0 +1,4 @@ +- Parent + -   + - x + - c diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-siblings.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-siblings.md new file mode 100644 index 00000000000..3c74d2cddd8 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-siblings.md @@ -0,0 +1,9 @@ +- Parent + - + - c +- Next + +1. Parent + - + - c +2. Next diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-siblings.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-siblings.out.md new file mode 100644 index 00000000000..52848f45658 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-siblings.out.md @@ -0,0 +1,9 @@ +- Parent + -   + - c +- Next + +1. Parent + -   + - c +2. Next diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-sub-list.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-sub-list.md new file mode 100644 index 00000000000..1ec7b2d7042 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-sub-list.md @@ -0,0 +1,3 @@ +- a + - + - x diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-sub-list.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-sub-list.out.md new file mode 100644 index 00000000000..5e5449aaa7a --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item-with-sub-list.out.md @@ -0,0 +1,3 @@ +- a + -   + - x diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item.md new file mode 100644 index 00000000000..f00655dda55 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item.md @@ -0,0 +1,3 @@ +- Parent + - +- Next diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item.out.md new file mode 100644 index 00000000000..3c2e58c1054 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-empty-sub-item.out.md @@ -0,0 +1,3 @@ +- Parent + -   +- Next diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-start-number-0.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-start-number-0.md new file mode 100644 index 00000000000..525dccee1f5 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-start-number-0.md @@ -0,0 +1,2 @@ +0. a +1. b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-start-number-0.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-start-number-0.out.md new file mode 100644 index 00000000000..2af9cc001db --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-start-number-0.out.md @@ -0,0 +1,2 @@ +1. a +2. b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-loose.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-loose.md new file mode 100644 index 00000000000..535f4e91183 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-loose.md @@ -0,0 +1,3 @@ +1. [ ] a + +2. [x] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-loose.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-loose.out.md new file mode 100644 index 00000000000..5e2864b4e44 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-loose.out.md @@ -0,0 +1,2 @@ +1. \[ \] a +2. \[x\] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph-last-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph-last-item.md new file mode 100644 index 00000000000..69c570d3151 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph-last-item.md @@ -0,0 +1,4 @@ +2. [x] b +3. [ ] a + + more diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph-last-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph-last-item.out.md new file mode 100644 index 00000000000..3ed3d3bf360 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph-last-item.out.md @@ -0,0 +1,4 @@ +2. \[x\] b +3. \[ \] a + + more diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph.md new file mode 100644 index 00000000000..e9c2f14948a --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph.md @@ -0,0 +1,4 @@ +1. [ ] a + + more +2. [x] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph.out.md new file mode 100644 index 00000000000..d7bc8ba72e7 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-multi-paragraph.out.md @@ -0,0 +1,4 @@ +1. \[ \] a + + more +2. \[x\] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-nested.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-nested.md new file mode 100644 index 00000000000..6a43c9475e1 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-nested.md @@ -0,0 +1,3 @@ +- c + 1. [ ] a + 2. [x] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-nested.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-nested.out.md new file mode 100644 index 00000000000..803a7545399 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-nested.out.md @@ -0,0 +1,3 @@ +- c + 1. \[ \] a + 2. \[x\] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-sub-list.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-sub-list.md new file mode 100644 index 00000000000..e9e1d0076ac --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-sub-list.md @@ -0,0 +1,5 @@ +1. [ ] a + - sub + + more +2. [x] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-sub-list.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-sub-list.out.md new file mode 100644 index 00000000000..cd457c301f5 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-sub-list.out.md @@ -0,0 +1,5 @@ +1. \[ \] a + - sub + + more +2. \[x\] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-tight.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-tight.md new file mode 100644 index 00000000000..e9062c8adf0 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-tight.md @@ -0,0 +1,2 @@ +1. [ ] a +2. [x] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-tight.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-tight.out.md new file mode 100644 index 00000000000..5e2864b4e44 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/list-ordered-task-syntax-tight.out.md @@ -0,0 +1,2 @@ +1. \[ \] a +2. \[x\] b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-blank-line.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-blank-line.md new file mode 100644 index 00000000000..56c753b3713 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-blank-line.md @@ -0,0 +1,5 @@ +- [ ] a + + ~~~ + code + ~~~ diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-blank-line.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-blank-line.out.md new file mode 100644 index 00000000000..e36e9800ac8 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-blank-line.out.md @@ -0,0 +1,4 @@ +- [ ] a + ``` + code + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-nested-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-nested-item.md new file mode 100644 index 00000000000..e5e01592b3c --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-nested-item.md @@ -0,0 +1,5 @@ +- [ ] a + - [ ] b + ``` + code + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-nested-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-nested-item.out.md new file mode 100644 index 00000000000..2bdc115e2dd --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented-after-nested-item.out.md @@ -0,0 +1,5 @@ +- [ ] a + - [ ] b + ``` + code + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented.md new file mode 100644 index 00000000000..b05860727ae --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented.md @@ -0,0 +1,5 @@ +- [ ] a + ``` + code + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented.out.md new file mode 100644 index 00000000000..427b8602212 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-code-block-under-indented.out.md @@ -0,0 +1,5 @@ +- [ ] a + ``` + code + x + ``` diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-heading-under-indented.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-heading-under-indented.md new file mode 100644 index 00000000000..e67d0633653 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-heading-under-indented.md @@ -0,0 +1,2 @@ +- [ ] a + # h diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-heading-under-indented.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-heading-under-indented.out.md new file mode 100644 index 00000000000..f54d938ac41 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-heading-under-indented.out.md @@ -0,0 +1,2 @@ +- [ ] a + # h diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-line-tab-indented.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-line-tab-indented.md new file mode 100644 index 00000000000..0473d958e86 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-line-tab-indented.md @@ -0,0 +1,2 @@ +- [ ] a + b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-line-tab-indented.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-line-tab-indented.out.md new file mode 100644 index 00000000000..98eb88da72b --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-line-tab-indented.out.md @@ -0,0 +1,3 @@ +- [ ] a + + b diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-lines-under-indented.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-lines-under-indented.md new file mode 100644 index 00000000000..15d6c1e78b2 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-lines-under-indented.md @@ -0,0 +1,3 @@ +- [ ] a + b + c diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-lines-under-indented.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-lines-under-indented.out.md new file mode 100644 index 00000000000..ad33055278c --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-lines-under-indented.out.md @@ -0,0 +1,4 @@ +- [ ] a + + b + c diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-tab-indented-in-nested-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-tab-indented-in-nested-item.md new file mode 100644 index 00000000000..674d32021a3 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-tab-indented-in-nested-item.md @@ -0,0 +1,4 @@ +- [ ] a + - [ ] b + c + - [ ] d diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-tab-indented-in-nested-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-tab-indented-in-nested-item.out.md new file mode 100644 index 00000000000..5631b394adc --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-tab-indented-in-nested-item.out.md @@ -0,0 +1,5 @@ +- [ ] a + - [ ] b + + c + - [ ] d diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented-after-nested-item.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented-after-nested-item.md new file mode 100644 index 00000000000..c3404d2a42c --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented-after-nested-item.md @@ -0,0 +1,5 @@ +- [ ] a + - [ ] b + + x c +- [ ] d diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented-after-nested-item.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented-after-nested-item.out.md new file mode 100644 index 00000000000..8ee06c78559 --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented-after-nested-item.out.md @@ -0,0 +1,5 @@ +- [ ] a + - [ ] b + + x c +- [ ] d diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented.md new file mode 100644 index 00000000000..65f6f83b37e --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented.md @@ -0,0 +1,3 @@ +- [ ] task + + x paragraph diff --git a/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented.out.md b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented.out.md new file mode 100644 index 00000000000..674969b80cb --- /dev/null +++ b/packages/web-pkg/tests/unit/editor/strategies/fixtures/markdown/unlike-marked/task-list-paragraph-under-indented.out.md @@ -0,0 +1,3 @@ +- [ ] task + + x paragraph diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts index 18e95b7109a..3aeb4a9549c 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownFixtures.spec.ts @@ -10,6 +10,11 @@ vi.mock('vue3-gettext', () => ({ })) const fixturesDir = join(import.meta.dirname, 'fixtures', 'markdown') +// The editor reads these differently from marked on purpose, so they skip the render +// check: an empty item below text, task syntax in ordered lists, under or tab +// indented content below a task item, an indented tilde fence (marked keeps its +// indentation) and a list starting at 0 (the editor starts it at 1). +const unlikeMarkedDir = join(fixturesDir, 'unlike-marked') interface Fixture { name: string @@ -146,4 +151,8 @@ describe('markdown fixture roundtrip', () => { expect(render(saved), saved).toBe(render(fixture.markdown)) }) + + it.each(loadFixtures(unlikeMarkedDir))('keeps unlike-marked/$name', (fixture) => { + expectSaved(fixture) + }) }) diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts index e4762032c54..75b94c23904 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownListRoundtrip.spec.ts @@ -1,5 +1,5 @@ import { createTestingPinia } from '@opencloud-eu/web-test-helpers' -import { toJSON, load, expectStableRoundtrip, destroyEditors } from './helpers' +import { load, destroyEditors } from './helpers' vi.mock('vue3-gettext', () => ({ useGettext: () => ({ $gettext: (text: string) => text }) @@ -15,170 +15,11 @@ describe('markdown list roundtrip', () => { }) describe('list items', () => { - it('keeps the parent of an empty sub item', () => { - const { editor, serialized } = expectStableRoundtrip('- Parent\n - \n- Next\n') - - expect(toJSON(editor).content[0]).toMatchObject({ - type: 'bulletList', - content: [ - { - type: 'listItem', - content: [ - { type: 'paragraph', content: [{ text: 'Parent' }] }, - { type: 'bulletList', content: [{ type: 'listItem' }] } - ] - }, - { type: 'listItem', content: [{ type: 'paragraph', content: [{ text: 'Next' }] }] } - ] - }) - expect(serialized).toBe('- Parent\n -  \n- Next') - }) - - it.each(['- Parent\n - \n - c\n- Next\n', '1. Parent\n - \n - c\n2. Next\n'])( - 'keeps an empty sub item and its siblings in one list for %j', - (markdown) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(toJSON(editor).content[0].content[0].content).toMatchObject([ - { type: 'paragraph', content: [{ text: 'Parent' }] }, - { - type: 'bulletList', - content: [ - { type: 'listItem', content: [{ type: 'paragraph' }] }, - { type: 'listItem', content: [{ type: 'paragraph', content: [{ text: 'c' }] }] } - ] - } - ]) - } - ) - - it('keeps the children of an empty sub item', () => { - const { editor } = expectStableRoundtrip('- Parent\n -\n - x\n - c\n') - - expect(toJSON(editor).content[0].content[0].content[1]).toMatchObject({ - type: 'bulletList', - content: [ - { - type: 'listItem', - content: [ - { type: 'paragraph' }, - { type: 'bulletList', content: [{ content: [{ content: [{ text: 'x' }] }] }] } - ] - }, - { type: 'listItem', content: [{ type: 'paragraph', content: [{ text: 'c' }] }] } - ] - }) - }) - - it.each([ - '- # Title\n- b\n', - '1. # Title\n2. b\n', - '-\n # Title\n- b\n', - 'a. \n # Title\nb. y\n' - ])('keeps the heading in a list item of %j', (markdown) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(toJSON(editor).content[0].content[0]).toMatchObject({ - type: 'listItem', - content: [{ type: 'paragraph' }, { type: 'heading', content: [{ text: 'Title' }] }] - }) - }) - - it.each(['- # Title\n text\n', '1. ```\n x\n ```\n text\n'])( - 'wraps text after a block of %j into a paragraph', - (markdown) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(toJSON(editor).content[0].content[0].content.at(-1)).toMatchObject({ - type: 'paragraph', - content: [{ text: 'text' }] - }) - } - ) - - it.each([ - ['- \n', '-'], - ['- \n- b\n', '-\n- b'], - ['1. \n2. b\n', '1.\n2. b'], - ['- a\n- \n- b\n', '- a\n-\n- b'], - ['1. a\n2. \n', '1. a\n2.'], - ['- \n - x\n', '-  \n - x'], - ['> - \n', '> -'], - ['- a\n - b\n - \n', '- a\n - b\n -'], - ['- a\n 1. \n 2. b\n', '- a\n 1.  \n 2. b'], - ['- a\n - \n - x\n', '- a\n -  \n - x'] - ])('keeps the empty item in %j', (markdown, expected) => { - const { serialized } = expectStableRoundtrip(markdown) - - expect(serialized).toBe(expected) - }) - it('parses many lists starting with an empty item in linear time', () => { const start = performance.now() load('- \n- x\n# h\n'.repeat(30) + '- \n- x\n\n1. \n2. y\n\n'.repeat(30)) expect(performance.now() - start).toBeLessThan(1000) }) - - it('adds an empty paragraph when a list item starts with another block', () => { - const { editor } = expectStableRoundtrip('- > quote\n- b\n') - - expect(toJSON(editor).content[0].content[0]).toMatchObject({ - type: 'listItem', - content: [{ type: 'paragraph' }, { type: 'blockquote' }] - }) - }) - }) - - describe('ordered lists', () => { - it.each([ - ['a tight', '1. [ ] a\n2. [x] b\n'], - ['a loose', '1. [ ] a\n\n2. [x] b\n'], - ['a nested', '- c\n 1. [ ] a\n 2. [x] b\n'], - ['a multi paragraph', '1. [ ] a\n\n more\n2. [x] b\n'], - ['a multi paragraph last item of a', '2. [x] b\n3. [ ] a\n\n more\n'], - ['a sub list item of a', '1. [ ] a\n - sub\n\n more\n2. [x] b\n'] - ])('keeps the task syntax of %s list as text', (_, markdown) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(editor.getText()).toContain('[ ] a') - expect(editor.getText()).toContain('[x] b') - }) - - it('starts a list numbered from 0 at 1', () => { - const { editor } = expectStableRoundtrip('0. a\n1. b\n') - - expect(toJSON(editor).content[0].attrs.start).toBe(1) - }) - - it.each([ - ['a', 'a. one\nb. two'], - ['A', 'A. one\nB. two'], - ['i', 'i. one\nii. two'], - ['I', 'I. one\nII. two'] - ])('keeps a list of type %j', (type, markdown) => { - const { editor, serialized } = expectStableRoundtrip(`${markdown}\n`) - - expect(toJSON(editor).content[0]).toMatchObject({ - type: 'orderedList', - attrs: { type }, - content: [{ type: 'listItem' }, { type: 'listItem' }] - }) - expect(serialized).toBe(markdown) - }) - - it('keeps an empty item of a letter list', () => { - const { editor } = expectStableRoundtrip('a. one\nb. \nc. three\n') - - expect(toJSON(editor).content[0]).toMatchObject({ - type: 'orderedList', - attrs: { type: 'a' }, - content: [ - { type: 'listItem', content: [{ type: 'paragraph', content: [{ text: 'one' }] }] }, - { type: 'listItem', content: [{ type: 'paragraph' }] }, - { type: 'listItem', content: [{ type: 'paragraph', content: [{ text: 'three' }] }] } - ] - }) - }) }) }) diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts index 8bee1aba0f5..599187e4ce3 100644 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts +++ b/packages/web-pkg/tests/unit/editor/strategies/markdownParagraphRoundtrip.spec.ts @@ -83,38 +83,6 @@ describe('markdown paragraph roundtrip', () => { ) }) - it('leaves block syntax in table cells as it is', () => { - const { serialized } = expectStableRoundtrip('| a | b |\n|---|---|\n| - | 1. x |\n') - - expect(serialized).toContain('| - | 1. x |') - }) - - it('keeps an alert marker in a blockquote', () => { - const { serialized } = expectStableRoundtrip('> [!NOTE]\n> hint\n') - - expect(serialized).toBe('> [!NOTE]\n> hint') - }) - - it.each(['[!NOTE](x) text', '[!NOTE] text'])('keeps %j in a blockquote as text', (text) => { - const { editor, serialized } = expectStableRoundtrip(`> ${text.replace(/[[\]]/g, '\\$&')}\n`) - - expect(toJSON(editor).content[0].content[0].content).toEqual([{ type: 'text', text }]) - expect(serialized).toBe(`> ${text.replace(/[[\]]/g, '\\$&')}`) - }) - - it.each([ - [' x paragraph\n', [{ type: 'text', text: 'x paragraph' }]], - ['a\n b\n', [{ type: 'text', text: 'a\nb' }]], - [ - 'a \n b\n', - [{ type: 'text', text: 'a' }, { type: 'hardBreak' }, { type: 'text', text: 'b' }] - ] - ])('drops the indentation of the lines in %j', (markdown, content) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(toJSON(editor).content).toEqual([{ type: 'paragraph', content }]) - }) - it('keeps the indentation in a code span at the start of a line', () => { const { editor } = load('a\n ` b`\n') @@ -124,49 +92,4 @@ describe('markdown paragraph roundtrip', () => { ]) }) }) - - describe('list items', () => { - it('drops the indentation of a continuation line in a tight item', () => { - const { editor } = expectStableRoundtrip('1. a\n b\n') - - expect(toJSON(editor).content[0].content[0].content[0].content).toEqual([ - { type: 'text', text: 'a\nb' } - ]) - }) - - it.each([ - ['B.\u00a0b', 'B\\.\u00a0b'], - ['2.\u00a0b', '2\\.\u00a0b'], - ['-\u00a0b', '\\-\u00a0b'], - ['#\u00a0b', '\\#\u00a0b'] - ])('keeps %j after a soft line break in an ordered list item', (line, escaped) => { - const { editor, serialized } = expectStableRoundtrip(`1. a\n ${escaped}\n`) - - expect(serialized).toBe(`1. a\n${escaped}`) - - expect(toJSON(editor).content).toEqual([ - { - type: 'orderedList', - attrs: { start: 1, type: null }, - content: [ - { - type: 'listItem', - content: [{ type: 'paragraph', content: [{ type: 'text', text: `a\n${line}` }] }] - } - ] - } - ]) - }) - }) - - describe('task lists', () => { - it('drops the indentation of a tab indented paragraph in a task item', () => { - const { editor } = expectStableRoundtrip('- [ ] a\n\t- [ ] b\n\t\tc\n\t- [ ] d\n') - - expect(toJSON(editor).content[0].content[0].content[1].content[0].content[1]).toEqual({ - type: 'paragraph', - content: [{ type: 'text', text: 'c' }] - }) - }) - }) }) diff --git a/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts b/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts deleted file mode 100644 index 0fe7c9ed558..00000000000 --- a/packages/web-pkg/tests/unit/editor/strategies/markdownTaskListRoundtrip.spec.ts +++ /dev/null @@ -1,145 +0,0 @@ -import type { JSONContent } from '@tiptap/core' -import { createTestingPinia } from '@opencloud-eu/web-test-helpers' -import { toJSON, expectStableRoundtrip, destroyEditors } from './helpers' - -vi.mock('vue3-gettext', () => ({ - useGettext: () => ({ $gettext: (text: string) => text }) -})) - -function codeBlockTexts(node: JSONContent): string[] { - if (node.type === 'codeBlock') { - return [node.content?.map(({ text }) => text).join('') ?? ''] - } - return (node.content ?? []).flatMap(codeBlockTexts) -} - -describe('markdown task list and code block roundtrip', () => { - beforeEach(() => { - createTestingPinia() - }) - - afterEach(() => { - destroyEditors() - }) - - describe('code blocks', () => { - // marked keeps the indentation of tilde fenced code, so no fixture - it('keeps the code of an indented tilde fence', () => { - const { editor } = expectStableRoundtrip(' ~~~\n code\n x\n ~~~\n') - - expect(codeBlockTexts(toJSON(editor))).toEqual([' code\n x']) - }) - }) - - describe('task lists', () => { - it('keeps the first letter of an under indented paragraph after a task list', () => { - const { editor } = expectStableRoundtrip('- [ ] task\n\n x paragraph\n') - - expect(toJSON(editor).content[0].content[0].content[1]).toEqual({ - type: 'paragraph', - content: [{ type: 'text', text: 'x paragraph' }] - }) - }) - - it('keeps an under indented line directly below a task item in the item', () => { - const { editor } = expectStableRoundtrip('- [ ] a\n b\n c\n') - - expect(toJSON(editor).content).toMatchObject([ - { - type: 'taskList', - content: [ - { - type: 'taskItem', - content: [ - { type: 'paragraph', content: [{ text: 'a' }] }, - { type: 'paragraph', content: [{ text: 'b\nc' }] } - ] - } - ] - } - ]) - }) - - it('keeps an under indented heading below a task item', () => { - const { editor } = expectStableRoundtrip('- [ ] a\n # h\n') - - expect(toJSON(editor).content[0].content[0].content[1]).toMatchObject({ - type: 'heading', - content: [{ text: 'h' }] - }) - }) - - it('keeps a tab indented line as a paragraph in the task item', () => { - const { editor } = expectStableRoundtrip('- [ ] a\n\tb\n') - - expect(toJSON(editor).content).toHaveLength(1) - expect(toJSON(editor).content[0].content[0].content[1]).toMatchObject({ type: 'paragraph' }) - }) - - // The fixtures cannot guard these: marked expands tabs in list items to spaces - it.each([ - ['directly below the item', '- [ ] run\n ```make\n build:\n \tgo build\n ```\n'], - ['after a blank line', '- [ ] run\n\n ```make\n build:\n \tgo build\n ```\n'] - ])('keeps tabs in a code block in a task item %s', (_, markdown) => { - const { editor, serialized } = expectStableRoundtrip(markdown) - - expect(toJSON(editor).content[0].content[0].content[1]).toMatchObject({ - type: 'codeBlock', - content: [{ text: 'build:\n\tgo build' }] - }) - expect(serialized).toContain('\n \tgo build\n') - }) - - it.each([ - ['after a nested item', '- [ ] a\n - [ ] b\n ```\n \tx\n ```\n', '\tx'], - [ - 'in a tilde fence after a nested item', - '- [ ] a\n - [ ] b\n\n ~~~\n \tx\n ~~~\n', - '\tx' - ], - [ - 'three levels deep', - '- [ ] a\n - [ ] b\n - [ ] c\n\n ```\n \tx\n ```\n', - '\tx' - ], - [ - 'with task item syntax', - '- [ ] a\n ```md\n - [ ] nested example\n \tx\n ```\n', - ' - [ ] nested example\n\tx' - ], - [ - 'with a tab indented fence', - '- [ ] a\n\t- [ ] b\n\t\t```\n\t\tcode\n\t\t\tindented\n\t\t```\n', - 'code\n\tindented' - ], - ['in an indented code block', '- [ ] a\n\n \tx\n', '\tx'], - ['in a tab indented code block', '- [ ] a\n\n \t\tx\n', '\tx'], - [ - 'in an indented code block after a nested item', - '- [ ] a\n - [ ] b\n\n \tx\n', - '\tx' - ] - ])('keeps tabs in a code block in a task item %s', (_, markdown, code) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(codeBlockTexts(toJSON(editor))).toEqual([code]) - }) - - it.each([ - ['directly below the item', '- [ ] a\n ```\n code\n x\n ```\n', 'code\n x'], - ['after a blank line', '- [ ] a\n\n ~~~\n code\n ~~~\n', 'code'], - ['after a nested item', '- [ ] a\n - [ ] b\n ```\n code\n ```\n', 'code'] - ])('keeps an under indented code block below a task item %s', (_, markdown, code) => { - const { editor } = expectStableRoundtrip(markdown) - - expect(codeBlockTexts(toJSON(editor))).toEqual([code]) - }) - - it('keeps the first letter of an under indented paragraph after a nested task item', () => { - const { editor } = expectStableRoundtrip('- [ ] a\n - [ ] b\n\n x c\n- [ ] d\n') - - expect(editor.getText()).toContain('x c') - expect(toJSON(editor).content[0].content).toHaveLength(2) - }) - }) -})