Files
gitmost/packages/editor-ext/src/lib/html-embed/html-embed.height.test.ts
claude_code 0b2af34029 test(integrations/client/packages): batch 2-4 unit coverage + zip-slip guard extraction
Batch 2-4 of the test-strategy rollout. Test-only except one minimal,
behaviour-preserving extraction in file.utils.ts. All suites green:
server 82 suites/836+1todo, editor-ext 86, mcp 270, client (new files) 86.

integrations (server):
- file.utils.ts: extract pure `isEntryPathSafe(entryName, targetDir)` from
  extractZipInternal so the zip-slip/path-traversal guard is unit-testable;
  call site rerouted, behaviour identical (only a warn-message string merged).
- file.utils.zip-safety.spec.ts: traversal/strip/__MACOSX/prefix-confusion
  cases (mutation-resistant: fails if containment loses the path.sep).
- import-formatter / import.utils / table-utils / export utils / import.service
  extractTitleAndRemoveHeading: pure import/export transforms, Notion/XWiki
  formatting, table colspan widths (idempotent), slug/link rewriting.

client:
- safeRedirectPath: open-redirect guard, every reject branch independently.
- buildChatMarkdown (fence anti-breakout), label-colors, normalize-label,
  share tree build, page URL builders, notification time-grouping (fake clock).

packages:
- editor-ext: deriveFootnoteId golden table, parseHtmlEmbedHeight crafted
  values, orphan footnote extraction.
- mcp: deriveFootnoteId parity (drift guard vs editor-ext), applyTextEdits
  idempotency + cross-block replaceAll, diffDocs/summarizeChange on reorder.

Reviewed (APPROVE): extraction behaviour-preserving, assertions mutation-resistant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:22:15 +03:00

64 lines
2.9 KiB
TypeScript

import { describe, it, expect } from "vitest";
import {
parseHtmlEmbedHeight,
renderHtmlEmbedHeight,
} from "./html-embed";
/**
* PIN the CURRENT behavior of `parseHtmlEmbedHeight` for crafted/corrupt
* `data-height` attribute values. The function is a thin parseInt + Number.isFinite
* guard; these tests document EXACTLY what it does today (including the cases
* where today's behavior is arguably wrong) so any future change is a conscious
* one and shows up as a failing test rather than a silent regression.
*/
describe("parseHtmlEmbedHeight: crafted / corrupt data-height", () => {
it('"-5" passes through as -5 (DOCUMENTED QUIRK: negative height is not rejected)', () => {
// Number.isFinite(-5) is true, so the guard does NOT catch it. A negative
// fixed height is almost certainly wrong downstream (it disables auto-resize
// and yields a negative/clamped iframe height), but the function as written
// returns it verbatim. This asserts the REAL behavior, not the ideal one.
expect(parseHtmlEmbedHeight("-5")).toBe(-5);
});
it('"0" returns 0 (NOT null) — note: renderHtmlEmbedHeight treats 0 as auto-resize, so parse/render are asymmetric at 0', () => {
// parseInt("0") === 0 and Number.isFinite(0) is true, so parse keeps 0.
expect(parseHtmlEmbedHeight("0")).toBe(0);
// But the render side treats a falsy 0 as "auto-resize" => emits NO attribute.
// So a stored height of 0 does not round-trip back to data-height="0".
expect(renderHtmlEmbedHeight(0)).toEqual({});
});
it('" 300 " (surrounding whitespace) parses to 300 — parseInt trims leading space', () => {
expect(parseHtmlEmbedHeight(" 300 ")).toBe(300);
});
it('"3.9" truncates to 3 — parseInt drops the fractional part', () => {
expect(parseHtmlEmbedHeight("3.9")).toBe(3);
});
it('a huge "99999999999" passes through unclamped (finite => no upper bound here)', () => {
// The guard only rejects NaN/Infinity; it does not clamp magnitude. Any
// clamping is a downstream concern, NOT this function's job.
expect(parseHtmlEmbedHeight("99999999999")).toBe(99999999999);
});
it('"12px" parses the leading integer (12) — parseInt stops at the first non-digit', () => {
expect(parseHtmlEmbedHeight("12px")).toBe(12);
});
it("null / empty / whitespace-only / non-numeric => null (the auto-resize sentinel)", () => {
expect(parseHtmlEmbedHeight(null)).toBeNull();
expect(parseHtmlEmbedHeight("")).toBeNull();
expect(parseHtmlEmbedHeight(" ")).toBeNull();
expect(parseHtmlEmbedHeight("abc")).toBeNull();
});
it("never returns NaN for a non-numeric value (the Number.isFinite guard's point)", () => {
// NaN is typeof "number" and would slip past a naive `typeof n === number`
// check; the guard must map it to null. This is the core invariant.
const out = parseHtmlEmbedHeight("not-a-number");
expect(out).toBeNull();
expect(Number.isNaN(out as unknown as number)).toBe(false);
});
});