Files
ln-bi/src/modules/assets/assistant/result-presentation.test.ts
T
shishengliang f1b3f8d3da
ci/woodpecker/push/woodpecker Pipeline was successful
feat(assets): add dimension analysis and authorized user previews
Refactor asset drilldowns with combined dimension filters, parent summaries and progressive loading. Add the hidden /who read-only permission preview with scoped authorization, identity mapping and audit logging. Refine inventory counts and AI问数 presentation.
2026-09-28 12:29:51 +08:00

226 lines
6.8 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import {
copyResultText,
resultScope,
resultDisplay,
queryPath,
compactAnalysisPath,
} from "./result-presentation.js";
import type { AssistantResult } from "../../../shared/assets/assistant.js";
const result: AssistantResult = {
plan: {
kind: "assets",
category: "available",
groupBy: "region",
view: "table",
filters: { type: ["4.5T"] },
},
title: "可运营库存 · 按区域统计",
summary: "当前范围共有135台可运营库存。",
source: "资产台账",
fetchedAt: "2026-09-23T08:00:00Z",
groups: [],
rows: [],
metrics: [{ label: "可运营库存", value: 135, unit: "台" }],
scope: {
company: "演示公司",
permission: "当前账号可见车辆",
filters: ["4.5T", "可运营库存"],
grouping: "区域",
period: "当前资产台账",
definitions: ["车型按吨位汇总,4.5T包含普货与冷链"],
sourceUpdatedAt: null,
},
};
test("copy preserves facts, scope, definitions and distinguishes unknown source update from query time", () => {
const text = copyResultText(result, null);
for (const expected of [
"135台",
"公司:演示公司",
"权限范围:当前账号可见车辆",
"筛选条件:4.5T;可运营库存",
"分组:区域",
"4.5T包含普货与冷链",
"源数据更新时间:未提供",
"查询时间:",
])
assert.ok(text.includes(expected), expected);
});
test("partial briefing copies missing answers and inventory evidence without inventing a source timestamp", () => {
const partial: AssistantResult = {
...result,
outcome: "partial",
unanswered: [
{ question: "闲置损失多少钱", reason: "未接入成本数据,不估算金额。" },
],
inventoryBreakdown: {
title: "库存集中情况",
summary: "4.5T冷链库存最多。",
groups: [
{ name: "4.5T冷链", count: 155, operating: 0, rate: 0, share: 53.3 },
],
},
};
const text = copyResultText(partial, null);
assert.match(text, /4.5T冷链:155台,占库存53.3%/);
assert.match(text, /尚未回答:[\s\S]*未接入成本数据,不估算金额/);
assert.match(text, /源数据更新时间:未提供/);
});
test("copying a revoked result keeps the revocation explicit", () => {
const text = copyResultText(
result,
null,
"上一条回答的是待运营,不能用于判断待交车。",
);
assert.match(
text,
/【此回答已撤回】上一条回答的是待运营,不能用于判断待交车/,
);
});
test("fallback scope keeps exclusion and selected vehicle filters", () => {
const fallback = resultScope(
{
...result,
scope: undefined,
plan: {
...result.plan,
excludeFilters: { city: ["嘉兴市"] },
vehicleIds: ["example-1"],
exception: "overdue",
},
},
"演示公司",
);
assert.deepEqual(fallback.filters, [
"可运营库存",
"车型:4.5T",
"排除城市:嘉兴市",
"指定车辆:1台",
"已超过预计完成时间",
]);
assert.equal(fallback.sourceUpdatedAt, null);
});
test("copy includes regional facts and daily flow without duplicating groups or copying vehicle details", () => {
const regional: AssistantResult = {
...result,
groups: [
{
name: "华东",
count: 99,
operating: 0,
rate: 0,
share: 73.3,
abnormal: 1,
pending: 0,
},
],
insights: ["华东占当前可运营库存73.3%。"],
rows: [
{
id: "private-vehicle",
plate: "测试车牌不应复制",
vehicleClass: "4.5T普货",
type: "4.5T",
model: "演示型号",
region: "华东",
city: "嘉兴市",
department: "演示部门",
status: "可运营",
},
],
};
const regionalText = copyResultText(regional, null);
assert.match(regionalText, /华东:99台,占比73.3%/);
assert.match(regionalText, /异动1台,待交车0台/);
assert.match(regionalText, /分析发现:[\s\S]*华东占当前可运营库存73.3%/);
assert.ok(!regionalText.includes("测试车牌不应复制"));
const flowText = copyResultText(
{
...regional,
plan: {
...regional.plan,
kind: "flow",
start: "2026-09-23",
end: "2026-09-23",
},
daily: [
{
date: "2026-09-23",
delivered: 5,
returned: 2,
replaced: 1,
total: 7,
},
],
},
null,
);
assert.match(
flowText,
/2026-09-23:交车5车次,还车2车次,其中替换交车1车次,合计7车次/,
);
assert.match(flowText, /替换交车包含在交车中,不重复相加/);
assert.ok(!flowText.includes("华东:99台"));
assert.ok(!flowText.includes("测试车牌不应复制"));
});
test("single totals use metric cards while comparisons, trends and explicit records retain their display", () => {
const total = {
...result.plan,
groupBy: "none" as const,
view: "chart" as const,
};
assert.equal(resultDisplay(total), "metrics");
assert.equal(resultDisplay({ ...total, groupBy: "region" }), "chart");
assert.equal(resultDisplay({ ...total, secondaryGroupBy: "type" }), "chart");
assert.equal(resultDisplay({ ...total, kind: "flow" }), "chart");
assert.equal(resultDisplay({ ...total, view: "list" }), "list");
assert.equal(resultDisplay({ ...total, view: "table" }), "table");
});
test("current path retains every active slice and highlights the current grouping", () => {
const path = queryPath({
...result.plan,
filters: { region: ["华东"], city: ["嘉兴市"] },
excludeFilters: { model: ["演示型号"] },
groupBy: "vehicleClass",
exception: "overdue",
});
assert.deepEqual(path, [
"可运营库存",
"区域:华东",
"城市:嘉兴市",
"排除型号:演示型号",
"已超期",
"按车型细分统计",
]);
});
test("analysis path collapses display-only steps and preserves the latest node of each scope", () => {
const path = compactAnalysisPath([
{ resultId: "all", label: "全部库存" },
{ resultId: "east-chart", label: "库存 · 华东" },
{ resultId: "east-table", label: "库存 · 华东" },
{ resultId: "jiaxing", label: "库存 · 华东 / 嘉兴" },
]);
assert.deepEqual(
path.map((crumb) => crumb.resultId),
["all", "east-table", "jiaxing"],
);
assert.equal(path.at(-2)?.label, "库存 · 华东");
});
test("vehicle status navigation identifies a vehicle answer instead of a total", () => {
const path = queryPath({ kind: "assets", category: "all", groupBy: "none", view: "list", filters: {}, vehicleIds: ["v1"], responseMode: "vehicle-status" });
assert.ok(path.includes("车辆状态"));
assert.ok(!path.includes("总量"));
});