@stesura/core/testing
Helpers for writing tests against the Stesura schema. Build documents with the tb builders and testDoc, which wraps content in a section and validates it against the schema.
Requires prosemirror-test-builder, an optional peer dependency that is not auto-installed: add it to your devDependencies. tempEditor mounts a real EditorView, so it needs a DOM (for example jsdom).
Functions & values
checkedDoc
Validates a built doc against the schema (doc.check()) before handing it
to a test, so schema-invalid fixtures fail loudly at build time instead of
silently producing states no real editor could reach.
| Name | Type | Default |
|---|---|---|
doc | T |
colCount
Cell count of the first row of the table around the selection.
| Name | Type | Default |
|---|---|---|
state | EditorState |
collectAttr
attrName values with their positions, across nodes matching predicate
(default: block nodes) that declare the attr.
| Name | Type | Default |
|---|---|---|
doc | Node | |
attrName | string | |
predicate | (node: Node) => boolean |
expectSectionIntegrity
Throws (with every problem listed) unless after is a sound sectioned doc:
it passes doc.check() and its section ids are unique and non-null. Without
allowStructure, it must also keep before’s sections: the same
[sectionId, headerId, footerId] triples, each header and footer eq its
old self.
Framework-free, so any test runner can use it.
| Name | Type | Default |
|---|---|---|
before | Node | |
after | Node | |
__2 | { allowStructure?: boolean; } |
findFirstInContent
Finds the first node of typeName inside the first section_content,
returning the node and its absolute position in the document.
Use this instead of doc.descendants when you want to ignore the
identical empty paragraphs that live in the section header and footer.
| Name | Type | Default |
|---|---|---|
doc | Node | |
typeName | string |
getAllSections
Returns all section nodes in the doc as an array.
| Name | Type | Default |
|---|---|---|
state | EditorState |
getCommentAttrs
Attrs of the LAST comment_open and comment_close in the doc (meant for single-comment fixtures).
| Name | Type | Default |
|---|---|---|
state | EditorState |
getCursorSection
Returns the section node at depth 1 that contains the cursor.
| Name | Type | Default |
|---|---|---|
state | EditorState |
getTableNode
The table around the selection head; throws when there is none.
| Name | Type | Default |
|---|---|---|
state | EditorState |
make2x2State
A 2×2 table (2 rows, 2 cols) with cursor in cell (0,0).
make3x3State
A 3×3 table with cursor in cell (0,0).
makeCell
Creates a table_cell with an empty paragraph inside.
| Name | Type | Default |
|---|---|---|
colwidth | number |
makeCellWithText
Creates a table_cell with the given text inside.
| Name | Type | Default |
|---|---|---|
text | string | |
colwidth | number |
makeLinkEditorState
EditorState with the given range selected, for exercising the link commands.
| Name | Type | Default |
|---|---|---|
doc | TaggedNode | |
from | number | |
to | number |
makeRow
Creates a table_row from an array of cells.
| Name | Type | Default |
|---|---|---|
cells | Node[] |
makeTable
Creates a table node from an array of rows.
| Name | Type | Default |
|---|---|---|
rows | Node[] |
rowCount
Row count of the table around the selection.
| Name | Type | Default |
|---|---|---|
state | EditorState |
selectionInContent
Returns a TextSelection with the cursor at the start of the first
section_content in the document.
Use this instead of hardcoding positions — the header and footer each
contain an empty paragraph (required by block+), so a naive position
like 1 or 4 lands inside the header, not the content.
| Name | Type | Default |
|---|---|---|
doc | Node |
singleSectionState
EditorState with cursor in the section_content of a single-section doc.
| Name | Type | Default |
|---|---|---|
content | [attrsOrFirstChild?: Attrs | ChildSpec | undefined, ...children: ChildSpec[]] |
stateWithCursorAt
Builds an EditorState whose cursor is inside the cell at (rowIndex, colIndex) of the given table.
| Name | Type | Default |
|---|---|---|
table | Node | |
rowIndex | number | |
colIndex | number |
stateWithSelectedImage
EditorState with a single image in section_content selected via NodeSelection.
| Name | Type | Default |
|---|---|---|
imageAttrs | Record<string, unknown> |
stateWithTable
EditorState with the cursor in the table’s first cell.
| Name | Type | Default |
|---|---|---|
table | Node |
tb
Node/mark builders bound to testSchema: every node and mark name plus the
short aliases below. Accessed with ! (tb.p!) under noUncheckedIndexedAccess.
| Name | Type | Default |
|---|---|---|
schema | Schema<any, any> |
tempEditor
Creates a real ProseMirror EditorView mounted to a throwaway DOM element.
Unlike EditorState.apply(tr), the view runs the full plugin lifecycle:
appendTransaction, view hooks, handleDOMEvents, transformPasted, etc.
Call destroy() when done (typically in afterEach).
| Name | Type | Default |
|---|---|---|
opts | { doc?: Node; plugins?: Plugin<any>[]; } |
testDoc
A schema-checked doc with content in one section’s section_content, plus
the footnotes container.
testDoc(tb.p!("hello"))| Name | Type | Default |
|---|---|---|
content | [attrsOrFirstChild?: Attrs | ChildSpec | undefined, ...children: ChildSpec[]] |
testSection
A section node wrapping the given content in the required header/content/footer shape.
| Name | Type | Default |
|---|---|---|
content | [attrsOrFirstChild?: Attrs | ChildSpec | undefined, ...children: ChildSpec[]] | |
attrs | Partial<SectionAttrs> |
twoSectionState
A two-section doc with the cursor at the end of the second section’s paragraph.
uncheckedTestDoc
testDoc WITHOUT the schema check — only for specs that deliberately
build invalid docs (e.g. the nested-tables normalize heal, which exercises
the Node.fromJSON door). Everything else should use testDoc.
| Name | Type | Default |
|---|---|---|
content | [attrsOrFirstChild?: Attrs | ChildSpec | undefined, ...children: ChildSpec[]] |
Types
TaggedNode
A node with position tags attached by prosemirror-test-builder.
| Name | Type | Default |
|---|---|---|
type | NodeTypeThe type of node that this is. | |
attrs | AttrsAn object mapping attribute names to values. The kind of attributes allowed and required are determined by the node type. | |
marks | readonly Mark[]The marks (things like whether it is emphasized or part of a link) applied to this node. | |
content | FragmentA container holding the node’s children. | |
children | readonly Node[]The array of this node’s child nodes. | |
text | string | undefinedFor text nodes, this contains the node’s text content. | |
nodeSize | numberThe size of this node, as defined by the integer-based indexing scheme . For text nodes, this is the amount of characters. For other leaf nodes, it is one. For non-leaf nodes, it is the size of the content plus two (the start and end token). | |
childCount | numberThe number of children that the node has. | |
child | (index: number) => NodeGet the child node at the given index. Raises an error when the index is out of range. | |
maybeChild | (index: number) => Node | nullGet the child node at the given index, if it exists. | |
forEach | (f: (node: Node, offset: number, index: number) => void) => voidCall | |
nodesBetween | (from: number, to: number, f: (node: Node, pos: number, parent: Node | null, index: number) => boolean | void, startPos?: number | undefined) => voidInvoke a callback for all descendant nodes recursively overlapping the given two positions that are relative to start of this node’s content. This includes all ancestors of the nodes containing the two positions. The callback is invoked with the node, its position relative to the original node (method receiver), its parent node, and its child index. When the callback returns false for a given node, that node’s children will not be recursed over. The last parameter can be used to specify a starting position to count from. | |
descendants | (f: (node: Node, pos: number, parent: Node | null, index: number) => boolean | void) => voidCall the given callback for every descendant node. Doesn’t
descend into a node when the callback returns | |
textContent | stringConcatenates all the text nodes found in this fragment and its children. | |
textBetween | (from: number, to: number, blockSeparator?: string | null | undefined, leafText?: string | ((leafNode: Node) => string) | null | undefined) => stringGet all text between positions | |
firstChild | Node | nullReturns this node’s first child, or | |
lastChild | Node | nullReturns this node’s last child, or | |
eq | (other: Node) => booleanTest whether two nodes represent the same piece of document. | |
sameMarkup | (other: Node) => booleanCompare the markup (type, attributes, and marks) of this node to
those of another. Returns | |
hasMarkup | (type: NodeType, attrs?: Attrs | null | undefined, marks?: readonly Mark[] | undefined) => booleanCheck whether this node’s markup correspond to the given type, attributes, and marks. | |
copy | (content?: Fragment | null | undefined) => NodeCreate a new node with the same markup as this node, containing the given content (or empty, if no content is given). | |
mark | (marks: readonly Mark[]) => NodeCreate a copy of this node, with the given set of marks instead of the node’s own marks. | |
cut | (from: number, to?: number | undefined) => NodeCreate a copy of this node with only the content between the
given positions. If | |
slice | (from: number, to?: number | undefined, includeParents?: boolean | undefined) => SliceCut out the part of the document between the given positions, and
return it as a | |
replace | (from: number, to: number, slice: Slice) => NodeReplace the part of the document between the given positions with
the given slice. The slice must ‘fit’, meaning its open sides
must be able to connect to the surrounding content, and its
content nodes must be valid children for the node they are placed
into. If any of this is violated, an error of type
| |
nodeAt | (pos: number) => Node | nullFind the node directly after the given position. | |
childAfter | (pos: number) => { node: Node | null; index: number; offset: number; }Find the (direct) child node after the given offset, if any, and return it along with its index and offset relative to this node. | |
childBefore | (pos: number) => { node: Node | null; index: number; offset: number; }Find the (direct) child node before the given offset, if any, and return it along with its index and offset relative to this node. | |
resolve | (pos: number) => ResolvedPosResolve the given position in the document, returning an object with information about its context. | |
rangeHasMark | (from: number, to: number, type: Mark | MarkType) => booleanTest whether a given mark or mark type occurs in this document between the two given positions. | |
isBlock | booleanTrue when this is a block (non-inline node) | |
isTextblock | booleanTrue when this is a textblock node, a block node with inline content. | |
inlineContent | booleanTrue when this node allows inline content. | |
isInline | booleanTrue when this is an inline node (a text node or a node that can appear among text). | |
isText | booleanTrue when this is a text node. | |
isLeaf | booleanTrue when this is a leaf node. | |
isAtom | booleanTrue when this is an atom, i.e. when it does not have directly
editable content. This is usually the same as | |
toString | () => stringReturn a string representation of this node for debugging purposes. | |
contentMatchAt | (index: number) => ContentMatchGet the content match in this node at the given index. | |
canReplace | (from: number, to: number, replacement?: Fragment | undefined, start?: number | undefined, end?: number | undefined) => booleanTest whether replacing the range between | |
canReplaceWith | (from: number, to: number, type: NodeType, marks?: readonly Mark[] | undefined) => booleanTest whether replacing the range | |
canAppend | (other: Node) => booleanTest whether the given node’s content could be appended to this node. If that node is empty, this will only return true if there is at least one node type that can appear in both nodes (to avoid merging completely incompatible nodes). | |
check | () => voidCheck whether this node and its descendants conform to the schema, and raise an exception when they do not. | |
toJSON | () => anyReturn a JSON-serializeable representation of this node. | |
tag | Record<string, number> |