mirror of
https://github.com/penpot/penpot.git
synced 2025-05-08 07:45:54 +02:00
1178 lines
43 KiB
JavaScript
1178 lines
43 KiB
JavaScript
import { expect, describe, test } from "vitest";
|
|
import TextEditor from "../TextEditor.js";
|
|
import {
|
|
createEmptyParagraph,
|
|
createParagraph,
|
|
} from "../content/dom/Paragraph.js";
|
|
import { createInline } from "../content/dom/Inline.js";
|
|
import { createLineBreak } from "../content/dom/LineBreak.js";
|
|
import { TextEditorMock } from "../../test/TextEditorMock.js";
|
|
import { SelectionController } from "./SelectionController.js";
|
|
import { SelectionDirection } from "./SelectionDirection.js";
|
|
|
|
/* @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!",
|
|
);
|
|
});
|
|
});
|