import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; interface PackageManifest { version?: string; productName?: string; scripts?: Record; } interface ProductBrand { appId: string; englishName: string; displayName: string; windowTitle: string; executableName: string; artifactPrefix: string; } const desktopRoot = fileURLToPath(new URL("../", import.meta.url)); const projectRoot = fileURLToPath(new URL("../../../", import.meta.url)); function readManifest(path: string): T { return JSON.parse(readFileSync(path, "utf8")) as T; } describe("桌面发行构建链", () => { it("打包前按依赖顺序完整重建内嵌 Web", () => { const rootManifest = readManifest(`${projectRoot}/package.json`); const desktopManifest = readManifest(`${desktopRoot}/package.json`); const webBuild = rootManifest.scripts?.["build:web-runtime"] ?? ""; const expectedWorkspaces = [ "@md-to-pdf/markdown-echarts", "@md-to-pdf/core", "@md-to-pdf/renderer", "@md-to-pdf/application", "@md-to-pdf/preview-engine", "@md-to-pdf/web" ]; let previousIndex = -1; for (const workspace of expectedWorkspaces) { const workspaceIndex = webBuild.indexOf(workspace); expect(workspaceIndex).toBeGreaterThan(previousIndex); previousIndex = workspaceIndex; } expect(desktopManifest.scripts?.["build:embedded-web"]).toBe( "npm --prefix ../.. run build:web-runtime" ); expect(desktopManifest.scripts?.package).toMatch( /^npm run build:embedded-web && / ); expect(desktopManifest.scripts?.make).toMatch( /^npm run build:embedded-web && / ); expect(rootManifest.scripts?.["desktop:package"]).toBe( "npm run package -w @md-to-pdf/desktop" ); }); it("将内置主题示例作为独立资源复制到发行目录", () => { const builderConfig = readFileSync( `${desktopRoot}/electron-builder.config.cjs`, "utf8" ); expect(builderConfig).toContain('from: "../../samples"'); expect(builderConfig).toContain('to: "samples"'); }); it("保持安装身份并从统一配置生成 MorphDoc 发行名称", () => { const brand = readManifest( `${projectRoot}/product.json` ); const desktopManifest = readManifest( `${desktopRoot}/package.json` ); const builderConfig = readFileSync( `${desktopRoot}/electron-builder.config.cjs`, "utf8" ); const installerInclude = readFileSync( `${desktopRoot}/build/installer.nsh`, "utf8" ); expect(brand).toMatchObject({ appId: "com.md-to-pdf.desktop", englishName: "MorphDoc", displayName: "墨呈", windowTitle: "墨呈 · MorphDoc", executableName: "MorphDoc", artifactPrefix: "MorphDoc" }); expect(desktopManifest).toMatchObject({ version: "0.6.0", productName: "MorphDoc" }); expect(builderConfig).toContain("appId: brand.appId"); expect(builderConfig).toContain("productName: brand.englishName"); expect(builderConfig).toContain("executableName: brand.executableName"); expect(builderConfig).toContain("shortcutName: brand.displayName"); expect(installerInclude).toContain( '!define MORPHDOC_EXECUTABLE "MorphDoc.exe"' ); expect(installerInclude).toContain( '!define MORPHDOC_DISPLAY_NAME "墨呈"' ); expect(installerInclude).toContain( "Software\\Classes\\Applications\\${MORPHDOC_LEGACY_EXECUTABLE}" ); }); it("仅在组合构建时接入经过哈希校验的同目录字体包", () => { const builderConfig = readFileSync( `${desktopRoot}/electron-builder.config.cjs`, "utf8" ); const installerInclude = readFileSync( `${desktopRoot}/build/installer.nsh`, "utf8" ); const companionBuild = readFileSync( `${projectRoot}/scripts/build-desktop-with-font-pack.mjs`, "utf8" ); expect(builderConfig).toContain("MD_TO_PDF_NSIS_INCLUDE"); expect(installerInclude).toContain("FONT_PACK_COMPANION_SHA256"); expect(installerInclude).toContain("StdUtils.HashFile"); expect(installerInclude).toContain("/WITHFONTPACK="); expect(companionBuild).toContain("createDesktopCompanionInclude"); expect(companionBuild).toContain("MD_TO_PDF_NSIS_INCLUDE"); }); it("将 DOCX Lua Filter 复制到桌面主进程资源目录", () => { const buildScript = readFileSync( `${desktopRoot}/scripts/build-main.mjs`, "utf8" ); expect(buildScript).toContain( "packages/docx-engine/assets/docx-media-filter.lua" ); expect(buildScript).toContain("dist/docx-media-filter.lua"); }); it("为 ESM 主进程中的 CommonJS 字体转换依赖保留 __dirname", () => { const buildScript = readFileSync( `${desktopRoot}/scripts/build-main.mjs`, "utf8" ); expect(buildScript).toContain( 'dirname as __mdToPdfDirname' ); expect(buildScript).toContain( 'fileURLToPath as __mdToPdfFileURLToPath' ); expect(buildScript).toContain( "const __dirname = __mdToPdfDirname(__mdToPdfFileURLToPath(import.meta.url));" ); }); it("在 Docker Web 构建前复制样例并保留到运行镜像", () => { const dockerfile = readFileSync( `${projectRoot}/deploy/Dockerfile`, "utf8" ); const samplesBuildCopyIndex = dockerfile.indexOf( "COPY samples ./samples" ); const webBuildIndex = dockerfile.indexOf( "npm run build -w @md-to-pdf/web" ); expect(samplesBuildCopyIndex).toBeGreaterThan(-1); expect(webBuildIndex).toBeGreaterThan(samplesBuildCopyIndex); expect(dockerfile).toContain( "COPY --chown=pwuser:pwuser --from=build /app/samples ./samples" ); }); });