Files
MorphDoc/apps/web/tests/sample-markdown.test.ts
T
SkyJourney 925b0d1485 release: 发布 v0.4.5
新增能力:Web 与 Desktop 支持新建和保存 Markdown;桌面端注册 .md/.markdown 打开程序,支持单实例文件转交、自定义主题目录以及窗口位置、尺寸和最大化状态的延迟原子持久化与屏幕越界修正。

界面与兼容性:保留打开 Markdown 为独立主操作,将新建、保存和主题目录收纳到更多菜单;Web 移除本地素材目录入口并明确默认不支持本地素材;新文档默认使用一级标题或首行合法化生成文件名,可不保存直接导出 PDF。

渲染修复:图片、Mermaid 和 ECharts 按文档顺序串行执行媒体分页回填,每个媒体元素至多重排一次;图片以限宽后的高度作为缩放基准,只缩放媒体主体并保持标题尺寸;ECharts 冻结为 SVG 图片后参与统一分页。

示例与文档:默认示例仅保留一张网络图片,增加有效 Base64 横图、竖图、边界图片及多尺寸 Mermaid/ECharts;更新根 README、Desktop README、部署文档、四个 packages README、PROGRESS 和 AGENTS 发布规范;登记 v0.4.6 超链接导航问题。

部署与验证:构建并运行 yixiong/md-to-pdf:v0.4.5 正式镜像,Compose 健康且 PDF 冒烟无 Mermaid/ECharts 错误;生成 NSIS 安装包和免安装 ZIP,本机已升级到 NSIS v0.4.5 并清理旧 Squirrel 安装;202 项测试、类型检查、生产构建和 git diff --check 全部通过。

发布产物:Setup.exe SHA-256 9CBD6362E15AA745185805E753D5A7749434E0E142E6CE0F66463E6A19468F1D;ZIP SHA-256 97B2D44E72F626A3396E5AB5B330FFB7F9BECAF945A1707808C876940A82E850;当前 Windows 产物未配置代码签名。
2026-07-28 13:31:42 +08:00

82 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { inflateSync } from "node:zlib";
import { describe, expect, it } from "vitest";
import { sampleMarkdown } from "../src/sample-markdown";
function readPngDimensions(base64: string) {
const png = Buffer.from(base64, "base64");
expect(png.subarray(0, 8)).toEqual(
Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])
);
const width = png.readUInt32BE(16);
const height = png.readUInt32BE(20);
const bitDepth = png[24] ?? 0;
const colorType = png[25] ?? 0;
const samplesPerPixel =
colorType === 0 || colorType === 3
? 1
: colorType === 2
? 3
: colorType === 4
? 2
: 4;
const idatParts: Buffer[] = [];
let offset = 8;
while (offset + 12 <= png.length) {
const length = png.readUInt32BE(offset);
const type = png.toString("ascii", offset + 4, offset + 8);
if (type === "IDAT") {
idatParts.push(
png.subarray(offset + 8, offset + 8 + length)
);
}
offset += 12 + length;
}
const decoded = inflateSync(Buffer.concat(idatParts));
const rowBytes = Math.ceil(
(width * bitDepth * samplesPerPixel) / 8
);
expect(decoded.length).toBe((rowBytes + 1) * height);
return { width, height };
}
describe("默认示例 Markdown", () => {
it("仅保留一张网络图片并提供三种 Base64 图片尺寸", () => {
expect(
sampleMarkdown.match(/https?:\/\/[^\s)]+/gu)
).toHaveLength(1);
expect(
sampleMarkdown.match(/data:image\/png;base64,/gu)
).toHaveLength(3);
expect(sampleMarkdown).toContain("1600×900");
expect(sampleMarkdown).toContain("900×1800");
expect(sampleMarkdown).toContain("1200×880");
});
it("所有内嵌 PNG 均可完整解压且尺寸符合描述", () => {
const images = Array.from(
sampleMarkdown.matchAll(
/data:image\/png;base64,([A-Za-z0-9+/=]+)/gu
),
(match) => readPngDimensions(match[1] ?? "")
);
expect(images).toEqual([
{ width: 1600, height: 900 },
{ width: 900, height: 1800 },
{ width: 1200, height: 880 }
]);
});
it("覆盖 Mermaid、ECharts 分档和串行媒体场景", () => {
expect(
sampleMarkdown.match(/```mermaid/gu)
).toHaveLength(3);
expect(
sampleMarkdown.match(/```echarts/gu)
).toHaveLength(4);
expect(sampleMarkdown).toContain("height: 40mm");
expect(sampleMarkdown).toContain("height: 58mm");
expect(sampleMarkdown).toContain("height: 85mm");
expect(sampleMarkdown).toContain("## 串行媒体块");
});
});