131 lines
5.3 KiB
TypeScript
131 lines
5.3 KiB
TypeScript
import { describe, expect, it } from "@suaveplan/testing/runner";
|
|
import { compressSvg } from "../src/core/compress-svg/compress-svg.js";
|
|
import { parseSvg } from "../src/parser/svg/svg.js";
|
|
import {
|
|
PRESET_AGGRESSIVE,
|
|
PRESET_DEFAULT,
|
|
PRESET_SAFE,
|
|
} from "../src/presets/index.js";
|
|
|
|
const REAL_SVG_ICON = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
<!-- This is an SVG icon -->
|
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="24" height="24" fill="black" opacity="1">
|
|
<metadata>
|
|
<dc:title xmlns:dc="http://purl.org/dc/elements/1.1/">Home Icon</dc:title>
|
|
</metadata>
|
|
<!-- house shape -->
|
|
<g id="layer1">
|
|
<g>
|
|
<path d="M 10.000000001 20.0000000009 L 14.000000001 20.0000000009 L 14.000000001 15.0000000009 L 10.000000001 15.0000000009 Z" fill="black" opacity="1"/>
|
|
</g>
|
|
</g>
|
|
<path d="M 12 3.0000000009 L 2.0000000001 12 L 4.0000000001 12 L 4.0000000001 21 L 10.000000001 21 L 10.000000001 15 L 14 15 L 14 21 L 20 21 L 20 12 L 22 12 Z" fill-opacity="1" stroke-opacity="1"/>
|
|
</svg>`;
|
|
|
|
const MINIMAL_SVG =
|
|
'<svg xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100"/></svg>';
|
|
|
|
describe("integration: PRESET_DEFAULT", () => {
|
|
it("compresses real SVG icon and reduces size", { timeout: 5000 }, () => {
|
|
const result = compressSvg(REAL_SVG_ICON, { plugins: PRESET_DEFAULT });
|
|
expect(result.ratio).toBeLessThanOrEqual(1);
|
|
expect(result.data).not.toContain("<!--");
|
|
expect(result.data).not.toContain("DOCTYPE");
|
|
expect(result.data).not.toContain("<metadata>");
|
|
});
|
|
|
|
it("removes XML declaration", { timeout: 5000 }, () => {
|
|
const result = compressSvg(REAL_SVG_ICON, { plugins: PRESET_DEFAULT });
|
|
expect(result.data).not.toContain("<?xml");
|
|
});
|
|
|
|
it("output is parseable after compression", { timeout: 5000 }, () => {
|
|
const result = compressSvg(REAL_SVG_ICON, { plugins: PRESET_DEFAULT });
|
|
expect(() => parseSvg(result.data)).not.toThrow();
|
|
});
|
|
|
|
it("reduces float precision in path data", { timeout: 5000 }, () => {
|
|
const result = compressSvg(REAL_SVG_ICON, {
|
|
plugins: PRESET_DEFAULT,
|
|
floatPrecision: 1,
|
|
});
|
|
expect(result.data).not.toMatch(/\d\.\d{4,}/);
|
|
});
|
|
|
|
it("collapses single-child groups", { timeout: 5000 }, () => {
|
|
const svg = '<svg><g><rect width="10" height="10"/></g></svg>';
|
|
const result = compressSvg(svg, { plugins: PRESET_DEFAULT });
|
|
expect(result.data).not.toContain("<g>");
|
|
expect(result.data).toContain("<rect");
|
|
});
|
|
|
|
it("reports passCount >= 1", { timeout: 5000 }, () => {
|
|
const result = compressSvg(REAL_SVG_ICON, { plugins: PRESET_DEFAULT });
|
|
expect(result.passCount).toBeGreaterThanOrEqual(1);
|
|
});
|
|
});
|
|
|
|
describe("integration: PRESET_SAFE", () => {
|
|
it("compresses without converting transforms", { timeout: 5000 }, () => {
|
|
const svg =
|
|
'<svg><rect transform="translate(1.123456789 2.987654321)"/></svg>';
|
|
const defaultResult = compressSvg(svg, { plugins: PRESET_DEFAULT });
|
|
const safeResult = compressSvg(svg, { plugins: PRESET_SAFE });
|
|
// PRESET_SAFE does not include convertTransforms
|
|
expect(safeResult.data).toContain("1.123456789");
|
|
// PRESET_DEFAULT does not include convertTransforms either, so both same
|
|
expect(defaultResult.data).toContain("1.123456789");
|
|
});
|
|
|
|
it("still removes comments", { timeout: 5000 }, () => {
|
|
const svg = "<svg><!-- note --><rect/></svg>";
|
|
const result = compressSvg(svg, { plugins: PRESET_SAFE });
|
|
expect(result.data).not.toContain("<!--");
|
|
});
|
|
});
|
|
|
|
describe("integration: PRESET_AGGRESSIVE", () => {
|
|
it("mangles ids", { timeout: 5000 }, () => {
|
|
const svg = '<svg><rect id="veryLongDescriptiveName"/></svg>';
|
|
const result = compressSvg(svg, { plugins: PRESET_AGGRESSIVE });
|
|
expect(result.data).not.toContain("veryLongDescriptiveName");
|
|
expect(result.data).toContain("id=");
|
|
});
|
|
|
|
it("converts transforms", { timeout: 5000 }, () => {
|
|
const svg =
|
|
'<svg><rect transform="translate(1.123456789 2.987654321)"/></svg>';
|
|
const result = compressSvg(svg, {
|
|
plugins: PRESET_AGGRESSIVE,
|
|
transformPrecision: 2,
|
|
});
|
|
expect(result.data).toContain("translate(1.12 2.99)");
|
|
});
|
|
|
|
it("has smaller output than PRESET_SAFE for icon", {
|
|
timeout: 5000,
|
|
}, () => {
|
|
const safe = compressSvg(REAL_SVG_ICON, { plugins: PRESET_SAFE });
|
|
const aggressive = compressSvg(REAL_SVG_ICON, {
|
|
plugins: PRESET_AGGRESSIVE,
|
|
});
|
|
expect(aggressive.compressedSize).toBeLessThanOrEqual(
|
|
safe.compressedSize
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("integration: minimal SVG", () => {
|
|
it("handles minimal SVG without error", { timeout: 5000 }, () => {
|
|
const result = compressSvg(MINIMAL_SVG);
|
|
expect(result.data).toBeTruthy();
|
|
expect(result.originalSize).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("passCount is 1 when multipass=false", { timeout: 5000 }, () => {
|
|
const result = compressSvg(MINIMAL_SVG, { multipass: false });
|
|
expect(result.passCount).toBe(1);
|
|
});
|
|
});
|