import { describe, expect, test } from "@odoo/hoot";
import { setupEditor, testEditor } from "../_helpers/editor";
import { unformat } from "../_helpers/format";
import { microTick, press } from "@odoo/hoot-dom";
import { animationFrame, tick } from "@odoo/hoot-mock";
import { deleteBackward, insertText, tripleClick, undo } from "../_helpers/user_actions";
import { getContent } from "../_helpers/selection";
/**
* content of the "deleteBackward" sub suite in editor.test.js
*/
describe("Selection collapsed", () => {
describe("Basic", () => {
test("should do nothing", async () => {
// TODO the addition of
"correction" part was judged
// unnecessary to enforce, the rest of the test still makes
// sense: not removing the unique
[]
", stepFunction: deleteBackward, contentAfter: "[]
", }); // TODO this cannot actually be tested currently as a // backspace/delete in that case is not even detected // (no input event to rollback) // await testEditor({ // contentBefore: '[
]
visible. // // It does not exist in VDocument and selecting it // // has no meaning in the DOM. // contentAfter: '
[]
[]abc
", stepFunction: deleteBackward, contentAfter: "[]abc
", }); }); test("should delete the first character in a paragraph", async () => { await testEditor({ contentBefore: "a[]bc
", stepFunction: deleteBackward, contentAfter: "[]bc
", }); }); test("should delete a character within a paragraph", async () => { await testEditor({ contentBefore: "ab[]c
", stepFunction: deleteBackward, contentAfter: "a[]c
", }); }); test("should delete the last character in a paragraph", async () => { await testEditor({ contentBefore: "abc[]
", stepFunction: deleteBackward, contentAfter: "ab[]
", }); await testEditor({ contentBefore: "ab c[]
", stepFunction: deleteBackward, // The space should be converted to an unbreakable space // so it is visible. contentAfter: "ab []
", }); }); test("should merge a paragraph into an empty paragraph", async () => { await testEditor({ contentBefore: "[]abc
", stepFunction: deleteBackward, contentAfter: "[]abc
", }); }); test("should merge node correctly", async () => { await testEditor({ contentBefore: '[]c
dab\u200B[]c
", stepFunction: deleteBackward, contentAfter: "a[]c
", }); }); test("should keep inline block", async () => { await testEditor({ contentBefore: "ab
ab
ab
uv
uv
uv
cd
cd
cd
abcd[]e
', stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); }, contentAfter: "a[]e
", }); }); test("ZWS: should delete element content but keep cursor in", async () => { await testEditor({ contentBefore: 'uvw[]xy
', stepFunction: async (editor) => { deleteBackward(editor); }, contentAfterEdit: 'uv[]\u200Bxy
', contentAfter: "uv[]xy
", }); await testEditor({ contentBefore: 'uvw[]xy
', stepFunction: async (editor) => { deleteBackward(editor); await insertText(editor, "i"); }, contentAfterEdit: 'uvi[]xy
', contentAfter: 'uvi[]xy
', }); await testEditor({ contentBefore: 'abcd[]ef
', stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); }, contentAfterEdit: 'ab[]\u200Bef
', contentAfter: 'ab[]\u200Bef
', }); await testEditor({ contentBefore: 'abcd[]ef
', stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); await insertText(editor, "x"); }, contentAfterEdit: 'abx[]ef
', contentAfter: 'abx[]ef
', }); }); test("should ignore ZWS and merge (1)", async () => { await testEditor({ contentBefore: 'ab[]\u200B
', stepFunction: async (editor) => { deleteBackward(editor); await insertText(editor, "x"); }, contentAfter: "ax[]
", }); await testEditor({ contentBefore: 'cd[]\u200B
', stepFunction: async (editor) => { deleteBackward(editor); await insertText(editor, "x"); }, contentAfter: 'cx[]
', }); await testEditor({ contentBefore: 'ef
[]\u200B
efx[]
", }); }); test("should ignore ZWS and merge (2)", async () => { await testEditor({ contentBefore: 'ab
[]\u200Bab[]
cd
cd
x[]ABC
ABC
ABC
ABC
ABC
ABC
abc
[]defabc[]def
abc
[]defghi
abc[]def
ghi
abc
[]def
', stepFunction: deleteBackward, contentAfter: "abc[]def
", }); await testEditor({ contentBefore: 'abc
[]def
ghi
', stepFunction: deleteBackward, contentAfter: "abc[]def
ghi
", }); }); test("should delete starting white space and merge paragraphs", async () => { await testEditor({ contentBefore: `mollis.
\n []Pelentesque
`, stepFunction: deleteBackward, contentAfter: `mollis.[]Pelentesque
`, }); }); test('should remove contenteditable="false"', async () => { await testEditor({ contentBefore: `abc
[]ghi
`, stepFunction: async (editor) => { deleteBackward(editor); }, contentAfter: `abc
[]ghi
`, }); }); test("should remove a fontawesome", async () => { await testEditor({ contentBefore: `abc[]def
abc[]def
abc
xyz[]def
abc
xyz[]defabc
[]def
abc
[]defabc
[]defabc
[]defabc
[]
abc[]
`, }); }); test("should not remove a non editable sibling (inline)", async () => { await testEditor({ contentBefore: unformat(`[]
[]
[]
[]
abc
[]def
abc
[]def
abc
[]def
`, stepFunction: deleteBackward, contentAfterEdit: `abc
abc
abc
abc
[]def
`, }); }); test("should remove a link to uploaded document", async () => { await testEditor({ contentBefore: ``, stepFunction: deleteBackward, contentAfter: `abc[]
`, }); }); test("should remove a link to uploaded document at the beginning of the editable", async () => { await testEditor({ contentBefore: ``, stepFunction: deleteBackward, contentAfter: `[]
ab[]cdef
`, stepFunction: deleteBackward, contentAfter: `ab[]cdef
`, }); }); test("should merge p elements inside conteneditbale=true inside contenteditable=false", async () => { await testEditor({ contentBefore: `abc
[]def
abc[]def
abcd\u0020[]
`, stepFunction: deleteBackward, contentAfter: `abcd[]
`, }); }); }); describe("Line breaks", () => { describe("Single", () => { test("should delete a leading line break", async () => { await testEditor({ contentBefore: "
[]abc
[]abc
", }); await testEditor({ contentBefore: "
[] abc
[]abc
", }); }); test("should delete a line break within a paragraph", async () => { await testEditor({ contentBefore: "ab
[]cd
ab[]cd
", }); await testEditor({ contentBefore: "ab
[]cd
ab []cd
", }); await testEditor({ contentBefore: "ab
[] cd
ab[]cd
", }); }); test("should delete a trailing line break", async () => { await testEditor({ contentBefore: "abc
[]
abc[]
", }); await testEditor({ contentBefore: "abc
[]
abc[]
", }); await testEditor({ contentBefore: "abc
[]
abc []
", }); }); test("should delete a character and a line break, emptying a paragraph", async () => { await testEditor({ contentBefore: "aaa
a[]
aaa
[]
ab
c[]
ab
[]
ab
[]
cd
", stepFunction: deleteBackward, contentAfter: "ab[]
cd
", }); }); test("should delete a line break (1)", async () => { // 2-1 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: deleteBackward, contentAfter: "ab
[]
cd
", }); }); test("should delete a line break, then merge a paragraph with 3ab
[]
cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); }, contentAfter: "ab[]
cd
", }); }); test("should delete a line break (2)", async () => { // 3-1 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: deleteBackward, contentAfter: "ab
[]
cd
", }); }); test("should delete two line breaks (3)", async () => { // 3-2 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); }, contentAfter: "ab
[]
cd
", }); }); test("should delete two line breaks, then merge a paragraph with 3ab
[]
cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); }, contentAfter: "ab[]
cd
", }); }); test("should delete a line break when several", async () => { // 4-1 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: deleteBackward, // A trailing line break is rendered as twoab
[]
cd
", }); // 5-1 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: deleteBackward, // This should be identical to 4-1 contentAfter: "ab
[]
cd
", }); }); test("should delete two line breaks", async () => { // 4-2 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); }, // A trailing line break is rendered as twoab
[]
cd
", }); // 5-2 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); }, // This should be identical to 4-2 contentAfter: "ab
[]
cd
", }); }); test("should delete three line breaks (emptying a paragraph)", async () => { // 4-3 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); }, contentAfter: "ab
[]
cd
", }); // 5-3 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); }, // This should be identical to 4-3 contentAfter: "ab
[]
cd
", }); }); test("should delete three line breaks, then merge an empty parargaph into a paragraph with text", async () => { // 4-4 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); }, // This should be identical to 4-4 contentAfter: "ab[]
cd
", }); // 5-4 await testEditor({ contentBefore: "ab
[]
cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); }, contentAfter: "ab[]
cd
", }); }); test("should merge a paragraph into a paragraph with 4ab
[]cd
", stepFunction: deleteBackward, contentAfter: "ab
[]cd
ab
[]cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); }, contentAfter: "ab
[]cd
ab
[]cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); }, contentAfter: "ab
[]cd
ab
[]cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); }, contentAfter: "ab
[]cd
", }); }); test("should merge a paragraph into a paragraph with 4ab
[]cd
", stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); }, contentAfter: "ab[]cd
", }); }); }); }); describe("Pre", () => { test("should delete a character in a pre", async () => { await testEditor({ contentBefore: "ab[]cd", stepFunction: deleteBackward, contentAfter: "
a[]cd", }); }); test("should delete a character in a pre (space before)", async () => { await testEditor({ contentBefore: "
ab[]cd", stepFunction: deleteBackward, contentAfter: "
a[]cd", }); }); test("should delete a character in a pre (space after)", async () => { await testEditor({ contentBefore: "
ab[]cd", stepFunction: deleteBackward, contentAfter: "
a[]cd", }); }); test("should delete a character in a pre (space before and after)", async () => { await testEditor({ contentBefore: "
ab[]cd", stepFunction: deleteBackward, contentAfter: "
a[]cd", }); }); test("should delete a space in a pre", async () => { await testEditor({ contentBefore: "
[] ab", stepFunction: deleteBackward, contentAfter: "
[] ab", }); }); test("should delete a newline in a pre", async () => { await testEditor({ contentBefore: "
ab\n[]cd", stepFunction: deleteBackward, contentAfter: "
ab[]cd", }); }); test("should delete all leading space in a pre", async () => { await testEditor({ contentBefore: "
[]ab", stepFunction: async (BasicEditor) => { deleteBackward(BasicEditor); deleteBackward(BasicEditor); deleteBackward(BasicEditor); deleteBackward(BasicEditor); deleteBackward(BasicEditor); }, contentAfter: "
[]ab", }); }); test("should delete all trailing space in a pre", async () => { await testEditor({ contentBefore: "
ab []", stepFunction: async (BasicEditor) => { deleteBackward(BasicEditor); deleteBackward(BasicEditor); deleteBackward(BasicEditor); deleteBackward(BasicEditor); deleteBackward(BasicEditor); }, contentAfter: "
ab[]", }); }); }); describe("Formats", () => { test("should delete a character before a format node", async () => { await testEditor({ contentBefore: "
abc[]def
", stepFunction: deleteBackward, // The selection is normalized so we only have one way // to represent a position. contentAfter: "ab[]def
", }); await testEditor({ contentBefore: "abc[]def
", stepFunction: deleteBackward, contentAfter: "ab[]def
", }); }); }); describe("Nested Elements", () => { test("should delete a h1 inside a td immediately after insertion", async () => { await testEditor({ contentBefore: "[] | ||
[] | ||
ab
[]cd
", stepFunction: deleteBackward, contentAfter: "ab[]cd
", }); }); test("should merge a paragraph with formated text into a paragraph with text", async () => { await testEditor({ contentBefore: "aa
[]abbb
", stepFunction: deleteBackward, contentAfter: "aa[]abbb
", }); }); test("should merge a paragraph with text into a heading1 with text", async () => { await testEditor({ contentBefore: "[]cd
", stepFunction: deleteBackward, contentAfter: "[]
[]
[]cd
[]cd
ef[]abc
', stepFunction: deleteBackward, contentAfter: "[]abc
", }); }); test("should merge two paragraphs with spans of same classes", async () => { await testEditor({ contentBefore: 'ab
[]cd
', stepFunction: deleteBackward, contentAfter: 'ab[]cd
', }); }); test("should merge two paragraphs with spans of different classes without merging the spans", async () => { await testEditor({ contentBefore: 'ab
[]cd
', stepFunction: deleteBackward, contentAfter: 'ab[]cd
', }); }); test("should merge two paragraphs of different classes, each containing spans of the same class", async () => { await testEditor({ contentBefore: 'ab
[]cd
', stepFunction: deleteBackward, contentAfter: 'ab[]cd
', }); }); test("should merge two paragraphs of different classes, each containing spans of different classes without merging the spans", async () => { await testEditor({ contentBefore: 'ab
[]cd
', stepFunction: deleteBackward, contentAfter: 'ab[]cd
', }); }); test("should delete a line break between two spans with bold and merge these formats", async () => { await testEditor({ contentBefore: 'ab
[]cd
ab[]cd
', }); }); test("should delete a character in a span with bold, then a line break between two spans with bold and merge these formats", async () => { await testEditor({ contentBefore: 'ab
c[]de
ab
[]de
[]
[]
[]
content
`), stepFunction: deleteBackward, contentAfter: unformat(`[]
content
`), }); }); test("should not remove the uneditable nesting zone nor the editable nested zone if the last element of the nested zone is not empty", async () => { await testEditor({ contentBefore: unformat(`[]content
[]content
content
[]content
`), stepFunction: deleteBackward, contentAfter: unformat(`[]content
`), }); }); }); describe("POC extra tests", () => { test("should delete an unique space between letters", async () => { await testEditor({ contentBefore: "ab []cd
", stepFunction: deleteBackward, contentAfter: "ab[]cd
", }); }); test("should delete the first character in a paragraph (2)", async () => { await testEditor({ contentBefore: "a[] bc
", stepFunction: deleteBackward, contentAfter: "[] bc
", }); }); test("should delete a space", async () => { await testEditor({ contentBefore: "ab [] de
", stepFunction: deleteBackward, contentAfter: "ab[]de
", }); }); test("should delete a one letter word followed by visible space (start of block)", async () => { await testEditor({ contentBefore: "a[] b
", stepFunction: deleteBackward, contentAfter: "[] b
", }); await testEditor({ contentBefore: "[a] b
", stepFunction: deleteBackward, contentAfter: "[] b
", }); }); test("should delete a one letter word surrounded by visible space", async () => { await testEditor({ contentBefore: "ab c[] de
", stepFunction: deleteBackward, contentAfter: "ab [] de
", }); await testEditor({ contentBefore: "ab [c] de
", stepFunction: deleteBackward, contentAfter: "ab [] de
", }); }); test("should delete a one letter word preceded by visible space (end of block)", async () => { await testEditor({ contentBefore: "a b[]
", stepFunction: deleteBackward, contentAfter: "a []
", }); await testEditor({ contentBefore: "a [b]
", stepFunction: deleteBackward, contentAfter: "a []
", }); }); test("should delete an empty paragraph in a table cell", async () => await testEditor({ contentBefore: "a [] |
a[] |
a[]
", stepFunction: deleteBackward, contentAfter: "[]
[]
[]
ab
[]cd
", stepFunction: deleteBackward, // This is a tricky case: the spaces after ab are // visible on Firefox but not on Chrome... to be // consistent we enforce the space removal here but // maybe not a good idea... see next case -> contentAfter: "ab[]cd
", }); await testEditor({ contentBefore: "ab
[]cd
", stepFunction: deleteBackward, // This is the same visible case as the one above. The // difference is that here the space after ab is visible // on both Firefox and Chrome, so it should stay // visible. contentAfter: "ab []cd
", }); }); test("should remove a br and remove following spaces", async () => { await testEditor({ contentBefore: "ab
[] cd
ab[]cd
", }); await testEditor({ contentBefore: "ab
[] xcd
ab[]xcd
", }); }); test("should ignore empty inline node between blocks being merged", async () => { await testEditor({ contentBefore: "abc
[]def
abc[]def
ab
[]c
', stepFunction: deleteBackward, contentAfter: 'ab[]c
ab
[]c
', stepFunction: deleteBackward, contentAfter: 'ab[]c
ab
de[]fg
', stepFunction: deleteBackward, contentAfter: 'ab
de[]fgab
[]fg
', stepFunction: deleteBackward, contentAfter: 'ab
abc
[]def
", stepFunction: deleteBackward, contentAfter: "abc
[]def
", }); }); test("should remove only one br between contents", async () => { await testEditor({ contentBefore: "abc
[]
def
abc[]
def
[]
[]
ab
cd | ef |
gh | ij |
[]kl
` ), stepFunction: deleteBackward, contentAfter: unformat( `ab
cd | ef |
gh | ij |
[]kl
` ), }); }); test("should not merge a table into its previous sibling", async () => { await testEditor({ contentBefore: unformat( `ab
[]cd | ef |
gh | ij |
kl
` ), stepFunction: deleteBackward, contentAfter: unformat( `ab
[]cd | ef |
gh | ij |
kl
` ), }); }); test("should delete an image that is displayed as a block", async () => { await testEditor({ // @phoenix content adapted to make it valid html contentBefore: unformat(`ab [c] d
ab []\u200B d
ab []\u200B d
ab [c] d
ab x[] d
ab x[] d
ab [c] d
ab []\u200B d
ab [] d
ab[c]d
abx[]d
abx[]d
ab [cde] f
ab x[] f
ab x[] f
d]e
f// Instead of removing the
, // ex :
ab[]e
fb[c
d]efxxx
b[]ef
xxx
ab[cd]ef
", stepFunction: deleteBackward, contentAfter: "ab[]ef
", }); }); test("should delete part of the text within a paragraph (backward, backward selection)", async () => { // Backward selection await testEditor({ contentBefore: "ab]cd[ef
", stepFunction: deleteBackward, contentAfter: "ab[]ef
", }); }); test("should delete across two paragraphs", async () => { // Forward selection await testEditor({ contentBefore: "ab[cd
ef]gh
", stepFunction: deleteBackward, contentAfter: "ab[]gh
", }); // Backward selection await testEditor({ contentBefore: "ab]cd
ef[gh
", stepFunction: deleteBackward, contentAfter: "ab[]gh
", }); }); test("should delete part of the text across two paragraphs (backward, forward selection)", async () => { await testEditor({ contentBefore: "b[c
d]e
fb[]e
fb]c
d[e
fb[]e
f[abc]
", stepFunction: deleteBackward, contentAfter: "[]
]abc[
", stepFunction: deleteBackward, contentAfter: "[]
ab[cd
ef
ghijkl]mn
ab[]mn
", }); await testEditor({ contentBefore: "ab[cd
ef
ghijk]lmn
ab[]lmn
", }); // Backward selection await testEditor({ contentBefore: "ab]cd
ef
ghijkl[mn
ab[]mn
", }); await testEditor({ contentBefore: "ab]cd
ef
ghijk[lmn
ab[]lmn
", }); }); // test("should delete all contents of a complex DOM with format nodes and multiple paragraphs (backward, forward selection)", async () => { await testEditor({ contentBefore: "[abcd
ef
ghijklmn]
[]
]abcd
ef
ghijklmn[
[]
ef]gh
", stepFunction: deleteBackward, contentAfter: "ef[gh
", stepFunction: deleteBackward, contentAfter: "ef]gh1
", stepFunction: deleteBackward, contentAfter: "[]gh1
", }); await testEditor({ contentBefore: "ef]gh2
", stepFunction: deleteBackward, contentAfter: "[]gh2
", }); // Backward selection await testEditor({ contentBefore: "ef[gh3
", stepFunction: deleteBackward, contentAfter: "[]gh3
", }); await testEditor({ contentBefore: "ef[gh4
", stepFunction: deleteBackward, contentAfter: "[]gh4
", }); }); test("should delete a heading (triple click backspace) (1)", async () => { const { editor, el } = await setupEditor("def
", {}); tripleClick(el.querySelector("h1")); await microTick(); // Chrome puts the cursor at the start of next sibling expect(getContent(el)).toBe("]def
"); await tick(); // The Editor corrects it on selection change expect(getContent(el)).toBe("def
"); tripleClick(el.querySelector("h1")); await microTick(); // Chrome puts the cursor at the start of next sibling expect(getContent(el)).toBe("]def
"); await tick(); // The Editor corrects it repeatedly on selection change expect(getContent(el)).toBe("def
"); deleteBackward(editor); expect(getContent(el)).toBe( 'def
' ); }); test("should delete a heading (triple click backspace) (2)", async () => { const { editor, el } = await setupEditor("def
", {}); tripleClick(el.querySelector("h1")); await microTick(); // Chrome puts the cursor at the start of next sibling expect(getContent(el)).toBe("]
def
"); await tick(); // The Editor corrects it on selection change expect(getContent(el)).toBe("def
"); deleteBackward(editor); expect(getContent(el)).toBe( 'def
' ); }); test("should delete last character of paragraph and merge the two p elements", async () => { await testEditor({ contentBefore: "ab[c
]def
", stepFunction: deleteBackward, contentAfter: "ab[]def
", }); await testEditor({ contentBefore: "ab[c
]
def
", stepFunction: deleteBackward, contentAfter: "ab[]
def
", }); }); test("should delete first character of paragraph, as well as selected paragraph break", async () => { await testEditor({ contentBefore: "abc[
d]ef
", stepFunction: deleteBackward, contentAfter: "abc[]ef
", }); }); test("should remove a fully selected table", async () => { await testEditor({ contentBefore: unformat( `a[b
cd | ef |
gh | ij |
k]l
` ), stepFunction: deleteBackward, contentAfter: "a[]l
", }); }); test("should remove a fully selected nested table", async () => { await testEditor({ contentBefore: unformat( `a[b
|
ef | ||||
gh | ij |
k]l
` ), stepFunction: deleteBackward, contentAfter: "a[]l
", }); }); test("should delete nothing when in an empty table cell", async () => { await testEditor({ contentBefore: "abc | [] | abc |
abc | [] | abc |
abc | [] |
abc | [] |
cd | e[f | gh |
ij | k]l | mn |
op | qr | st |
cd | [] | gh |
ij | mn | |
op | qr | st |
[ab | cd] |
ef | gh |
[]ef | gh |
[ab | cd |
ef] | gh |
[]cd |
gh |
a[b
cd | ef |
g]h | ij |
kl
` ), stepFunction: deleteBackward, contentAfter: unformat( `a[]
kl
` ), }); }); test("should remove a table and some text (even if the table is partly selected)", async () => { await testEditor({ contentBefore: unformat( `ab
cd | ef |
gh | i[j |
k]l
` ), stepFunction: deleteBackward, contentAfter: unformat( `ab
[]l
` ), }); }); test("should remove some text, a table and some more text", async () => { await testEditor({ contentBefore: unformat( `a[b
cd | ef |
gh | ij |
k]l
` ), stepFunction: deleteBackward, contentAfter: `a[]l
`, }); }); test("should remove a selection of several tables", async () => { await testEditor({ contentBefore: unformat( `cd | e[f |
gh | ij |
cd | ef |
gh | ij |
cd | e]f |
gh | ij |
[]
0[1
cd | ef |
gh | ij |
23
cd | ef |
gh | ij |
45
cd | ef |
gh | ij |
67]
` ), stepFunction: deleteBackward, contentAfter: `0[]
`, }); }); test("should remove everything, including several tables", async () => { await testEditor({ contentBefore: unformat( `[01
cd | ef |
gh | ij |
23
cd | ef |
gh | ij |
45
cd | ef |
gh | ij |
67]
` ), stepFunction: deleteBackward, contentAfter: `[]
] |
[] | |
ab[cd]ef
', stepFunction: deleteBackward, contentAfter: 'ab[]\u200Bef
', }); }); test("should delete if first element and append in paragraph", async () => { await testEditor({ contentBefore: ``, stepFunction: deleteBackward, contentAfter: `
[]
[]
[]
[]
[]ab | cd | ef |
[]ab | cd | ef |
a[bcde]f
', stepFunction: deleteBackward, contentAfter: 'a[]\u200Bf
', }); }); test("should delete styling nodes when delete if empty with space around inline (backward)", async () => { // deleteBackward selection await testEditor({ contentBefore: 'ab [cd] ef
', stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); }, contentAfter: "ab[] ef
", }); }); test("should delete styling nodes when delete if empty (backward)", async () => { await testEditor({ contentBefore: 'uv[wx]yz
', stepFunction: async (editor) => { deleteBackward(editor); deleteBackward(editor); }, contentAfter: "u[]yz
", }); }); test("should transform the last space of a container to an after removing the last word through deleteRange", async () => { await testEditor({ contentBefore: `a [b]
`, stepFunction: async (editor) => { deleteBackward(editor); }, contentAfter: `a []
`, }); }); describe("Nested editable zone (inside contenteditable=false element)", () => { test("should extend the range to fully include contenteditable=false that are partially selected at the end of the range", async () => { await testEditor({ contentBefore: unformat(`before[o
intruder]
after
`), stepFunction: async (editor) => { deleteBackward(editor); }, contentAfter: unformat(`before[]
after
`), }); }); // @todo @phoenix: review this spec. It should not merge, like the test above. test("should extend the range to fully include contenteditable=false that are partially selected at the start of the range", async () => { await testEditor({ contentBefore: unformat(`before
[intruder
o]after
`), stepFunction: async (editor) => { deleteBackward(editor); }, contentAfter: unformat(`before[]after
`), }); }); test("should remove element which is contenteditable=true even if their parent is contenteditable=false", async () => { await testEditor({ contentBefore: unformat(`before[o
intruder
o]after
`), stepFunction: async (editor) => { deleteBackward(editor); }, contentAfter: unformat(`before[]after
`), }); }); test("should remove empty paragraph and content from the second one", async () => { await testEditor({ contentBefore: "ab
[
d]ef
", stepFunction: deleteBackward, contentAfter: "ab
[]ef
", }); }); test.todo("should not delete in contenteditable=false 1", async () => { await testEditor({ contentBefore: `ab[cd]ef
`, stepFunction: deleteBackward, contentAfter: `ab[cd]ef
`, }); }); test.todo("should not delete in contenteditable=false 2", async () => { await testEditor({ contentBefore: `a[b
cd
e]f
a[b
cd
e]f
abc
][]
def
][]