test(review): add the 4 new test-coverage points from PR #185 re-review

The re-review's blocking/structural points (lease leak, dup-id guard test,
body-before-title test, CHANGELOG, pg18, shared jsonb decoder) were already
addressed in commit 24264ef; this adds the 4 genuinely-new coverage requests:

- pt 6: `scrollToReference(id, index?)` exercised against a live editor DOM —
  selects the index-th `sup[data-footnote-ref][data-id]` occurrence, falls back
  to the first for out-of-range, returns false for an empty id (scrollIntoView
  stubbed). (#168)
- pt 7: export `backlinkLabel` and pin the base-26 carry boundary
  (25->z, 26->aa, 27->ab, 51->az, 52->ba). (#168)
- pt 8: integration fail-open — a PRESENT-but-corrupt tool_allowlist (jsonb
  string scalar holding non-array JSON) reads back as null ("no restriction"),
  covering normalizeRow's degrade branch. (#159 #172/#173)
- pt 9: getFootnoteRefCount cache invalidation — adding a `[^a]` reference bumps
  the cached count 2 -> 3. (#168)

Verified: editor-ext footnote 23; client structure 7 + tsc; server int 8.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
claude code agent 227
2026-06-25 12:08:21 +03:00
parent f80276d41a
commit 30c358a2f8
4 changed files with 141 additions and 2 deletions

View File

@@ -162,6 +162,111 @@ describe('getFootnoteRefCount (cached, live editor)', () => {
expect(getFootnoteRefCount(editor.state, 'nope')).toBe(0);
editor.destroy();
});
// #185 re-review pt 9: the cached count must update on a doc change (mirror of
// the number-cache invalidation test) — add another `[^a]` reference and the
// count goes 2 -> 3.
it('recomputes the cached ref count when a reference is added', () => {
const editor = makeEditor({
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{ type: FOOTNOTE_REFERENCE_NAME, attrs: { id: 'a' } },
{ type: 'text', text: ' and ' },
{ type: FOOTNOTE_REFERENCE_NAME, attrs: { id: 'a' } },
],
},
{
type: FOOTNOTES_LIST_NAME,
content: [
{
type: FOOTNOTE_DEFINITION_NAME,
attrs: { id: 'a' },
content: [{ type: 'paragraph' }],
},
],
},
],
});
expect(getFootnoteRefCount(editor.state, 'a')).toBe(2);
// Insert a THIRD reference to `a` at the start of the first paragraph.
const refType = editor.schema.nodes[FOOTNOTE_REFERENCE_NAME];
editor.view.dispatch(
editor.state.tr.insert(1, refType.create({ id: 'a' })),
);
expect(getFootnoteRefCount(editor.state, 'a')).toBe(3);
editor.destroy();
});
});
// #185 re-review pt 6: scrollToReference picks the index-th occurrence among the
// reused references, falls back to the first for an out-of-range index, and is a
// no-op (false) for an empty id. Runs the REAL command against the editor's DOM
// (scrollIntoView is stubbed — jsdom does not implement it).
describe('scrollToReference command (occurrence selection + fallback)', () => {
it('selects the index-th occurrence, falls back to the first, false for empty id', () => {
const scrolled: Element[] = [];
const original = (Element.prototype as any).scrollIntoView;
(Element.prototype as any).scrollIntoView = function () {
scrolled.push(this as Element);
};
try {
const editor = makeEditor({
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{ type: FOOTNOTE_REFERENCE_NAME, attrs: { id: 'a' } },
{ type: 'text', text: ' x ' },
{ type: FOOTNOTE_REFERENCE_NAME, attrs: { id: 'a' } },
{ type: 'text', text: ' y ' },
{ type: FOOTNOTE_REFERENCE_NAME, attrs: { id: 'a' } },
],
},
{
type: FOOTNOTES_LIST_NAME,
content: [
{
type: FOOTNOTE_DEFINITION_NAME,
attrs: { id: 'a' },
content: [{ type: 'paragraph' }],
},
],
},
],
});
const sups = editor.view.dom.querySelectorAll(
'sup[data-footnote-ref][data-id="a"]',
);
expect(sups.length).toBe(3);
// index 1 -> the SECOND occurrence.
expect(editor.commands.scrollToReference('a', 1)).toBe(true);
expect(scrolled[scrolled.length - 1]).toBe(sups[1]);
// out-of-range index -> falls back to the FIRST occurrence.
expect(editor.commands.scrollToReference('a', 99)).toBe(true);
expect(scrolled[scrolled.length - 1]).toBe(sups[0]);
// default index (0) -> first.
expect(editor.commands.scrollToReference('a')).toBe(true);
expect(scrolled[scrolled.length - 1]).toBe(sups[0]);
// empty id -> false, no scroll.
const before = scrolled.length;
expect(editor.commands.scrollToReference('')).toBe(false);
expect(scrolled.length).toBe(before);
editor.destroy();
} finally {
(Element.prototype as any).scrollIntoView = original;
}
});
});
describe('setFootnote command', () => {