summaryrefslogtreecommitdiff
path: root/spec/frontend/content_editor/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/content_editor/extensions')
-rw-r--r--spec/frontend/content_editor/extensions/attachment_spec.js20
-rw-r--r--spec/frontend/content_editor/extensions/blockquote_spec.js46
-rw-r--r--spec/frontend/content_editor/extensions/emoji_spec.js10
-rw-r--r--spec/frontend/content_editor/extensions/frontmatter_spec.js30
-rw-r--r--spec/frontend/content_editor/extensions/horizontal_rule_spec.js49
-rw-r--r--spec/frontend/content_editor/extensions/inline_diff_spec.js60
-rw-r--r--spec/frontend/content_editor/extensions/link_spec.js91
-rw-r--r--spec/frontend/content_editor/extensions/math_inline_spec.js11
-rw-r--r--spec/frontend/content_editor/extensions/table_of_contents_spec.js32
-rw-r--r--spec/frontend/content_editor/extensions/table_spec.js102
-rw-r--r--spec/frontend/content_editor/extensions/word_break_spec.js35
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());
+ });
+});