mirror of
https://github.com/penpot/penpot.git
synced 2025-05-05 21:05:55 +02:00
1166 lines
43 KiB
JavaScript
1166 lines
43 KiB
JavaScript
import { expect, describe, test } from "vitest";
|
|
import TextEditor from "~/editor/TextEditor";
|
|
import { createRoot } from "~/editor/content/dom/Root";
|
|
import { createEmptyParagraph, createParagraph } from "~/editor/content/dom/Paragraph";
|
|
import { createInline } from "~/editor/content/dom/Inline";
|
|
import { createLineBreak } from "~/editor/content/dom/LineBreak";
|
|
import { TextEditorMock } from "~/test/TextEditorMock";
|
|
import { SelectionController } from "./SelectionController";
|
|
import { SelectionDirection } from "./SelectionDirection";
|
|
|
|
/* @vitest-environment jsdom */
|
|
|
|
/**
|
|
* Utility function to make focus and selections work properly in JSDOM.
|
|
*
|
|
* @param {Selection} selection
|
|
* @param {TextEditor} textEditor
|
|
* @param {Node} focusNode
|
|
* @param {number} [focusOffset=0]
|
|
* @param {Node} [anchorNode=null]
|
|
* @param {number} [anchorOffset=0]
|
|
*/
|
|
function focus(selection, textEditor, focusNode, focusOffset = 0, anchorNode = focusNode, anchorOffset = focusOffset) {
|
|
textEditor.element.focus();
|
|
selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
|
|
document.dispatchEvent(new Event("selectionchange"));
|
|
}
|
|
|
|
describe("SelectionController", () => {
|
|
test("`selection` should return the Selection object kept by the SelectionController", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithText("");
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(textEditorMock, selection);
|
|
expect(selectionController.selection).toBe(selection);
|
|
});
|
|
|
|
test("`range` should return the Range object kept by the SelectionController", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithText("");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
// When the editor hasn't been focused
|
|
// range is null.
|
|
expect(selectionController.range).toBe(null);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
0,
|
|
root.firstChild.firstChild.firstChild,
|
|
0
|
|
);
|
|
expect(selectionController.range).toBeInstanceOf(Range);
|
|
});
|
|
|
|
test("`focusAtStart` should return `true` if the offset is 0", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithText("");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
0,
|
|
root.firstChild.firstChild.firstChild,
|
|
0
|
|
);
|
|
expect(selectionController.focusAtStart).toBe(true);
|
|
});
|
|
|
|
test("`focusAtEnd` should return `true` if the offset is the length of the `textContent`", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithText("Hello, World!");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
"Hello, World!".length,
|
|
root.firstChild.firstChild.firstChild,
|
|
0
|
|
);
|
|
expect(selectionController.focusAtEnd).toBe(true);
|
|
});
|
|
|
|
test("`anchorAtStart` should return `true` if the offset is 0", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithText("");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
0,
|
|
root.firstChild.firstChild.firstChild,
|
|
0
|
|
);
|
|
expect(selectionController.anchorAtStart).toBe(true);
|
|
});
|
|
|
|
test("`anchorAtEnd` should return `true` if the offset is the length of the `textContent`", () => {
|
|
const textEditorMock =
|
|
TextEditorMock.createTextEditorMockWithText("Hello, World!");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
0,
|
|
root.firstChild.firstChild.firstChild,
|
|
"Hello, World!".length
|
|
);
|
|
expect(selectionController.anchorAtEnd).toBe(true);
|
|
});
|
|
|
|
test("`direction` should return the direction of the focus and anchor nodes", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithText("Hello, World!");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
0,
|
|
root.firstChild.firstChild.firstChild,
|
|
0
|
|
);
|
|
expect(selectionController.direction).toBe(SelectionDirection.NONE);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
5,
|
|
root.firstChild.firstChild.firstChild,
|
|
0
|
|
);
|
|
expect(selectionController.direction).toBe(SelectionDirection.FORWARD);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
0,
|
|
root.firstChild.firstChild.firstChild,
|
|
5
|
|
);
|
|
expect(selectionController.direction).toBe(SelectionDirection.BACKWARD);
|
|
});
|
|
|
|
test("`insertText` should insert some text in a Text node", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithText("Hello");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
"Hello".length
|
|
);
|
|
selectionController.insertText(", World!");
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(HTMLSpanElement);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe("inline");
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild).toBeInstanceOf(Text);
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild.nodeValue).toBe("Hello, World!");
|
|
});
|
|
|
|
test("`replaceLineBreak` should replace a <br> with some text", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockEmpty();
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild
|
|
);
|
|
selectionController.replaceLineBreak("Hello, World!");
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(
|
|
HTMLDivElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe(
|
|
"paragraph"
|
|
);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild
|
|
).toBeInstanceOf(HTMLSpanElement);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.dataset.itype
|
|
).toBe("inline");
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
).toBeInstanceOf(Text);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
.nodeValue
|
|
).toBe("Hello, World!");
|
|
});
|
|
|
|
test("`removeBackwardText` should remove text in backward direction (backspace)", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithText("Hello, World!");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
"Hello, World!".length
|
|
);
|
|
selectionController.removeBackwardText();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(
|
|
HTMLDivElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe(
|
|
"paragraph"
|
|
);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild
|
|
).toBeInstanceOf(HTMLSpanElement);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.dataset.itype
|
|
).toBe("inline");
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World");
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
).toBeInstanceOf(Text);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
.nodeValue
|
|
).toBe("Hello, World");
|
|
});
|
|
|
|
test("`removeBackwardText` should remove text in backward direction (backspace) and create a new empty paragraph when there's nothing left", () => {
|
|
const textEditorMock =
|
|
TextEditorMock.createTextEditorMockWithText("H");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
"H".length
|
|
);
|
|
selectionController.removeBackwardText();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("");
|
|
});
|
|
|
|
test("`mergeBackwardParagraph` should merge two paragraphs in backward direction (backspace)", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([createInline(new Text("Hello, "))]),
|
|
createParagraph([createInline(new Text("World!"))]),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.childNodes.item(1).firstChild.firstChild,
|
|
0
|
|
);
|
|
selectionController.mergeBackwardParagraph();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.children.length).toBe(1);
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
});
|
|
|
|
test("`mergeBackwardParagraph` should merge two paragraphs in backward direction (backspace)", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([createInline(new Text("Hello, "))]),
|
|
createEmptyParagraph(),
|
|
createParagraph([createInline(new Text("World!"))])
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(textEditorMock, selection);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.childNodes.item(2).firstChild.firstChild,
|
|
0
|
|
);
|
|
selectionController.mergeBackwardParagraph();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children.length).toBe(2);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe("inline");
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
expect(textEditorMock.root.firstChild.textContent).toBe("Hello, ");
|
|
expect(textEditorMock.root.lastChild.textContent).toBe("World!");
|
|
});
|
|
|
|
test("`mergeForwardParagraph` should merge two paragraphs in forward direction (backspace)", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([createInline(new Text("Hello, "))]),
|
|
createParagraph([createInline(new Text("World!"))]),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
root.firstChild.firstChild.firstChild.nodeValue.length
|
|
);
|
|
selectionController.mergeForwardParagraph();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.children.length).toBe(1);
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
});
|
|
|
|
test("`mergeForwardParagraph` should merge two paragraphs in forward direction (backspace)", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([createInline(new Text("Hello, "))]),
|
|
createEmptyParagraph(),
|
|
createParagraph([createInline(new Text("World!"))]),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.childNodes.item(2).firstChild.firstChild,
|
|
0
|
|
);
|
|
selectionController.mergeBackwardParagraph();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children.length).toBe(2);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
expect(textEditorMock.root.firstChild.textContent).toBe("Hello, ");
|
|
expect(textEditorMock.root.lastChild.textContent).toBe("World!");
|
|
});
|
|
|
|
test("`removeForwardText` should remove text in forward direction (delete)", () => {
|
|
const textEditorMock =
|
|
TextEditorMock.createTextEditorMockWithText("Hello, World!");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
);
|
|
selectionController.removeForwardText();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(
|
|
HTMLDivElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe(
|
|
"paragraph"
|
|
);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild
|
|
).toBeInstanceOf(HTMLSpanElement);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.dataset.itype
|
|
).toBe("inline");
|
|
expect(textEditorMock.root.textContent).toBe("ello, World!");
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
).toBeInstanceOf(Text);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
.nodeValue
|
|
).toBe("ello, World!");
|
|
});
|
|
|
|
test("`replaceText` should replace the selected text", () => {
|
|
const textEditorMock =
|
|
TextEditorMock.createTextEditorMockWithText("Hello, World!");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
7,
|
|
root.firstChild.firstChild.firstChild,
|
|
12
|
|
);
|
|
selectionController.replaceText("Mundo");
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(
|
|
HTMLDivElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe(
|
|
"paragraph"
|
|
);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild
|
|
).toBeInstanceOf(HTMLSpanElement);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.dataset.itype
|
|
).toBe("inline");
|
|
expect(textEditorMock.root.textContent).toBe("Hello, Mundo!");
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
).toBeInstanceOf(Text);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
.nodeValue
|
|
).toBe("Hello, Mundo!");
|
|
});
|
|
|
|
test("`replaceInlines` should replace the selected text in multiple inlines (2 completelly selected)", () => {
|
|
const textEditorMock =
|
|
TextEditorMock.createTextEditorMockWithParagraph([
|
|
createInline(new Text("Hello, ")),
|
|
createInline(new Text("World!"))
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
0,
|
|
root.firstChild.lastChild.firstChild,
|
|
"World!".length
|
|
);
|
|
selectionController.replaceInlines("Mundo");
|
|
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(
|
|
HTMLDivElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe(
|
|
"paragraph"
|
|
);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild
|
|
).toBeInstanceOf(HTMLSpanElement);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.dataset.itype
|
|
).toBe("inline");
|
|
expect(textEditorMock.root.textContent).toBe("Mundo");
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
).toBeInstanceOf(Text);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
.nodeValue
|
|
).toBe("Mundo");
|
|
});
|
|
|
|
test("`replaceInlines` should replace the selected text in multiple inlines (2 partially selected)", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraph([
|
|
createInline(new Text("Hello, ")),
|
|
createInline(new Text("World!")),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
2,
|
|
root.firstChild.lastChild.firstChild,
|
|
"World!".length - 3
|
|
);
|
|
selectionController.replaceInlines("Mundo");
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(2);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("HeMundold!");
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild).toBeInstanceOf(
|
|
Text
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild.nodeValue).toBe(
|
|
"HeMundo"
|
|
);
|
|
expect(textEditorMock.root.firstChild.lastChild.firstChild).toBeInstanceOf(
|
|
Text
|
|
);
|
|
expect(textEditorMock.root.firstChild.lastChild.firstChild.nodeValue).toBe(
|
|
"ld!"
|
|
);
|
|
});
|
|
|
|
test("`replaceInlines` should replace the selected text in multiple inlines (1 partially selected, 1 completelly selected)", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraph([
|
|
createInline(new Text("Hello, ")),
|
|
createInline(new Text("World!")),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
2,
|
|
root.firstChild.lastChild.firstChild,
|
|
"World!".length
|
|
);
|
|
selectionController.replaceInlines("Mundo");
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("HeMundo");
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild).toBeInstanceOf(
|
|
Text
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild.nodeValue).toBe(
|
|
"HeMundo"
|
|
);
|
|
});
|
|
|
|
test("`replaceInlines` should replace the selected text in multiple inlines (1 completelly selected, 1 partially selected)", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraph([
|
|
createInline(new Text("Hello, ")),
|
|
createInline(new Text("World!")),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
0,
|
|
root.firstChild.lastChild.firstChild,
|
|
"World!".length - 3
|
|
);
|
|
selectionController.replaceInlines("Mundo");
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("Mundold!");
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild).toBeInstanceOf(
|
|
Text
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild.nodeValue).toBe(
|
|
"Mundold!"
|
|
);
|
|
});
|
|
|
|
test("`removeSelected` removes a word", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithText("Hello, World!");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
7,
|
|
root.firstChild.lastChild.firstChild,
|
|
"Hello, World!".length - 1
|
|
);
|
|
selectionController.removeSelected();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("Hello, !");
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
).toBeInstanceOf(Text);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild.nodeValue
|
|
).toBe("Hello, !");
|
|
});
|
|
|
|
test("`removeSelected` multiple inlines", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraph([
|
|
createInline(new Text("Hello, ")),
|
|
createInline(new Text("World!")),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
0,
|
|
root.firstChild.lastChild.firstChild,
|
|
"World!".length
|
|
);
|
|
selectionController.removeSelected();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("");
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLBRElement
|
|
);
|
|
});
|
|
|
|
test("`removeSelected` multiple paragraphs", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([
|
|
createInline(new Text("Hello, "))
|
|
]),
|
|
createParagraph([
|
|
createInline(createLineBreak())
|
|
]),
|
|
createParagraph([
|
|
createInline(new Text("World!"))
|
|
]),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.lastElementChild,
|
|
0,
|
|
root.children.item(1).firstChild,
|
|
0
|
|
);
|
|
selectionController.removeSelected();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children).toHaveLength(2);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild).toBeInstanceOf(
|
|
Text
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild.nodeValue).toBe(
|
|
"Hello, "
|
|
);
|
|
expect(textEditorMock.root.lastChild.firstChild.firstChild).toBeInstanceOf(
|
|
Text
|
|
);
|
|
expect(textEditorMock.root.lastChild.firstChild.firstChild.nodeValue).toBe(
|
|
"World!"
|
|
);
|
|
});
|
|
|
|
test("`removeSelected` and `removeBackwardParagraph`", () => {
|
|
const textEditorMock =
|
|
TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([createInline(new Text("Hello, World!"))]),
|
|
createParagraph([createInline(createLineBreak())]),
|
|
createParagraph([createInline(new Text("This is a test"))]),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.lastElementChild.firstElementChild.firstChild, // This is a test text
|
|
0,
|
|
root.lastElementChild.firstElementChild.firstChild,
|
|
"This is a test".length
|
|
);
|
|
selectionController.removeSelected();
|
|
selectionController.removeBackwardParagraph();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children).toHaveLength(2);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild
|
|
).toBeInstanceOf(Text);
|
|
expect(
|
|
textEditorMock.root.firstChild.firstChild.firstChild.nodeValue
|
|
).toBe("Hello, World!");
|
|
});
|
|
|
|
test("`removeSelected` and `removeForwardParagraph`", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([createInline(new Text("Hello, World!"))]),
|
|
createParagraph([createInline(createLineBreak())]),
|
|
createParagraph([createInline(new Text("This is a test"))]),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstElementChild.firstElementChild.firstChild, // This is a test text
|
|
0,
|
|
root.firstElementChild.firstElementChild.firstChild,
|
|
"Hello, World!".length
|
|
);
|
|
selectionController.removeSelected();
|
|
selectionController.removeForwardParagraph();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children).toHaveLength(2);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("This is a test");
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLBRElement
|
|
);
|
|
expect(textEditorMock.root.lastChild.firstChild.firstChild.nodeValue).toBe(
|
|
"This is a test"
|
|
);
|
|
});
|
|
|
|
test("performing a `removeSelected` after a `removeSelected` should do nothing", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([createInline(new Text("Hello, World!"))]),
|
|
createParagraph([createInline(createLineBreak())]),
|
|
createParagraph([createInline(new Text("This is a test"))]),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstElementChild.firstElementChild.firstChild, // This is a test text
|
|
0,
|
|
root.firstElementChild.firstElementChild.firstChild,
|
|
"Hello, World!".length
|
|
);
|
|
selectionController.removeSelected();
|
|
|
|
// This should do nothing.
|
|
selectionController.removeSelected();
|
|
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children).toHaveLength(3);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.textContent).toBe("This is a test");
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLBRElement
|
|
);
|
|
expect(textEditorMock.root.lastChild.firstChild.firstChild.nodeValue).toBe(
|
|
"This is a test"
|
|
);
|
|
});
|
|
|
|
test("`removeSelected` removes everything", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([createInline(new Text("Hello, World!"))]),
|
|
createParagraph([createInline(createLineBreak())]),
|
|
createParagraph([createInline(new Text("This is a test"))]),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstElementChild.firstElementChild.firstChild, // This is a test text
|
|
0,
|
|
root.lastElementChild.firstElementChild.firstChild,
|
|
"This is a test".length
|
|
);
|
|
selectionController.removeSelected();
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children).toHaveLength(1);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.textContent).toBe("");
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLBRElement
|
|
);
|
|
});
|
|
|
|
test("`removeSelected` removes everything and insert text", () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([createInline(new Text("Hello, World!"))]),
|
|
createParagraph([createInline(createLineBreak())]),
|
|
createParagraph([createInline(new Text("This is a test"))]),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstElementChild.firstElementChild.firstChild, // This is a test text
|
|
0,
|
|
root.lastElementChild.firstElementChild.firstChild,
|
|
"This is a test".length
|
|
);
|
|
selectionController.removeSelected();
|
|
selectionController.replaceLineBreak("Hello, World!");
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children).toHaveLength(1);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.children).toHaveLength(1);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild).toBeInstanceOf(
|
|
Text
|
|
);
|
|
expect(textEditorMock.root.firstChild.firstChild.firstChild.nodeValue).toBe(
|
|
"Hello, World!"
|
|
);
|
|
});
|
|
|
|
test('`applyStyles` to text', () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithText("Hello, World!");
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(textEditorMock, selection);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
root.firstChild.firstChild.firstChild.nodeValue.length - 1,
|
|
root.firstChild.firstChild.firstChild,
|
|
root.firstChild.firstChild.firstChild.nodeValue.length - 6
|
|
);
|
|
selectionController.applyStyles({
|
|
"font-weight": "bold"
|
|
});
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children.length).toBe(1);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.children.length).toBe(3);
|
|
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe("inline");
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
expect(textEditorMock.root.firstChild.children.item(0).textContent).toBe("Hello, ");
|
|
expect(textEditorMock.root.firstChild.children.item(1).textContent).toBe("World");
|
|
expect(textEditorMock.root.firstChild.children.item(2).textContent).toBe("!");
|
|
});
|
|
|
|
test('`applyStyles` to inlines', () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraph([
|
|
createInline(new Text("Hello, "), {
|
|
"font-style": "italic"
|
|
}),
|
|
createInline(new Text("World!"), {
|
|
"font-style": "oblique"
|
|
})
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(textEditorMock, selection);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
2,
|
|
root.firstChild.lastChild.firstChild,
|
|
root.firstChild.lastChild.firstChild.nodeValue.length - 3
|
|
);
|
|
selectionController.applyStyles({
|
|
"font-weight": "bold"
|
|
});
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children.length).toBe(1);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.children.length).toBe(4);
|
|
expect(textEditorMock.root.firstChild.children.item(0).dataset.itype).toBe("inline");
|
|
expect(textEditorMock.root.firstChild.children.item(0).textContent).toBe("He");
|
|
expect(textEditorMock.root.firstChild.children.item(1).dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.firstChild.children.item(1).textContent).toBe("llo, ");
|
|
expect(textEditorMock.root.firstChild.children.item(2).dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.firstChild.children.item(2).textContent).toBe("Wor");
|
|
expect(textEditorMock.root.firstChild.children.item(3).dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.firstChild.children.item(3).textContent).toBe("ld!");
|
|
});
|
|
|
|
test('`applyStyles` to paragraphs', () => {
|
|
const textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([
|
|
createParagraph([
|
|
createInline(new Text("Hello, "), {
|
|
"font-style": "italic",
|
|
}),
|
|
]),
|
|
createParagraph([
|
|
createInline(new Text("World!"), {
|
|
"font-style": "oblique",
|
|
}),
|
|
]),
|
|
]);
|
|
const root = textEditorMock.root;
|
|
const selection = document.getSelection();
|
|
const selectionController = new SelectionController(
|
|
textEditorMock,
|
|
selection
|
|
);
|
|
focus(
|
|
selection,
|
|
textEditorMock,
|
|
root.firstChild.firstChild.firstChild,
|
|
2,
|
|
root.lastChild.firstChild.firstChild,
|
|
root.lastChild.firstChild.firstChild.nodeValue.length - 3
|
|
);
|
|
selectionController.applyStyles({
|
|
"font-weight": "bold",
|
|
});
|
|
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.children.length).toBe(2);
|
|
expect(textEditorMock.root.dataset.itype).toBe("root");
|
|
expect(textEditorMock.root.textContent).toBe("Hello, World!");
|
|
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
|
|
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
|
|
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
|
|
HTMLSpanElement
|
|
);
|
|
expect(textEditorMock.root.firstChild.children.length).toBe(2);
|
|
expect(textEditorMock.root.firstChild.children.item(0).dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.firstChild.children.item(0).textContent).toBe(
|
|
"He"
|
|
);
|
|
expect(textEditorMock.root.firstChild.children.item(1).dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.firstChild.children.item(1).textContent).toBe(
|
|
"llo, "
|
|
);
|
|
expect(textEditorMock.root.lastChild.children.length).toBe(2);
|
|
expect(textEditorMock.root.lastChild.children.item(0).dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.lastChild.children.item(0).textContent).toBe(
|
|
"Wor"
|
|
);
|
|
expect(textEditorMock.root.lastChild.children.item(1).dataset.itype).toBe(
|
|
"inline"
|
|
);
|
|
expect(textEditorMock.root.lastChild.children.item(1).textContent).toBe(
|
|
"ld!"
|
|
);
|
|
});
|
|
});
|