vitest-prosemirror 0.5.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +38 -0
- package/dist/{vitest-prosemirror.js → renderProseMirror-CE37KmN_.js} +34 -225
- package/dist/setup.d.ts +21 -0
- package/dist/setup.js +165 -0
- package/package.json +16 -6
- package/dist/vitest-prosemirror.d.ts +0 -70
package/README.md
CHANGED
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
[](https://app.codecov.io/gh/marekdedic/vitest-prosemirror)
|
|
6
6
|
[](https://www.npmjs.com/package/vitest-prosemirror)
|
|
7
7
|
[](https://github.com/marekdedic/vitest-prosemirror/blob/master/LICENSE)
|
|
8
|
+
[](https://marekdedic.github.io/vitest-prosemirror/)
|
|
8
9
|
|
|
9
10
|

|
|
10
11
|
|
|
11
12
|
A plugin for Vitest that enables you to write tests using the ProseMirror editor
|
|
12
13
|
|
|
14
|
+
## Documentation
|
|
15
|
+
|
|
16
|
+
Full documentation — a getting-started guide and the API reference — is available at **[marekdedic.github.io/vitest-prosemirror](https://marekdedic.github.io/vitest-prosemirror/)**.
|
|
17
|
+
|
|
13
18
|
## How to install
|
|
14
19
|
|
|
15
20
|
```sh
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Command } from 'prosemirror-state';
|
|
2
|
+
import { DirectEditorProps } from 'prosemirror-view';
|
|
3
|
+
import { EditorState } from 'prosemirror-state';
|
|
4
|
+
import { Node as Node_2 } from 'prosemirror-model';
|
|
5
|
+
import { ParseOptions } from 'prosemirror-model';
|
|
6
|
+
import { Schema } from 'prosemirror-model';
|
|
7
|
+
import { Selection as Selection_2 } from 'prosemirror-state';
|
|
8
|
+
|
|
9
|
+
declare interface Clipboard_2 {
|
|
10
|
+
html: string;
|
|
11
|
+
text: string;
|
|
12
|
+
}
|
|
13
|
+
export { Clipboard_2 as Clipboard }
|
|
14
|
+
|
|
15
|
+
export declare interface Options {
|
|
16
|
+
autoCleanup: boolean;
|
|
17
|
+
editorProps: Omit<DirectEditorProps, "dispatchTransaction" | "state">;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export declare function parseHTML(html: string, schema: Schema, options?: ParseOptions): Node_2;
|
|
21
|
+
|
|
22
|
+
export { ParseOptions }
|
|
23
|
+
|
|
24
|
+
export declare interface PasteContent {
|
|
25
|
+
files?: Array<File>;
|
|
26
|
+
html?: string;
|
|
27
|
+
plainText?: boolean;
|
|
28
|
+
text?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export declare type PasteInput = PasteContent | Node_2 | string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The handle returned by `renderProseMirror`: a live editor mounted in jsdom,
|
|
35
|
+
* exposing readers for its document and rendered DOM plus verbs that drive the
|
|
36
|
+
* ProseMirror input path.
|
|
37
|
+
*/
|
|
38
|
+
export declare interface ProseMirrorEditor {
|
|
39
|
+
/** Dispatch a click at the target selector or captured element. */
|
|
40
|
+
click(target: Element | string): boolean;
|
|
41
|
+
/** Run a ProseMirror command against the current state. */
|
|
42
|
+
command(command: Command): boolean;
|
|
43
|
+
/** Serialise the current selection the way the copy handler would. */
|
|
44
|
+
copy(): Clipboard_2;
|
|
45
|
+
/** Tear down the editor, its DOM node and the global mocks. */
|
|
46
|
+
destroy(): void;
|
|
47
|
+
/** The current document (`state.doc`). */
|
|
48
|
+
readonly doc: Node_2;
|
|
49
|
+
/** The single element matching the selector. */
|
|
50
|
+
element(selector: string): HTMLElement;
|
|
51
|
+
/** Every element matching the selector. */
|
|
52
|
+
elements(selector: string): Array<HTMLElement>;
|
|
53
|
+
/** The rendered `innerHTML` of the editor DOM. */
|
|
54
|
+
readonly html: string;
|
|
55
|
+
/** Paste content through the DOM paste path. */
|
|
56
|
+
paste(content: PasteInput): void;
|
|
57
|
+
/** Set the selection from a {@link TesterSelection}. */
|
|
58
|
+
setSelection(selection: TesterSelection): void;
|
|
59
|
+
/** The current editor state. Live getter - reads the latest dispatch. */
|
|
60
|
+
readonly state: EditorState;
|
|
61
|
+
/** The rendered `textContent` of the editor DOM. */
|
|
62
|
+
readonly text: string;
|
|
63
|
+
/** Type key strings through the DOM input path. */
|
|
64
|
+
type(text: string): void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Mount a ProseMirror `EditorView` on a jsdom node and return a
|
|
69
|
+
* {@link ProseMirrorEditor} handle for driving it. Installs the mocks the
|
|
70
|
+
* tester relies on (`MutationObserver`, range rects) and registers the editor
|
|
71
|
+
* for automatic cleanup after each test unless `autoCleanup: false` is passed.
|
|
72
|
+
*/
|
|
73
|
+
export declare const renderProseMirror: (documentRoot: Node_2, options?: Partial<Options>) => ProseMirrorEditor;
|
|
74
|
+
|
|
75
|
+
export declare type TesterSelection = "all" | "end" | "start" | {
|
|
76
|
+
anchor: number | string;
|
|
77
|
+
head: number | string;
|
|
78
|
+
} | (string & {}) | Selection_2 | number;
|
|
79
|
+
|
|
80
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { r as renderProseMirror } from "./renderProseMirror-CE37KmN_.js";
|
|
2
|
+
import { DOMParser } from "prosemirror-model";
|
|
3
|
+
//#region src/parseHTML.ts
|
|
4
|
+
var wrapMap = {
|
|
5
|
+
caption: ["table"],
|
|
6
|
+
col: ["table", "colgroup"],
|
|
7
|
+
colgroup: ["table"],
|
|
8
|
+
tbody: ["table"],
|
|
9
|
+
td: [
|
|
10
|
+
"table",
|
|
11
|
+
"tbody",
|
|
12
|
+
"tr"
|
|
13
|
+
],
|
|
14
|
+
tfoot: ["table"],
|
|
15
|
+
th: [
|
|
16
|
+
"table",
|
|
17
|
+
"tbody",
|
|
18
|
+
"tr"
|
|
19
|
+
],
|
|
20
|
+
thead: ["table"],
|
|
21
|
+
tr: ["table", "tbody"]
|
|
22
|
+
};
|
|
23
|
+
function parseHTML(html, schema, options) {
|
|
24
|
+
return DOMParser.fromSchema(schema).parse(readHTML(html), options);
|
|
25
|
+
}
|
|
26
|
+
function readHTML(rawHtml) {
|
|
27
|
+
const metas = /^(\s*<meta [^>]*>)*/u.exec(rawHtml);
|
|
28
|
+
const stripped = metas ? rawHtml.slice(metas[0].length) : rawHtml;
|
|
29
|
+
const firstTag = /<([a-z][^>\s]+)/iu.exec(stripped);
|
|
30
|
+
const wrap = firstTag ? wrapMap[firstTag[1].toLowerCase()] : void 0;
|
|
31
|
+
const html = wrap === void 0 ? stripped : wrap.map((n) => `<${n}>`).join("") + stripped + wrap.map((n) => `</${n}>`).reverse().join("");
|
|
32
|
+
let elt = document.implementation.createHTMLDocument("title").body;
|
|
33
|
+
elt.innerHTML = html;
|
|
34
|
+
if (wrap) for (const n of wrap) elt = elt.querySelector(n) ?? elt;
|
|
35
|
+
return elt;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { parseHTML, renderProseMirror };
|
|
@@ -1,25 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Fragment, Node, Slice } from "prosemirror-model";
|
|
2
2
|
import { AllSelection, EditorState, Selection, TextSelection } from "prosemirror-state";
|
|
3
3
|
import { EditorView } from "prosemirror-view";
|
|
4
|
-
import { DOMParser, Fragment, Node, Slice } from "prosemirror-model";
|
|
5
|
-
import stringifyObject from "stringify-object";
|
|
6
|
-
//#region src/isProseMirrorNode.ts
|
|
7
|
-
var isProseMirrorNode = (val) => {
|
|
8
|
-
if (typeof val !== "object" || val === null) return false;
|
|
9
|
-
const node = val;
|
|
10
|
-
const type = node["type"];
|
|
11
|
-
if (typeof type !== "object" || type === null) return false;
|
|
12
|
-
const typeRecord = type;
|
|
13
|
-
return typeof typeRecord["name"] === "string" && typeof typeRecord["schema"] === "object" && "marks" in node && "attrs" in node && "content" in node;
|
|
14
|
-
};
|
|
15
|
-
//#endregion
|
|
16
|
-
//#region src/isEditorState.ts
|
|
17
|
-
var isEditorState = (val) => {
|
|
18
|
-
if (typeof val !== "object" || val === null) return false;
|
|
19
|
-
const state = val;
|
|
20
|
-
return isProseMirrorNode(state["doc"]) && typeof state["selection"] === "object" && state["selection"] !== null && "storedMarks" in state;
|
|
21
|
-
};
|
|
22
|
-
//#endregion
|
|
23
4
|
//#region src/clipboard/copy.ts
|
|
24
5
|
var copy = (view) => {
|
|
25
6
|
const { dom, text } = view.serializeForClipboard(view.state.selection.content());
|
|
@@ -409,7 +390,7 @@ var DataTransferMock = class {
|
|
|
409
390
|
this.store.set(normalizeType(format), data);
|
|
410
391
|
}
|
|
411
392
|
setDragImage() {
|
|
412
|
-
throw new Error("setDragImage is not supported:
|
|
393
|
+
throw new Error("setDragImage is not supported: vitest-prosemirror models clipboard paste/copy, not drag-and-drop.");
|
|
413
394
|
}
|
|
414
395
|
};
|
|
415
396
|
//#endregion
|
|
@@ -526,12 +507,12 @@ var resolvePos = (doc, value) => {
|
|
|
526
507
|
const tags = tagsOf(doc);
|
|
527
508
|
if (value in tags) return tags[value];
|
|
528
509
|
const available = Object.keys(tags);
|
|
529
|
-
throw new Error(`
|
|
510
|
+
throw new Error(`setSelection: no tag named "${value}" in the document. ${available.length > 0 ? `Available tags: ${available.map((tag) => `"${tag}"`).join(", ")}.` : "The document has no tags."}`);
|
|
530
511
|
};
|
|
531
512
|
var resolveSelection = (doc, selection) => {
|
|
532
513
|
if (typeof selection === "object" && "$anchor" in selection && "$head" in selection) return selection;
|
|
533
514
|
if (typeof selection === "object" && "anchor" in selection && "head" in selection) return TextSelection.between(doc.resolve(resolvePos(doc, selection.anchor)), doc.resolve(resolvePos(doc, selection.head)));
|
|
534
|
-
if (typeof selection === "object" && "from" in selection && "to" in selection) throw new Error("
|
|
515
|
+
if (typeof selection === "object" && "from" in selection && "to" in selection) throw new Error("setSelection no longer accepts { from, to } — use { anchor, head } instead. The values map directly: { from: a, to: b } becomes { anchor: a, head: b }.");
|
|
535
516
|
if (typeof selection === "number") return TextSelection.near(doc.resolve(selection));
|
|
536
517
|
const tags = tagsOf(doc);
|
|
537
518
|
if ([
|
|
@@ -539,7 +520,7 @@ var resolveSelection = (doc, selection) => {
|
|
|
539
520
|
"end",
|
|
540
521
|
"start"
|
|
541
522
|
].includes(selection)) {
|
|
542
|
-
if (selection in tags) throw new Error(`
|
|
523
|
+
if (selection in tags) throw new Error(`setSelection: "${selection}" is both a reserved selection and a tag in the document. Use { anchor, head } to select the tag, or rename the tag.`);
|
|
543
524
|
if (selection === "all") return new AllSelection(doc);
|
|
544
525
|
return TextSelection.near(doc.resolve(selection === "end" ? doc.nodeSize - 2 : 0));
|
|
545
526
|
}
|
|
@@ -703,7 +684,7 @@ var ignoredKeys = /* @__PURE__ */ new Set([
|
|
|
703
684
|
var hasModifiers = (modifiers) => modifiers !== void 0 && Object.values(modifiers).includes(true);
|
|
704
685
|
var suppressesCharacter = (modifiers) => modifiers?.altKey === true || modifiers?.ctrlKey === true || modifiers?.metaKey === true;
|
|
705
686
|
var isLetter = (key) => /^[a-z]$/iu.test(key);
|
|
706
|
-
function
|
|
687
|
+
function type(view, text) {
|
|
707
688
|
for (const token of tokenizeKeyboardInput(text)) {
|
|
708
689
|
const { key, modifiers } = parseKeyChord(token);
|
|
709
690
|
const character = isLetter(key) && modifiers.shiftKey === true ? key.toUpperCase() : key;
|
|
@@ -772,14 +753,14 @@ function keyAction(key, modifiers) {
|
|
|
772
753
|
throw new Error(`Cannot simulate the "${key}" key`);
|
|
773
754
|
}
|
|
774
755
|
//#endregion
|
|
775
|
-
//#region src/
|
|
756
|
+
//#region src/renderProseMirror.ts
|
|
776
757
|
var originalMutationObserver = global.MutationObserver;
|
|
777
|
-
var
|
|
778
|
-
var
|
|
779
|
-
var
|
|
780
|
-
for (const
|
|
758
|
+
var liveEditors = /* @__PURE__ */ new Set();
|
|
759
|
+
var autoCleanupEditors = /* @__PURE__ */ new Set();
|
|
760
|
+
var cleanupEditors = () => {
|
|
761
|
+
for (const editor of [...autoCleanupEditors]) editor.destroy();
|
|
781
762
|
};
|
|
782
|
-
var
|
|
763
|
+
var ProseMirrorEditorImpl = class {
|
|
783
764
|
get doc() {
|
|
784
765
|
this.assertAlive();
|
|
785
766
|
return this.view.state.doc;
|
|
@@ -803,7 +784,8 @@ var ProseMirrorTester = class {
|
|
|
803
784
|
if (typeof document === "undefined") throw new Error("TODO");
|
|
804
785
|
this.mountPoint = document.createElement("div");
|
|
805
786
|
document.body.append(this.mountPoint);
|
|
806
|
-
const { autoCleanup = true,
|
|
787
|
+
const { autoCleanup = true, editorProps = {} } = options;
|
|
788
|
+
const { plugins = [], ...directEditorProps } = editorProps;
|
|
807
789
|
const state = EditorState.create({
|
|
808
790
|
doc: documentRoot,
|
|
809
791
|
plugins
|
|
@@ -812,10 +794,10 @@ var ProseMirrorTester = class {
|
|
|
812
794
|
mockRangeRects();
|
|
813
795
|
this.view = new EditorView(this.mountPoint, {
|
|
814
796
|
state,
|
|
815
|
-
...
|
|
797
|
+
...directEditorProps
|
|
816
798
|
});
|
|
817
|
-
|
|
818
|
-
if (autoCleanup)
|
|
799
|
+
liveEditors.add(this);
|
|
800
|
+
if (autoCleanup) autoCleanupEditors.add(this);
|
|
819
801
|
}
|
|
820
802
|
click(target) {
|
|
821
803
|
this.assertAlive();
|
|
@@ -835,9 +817,9 @@ var ProseMirrorTester = class {
|
|
|
835
817
|
this.view.destroy();
|
|
836
818
|
this.mountPoint.remove();
|
|
837
819
|
document.getSelection()?.removeAllRanges();
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
if (
|
|
820
|
+
autoCleanupEditors.delete(this);
|
|
821
|
+
liveEditors.delete(this);
|
|
822
|
+
if (liveEditors.size === 0) global.MutationObserver = originalMutationObserver;
|
|
841
823
|
}
|
|
842
824
|
element(selector) {
|
|
843
825
|
this.assertAlive();
|
|
@@ -847,201 +829,28 @@ var ProseMirrorTester = class {
|
|
|
847
829
|
this.assertAlive();
|
|
848
830
|
return elements(this.view, selector);
|
|
849
831
|
}
|
|
850
|
-
insertText(text) {
|
|
851
|
-
this.assertAlive();
|
|
852
|
-
insertText(this.view, text);
|
|
853
|
-
}
|
|
854
832
|
paste(content) {
|
|
855
833
|
this.assertAlive();
|
|
856
834
|
paste(this.view, content);
|
|
857
835
|
}
|
|
858
|
-
|
|
836
|
+
setSelection(selection) {
|
|
859
837
|
this.assertAlive();
|
|
860
838
|
this.view.dispatch(this.view.state.tr.setSelection(resolveSelection(this.doc, selection)));
|
|
861
839
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
};
|
|
866
|
-
//#endregion
|
|
867
|
-
//#region src/stringifyMark.ts
|
|
868
|
-
var stringifyObjectOptions = {
|
|
869
|
-
indent: " ",
|
|
870
|
-
inlineCharacterLimit: 1e3
|
|
871
|
-
};
|
|
872
|
-
var stringifyMark = (mark) => Object.keys(mark.attrs).length > 0 ? `${mark.type.name}(${stringifyObject(mark.attrs, stringifyObjectOptions)})` : mark.type.name;
|
|
873
|
-
//#endregion
|
|
874
|
-
//#region src/stringifyProseMirrorNode.ts
|
|
875
|
-
function stringifyProseMirrorNode(node, selection, indentation = "") {
|
|
876
|
-
const markers = /* @__PURE__ */ new Map();
|
|
877
|
-
if (selection !== void 0) {
|
|
878
|
-
if (selection.anchor === selection.head) markers.set(selection.anchor, "<cursor>");
|
|
879
|
-
else {
|
|
880
|
-
markers.set(selection.anchor, "<anchor>");
|
|
881
|
-
markers.set(selection.head, "<head>");
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
return render(node, markers, indentation, 0);
|
|
885
|
-
}
|
|
886
|
-
function escapeText(text) {
|
|
887
|
-
return text.replace(/[\p{Cc}\p{Cf}'\\]/gu, (char) => {
|
|
888
|
-
switch (char) {
|
|
889
|
-
case "\f": return "\\f";
|
|
890
|
-
case "\n": return "\\n";
|
|
891
|
-
case "\r": return "\\r";
|
|
892
|
-
case " ": return "\\t";
|
|
893
|
-
case "\b": return "\\b";
|
|
894
|
-
case "'": return "\\'";
|
|
895
|
-
case "\\": return "\\\\";
|
|
896
|
-
default: return `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
897
|
-
}
|
|
898
|
-
});
|
|
899
|
-
}
|
|
900
|
-
function quoteWithMarkers(text, start, markers) {
|
|
901
|
-
const inside = [...markers.entries()].filter(([pos]) => pos >= start && pos <= start + text.length).sort(([a], [b]) => a - b);
|
|
902
|
-
const wrapMarker = containsRTL(text) ? (notation) => `\u2066${notation}\u2069` : (notation) => notation;
|
|
903
|
-
let quoted = "";
|
|
904
|
-
let last = 0;
|
|
905
|
-
for (const [pos, notation] of inside) {
|
|
906
|
-
markers.delete(pos);
|
|
907
|
-
const offset = pos - start;
|
|
908
|
-
quoted += escapeText(text.slice(last, offset)) + wrapMarker(notation);
|
|
909
|
-
last = offset;
|
|
910
|
-
}
|
|
911
|
-
quoted += escapeText(text.slice(last));
|
|
912
|
-
return `'${quoted}'`;
|
|
913
|
-
}
|
|
914
|
-
function render(node, markers, indentation, contentStart) {
|
|
915
|
-
if (node.type.spec.toDebugString !== void 0) return `${indentation}${wrapMarks(node.marks, node.type.spec.toDebugString(node))}`;
|
|
916
|
-
if (node.type.name === "text") return `${indentation}${wrapMarks(node.marks, quoteWithMarkers(node.textContent, contentStart, markers))}`;
|
|
917
|
-
return renderElement(node, markers, indentation, contentStart);
|
|
918
|
-
}
|
|
919
|
-
function renderElement(node, markers, indentation, contentStart) {
|
|
920
|
-
const type = node.type.name;
|
|
921
|
-
const hasAttrs = Object.keys(node.attrs).length > 0;
|
|
922
|
-
const nextIndentation = `${indentation} `;
|
|
923
|
-
const args = [];
|
|
924
|
-
const pushArg = (content) => {
|
|
925
|
-
args.push(`${nextIndentation}${content},`);
|
|
926
|
-
};
|
|
927
|
-
const pushMarkerAt = (pos) => {
|
|
928
|
-
const notation = markers.get(pos);
|
|
929
|
-
if (notation !== void 0) {
|
|
930
|
-
markers.delete(pos);
|
|
931
|
-
pushArg(`'${notation}'`);
|
|
932
|
-
}
|
|
933
|
-
};
|
|
934
|
-
if (hasAttrs) pushArg(stringifyObject(node.attrs, stringifyObjectOptions));
|
|
935
|
-
if (!node.type.isLeaf) {
|
|
936
|
-
if (node.content.childCount === 0) pushMarkerAt(contentStart);
|
|
937
|
-
node.content.forEach((child, offset, index) => {
|
|
938
|
-
const childStart = contentStart + offset;
|
|
939
|
-
const isText = child.type.name === "text";
|
|
940
|
-
if (!(index > 0 && node.content.child(index - 1).type.name === "text") && !isText) pushMarkerAt(childStart);
|
|
941
|
-
if (isText) pushArg(wrapMarks(child.marks, quoteWithMarkers(child.textContent, childStart, markers)));
|
|
942
|
-
else args.push(`${render(child, markers, nextIndentation, childStart + 1)},`);
|
|
943
|
-
});
|
|
944
|
-
if (node.content.lastChild?.type.name !== "text") pushMarkerAt(contentStart + node.content.size);
|
|
840
|
+
type(text) {
|
|
841
|
+
this.assertAlive();
|
|
842
|
+
type(this.view, text);
|
|
945
843
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
}
|
|
949
|
-
function wrapMarks(marks, origContent) {
|
|
950
|
-
let content = origContent;
|
|
951
|
-
for (const mark of [...marks].reverse()) {
|
|
952
|
-
const hasAttrs = Object.keys(mark.attrs).length > 0;
|
|
953
|
-
const items = [content];
|
|
954
|
-
if (hasAttrs) items.unshift(stringifyObject(mark.attrs, stringifyObjectOptions));
|
|
955
|
-
content = `${mark.type.name}(${items.join(", ")})`;
|
|
844
|
+
assertAlive() {
|
|
845
|
+
if (this.destroyed) throw new Error("This ProseMirror editor has been destroyed. Editors are destroyed automatically after each test; pass { autoCleanup: false } to keep one alive (e.g. across a beforeAll).");
|
|
956
846
|
}
|
|
957
|
-
return content;
|
|
958
|
-
}
|
|
959
|
-
//#endregion
|
|
960
|
-
//#region src/stringifyEditorState.ts
|
|
961
|
-
function stringifyEditorState(state, indentation = "") {
|
|
962
|
-
const { doc, selection, storedMarks } = state;
|
|
963
|
-
const lines = [stringifyProseMirrorNode(doc, selection, indentation), `${indentation}# selection: ${selection.constructor.name} ${String(selection.from)}..${String(selection.to)}`];
|
|
964
|
-
if (storedMarks !== null) lines.push(`${indentation}# storedMarks: [${storedMarks.map(stringifyMark).join(", ")}]`);
|
|
965
|
-
return lines.join("\n");
|
|
966
|
-
}
|
|
967
|
-
//#endregion
|
|
968
|
-
//#region src/parseHTML.ts
|
|
969
|
-
var wrapMap = {
|
|
970
|
-
caption: ["table"],
|
|
971
|
-
col: ["table", "colgroup"],
|
|
972
|
-
colgroup: ["table"],
|
|
973
|
-
tbody: ["table"],
|
|
974
|
-
td: [
|
|
975
|
-
"table",
|
|
976
|
-
"tbody",
|
|
977
|
-
"tr"
|
|
978
|
-
],
|
|
979
|
-
tfoot: ["table"],
|
|
980
|
-
th: [
|
|
981
|
-
"table",
|
|
982
|
-
"tbody",
|
|
983
|
-
"tr"
|
|
984
|
-
],
|
|
985
|
-
thead: ["table"],
|
|
986
|
-
tr: ["table", "tbody"]
|
|
987
847
|
};
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
const wrap = firstTag ? wrapMap[firstTag[1].toLowerCase()] : void 0;
|
|
996
|
-
const html = wrap === void 0 ? stripped : wrap.map((n) => `<${n}>`).join("") + stripped + wrap.map((n) => `</${n}>`).reverse().join("");
|
|
997
|
-
let elt = document.implementation.createHTMLDocument("title").body;
|
|
998
|
-
elt.innerHTML = html;
|
|
999
|
-
if (wrap) for (const n of wrap) elt = elt.querySelector(n) ?? elt;
|
|
1000
|
-
return elt;
|
|
1001
|
-
}
|
|
1002
|
-
//#endregion
|
|
1003
|
-
//#region src/index.ts
|
|
1004
|
-
afterEach(cleanupTesters);
|
|
1005
|
-
expect.extend({
|
|
1006
|
-
toEqualProseMirrorNode(received, expected) {
|
|
1007
|
-
const receivedDoc = `\n${stringifyProseMirrorNode(received)}\n`;
|
|
1008
|
-
const expectedDoc = `\n${stringifyProseMirrorNode(expected)}\n`;
|
|
1009
|
-
const sameSchema = received.type.schema === expected.type.schema;
|
|
1010
|
-
const pass = sameSchema && this.equals(receivedDoc, expectedDoc);
|
|
1011
|
-
return {
|
|
1012
|
-
message: pass ? () => `${this.utils.matcherHint(".not.toEqualProseMirrorNode")}\n\nExpected value of document to not equal:\n ${this.utils.printExpected(expectedDoc)}\nActual:\n ${this.utils.printReceived(receivedDoc)}` : () => {
|
|
1013
|
-
if (!sameSchema && this.equals(receivedDoc, expectedDoc)) return `${this.utils.matcherHint(".toEqualProseMirrorNode")}\n\nThe documents stringify identically but come from different schemas:\n${this.utils.printReceived(receivedDoc)}`;
|
|
1014
|
-
const diffString = this.utils.diff(expectedDoc, receivedDoc);
|
|
1015
|
-
return `${this.utils.matcherHint(".toEqualProseMirrorNode")}\n\nExpected value of document to equal:\n${this.utils.printExpected(expectedDoc)}\nActual:\n${this.utils.printReceived(receivedDoc)}${diffString === void 0 ? "" : `\n\nDifference:\n\n${diffString}`}`;
|
|
1016
|
-
},
|
|
1017
|
-
pass
|
|
1018
|
-
};
|
|
1019
|
-
},
|
|
1020
|
-
toHaveSelection(received, expected) {
|
|
1021
|
-
const state = received instanceof ProseMirrorTester ? received.state : received;
|
|
1022
|
-
const receivedSelection = state.selection;
|
|
1023
|
-
const expectedSelection = resolveSelection(state.doc, expected);
|
|
1024
|
-
const receivedDoc = `\n${stringifyProseMirrorNode(state.doc, receivedSelection)}\n`;
|
|
1025
|
-
const expectedDoc = `\n${stringifyProseMirrorNode(state.doc, expectedSelection)}\n`;
|
|
1026
|
-
const pass = receivedSelection.eq(expectedSelection);
|
|
1027
|
-
return {
|
|
1028
|
-
message: pass ? () => `${this.utils.matcherHint(".not.toHaveSelection")}\n\nExpected selection to not equal:\n${this.utils.printExpected(expectedDoc)}\nActual:\n${this.utils.printReceived(receivedDoc)}` : () => {
|
|
1029
|
-
const diffString = this.utils.diff(expectedDoc, receivedDoc);
|
|
1030
|
-
return `${this.utils.matcherHint(".toHaveSelection")}\n\nExpected selection to equal (${this.utils.printExpected(expectedSelection.constructor.name)}):\n${this.utils.printExpected(expectedDoc)}\nActual (${this.utils.printReceived(receivedSelection.constructor.name)}):\n${this.utils.printReceived(receivedDoc)}${diffString === void 0 ? "" : `\n\nDifference:\n\n${diffString}`}`;
|
|
1031
|
-
},
|
|
1032
|
-
pass
|
|
1033
|
-
};
|
|
1034
|
-
}
|
|
1035
|
-
});
|
|
1036
|
-
expect.addSnapshotSerializer({
|
|
1037
|
-
serialize: (val, _config, indentation) => stringifyProseMirrorNode(val, void 0, indentation).slice(indentation.length),
|
|
1038
|
-
test: isProseMirrorNode
|
|
1039
|
-
});
|
|
1040
|
-
expect.addSnapshotSerializer({
|
|
1041
|
-
serialize: (val, _config, indentation) => {
|
|
1042
|
-
return stringifyEditorState(val instanceof ProseMirrorTester ? val.state : val, indentation).slice(indentation.length);
|
|
1043
|
-
},
|
|
1044
|
-
test: (val) => val instanceof ProseMirrorTester || isEditorState(val)
|
|
1045
|
-
});
|
|
848
|
+
/**
|
|
849
|
+
* Mount a ProseMirror `EditorView` on a jsdom node and return a
|
|
850
|
+
* {@link ProseMirrorEditor} handle for driving it. Installs the mocks the
|
|
851
|
+
* tester relies on (`MutationObserver`, range rects) and registers the editor
|
|
852
|
+
* for automatic cleanup after each test unless `autoCleanup: false` is passed.
|
|
853
|
+
*/
|
|
854
|
+
var renderProseMirror = (documentRoot, options = {}) => new ProseMirrorEditorImpl(documentRoot, options);
|
|
1046
855
|
//#endregion
|
|
1047
|
-
export {
|
|
856
|
+
export { resolveSelection as a, containsRTL as i, cleanupEditors as n, renderProseMirror as r, ProseMirrorEditorImpl as t };
|
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Node } from "prosemirror-model";
|
|
2
|
+
|
|
3
|
+
import type { TesterSelection } from "./index.js";
|
|
4
|
+
|
|
5
|
+
import "vitest";
|
|
6
|
+
|
|
7
|
+
export interface CustomMatchers<R = unknown> {
|
|
8
|
+
toEqualProseMirrorNode(expected: Node): R;
|
|
9
|
+
toHaveSelection(expected: TesterSelection): R;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unused-vars -- This is an override for vitest matchers; the type parameters must match vitest's Matchers signature exactly */
|
|
13
|
+
|
|
14
|
+
declare module "vitest" {
|
|
15
|
+
interface Matchers<
|
|
16
|
+
R extends Promise<void> | void = Promise<void> | void,
|
|
17
|
+
T = unknown,
|
|
18
|
+
> extends CustomMatchers<R> {}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* eslint-enable */
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { a as resolveSelection, i as containsRTL, n as cleanupEditors, t as ProseMirrorEditorImpl } from "./renderProseMirror-CE37KmN_.js";
|
|
2
|
+
import { afterEach, expect } from "vitest";
|
|
3
|
+
import stringifyObject from "stringify-object";
|
|
4
|
+
//#region src/isProseMirrorNode.ts
|
|
5
|
+
var isProseMirrorNode = (val) => {
|
|
6
|
+
if (typeof val !== "object" || val === null) return false;
|
|
7
|
+
const node = val;
|
|
8
|
+
const type = node["type"];
|
|
9
|
+
if (typeof type !== "object" || type === null) return false;
|
|
10
|
+
const typeRecord = type;
|
|
11
|
+
return typeof typeRecord["name"] === "string" && typeof typeRecord["schema"] === "object" && "marks" in node && "attrs" in node && "content" in node;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/isEditorState.ts
|
|
15
|
+
var isEditorState = (val) => {
|
|
16
|
+
if (typeof val !== "object" || val === null) return false;
|
|
17
|
+
const state = val;
|
|
18
|
+
return isProseMirrorNode(state["doc"]) && typeof state["selection"] === "object" && state["selection"] !== null && "storedMarks" in state;
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/stringifyMark.ts
|
|
22
|
+
var stringifyObjectOptions = {
|
|
23
|
+
indent: " ",
|
|
24
|
+
inlineCharacterLimit: 1e3
|
|
25
|
+
};
|
|
26
|
+
var stringifyMark = (mark) => Object.keys(mark.attrs).length > 0 ? `${mark.type.name}(${stringifyObject(mark.attrs, stringifyObjectOptions)})` : mark.type.name;
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/stringifyProseMirrorNode.ts
|
|
29
|
+
function stringifyProseMirrorNode(node, selection, indentation = "") {
|
|
30
|
+
const markers = /* @__PURE__ */ new Map();
|
|
31
|
+
if (selection !== void 0) {
|
|
32
|
+
if (selection.anchor === selection.head) markers.set(selection.anchor, "<cursor>");
|
|
33
|
+
else {
|
|
34
|
+
markers.set(selection.anchor, "<anchor>");
|
|
35
|
+
markers.set(selection.head, "<head>");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return render(node, markers, indentation, 0);
|
|
39
|
+
}
|
|
40
|
+
function escapeText(text) {
|
|
41
|
+
return text.replace(/[\p{Cc}\p{Cf}'\\]/gu, (char) => {
|
|
42
|
+
switch (char) {
|
|
43
|
+
case "\f": return "\\f";
|
|
44
|
+
case "\n": return "\\n";
|
|
45
|
+
case "\r": return "\\r";
|
|
46
|
+
case " ": return "\\t";
|
|
47
|
+
case "\b": return "\\b";
|
|
48
|
+
case "'": return "\\'";
|
|
49
|
+
case "\\": return "\\\\";
|
|
50
|
+
default: return `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function quoteWithMarkers(text, start, markers) {
|
|
55
|
+
const inside = [...markers.entries()].filter(([pos]) => pos >= start && pos <= start + text.length).sort(([a], [b]) => a - b);
|
|
56
|
+
const wrapMarker = containsRTL(text) ? (notation) => `\u2066${notation}\u2069` : (notation) => notation;
|
|
57
|
+
let quoted = "";
|
|
58
|
+
let last = 0;
|
|
59
|
+
for (const [pos, notation] of inside) {
|
|
60
|
+
markers.delete(pos);
|
|
61
|
+
const offset = pos - start;
|
|
62
|
+
quoted += escapeText(text.slice(last, offset)) + wrapMarker(notation);
|
|
63
|
+
last = offset;
|
|
64
|
+
}
|
|
65
|
+
quoted += escapeText(text.slice(last));
|
|
66
|
+
return `'${quoted}'`;
|
|
67
|
+
}
|
|
68
|
+
function render(node, markers, indentation, contentStart) {
|
|
69
|
+
if (node.type.spec.toDebugString !== void 0) return `${indentation}${wrapMarks(node.marks, node.type.spec.toDebugString(node))}`;
|
|
70
|
+
if (node.type.name === "text") return `${indentation}${wrapMarks(node.marks, quoteWithMarkers(node.textContent, contentStart, markers))}`;
|
|
71
|
+
return renderElement(node, markers, indentation, contentStart);
|
|
72
|
+
}
|
|
73
|
+
function renderElement(node, markers, indentation, contentStart) {
|
|
74
|
+
const type = node.type.name;
|
|
75
|
+
const hasAttrs = Object.keys(node.attrs).length > 0;
|
|
76
|
+
const nextIndentation = `${indentation} `;
|
|
77
|
+
const args = [];
|
|
78
|
+
const pushArg = (content) => {
|
|
79
|
+
args.push(`${nextIndentation}${content},`);
|
|
80
|
+
};
|
|
81
|
+
const pushMarkerAt = (pos) => {
|
|
82
|
+
const notation = markers.get(pos);
|
|
83
|
+
if (notation !== void 0) {
|
|
84
|
+
markers.delete(pos);
|
|
85
|
+
pushArg(`'${notation}'`);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
if (hasAttrs) pushArg(stringifyObject(node.attrs, stringifyObjectOptions));
|
|
89
|
+
if (!node.type.isLeaf) {
|
|
90
|
+
if (node.content.childCount === 0) pushMarkerAt(contentStart);
|
|
91
|
+
node.content.forEach((child, offset, index) => {
|
|
92
|
+
const childStart = contentStart + offset;
|
|
93
|
+
const isText = child.type.name === "text";
|
|
94
|
+
if (!(index > 0 && node.content.child(index - 1).type.name === "text") && !isText) pushMarkerAt(childStart);
|
|
95
|
+
if (isText) pushArg(wrapMarks(child.marks, quoteWithMarkers(child.textContent, childStart, markers)));
|
|
96
|
+
else args.push(`${render(child, markers, nextIndentation, childStart + 1)},`);
|
|
97
|
+
});
|
|
98
|
+
if (node.content.lastChild?.type.name !== "text") pushMarkerAt(contentStart + node.content.size);
|
|
99
|
+
}
|
|
100
|
+
const body = !hasAttrs && (node.content.childCount === 0 || node.content.childCount === 1 && node.content.firstChild?.type.name === "text") ? `${type}(${args.map((arg) => arg.slice(nextIndentation.length, -1)).join("")})` : `${type}(\n${args.join("\n")}\n${indentation})`;
|
|
101
|
+
return `${indentation}${wrapMarks(node.marks, body)}`;
|
|
102
|
+
}
|
|
103
|
+
function wrapMarks(marks, origContent) {
|
|
104
|
+
let content = origContent;
|
|
105
|
+
for (const mark of [...marks].reverse()) {
|
|
106
|
+
const hasAttrs = Object.keys(mark.attrs).length > 0;
|
|
107
|
+
const items = [content];
|
|
108
|
+
if (hasAttrs) items.unshift(stringifyObject(mark.attrs, stringifyObjectOptions));
|
|
109
|
+
content = `${mark.type.name}(${items.join(", ")})`;
|
|
110
|
+
}
|
|
111
|
+
return content;
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/stringifyEditorState.ts
|
|
115
|
+
function stringifyEditorState(state, indentation = "") {
|
|
116
|
+
const { doc, selection, storedMarks } = state;
|
|
117
|
+
const lines = [stringifyProseMirrorNode(doc, selection, indentation), `${indentation}# selection: ${selection.constructor.name} ${String(selection.from)}..${String(selection.to)}`];
|
|
118
|
+
if (storedMarks !== null) lines.push(`${indentation}# storedMarks: [${storedMarks.map(stringifyMark).join(", ")}]`);
|
|
119
|
+
return lines.join("\n");
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/setup.ts
|
|
123
|
+
afterEach(cleanupEditors);
|
|
124
|
+
expect.extend({
|
|
125
|
+
toEqualProseMirrorNode(received, expected) {
|
|
126
|
+
const receivedDoc = `\n${stringifyProseMirrorNode(received)}\n`;
|
|
127
|
+
const expectedDoc = `\n${stringifyProseMirrorNode(expected)}\n`;
|
|
128
|
+
const sameSchema = received.type.schema === expected.type.schema;
|
|
129
|
+
const pass = sameSchema && this.equals(receivedDoc, expectedDoc);
|
|
130
|
+
return {
|
|
131
|
+
message: pass ? () => `${this.utils.matcherHint(".not.toEqualProseMirrorNode")}\n\nExpected value of document to not equal:\n ${this.utils.printExpected(expectedDoc)}\nActual:\n ${this.utils.printReceived(receivedDoc)}` : () => {
|
|
132
|
+
if (!sameSchema && this.equals(receivedDoc, expectedDoc)) return `${this.utils.matcherHint(".toEqualProseMirrorNode")}\n\nThe documents stringify identically but come from different schemas:\n${this.utils.printReceived(receivedDoc)}`;
|
|
133
|
+
const diffString = this.utils.diff(expectedDoc, receivedDoc);
|
|
134
|
+
return `${this.utils.matcherHint(".toEqualProseMirrorNode")}\n\nExpected value of document to equal:\n${this.utils.printExpected(expectedDoc)}\nActual:\n${this.utils.printReceived(receivedDoc)}${diffString === void 0 ? "" : `\n\nDifference:\n\n${diffString}`}`;
|
|
135
|
+
},
|
|
136
|
+
pass
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
toHaveSelection(received, expected) {
|
|
140
|
+
const state = received instanceof ProseMirrorEditorImpl ? received.state : received;
|
|
141
|
+
const receivedSelection = state.selection;
|
|
142
|
+
const expectedSelection = resolveSelection(state.doc, expected);
|
|
143
|
+
const receivedDoc = `\n${stringifyProseMirrorNode(state.doc, receivedSelection)}\n`;
|
|
144
|
+
const expectedDoc = `\n${stringifyProseMirrorNode(state.doc, expectedSelection)}\n`;
|
|
145
|
+
const pass = receivedSelection.eq(expectedSelection);
|
|
146
|
+
return {
|
|
147
|
+
message: pass ? () => `${this.utils.matcherHint(".not.toHaveSelection")}\n\nExpected selection to not equal:\n${this.utils.printExpected(expectedDoc)}\nActual:\n${this.utils.printReceived(receivedDoc)}` : () => {
|
|
148
|
+
const diffString = this.utils.diff(expectedDoc, receivedDoc);
|
|
149
|
+
return `${this.utils.matcherHint(".toHaveSelection")}\n\nExpected selection to equal (${this.utils.printExpected(expectedSelection.constructor.name)}):\n${this.utils.printExpected(expectedDoc)}\nActual (${this.utils.printReceived(receivedSelection.constructor.name)}):\n${this.utils.printReceived(receivedDoc)}${diffString === void 0 ? "" : `\n\nDifference:\n\n${diffString}`}`;
|
|
150
|
+
},
|
|
151
|
+
pass
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
expect.addSnapshotSerializer({
|
|
156
|
+
serialize: (val, _config, indentation) => stringifyProseMirrorNode(val, void 0, indentation).slice(indentation.length),
|
|
157
|
+
test: isProseMirrorNode
|
|
158
|
+
});
|
|
159
|
+
expect.addSnapshotSerializer({
|
|
160
|
+
serialize: (val, _config, indentation) => {
|
|
161
|
+
return stringifyEditorState(val instanceof ProseMirrorEditorImpl ? val.state : val, indentation).slice(indentation.length);
|
|
162
|
+
},
|
|
163
|
+
test: (val) => val instanceof ProseMirrorEditorImpl || isEditorState(val)
|
|
164
|
+
});
|
|
165
|
+
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vitest-prosemirror",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "A plugin for Vitest that enables you to write tests using the ProseMirror editor",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"vitest",
|
|
@@ -17,16 +17,22 @@
|
|
|
17
17
|
},
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"author": "Marek Dědič",
|
|
20
|
-
"sideEffects":
|
|
20
|
+
"sideEffects": [
|
|
21
|
+
"./dist/setup.js"
|
|
22
|
+
],
|
|
21
23
|
"type": "module",
|
|
22
24
|
"exports": {
|
|
23
25
|
".": {
|
|
24
|
-
"types": "./dist/
|
|
25
|
-
"import": "./dist/
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"import": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./setup": {
|
|
30
|
+
"types": "./dist/setup.d.ts",
|
|
31
|
+
"import": "./dist/setup.js"
|
|
26
32
|
}
|
|
27
33
|
},
|
|
28
|
-
"module": "dist/
|
|
29
|
-
"types": "dist/
|
|
34
|
+
"module": "dist/index.js",
|
|
35
|
+
"types": "dist/index.d.ts",
|
|
30
36
|
"files": [
|
|
31
37
|
"dist"
|
|
32
38
|
],
|
|
@@ -36,6 +42,9 @@
|
|
|
36
42
|
"check": "FORCE_COLOR=1 run-p -c --aggregate-output check:*",
|
|
37
43
|
"check:js-compat": "es-check es2023 --module --checkFeatures 'dist/**/*.js'",
|
|
38
44
|
"clean": "rimraf dist/*",
|
|
45
|
+
"docs:build": "vitepress build docs",
|
|
46
|
+
"docs:dev": "vitepress dev docs",
|
|
47
|
+
"docs:preview": "vitepress preview docs",
|
|
39
48
|
"lint": "FORCE_COLOR=1 run-p -c --aggregate-output lint:*",
|
|
40
49
|
"lint:eslint": "eslint",
|
|
41
50
|
"lint:ts": "FORCE_COLOR=1 run-p -c --aggregate-output lint:ts:*",
|
|
@@ -85,6 +94,7 @@
|
|
|
85
94
|
"typescript-eslint": "^8.58.0",
|
|
86
95
|
"unplugin-dts": "^1.0.1",
|
|
87
96
|
"vite": "^8.0.0",
|
|
97
|
+
"vitepress": "^1.6.4",
|
|
88
98
|
"vitest": "^5.0.0",
|
|
89
99
|
"w3c-keyname": "^2.2.8"
|
|
90
100
|
},
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import 'vitest';
|
|
2
|
-
import { Command } from 'prosemirror-state';
|
|
3
|
-
import { DirectEditorProps } from 'prosemirror-view';
|
|
4
|
-
import { EditorState } from 'prosemirror-state';
|
|
5
|
-
import { Node as Node_2 } from 'prosemirror-model';
|
|
6
|
-
import { ParseOptions } from 'prosemirror-model';
|
|
7
|
-
import { Schema } from 'prosemirror-model';
|
|
8
|
-
import { Selection as Selection_2 } from 'prosemirror-state';
|
|
9
|
-
|
|
10
|
-
declare interface Clipboard_2 {
|
|
11
|
-
html: string;
|
|
12
|
-
text: string;
|
|
13
|
-
}
|
|
14
|
-
export { Clipboard_2 as Clipboard }
|
|
15
|
-
|
|
16
|
-
export declare interface CustomMatchers<R = unknown> {
|
|
17
|
-
toEqualProseMirrorNode(expected: Node_2): R;
|
|
18
|
-
toHaveSelection(expected: TesterSelection): R;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export declare interface Options extends Omit<DirectEditorProps, "dispatchTransaction" | "state"> {
|
|
22
|
-
autoCleanup: boolean;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export declare function parseHTML(html: string, schema: Schema, options?: ParseOptions): Node_2;
|
|
26
|
-
|
|
27
|
-
export { ParseOptions }
|
|
28
|
-
|
|
29
|
-
export declare interface PasteContent {
|
|
30
|
-
files?: Array<File>;
|
|
31
|
-
html?: string;
|
|
32
|
-
plainText?: boolean;
|
|
33
|
-
text?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export declare type PasteInput = PasteContent | Node_2 | string;
|
|
37
|
-
|
|
38
|
-
export declare class ProseMirrorTester {
|
|
39
|
-
get doc(): Node_2;
|
|
40
|
-
get html(): string;
|
|
41
|
-
get state(): EditorState;
|
|
42
|
-
get text(): string;
|
|
43
|
-
private destroyed;
|
|
44
|
-
private readonly mountPoint;
|
|
45
|
-
private readonly view;
|
|
46
|
-
constructor(documentRoot: Node_2, options?: Partial<Options>);
|
|
47
|
-
click(target: Element | string): boolean;
|
|
48
|
-
command(command: Command): boolean;
|
|
49
|
-
copy(): Clipboard_2;
|
|
50
|
-
destroy(): void;
|
|
51
|
-
element(selector: string): HTMLElement;
|
|
52
|
-
elements(selector: string): Array<HTMLElement>;
|
|
53
|
-
insertText(text: string): void;
|
|
54
|
-
paste(content: PasteInput): void;
|
|
55
|
-
selectText(selection: TesterSelection): void;
|
|
56
|
-
private assertAlive;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export declare type TesterSelection = "all" | "end" | "start" | {
|
|
60
|
-
anchor: number | string;
|
|
61
|
-
head: number | string;
|
|
62
|
-
} | (string & {}) | Selection_2 | number;
|
|
63
|
-
|
|
64
|
-
export { }
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
declare module "vitest" {
|
|
68
|
-
interface Matchers<R extends Promise<void> | void = Promise<void> | void, T = unknown> extends CustomMatchers<R> {
|
|
69
|
-
}
|
|
70
|
-
}
|