test(editor-ext): cover the html-embed height attr codec (#98, #99)

Extract parse/renderHtmlEmbedHeight and test: '300'->300, absent->null,
'abc'->null (pins the NaN guard), '120px'->120; render 120->data-height, null/0->{}.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
claude code agent 227
2026-06-21 05:46:36 +03:00
parent a341489620
commit 11176c1c9e
2 changed files with 67 additions and 10 deletions

View File

@@ -2,6 +2,8 @@ import { afterEach, describe, expect, it } from "vitest";
import {
encodeHtmlEmbedSource,
decodeHtmlEmbedSource,
parseHtmlEmbedHeight,
renderHtmlEmbedHeight,
} from "./html-embed";
// Unit coverage for the base64 codec used by the htmlEmbed node's
@@ -118,6 +120,45 @@ describe("html-embed codec — encode failure fallback", () => {
});
});
describe("html-embed height — parseHtmlEmbedHeight (data-height -> px | null)", () => {
it('parses a numeric string ("300" -> 300)', () => {
expect(parseHtmlEmbedHeight("300")).toBe(300);
});
it("parses an absent value (null -> null = auto-resize)", () => {
expect(parseHtmlEmbedHeight(null)).toBeNull();
expect(parseHtmlEmbedHeight("")).toBeNull();
});
it('rejects a non-numeric value ("abc" -> null) — pins the NaN guard (BUG-2)', () => {
// Without Number.isFinite this would be NaN (typeof "number"), disabling
// auto-resize and yielding an unclamped iframe height downstream.
expect(parseHtmlEmbedHeight("abc")).toBeNull();
});
it('parses a trailing-unit value ("120px" -> 120) via parseInt', () => {
expect(parseHtmlEmbedHeight("120px")).toBe(120);
});
});
describe("html-embed height — renderHtmlEmbedHeight (px -> data-height | {})", () => {
it("renders a fixed height (120 -> { data-height: '120' })", () => {
expect(renderHtmlEmbedHeight(120)).toEqual({ "data-height": "120" });
});
it("renders auto-resize as no attribute (null -> {})", () => {
expect(renderHtmlEmbedHeight(null)).toEqual({});
});
it("renders 0 as no attribute (0 is auto -> {})", () => {
expect(renderHtmlEmbedHeight(0)).toEqual({});
});
it("renders undefined as no attribute (absent -> {})", () => {
expect(renderHtmlEmbedHeight(undefined)).toEqual({});
});
});
describe("html-embed codec — decode of malformed input (browser branch)", () => {
it("returns '' for input atob rejects (catch branch)", () => {
// atob throws on characters outside the base64 alphabet; the codec catches

View File

@@ -69,6 +69,30 @@ export function decodeHtmlEmbedSource(encoded: string): string {
}
}
/**
* Parse the `data-height` attribute value into a fixed iframe height in px.
*
* Returns null (auto-resize) when the value is absent, empty, or non-numeric.
* A non-numeric `data-height` (e.g. a crafted/corrupted import) must NOT become
* NaN: NaN is typeof "number" and would disable auto-resize and yield an
* unclamped iframe height downstream. The Number.isFinite guard pins that fix.
*/
export function parseHtmlEmbedHeight(value: string | null): number | null {
if (!value) return null;
const n = parseInt(value, 10);
return Number.isFinite(n) ? n : null;
}
/**
* Render a fixed height back to a `data-height` attribute. A null/0/absent
* height means auto-resize, so no attribute is emitted.
*/
export function renderHtmlEmbedHeight(
height: number | null | undefined,
): { "data-height": string } | Record<string, never> {
return height ? { "data-height": String(height) } : {};
}
export const HtmlEmbed = Node.create<HtmlEmbedOptions>({
name: "htmlEmbed",
inline: false,
@@ -103,17 +127,9 @@ export const HtmlEmbed = Node.create<HtmlEmbedOptions>({
// Fixed iframe height in px. null/absent => auto-resize on the client.
height: {
default: null,
parseHTML: (el) => {
const v = el.getAttribute("data-height");
if (!v) return null;
const n = parseInt(v, 10);
// A non-numeric data-height (e.g. crafted/corrupted import) must not
// become NaN: NaN is typeof "number" and would disable auto-resize and
// yield an unclamped iframe height downstream. Treat it as auto (null).
return Number.isFinite(n) ? n : null;
},
parseHTML: (el) => parseHtmlEmbedHeight(el.getAttribute("data-height")),
renderHTML: (attrs: HtmlEmbedAttributes) =>
attrs.height ? { "data-height": String(attrs.height) } : {},
renderHtmlEmbedHeight(attrs.height),
},
};
},