Files
MorphDoc/apps/web/tests/pdf-export.test.ts
T
SkyJourney f5a46f79f1 feat: 增加 ECharts 渲染与预览交互增强
- 新增可复用的 markdown-echarts 工作区,支持安全的 YAML 围栏、默认值、语义校验、错误占位和 SVG 渲染
- 将 ECharts 接入统一 Markdown、快速预览、精确预览与 PDF 链路,并复用 Mermaid 的不可跨页和超高图单页适配策略
- 默认示例加入 ECharts,增加源文本折叠、顶部文档状态、页码输入跳转与滚动同步
- 快速预览改用外层容器滚动,使滚动条与精确预览统一贴在预览区域右侧,并兼容显示缩放
- 完善 Docker 工作区复制、可配置 Compose 镜像、测试覆盖和进度文档
2026-07-27 16:05:14 +08:00

182 lines
4.7 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { defaultExportConfig } from "@md-to-pdf/core";
import {
createPdfExportCacheKey,
getCachedPdfExport,
getOrRequestPdfExport,
parseContentDispositionFileName,
requestPdfExport,
type CachedPdfExport,
type PdfExportRequest
} from "../src/pdf-export";
describe("PDF 导出客户端", () => {
it("仅复用与当前文档和导出配置完全匹配的 PDF", () => {
const request: PdfExportRequest = {
markdown: "# 测试",
fileName: "测试.md",
language: "zh-CN",
exportConfig: defaultExportConfig
};
const key = createPdfExportCacheKey(request);
const result = {
blob: new Blob(["%PDF-test"]),
fileName: "测试.pdf",
pageCount: 1,
echartsErrorCount: 0,
mermaidErrorCount: 0
};
const cache: CachedPdfExport = { key, result };
expect(getCachedPdfExport(cache, key)).toBe(result);
expect(
getCachedPdfExport(
cache,
createPdfExportCacheKey({
...request,
markdown: "# 已修改"
})
)
).toBeUndefined();
expect(
getCachedPdfExport(
cache,
createPdfExportCacheKey({
...request,
exportConfig: {
...defaultExportConfig,
paper: {
...defaultExportConfig.paper,
orientation: "landscape"
}
}
})
)
).toBeUndefined();
});
it("命中缓存时复用同一个 PDF Blob 且不重复请求", async () => {
const request: PdfExportRequest = {
markdown: "# 测试",
fileName: "测试.md",
language: "zh-CN",
exportConfig: defaultExportConfig
};
const result = {
blob: new Blob(["%PDF-cached"]),
fileName: "测试.pdf",
pageCount: 1,
echartsErrorCount: 0,
mermaidErrorCount: 0
};
const cache: CachedPdfExport = {
key: createPdfExportCacheKey(request),
result
};
const requester = vi.fn();
const resolved = await getOrRequestPdfExport(
request,
cache,
requester
);
expect(requester).not.toHaveBeenCalled();
expect(resolved).toEqual(cache);
expect(resolved.result.blob).toBe(result.blob);
});
it("缓存失效时请求并保存当前 PDF", async () => {
const request: PdfExportRequest = {
markdown: "# 新内容",
fileName: "测试.md",
language: "zh-CN",
exportConfig: defaultExportConfig
};
const result = {
blob: new Blob(["%PDF-new"]),
fileName: "测试.pdf",
pageCount: 2,
echartsErrorCount: 0,
mermaidErrorCount: 0
};
const requester = vi.fn(async () => result);
const resolved = await getOrRequestPdfExport(
request,
undefined,
requester
);
expect(requester).toHaveBeenCalledOnce();
expect(resolved.key).toBe(createPdfExportCacheKey(request));
expect(resolved.result).toBe(result);
});
it("优先解析 UTF-8 下载文件名", () => {
expect(
parseContentDispositionFileName(
"attachment; filename=\"document.pdf\"; " +
"filename*=UTF-8''%E6%B5%8B%E8%AF%95.pdf"
)
).toBe("测试.pdf");
});
it("请求 PDF 并读取生成信息", async () => {
const fetcher = vi.fn(async () => {
return new Response(new Blob(["%PDF-test"]), {
status: 200,
headers: {
"content-type": "application/pdf",
"content-disposition":
"attachment; filename=\"document.pdf\"",
"x-pdf-page-count": "4",
"x-echarts-error-count": "2",
"x-mermaid-error-count": "1"
}
});
});
const result = await requestPdfExport(
{
markdown: "# 测试",
fileName: "测试.md",
language: "zh-CN",
exportConfig: defaultExportConfig
},
fetcher
);
expect(fetcher).toHaveBeenCalledWith(
"/api/pdf",
expect.objectContaining({ method: "POST" })
);
expect(result.fileName).toBe("document.pdf");
expect(result.pageCount).toBe(4);
expect(result.echartsErrorCount).toBe(2);
expect(result.mermaidErrorCount).toBe(1);
expect(await result.blob.text()).toBe("%PDF-test");
});
it("显示服务端返回的错误信息", async () => {
const fetcher = vi.fn(async () => {
return Response.json(
{ message: "PDF 生成队列已满" },
{ status: 503 }
);
});
await expect(
requestPdfExport(
{
markdown: "# 测试",
fileName: "测试.md",
language: "zh-CN",
exportConfig: defaultExportConfig
},
fetcher
)
).rejects.toThrow("PDF 生成队列已满");
});
});