92 lines
3.6 KiB
TypeScript
92 lines
3.6 KiB
TypeScript
/**
|
||
* 端到端链路冒烟测试(§17 V1 验收标准)。
|
||
*
|
||
* 验证完整链路:
|
||
* ReportDocument(core)
|
||
* → 数据注入 + 布局(layout,含分组/聚合)
|
||
* → LayoutDocument
|
||
* → HTML/SVG Renderer(renderer)
|
||
* → Designer 编辑(designer)
|
||
*/
|
||
import { describe, expect, it } from "vitest"
|
||
import { createDocument, createTableElement } from "@report/core"
|
||
import { createEstimateMeasurer, createPassthroughFontResolver, layoutDocument } from "@report/layout"
|
||
import { renderHtml, renderSvg, createPdfRenderer } from "@report/renderer"
|
||
import { EditorSession, createTextElement } from "@report/designer"
|
||
|
||
const measurer = createEstimateMeasurer()
|
||
const fontResolver = createPassthroughFontResolver()
|
||
|
||
describe("端到端冒烟(§17)", () => {
|
||
it("完整链路:建文档 → 布局 → HTML/SVG → Designer 编辑", async () => {
|
||
// 1. Core:创建文档 + 明细表
|
||
const doc = createDocument({ name: "销售单" })
|
||
doc.datasets = { sales: { id: "sales" } }
|
||
const detail = doc.sections.find((s) => s.kind === "detail")!
|
||
detail.children.push(
|
||
createTableElement("tbl", { x: 0, y: 0, width: 180, height: 20 }, "sales", [
|
||
{ id: "c1", width: 90, header: "商品", binding: { field: "name" } },
|
||
{ id: "c2", width: 90, header: "金额", binding: { field: "amount" }, align: "right" },
|
||
]),
|
||
)
|
||
const header = doc.sections.find((s) => s.kind === "page-header")!
|
||
header.children.push({
|
||
id: "title",
|
||
type: "text",
|
||
frame: { x: 0, y: 0, width: 100, height: 8 },
|
||
props: { text: "销售单" },
|
||
})
|
||
|
||
const rows = [
|
||
{ name: "苹果", amount: 100 },
|
||
{ name: "香蕉", amount: 200 },
|
||
{ name: "橙子", amount: 300 },
|
||
]
|
||
|
||
// 2. Layout:数据注入 + 布局
|
||
const layout = await layoutDocument(
|
||
doc,
|
||
{ data: { sales: rows }, parameters: { } },
|
||
{ textMeasurer: measurer, fontResolver },
|
||
)
|
||
expect(layout.pageCount).toBeGreaterThanOrEqual(1)
|
||
expect(layout.diagnostics.filter((d) => d.severity === "error")).toHaveLength(0)
|
||
|
||
// 3. Renderer:HTML + SVG 渲染,页数一致
|
||
const html = renderHtml(layout)
|
||
const svg = renderSvg(layout)
|
||
expect(html.pageCount).toBe(layout.pageCount)
|
||
expect(svg.pageCount).toBe(layout.pageCount)
|
||
expect(html.content).toContain("销售单")
|
||
expect(html.content).toContain("苹果")
|
||
expect(svg.content).toContain("苹果")
|
||
|
||
// PDF 缺后端 → 诊断而非抛异常
|
||
const pdf = createPdfRenderer().render(layout)
|
||
expect(pdf.target).toBe("pdf")
|
||
expect(pdf.diagnostics.length).toBeGreaterThan(0)
|
||
|
||
// 4. Designer:编辑(移动 + 撤销)
|
||
const editor = new EditorSession(doc)
|
||
editor.select("title")
|
||
const before = editor.getDocument().sections
|
||
.find((s) => s.kind === "page-header")!.children[0]!.frame
|
||
editor.moveElements({ title: { x: 20, y: 0, width: 100, height: 8 } })
|
||
const afterMove = editor.getDocument().sections
|
||
.find((s) => s.kind === "page-header")!.children[0]!.frame
|
||
expect(afterMove.x).toBe(20)
|
||
editor.undo()
|
||
const afterUndo = editor.getDocument().sections
|
||
.find((s) => s.kind === "page-header")!.children[0]!.frame
|
||
expect(afterUndo.x).toBe(before.x)
|
||
|
||
// 新增元素
|
||
const beforeCount = editor.getDocument().sections
|
||
.find((s) => s.kind === "detail")!.children.length
|
||
editor.addElement(detail.id, createTextElement({ x: 0, y: 0, width: 30, height: 8 }, "备注"))
|
||
const afterAdd = editor.getDocument().sections
|
||
.find((s) => s.kind === "detail")!.children.length
|
||
expect(afterAdd).toBe(beforeCount + 1)
|
||
})
|
||
})
|