From f0d8c00cdf1ea392b6983f1e4c66edd3fbb34e64 Mon Sep 17 00:00:00 2001 From: MarsLuay <70299537+MarsLuay@users.noreply.github.com> Date: Sun, 6 Sep 2026 04:46:08 +0000 Subject: [PATCH 1/3] test(font-fidelity): add comprehensive unit tests for FontFidelity module Add tests to cover FontFidelity constructor options, measureText delegation with safe fallback handling for NaN/negative measurements, SVG element style/font-family replacements using a custom MockElement, and the font availability caching mechanism. --- tests/font-fidelity.test.mjs | 120 +++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/tests/font-fidelity.test.mjs b/tests/font-fidelity.test.mjs index c0fac03..46d4d3c 100644 --- a/tests/font-fidelity.test.mjs +++ b/tests/font-fidelity.test.mjs @@ -53,3 +53,123 @@ test("splitCssFontFamilies", async () => { assert.deepEqual(splitCssFontFamilies(""), []); assert.deepEqual(splitCssFontFamilies(" "), []); }); + +test("FontFidelity constructor options", async () => { + const { FontFidelity, POWERPOINT_FONT_FALLBACKS } = await loadFontFidelityModule(); + + const customFallbacks = { 'Custom Font': ['Fallback1', 'sans-serif'] }; + const fidelity = new FontFidelity({ fontFallbacks: customFallbacks }); + + const fallbacks = fidelity.getRendererFallbacks(); + assert.deepEqual(fallbacks['Custom Font'], ['Fallback1', 'sans-serif']); + assert.deepEqual(fallbacks['Aptos'], POWERPOINT_FONT_FALLBACKS['Aptos']); +}); + +test("FontFidelity.prototype.measureText delegates to measureTextFn and safely fallbacks", async () => { + const { FontFidelity } = await loadFontFidelityModule(); + + const mockMeasureText = (text, fontFamily, fontSizePx) => { + if (text === "invalid") return NaN; + if (text === "negative") return -1; + return text.length * fontSizePx; + }; + + const fidelity = new FontFidelity({ + measureText: mockMeasureText, + isFontAvailable: () => true + }); + + // Delegates properly + assert.equal(fidelity.measureText("hello", "Arial", 10), 50); + + // Safely falls back on NaN + assert.equal(fidelity.measureText("invalid", "Arial", 10), 7 * 10 * 0.6); + + // Safely falls back on negative + assert.equal(fidelity.measureText("negative", "Arial", 10), 8 * 10 * 0.6); +}); + +class MockElement { + constructor(tagName) { + this.tagName = tagName; + this.attributes = new Map(); + this.children = []; + } + getAttribute(name) { + return this.attributes.get(name) || null; + } + setAttribute(name, value) { + this.attributes.set(name, value); + } + getElementsByTagName(name) { + let results = []; + for (const child of this.children) { + if (name === '*' || child.tagName === name) { + results.push(child); + } + results.push(...child.getElementsByTagName(name)); + } + return results; + } +} + +test("FontFidelity.prototype.applySvgSubstitutions substitutes fonts and styles", async () => { + const { FontFidelity } = await loadFontFidelityModule(); + + const fidelity = new FontFidelity({ + isFontAvailable: (font) => font.toLowerCase() === "arial" || font.toLowerCase() === "sans-serif" + }); + + const svg = new MockElement("svg"); + svg.setAttribute("font-family", "Unknown Font"); + + const textElement = new MockElement("text"); + textElement.setAttribute("style", "font-family: 'Another Unknown'; color: red;"); + svg.children.push(textElement); + + const substitutions = fidelity.applySvgSubstitutions(svg); + + // Check svg attributes + assert.equal(svg.getAttribute("data-native-powerpoint-requested-font"), "Unknown Font"); + assert.equal(svg.getAttribute("data-native-powerpoint-font-substitution"), "Arial"); + assert.ok(svg.getAttribute("font-family").includes("Arial")); + + // Check text element style + assert.equal(textElement.getAttribute("data-native-powerpoint-requested-font"), "Another Unknown"); + assert.equal(textElement.getAttribute("data-native-powerpoint-font-substitution"), "Arial"); + assert.ok(textElement.getAttribute("style").includes("font-family:")); + assert.ok(textElement.getAttribute("style").includes("color: red;")); + + // Check substitutions array + assert.equal(substitutions.length, 2); + // Sorted by requested font string + assert.equal(substitutions[0].requested, "Another Unknown"); + assert.equal(substitutions[0].substitute, "Arial"); + assert.equal(substitutions[1].requested, "Unknown Font"); + assert.equal(substitutions[1].substitute, "Arial"); +}); + +test("FontFidelity caches isFontAvailableFn results", async () => { + const { FontFidelity } = await loadFontFidelityModule(); + + let callCount = 0; + const mockIsFontAvailable = (font) => { + callCount++; + return true; + }; + + const fidelity = new FontFidelity({ + isFontAvailable: mockIsFontAvailable + }); + + fidelity.measureText("hello", "CustomCacheFont", 10); + const callsAfterFirst = callCount; + + // Should not trigger again + fidelity.measureText("hello", "CustomCacheFont", 10); + assert.equal(callCount, callsAfterFirst); + + // Same font with quotes and mixed casing should hit cache + fidelity.measureText("hello", "'customcachefont'", 10); + assert.equal(callCount, callsAfterFirst); +}); From bdb48eefb4661942f48385d43503b429dcf60869 Mon Sep 17 00:00:00 2001 From: MarsLuay <70299537+MarsLuay@users.noreply.github.com> Date: Sun, 6 Sep 2026 04:49:08 +0000 Subject: [PATCH 2/3] test(font-fidelity): add unit tests for FontFidelity module Add tests to cover FontFidelity constructor options, measureText delegation with safe fallback handling for NaN/negative measurements, SVG element style/font-family replacements using a custom MockElement, and the font availability caching mechanism. From a1e58ec05afbe285b2345748d8c6e43f00557c17 Mon Sep 17 00:00:00 2001 From: MarsLuay <70299537+MarsLuay@users.noreply.github.com> Date: Sun, 6 Sep 2026 04:52:41 +0000 Subject: [PATCH 3/3] test(font-fidelity): add unit tests for FontFidelity module Add tests to cover FontFidelity constructor options, measureText delegation with safe fallback handling for NaN/negative measurements, SVG element style/font-family replacements using a custom MockElement, and the font availability caching mechanism.