diff options
Diffstat (limited to 'spec/frontend/content_editor/extensions')
11 files changed, 341 insertions, 145 deletions
diff --git a/spec/frontend/content_editor/extensions/attachment_spec.js b/spec/frontend/content_editor/extensions/attachment_spec.js index d4f05a25bd6..d2d2cd98a78 100644 --- a/spec/frontend/content_editor/extensions/attachment_spec.js +++ b/spec/frontend/content_editor/extensions/attachment_spec.js @@ -74,10 +74,10 @@ describe('content_editor/extensions/attachment', () => { }); it.each` - eventType | propName | eventData | output - ${'paste'} | ${'handlePaste'} | ${{ clipboardData: { files: [attachmentFile] } }} | ${true} - ${'paste'} | ${'handlePaste'} | ${{ clipboardData: { files: [] } }} | ${undefined} - ${'drop'} | ${'handleDrop'} | ${{ dataTransfer: { files: [attachmentFile] } }} | ${true} + eventType | propName | eventData | output + ${'paste'} | ${'handlePaste'} | ${{ clipboardData: { getData: jest.fn(), files: [attachmentFile] } }} | ${true} + ${'paste'} | ${'handlePaste'} | ${{ clipboardData: { getData: jest.fn(), files: [] } }} | ${undefined} + ${'drop'} | ${'handleDrop'} | ${{ dataTransfer: { getData: jest.fn(), files: [attachmentFile] } }} | ${true} `('handles $eventType properly', ({ eventType, propName, eventData, output }) => { const event = Object.assign(new Event(eventType), eventData); const handled = tiptapEditor.view.someProp(propName, (eventHandler) => { @@ -157,11 +157,11 @@ describe('content_editor/extensions/attachment', () => { }); }); - it('emits an error event that includes an error message', (done) => { + it('emits an alert event that includes an error message', (done) => { tiptapEditor.commands.uploadAttachment({ file: imageFile }); - tiptapEditor.on('error', ({ error }) => { - expect(error).toBe('An error occurred while uploading the image. Please try again.'); + tiptapEditor.on('alert', ({ message }) => { + expect(message).toBe('An error occurred while uploading the image. Please try again.'); done(); }); }); @@ -233,11 +233,11 @@ describe('content_editor/extensions/attachment', () => { }); }); - it('emits an error event that includes an error message', (done) => { + it('emits an alert event that includes an error message', (done) => { tiptapEditor.commands.uploadAttachment({ file: attachmentFile }); - tiptapEditor.on('error', ({ error }) => { - expect(error).toBe('An error occurred while uploading the file. Please try again.'); + tiptapEditor.on('alert', ({ message }) => { + expect(message).toBe('An error occurred while uploading the file. Please try again.'); done(); }); }); diff --git a/spec/frontend/content_editor/extensions/blockquote_spec.js b/spec/frontend/content_editor/extensions/blockquote_spec.js index c5b5044352d..1644647ba69 100644 --- a/spec/frontend/content_editor/extensions/blockquote_spec.js +++ b/spec/frontend/content_editor/extensions/blockquote_spec.js @@ -1,19 +1,37 @@ -import { multilineInputRegex } from '~/content_editor/extensions/blockquote'; +import Blockquote from '~/content_editor/extensions/blockquote'; +import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils'; describe('content_editor/extensions/blockquote', () => { - describe.each` - input | matches - ${'>>> '} | ${true} - ${' >>> '} | ${true} - ${'\t>>> '} | ${true} - ${'>> '} | ${false} - ${'>>>x '} | ${false} - ${'> '} | ${false} - `('multilineInputRegex', ({ input, matches }) => { - it(`${matches ? 'matches' : 'does not match'}: "${input}"`, () => { - const match = new RegExp(multilineInputRegex).test(input); + let tiptapEditor; + let doc; + let p; + let blockquote; - expect(match).toBe(matches); - }); + beforeEach(() => { + tiptapEditor = createTestEditor({ extensions: [Blockquote] }); + + ({ + builders: { doc, p, blockquote }, + } = createDocBuilder({ + tiptapEditor, + names: { + blockquote: { nodeType: Blockquote.name }, + }, + })); + }); + + it.each` + input | insertedNode + ${'>>> '} | ${() => blockquote({ multiline: true }, p())} + ${'> '} | ${() => blockquote(p())} + ${' >>> '} | ${() => blockquote({ multiline: true }, p())} + ${'>> '} | ${() => p()} + ${'>>>x '} | ${() => p()} + `('with input=$input, then should insert a $insertedNode', ({ input, insertedNode }) => { + const expectedDoc = doc(insertedNode()); + + triggerNodeInputRule({ tiptapEditor, inputRuleText: input }); + + expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON()); }); }); diff --git a/spec/frontend/content_editor/extensions/emoji_spec.js b/spec/frontend/content_editor/extensions/emoji_spec.js index c1b8dc9bdbb..939c46e991a 100644 --- a/spec/frontend/content_editor/extensions/emoji_spec.js +++ b/spec/frontend/content_editor/extensions/emoji_spec.js @@ -1,6 +1,6 @@ import { initEmojiMock } from 'helpers/emoji'; import Emoji from '~/content_editor/extensions/emoji'; -import { createTestEditor, createDocBuilder } from '../test_utils'; +import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils'; describe('content_editor/extensions/emoji', () => { let tiptapEditor; @@ -28,18 +28,16 @@ describe('content_editor/extensions/emoji', () => { describe('when typing a valid emoji input rule', () => { it('inserts an emoji node', () => { - const { view } = tiptapEditor; - const { selection } = view.state; const expectedDoc = doc( p( ' ', emoji({ moji: '❤', name: 'heart', title: 'heavy black heart', unicodeVersion: '1.1' }), ), ); - // Triggers the event handler that input rules listen to - view.someProp('handleTextInput', (f) => f(view, selection.from, selection.to, ':heart:')); - expect(eq(tiptapEditor.state.doc, expectedDoc)).toBe(true); + triggerNodeInputRule({ tiptapEditor, inputRuleText: ':heart:' }); + + expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON()); }); }); diff --git a/spec/frontend/content_editor/extensions/frontmatter_spec.js b/spec/frontend/content_editor/extensions/frontmatter_spec.js new file mode 100644 index 00000000000..517f6947b9a --- /dev/null +++ b/spec/frontend/content_editor/extensions/frontmatter_spec.js @@ -0,0 +1,30 @@ +import Frontmatter from '~/content_editor/extensions/frontmatter'; +import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils'; + +describe('content_editor/extensions/frontmatter', () => { + let tiptapEditor; + let doc; + let p; + + beforeEach(() => { + tiptapEditor = createTestEditor({ extensions: [Frontmatter] }); + + ({ + builders: { doc, p }, + } = createDocBuilder({ + tiptapEditor, + names: { + frontmatter: { nodeType: Frontmatter.name }, + }, + })); + }); + + it('does not insert a frontmatter block when executing code block input rule', () => { + const expectedDoc = doc(p('')); + const inputRuleText = '``` '; + + triggerNodeInputRule({ tiptapEditor, inputRuleText }); + + expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON()); + }); +}); diff --git a/spec/frontend/content_editor/extensions/horizontal_rule_spec.js b/spec/frontend/content_editor/extensions/horizontal_rule_spec.js index a1bc7f0e8ed..322c04a42e1 100644 --- a/spec/frontend/content_editor/extensions/horizontal_rule_spec.js +++ b/spec/frontend/content_editor/extensions/horizontal_rule_spec.js @@ -1,20 +1,39 @@ -import { hrInputRuleRegExp } from '~/content_editor/extensions/horizontal_rule'; +import HorizontalRule from '~/content_editor/extensions/horizontal_rule'; +import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils'; describe('content_editor/extensions/horizontal_rule', () => { - describe.each` - input | matches - ${'---'} | ${true} - ${'--'} | ${false} - ${'---x'} | ${false} - ${' ---x'} | ${false} - ${' --- '} | ${false} - ${'x---x'} | ${false} - ${'x---'} | ${false} - `('hrInputRuleRegExp', ({ input, matches }) => { - it(`${matches ? 'matches' : 'does not match'}: "${input}"`, () => { - const match = new RegExp(hrInputRuleRegExp).test(input); + let tiptapEditor; + let doc; + let p; + let horizontalRule; - expect(match).toBe(matches); - }); + beforeEach(() => { + tiptapEditor = createTestEditor({ extensions: [HorizontalRule] }); + + ({ + builders: { doc, p, horizontalRule }, + } = createDocBuilder({ + tiptapEditor, + names: { + horizontalRule: { nodeType: HorizontalRule.name }, + }, + })); + }); + + it.each` + input | insertedNodes + ${'---'} | ${() => [p(), horizontalRule()]} + ${'--'} | ${() => [p()]} + ${'---x'} | ${() => [p()]} + ${' ---x'} | ${() => [p()]} + ${' --- '} | ${() => [p()]} + ${'x---x'} | ${() => [p()]} + ${'x---'} | ${() => [p()]} + `('with input=$input, then should insert a $insertedNode', ({ input, insertedNodes }) => { + const expectedDoc = doc(...insertedNodes()); + + triggerNodeInputRule({ tiptapEditor, inputRuleText: input }); + + expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON()); }); }); diff --git a/spec/frontend/content_editor/extensions/inline_diff_spec.js b/spec/frontend/content_editor/extensions/inline_diff_spec.js index 63cdf665e7f..99c559a20b1 100644 --- a/spec/frontend/content_editor/extensions/inline_diff_spec.js +++ b/spec/frontend/content_editor/extensions/inline_diff_spec.js @@ -1,27 +1,43 @@ -import { inputRegexAddition, inputRegexDeletion } from '~/content_editor/extensions/inline_diff'; +import InlineDiff from '~/content_editor/extensions/inline_diff'; +import { createTestEditor, createDocBuilder, triggerMarkInputRule } from '../test_utils'; describe('content_editor/extensions/inline_diff', () => { - describe.each` - inputRegex | description | input | matches - ${inputRegexAddition} | ${'inputRegexAddition'} | ${'hello{+world+}'} | ${true} - ${inputRegexAddition} | ${'inputRegexAddition'} | ${'hello{+ world +}'} | ${true} - ${inputRegexAddition} | ${'inputRegexAddition'} | ${'hello {+ world+}'} | ${true} - ${inputRegexAddition} | ${'inputRegexAddition'} | ${'{+hello world +}'} | ${true} - ${inputRegexAddition} | ${'inputRegexAddition'} | ${'{+hello with \nnewline+}'} | ${false} - ${inputRegexAddition} | ${'inputRegexAddition'} | ${'{+open only'} | ${false} - ${inputRegexAddition} | ${'inputRegexAddition'} | ${'close only+}'} | ${false} - ${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'hello{-world-}'} | ${true} - ${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'hello{- world -}'} | ${true} - ${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'hello {- world-}'} | ${true} - ${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'{-hello world -}'} | ${true} - ${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'{+hello with \nnewline+}'} | ${false} - ${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'{-open only'} | ${false} - ${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'close only-}'} | ${false} - `('$description', ({ inputRegex, input, matches }) => { - it(`${matches ? 'matches' : 'does not match'}: "${input}"`, () => { - const match = new RegExp(inputRegex).test(input); + let tiptapEditor; + let doc; + let p; + let inlineDiff; - expect(match).toBe(matches); - }); + beforeEach(() => { + tiptapEditor = createTestEditor({ extensions: [InlineDiff] }); + ({ + builders: { doc, p, inlineDiff }, + } = createDocBuilder({ + tiptapEditor, + names: { + inlineDiff: { markType: InlineDiff.name }, + }, + })); + }); + + it.each` + input | insertedNode + ${'hello{+world+}'} | ${() => p('hello', inlineDiff('world'))} + ${'hello{+ world +}'} | ${() => p('hello', inlineDiff(' world '))} + ${'{+hello with \nnewline+}'} | ${() => p('{+hello with newline+}')} + ${'{+open only'} | ${() => p('{+open only')} + ${'close only+}'} | ${() => p('close only+}')} + ${'hello{-world-}'} | ${() => p('hello', inlineDiff({ type: 'deletion' }, 'world'))} + ${'hello{- world -}'} | ${() => p('hello', inlineDiff({ type: 'deletion' }, ' world '))} + ${'hello {- world-}'} | ${() => p('hello ', inlineDiff({ type: 'deletion' }, ' world'))} + ${'{-hello world -}'} | ${() => p(inlineDiff({ type: 'deletion' }, 'hello world '))} + ${'{-hello with \nnewline-}'} | ${() => p('{-hello with newline-}')} + ${'{-open only'} | ${() => p('{-open only')} + ${'close only-}'} | ${() => p('close only-}')} + `('with input=$input, then should insert a $insertedNode', ({ input, insertedNode }) => { + const expectedDoc = doc(insertedNode()); + + triggerMarkInputRule({ tiptapEditor, inputRuleText: input }); + + expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON()); }); }); diff --git a/spec/frontend/content_editor/extensions/link_spec.js b/spec/frontend/content_editor/extensions/link_spec.js index 026b2a06df3..ead898554d1 100644 --- a/spec/frontend/content_editor/extensions/link_spec.js +++ b/spec/frontend/content_editor/extensions/link_spec.js @@ -1,61 +1,46 @@ -import { - markdownLinkSyntaxInputRuleRegExp, - urlSyntaxRegExp, - extractHrefFromMarkdownLink, -} from '~/content_editor/extensions/link'; +import Link from '~/content_editor/extensions/link'; +import { createTestEditor, createDocBuilder, triggerMarkInputRule } from '../test_utils'; describe('content_editor/extensions/link', () => { - describe.each` - input | matches - ${'[gitlab](https://gitlab.com)'} | ${true} - ${'[documentation](readme.md)'} | ${true} - ${'[link 123](readme.md)'} | ${true} - ${'[link 123](read me.md)'} | ${true} - ${'text'} | ${false} - ${'documentation](readme.md'} | ${false} - ${'https://www.google.com'} | ${false} - `('markdownLinkSyntaxInputRuleRegExp', ({ input, matches }) => { - it(`${matches ? 'matches' : 'does not match'} ${input}`, () => { - const match = new RegExp(markdownLinkSyntaxInputRuleRegExp).exec(input); - - expect(Boolean(match?.groups.href)).toBe(matches); - }); + let tiptapEditor; + let doc; + let p; + let link; + + beforeEach(() => { + tiptapEditor = createTestEditor({ extensions: [Link] }); + ({ + builders: { doc, p, link }, + } = createDocBuilder({ + tiptapEditor, + names: { + link: { markType: Link.name }, + }, + })); }); - describe.each` - input | matches - ${'http://example.com '} | ${true} - ${'https://example.com '} | ${true} - ${'www.example.com '} | ${true} - ${'example.com/ab.html '} | ${false} - ${'text'} | ${false} - ${' http://example.com '} | ${true} - ${'https://www.google.com '} | ${true} - `('urlSyntaxRegExp', ({ input, matches }) => { - it(`${matches ? 'matches' : 'does not match'} ${input}`, () => { - const match = new RegExp(urlSyntaxRegExp).exec(input); - - expect(Boolean(match?.groups.href)).toBe(matches); - }); + afterEach(() => { + tiptapEditor.destroy(); }); - describe('extractHrefFromMarkdownLink', () => { - const input = '[gitlab](https://gitlab.com)'; - const href = 'https://gitlab.com'; - let match; - let result; - - beforeEach(() => { - match = new RegExp(markdownLinkSyntaxInputRuleRegExp).exec(input); - result = extractHrefFromMarkdownLink(match); - }); - - it('extracts the url from a markdown link captured by markdownLinkSyntaxInputRuleRegExp', () => { - expect(result).toEqual({ href }); - }); - - it('makes sure that url text is the last capture group', () => { - expect(match[match.length - 1]).toEqual('gitlab'); - }); + it.each` + input | insertedNode + ${'[gitlab](https://gitlab.com)'} | ${() => p(link({ href: 'https://gitlab.com' }, 'gitlab'))} + ${'[documentation](readme.md)'} | ${() => p(link({ href: 'readme.md' }, 'documentation'))} + ${'[link 123](readme.md)'} | ${() => p(link({ href: 'readme.md' }, 'link 123'))} + ${'[link 123](read me.md)'} | ${() => p(link({ href: 'read me.md' }, 'link 123'))} + ${'text'} | ${() => p('text')} + ${'documentation](readme.md'} | ${() => p('documentation](readme.md')} + ${'http://example.com '} | ${() => p(link({ href: 'http://example.com' }, 'http://example.com'))} + ${'https://example.com '} | ${() => p(link({ href: 'https://example.com' }, 'https://example.com'))} + ${'www.example.com '} | ${() => p(link({ href: 'www.example.com' }, 'www.example.com'))} + ${'example.com/ab.html '} | ${() => p('example.com/ab.html')} + ${'https://www.google.com '} | ${() => p(link({ href: 'https://www.google.com' }, 'https://www.google.com'))} + `('with input=$input, then should insert a $insertedNode', ({ input, insertedNode }) => { + const expectedDoc = doc(insertedNode()); + + triggerMarkInputRule({ tiptapEditor, inputRuleText: input }); + + expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON()); }); }); diff --git a/spec/frontend/content_editor/extensions/math_inline_spec.js b/spec/frontend/content_editor/extensions/math_inline_spec.js index 82eb85477de..abf10317b5a 100644 --- a/spec/frontend/content_editor/extensions/math_inline_spec.js +++ b/spec/frontend/content_editor/extensions/math_inline_spec.js @@ -1,5 +1,5 @@ import MathInline from '~/content_editor/extensions/math_inline'; -import { createTestEditor, createDocBuilder } from '../test_utils'; +import { createTestEditor, createDocBuilder, triggerMarkInputRule } from '../test_utils'; describe('content_editor/extensions/math_inline', () => { let tiptapEditor; @@ -26,16 +26,9 @@ describe('content_editor/extensions/math_inline', () => { ${'$`a^2`'} | ${() => p('$`a^2`')} ${'`a^2`$'} | ${() => p('`a^2`$')} `('with input=$input, then should insert a $insertedNode', ({ input, insertedNode }) => { - const { view } = tiptapEditor; const expectedDoc = doc(insertedNode()); - tiptapEditor.chain().setContent(input).setTextSelection(0).run(); - - const { state } = tiptapEditor; - const { selection } = state; - - // Triggers the event handler that input rules listen to - view.someProp('handleTextInput', (f) => f(view, selection.from, input.length + 1, input)); + triggerMarkInputRule({ tiptapEditor, inputRuleText: input }); expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON()); }); diff --git a/spec/frontend/content_editor/extensions/table_of_contents_spec.js b/spec/frontend/content_editor/extensions/table_of_contents_spec.js index 83818899c17..0ddd88b39fe 100644 --- a/spec/frontend/content_editor/extensions/table_of_contents_spec.js +++ b/spec/frontend/content_editor/extensions/table_of_contents_spec.js @@ -1,13 +1,17 @@ import TableOfContents from '~/content_editor/extensions/table_of_contents'; -import { createTestEditor, createDocBuilder } from '../test_utils'; +import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils'; -describe('content_editor/extensions/emoji', () => { +describe('content_editor/extensions/table_of_contents', () => { let tiptapEditor; - let builders; + let doc; + let tableOfContents; + let p; beforeEach(() => { tiptapEditor = createTestEditor({ extensions: [TableOfContents] }); - ({ builders } = createDocBuilder({ + ({ + builders: { doc, p, tableOfContents }, + } = createDocBuilder({ tiptapEditor, names: { tableOfContents: { nodeType: TableOfContents.name } }, })); @@ -15,20 +19,16 @@ describe('content_editor/extensions/emoji', () => { it.each` input | insertedNode - ${'[[_TOC_]]'} | ${'tableOfContents'} - ${'[TOC]'} | ${'tableOfContents'} - ${'[toc]'} | ${'p'} - ${'TOC'} | ${'p'} - ${'[_TOC_]'} | ${'p'} - ${'[[TOC]]'} | ${'p'} + ${'[[_TOC_]]'} | ${() => tableOfContents()} + ${'[TOC]'} | ${() => tableOfContents()} + ${'[toc]'} | ${() => p()} + ${'TOC'} | ${() => p()} + ${'[_TOC_]'} | ${() => p()} + ${'[[TOC]]'} | ${() => p()} `('with input=$input, then should insert a $insertedNode', ({ input, insertedNode }) => { - const { doc } = builders; - const { view } = tiptapEditor; - const { selection } = view.state; - const expectedDoc = doc(builders[insertedNode]()); + const expectedDoc = doc(insertedNode()); - // Triggers the event handler that input rules listen to - view.someProp('handleTextInput', (f) => f(view, selection.from, selection.to, input)); + triggerNodeInputRule({ tiptapEditor, inputRuleText: input }); expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON()); }); diff --git a/spec/frontend/content_editor/extensions/table_spec.js b/spec/frontend/content_editor/extensions/table_spec.js new file mode 100644 index 00000000000..121fe9192db --- /dev/null +++ b/spec/frontend/content_editor/extensions/table_spec.js @@ -0,0 +1,102 @@ +import Bold from '~/content_editor/extensions/bold'; +import BulletList from '~/content_editor/extensions/bullet_list'; +import ListItem from '~/content_editor/extensions/list_item'; +import Table from '~/content_editor/extensions/table'; +import TableCell from '~/content_editor/extensions/table_cell'; +import TableRow from '~/content_editor/extensions/table_row'; +import TableHeader from '~/content_editor/extensions/table_header'; +import { createTestEditor, createDocBuilder } from '../test_utils'; + +describe('content_editor/extensions/table', () => { + let tiptapEditor; + let doc; + let p; + let table; + let tableHeader; + let tableCell; + let tableRow; + let initialDoc; + let mockAlert; + + beforeEach(() => { + tiptapEditor = createTestEditor({ + extensions: [Table, TableCell, TableRow, TableHeader, BulletList, Bold, ListItem], + }); + + ({ + builders: { doc, p, table, tableCell, tableHeader, tableRow }, + } = createDocBuilder({ + tiptapEditor, + names: { + bold: { markType: Bold.name }, + table: { nodeType: Table.name }, + tableHeader: { nodeType: TableHeader.name }, + tableCell: { nodeType: TableCell.name }, + tableRow: { nodeType: TableRow.name }, + bulletList: { nodeType: BulletList.name }, + listItem: { nodeType: ListItem.name }, + }, + })); + + initialDoc = doc( + table( + { isMarkdown: true }, + tableRow(tableHeader(p('This is')), tableHeader(p('a table'))), + tableRow(tableCell(p('this is')), tableCell(p('the first row'))), + ), + ); + + mockAlert = jest.fn(); + }); + + it('triggers a warning (just once) if the table is markdown, but the changes in the document will render an HTML table instead', () => { + tiptapEditor.commands.setContent(initialDoc.toJSON()); + + tiptapEditor.on('alert', mockAlert); + + tiptapEditor.commands.setTextSelection({ from: 20, to: 22 }); + tiptapEditor.commands.toggleBulletList(); + + jest.advanceTimersByTime(1001); + expect(mockAlert).toHaveBeenCalled(); + + mockAlert.mockReset(); + + tiptapEditor.commands.setTextSelection({ from: 4, to: 6 }); + tiptapEditor.commands.toggleBulletList(); + + jest.advanceTimersByTime(1001); + expect(mockAlert).not.toHaveBeenCalled(); + }); + + it('does not trigger a warning if the table is markdown, and the changes in the document can generate a markdown table', () => { + tiptapEditor.commands.setContent(initialDoc.toJSON()); + + tiptapEditor.on('alert', mockAlert); + + tiptapEditor.commands.setTextSelection({ from: 20, to: 22 }); + tiptapEditor.commands.toggleBold(); + + jest.advanceTimersByTime(1001); + expect(mockAlert).not.toHaveBeenCalled(); + }); + + it('does not trigger any warnings if the table is not markdown', () => { + initialDoc = doc( + table( + tableRow(tableHeader(p('This is')), tableHeader(p('a table'))), + tableRow(tableCell(p('this is')), tableCell(p('the first row'))), + ), + ); + + tiptapEditor.commands.setContent(initialDoc.toJSON()); + + tiptapEditor.on('alert', mockAlert); + + tiptapEditor.commands.setTextSelection({ from: 20, to: 22 }); + tiptapEditor.commands.toggleBulletList(); + + jest.advanceTimersByTime(1001); + expect(mockAlert).not.toHaveBeenCalled(); + }); +}); diff --git a/spec/frontend/content_editor/extensions/word_break_spec.js b/spec/frontend/content_editor/extensions/word_break_spec.js new file mode 100644 index 00000000000..23167269d7d --- /dev/null +++ b/spec/frontend/content_editor/extensions/word_break_spec.js @@ -0,0 +1,35 @@ +import WordBreak from '~/content_editor/extensions/word_break'; +import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils'; + +describe('content_editor/extensions/word_break', () => { + let tiptapEditor; + let doc; + let p; + let wordBreak; + + beforeEach(() => { + tiptapEditor = createTestEditor({ extensions: [WordBreak] }); + + ({ + builders: { doc, p, wordBreak }, + } = createDocBuilder({ + tiptapEditor, + names: { + wordBreak: { nodeType: WordBreak.name }, + }, + })); + }); + + it.each` + input | insertedNode + ${'<wbr>'} | ${() => p(wordBreak())} + ${'<wbr'} | ${() => p()} + ${'wbr>'} | ${() => p()} + `('with input=$input, then should insert a $insertedNode', ({ input, insertedNode }) => { + const expectedDoc = doc(insertedNode()); + + triggerNodeInputRule({ tiptapEditor, inputRuleText: input }); + + expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON()); + }); +}); |