fix(git-sync): propagate nested details open; drop dead delete-cap wiring; cover lost-lock abort + lose-prone atom round-trips
Addresses review 1863 (delta) on PR #119. MUST-FIX: - detailsToHtml (the raw-HTML path used for a details nested inside columns/spanned cells) now emits `<details${open}>`, mirroring the top-level case, so `open` no longer silently drops every round trip. - Remove the dead `resolveApplyClient` delete-cap hook from the engine `runCycle`: the orchestrator stopped passing it, so the hook + its dry-run pass were inert. Deletes are soft (Trash) + always logged and engine convergence is the guard, so no cap is re-added — just the dead wiring removed. TEST COVERAGE: - space-lock: heartbeat refresh CAS-miss (eval -> 0) and Redis-error (eval throws) both abort the in-flight fn's signal. - cycle: a pre-aborted signal (and an abort during the pull read) throws before the push apply / first destructive phase. - converter: htmlEmbed source VALUE + height survive; encode/decode UTF-8 symmetry and '' -> ''; footnote definition body + ref/def id match; transclusionReference both ids survive; fix the bad transclusionSource fixture (wrong `pageId` attr + empty content -> schema `id` + a block child); nested details `open` parity test. - orchestrator: autoMergeConflicts:true reaches engine settings; default false on a missing settings row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,8 @@ import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
sanitizeCssColor,
|
||||
clampCalloutType,
|
||||
encodeHtmlEmbedSource,
|
||||
decodeHtmlEmbedSource,
|
||||
} from '../src/lib/docmost-schema.js';
|
||||
|
||||
// These tests pin the two security/normalization helpers that Docmost
|
||||
@@ -73,3 +75,26 @@ describe('clampCalloutType', () => {
|
||||
expect(clampCalloutType(null)).toBe('info');
|
||||
});
|
||||
});
|
||||
|
||||
// The htmlEmbed `source` rides the data-source attribute base64-encoded so the
|
||||
// raw HTML/CSS/JS stays inert and double-encoding-free across a round trip.
|
||||
// Encode/decode MUST be exact inverses (incl. UTF-8) or the embed body corrupts.
|
||||
describe('encode/decodeHtmlEmbedSource', () => {
|
||||
it('round-trips ASCII HTML losslessly', () => {
|
||||
const src = '<b>hi</b>';
|
||||
expect(decodeHtmlEmbedSource(encodeHtmlEmbedSource(src))).toBe(src);
|
||||
});
|
||||
|
||||
it('round-trips multi-byte UTF-8 (Cyrillic + emoji) losslessly', () => {
|
||||
const src = '<p>Привет, мир 🌍 — café</p>';
|
||||
const encoded = encodeHtmlEmbedSource(src);
|
||||
// It is actually encoded (not passed through verbatim).
|
||||
expect(encoded).not.toBe(src);
|
||||
expect(decodeHtmlEmbedSource(encoded)).toBe(src);
|
||||
});
|
||||
|
||||
it('maps empty string to empty string both ways', () => {
|
||||
expect(encodeHtmlEmbedSource('')).toBe('');
|
||||
expect(decodeHtmlEmbedSource('')).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user