@rtif-sdk/test-kit
v3.3.0
Published
Builders and assertions for testing RTIF documents.
Readme
@rtif-sdk/test-kit
Document builders and assertions for testing RTIF. Framework-agnostic — every
assertion throws a plain Error with a focused message, so it works under any
test runner. Depends on @rtif-sdk/core only.
npm install -D @rtif-sdk/test-kit @rtif-sdk/core30 seconds
import { doc, p, h1, b, sel, assertDocEqual } from '@rtif-sdk/test-kit';
import { apply, invert } from '@rtif-sdk/core';
const before = doc(p('Hello ', b('world')), h1('Title'), p());
const op = { type: 'split_block', at: 3, id: 'x1' } as const;
assertDocEqual(apply(apply(before, op), invert(before, op)), before);doc() returns a finished Document directly — no .build() step.
Builders
| Builder | Produces |
|---|---|
| doc(...blocks) | Document; no args → one empty paragraph |
| p(...) | paragraph block |
| h1(...) / h2(...) / h3(...) | heading with attrs: { level: n } |
| blockquote(...) | blockquote block |
| codeBlock(...) | code_block block |
| li(...) | list block (one block per item) |
| hr(opts?) | horizontal_rule block (empty content) |
| block(type, ...) | any block type |
| t(text, marks?) | span with optional marks |
| b / i / u / s / code | bold / italic / underline / strikethrough / code span |
| link(text, href) | span with { link: { href } } |
| sel(anchor, focus?) | Selection; focus defaults to anchor |
Block builders take strings (unmarked spans), spans, and an optional
{ id?, attrs? } object first or last:
block('paragraph', 'Hello ', b('world'), { id: 'intro' })
li('first', { kind: 'ordered' }) // a non-{id,attrs} trailing object IS the attrs
h2('Subtitle', { id: 'sub' })
doc(p({ id: 'a' }, 'one'), p('two')) // unpinned blocks get b1, b2, ... (per doc() call)Ids are assigned deterministically and skip pinned ones. Builder output satisfies the normalization invariants the builders can guarantee locally; adjacent equal-mark spans are emitted as written (builders never merge).
Assertions
assertDocEqual(actual, expected, opts?)
Structural equality. Block ids are ignored by default — parsers and
round trips regenerate ids, and most tests shouldn't care. Pass
{ compareIds: true } to catch id drift. On mismatch the error names the first
differing block and shows just that block side by side, never the whole
document:
Documents differ at block 1:
actual: {"type":"paragraph","spans":[{"text":"wrld"}]}
expected: {"type":"paragraph","spans":[{"text":"world"}]}assertValidDoc(doc)
Checks all six normalization invariants (block/span shape, no stray empty
spans, no adjacent equal-mark spans, no {} marks/attrs, unique ids, ≥ 1
block) and names the violated invariant and offending block.
docToText(doc)
Compact debug rendering: blocks joined by \n; unmarked spans are raw text;
marked spans render as <keys>text</> with keys sorted and non-true values
appended as =JSON:
docToText(doc(p('Hello ', b('world')), p(link('here', '/x'))));
// 'Hello <bold>world</>\n<link={"href":"/x"}>here</>'Handy in failure messages and snapshot-ish comparisons:
expect(docToText(result)).toBe('Title\nHello <bold|italic>world</>');