整理测试代码并清理文档引用

This commit is contained in:
Cheng Zhou
2026-06-22 17:27:11 +08:00
parent 6056c8364a
commit c351ca59c4
75 changed files with 15 additions and 4415 deletions
@@ -1,347 +0,0 @@
import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
const readSource = () => readFileSync(resolve(__dirname, "./PermissionIpLocations.vue"), "utf8");
const readMapSource = () => readFileSync(resolve(__dirname, "./chinaProvinceMap.ts"), "utf8");
const readWorldMapSource = () => readFileSync(resolve(__dirname, "./worldMapSource.ts"), "utf8");
describe("PermissionIpLocations", () => {
it("renders IP location visualization without duplicate region detail table", () => {
const source = readSource();
expect(source).toContain("fetchIpLocations");
expect(source).toContain("unique_ip_count");
expect(source).not.toContain("来源地域明细");
expect(source).not.toContain("table-card");
expect(source).not.toContain("<el-table :data=\"items\"");
});
it("renders an interactive China map and primary metric cards", () => {
const source = readSource();
expect(source).toContain("VChart");
expect(source).toContain("sourceMapOption");
expect(source).toContain("来源分布");
expect(source).toContain("访问次数");
expect(source).toContain("访问用户数");
expect(source).toContain("来源 IP 数");
expect(source).toContain("summary");
});
it("defaults the access source period to 90 days", () => {
const source = readSource();
expect(source).toContain("const days = ref(90);");
expect(source).not.toContain("const days = ref(7);");
expect(source).toContain('<el-radio-button :value="90">90天</el-radio-button>');
expect(source).toContain('90: "近 90 天"');
});
it("does not overlay the source distribution card with a loading mask", () => {
const source = readSource();
expect(source).toContain('<section class="distribution-card">');
expect(source).toContain('<el-button :loading="loading" size="small" :disabled="loading" @click="loadData">');
expect(source).not.toContain('<section v-loading="loading" class="distribution-card">');
});
it("supports switching source distribution between China and global flow views without the global heat map", () => {
const source = readSource();
const worldMapSource = readWorldMapSource();
expect(source).toContain("../assets/world.json");
expect(source).toContain('registerMap("ctms-world"');
expect(source).toContain('const mapView = ref<"china" | "flow">("china");');
expect(source).toContain("mapViewOptions");
expect(source).toContain("<el-segmented v-model=\"mapView\"");
expect(source).toContain("sourceMapOption");
expect(source).toContain('label: "中国"');
expect(source).toContain('label: "全球"');
expect(source).not.toContain('label: "全球", value: "world"');
expect(source).not.toContain("worldData");
expect(source).not.toContain("buildMapOption");
expect(worldMapSource).toContain("unpkg.com/echarts@4.9.0/map/json/world.json");
expect(worldMapSource).toContain("ECharts 世界地图 GeoJSON");
expect(worldMapSource).toContain('"United States": "United States"');
});
it("supports a global access flow view pointing sources to the server location", () => {
const source = readSource();
const worldMapSource = readWorldMapSource();
expect(source).toContain('const mapView = ref<"china" | "flow">("china");');
expect(source).toContain('label: "全球"');
expect(source).toContain("LinesChart");
expect(source).toContain("EffectScatterChart");
expect(source).toContain("GeoComponent");
expect(source).toContain("buildFlowMapOption");
expect(source).toContain("serverLocation");
expect(source).toContain("resolveSourceCoordinate");
expect(source).toContain('coordinateSystem: "geo"');
expect(source).toContain("coords: [point.coord, serverLocation.coord]");
expect(source).toContain("服务器所在地");
expect(worldMapSource).toContain("resolveSourceCoordinate");
expect(worldMapSource).toContain('"United States": [-95.7129, 37.0902]');
});
it("uses a China access flow map for the China view", () => {
const source = readSource();
const worldMapSource = readWorldMapSource();
expect(source).toContain("chinaFlowSourceData");
expect(source).toContain('buildFlowMapOption(chinaFlowSourceData.value, "ctms-china", 1.08, "中国访问链路")');
expect(source).not.toContain('buildMapOption("ctms-china", provinceData.value, 1.08)');
expect(source).toContain('mapView.value === "china" ? chinaFlowSourceData.value');
expect(worldMapSource).toContain('"江苏省": [118.7633, 32.0617]');
expect(worldMapSource).toContain('"上海市": [121.4737, 31.2304]');
});
it("uses the same source rows for the global flow map and the source ranking", () => {
const source = readSource();
const worldMapSource = readWorldMapSource();
expect(source).toContain("flowSourceData");
expect(source).toContain('mapView.value === "flow" ? flowSourceData.value : rankedSourceRows.value');
expect(source).toContain("buildFlowMapOption(flowSourceData.value)");
expect(source).not.toContain("buildFlowMapOption(worldData.value)");
expect(source).toContain('const buildFlowMapOption = (data: IpLocationStatItem[], mapName = "ctms-world"');
expect(source).toContain("coord: resolveSourceCoordinate(item)");
expect(source).toContain("name: formatLocation(point)");
expect(worldMapSource).toContain("cityCoordinates");
expect(worldMapSource).toContain('"重庆市": [106.5516, 29.563]');
expect(worldMapSource).toContain('"南京市": [118.7969, 32.0603]');
expect(worldMapSource).toContain('"Istanbul": [28.9784, 41.0082]');
expect(worldMapSource).toContain('"South Holland": [4.493, 52.0208]');
});
it("keeps global flow lines thin and readable", () => {
const source = readSource();
expect(source).toContain("const lineWidth = point.abnormal ? 1.1 : 0.8");
expect(source).toContain("width: lineWidth");
expect(source).toContain("opacity: point.abnormal ? 0.58 : 0.38");
expect(source).not.toContain("width: Math.min(5");
expect(source).not.toContain("Math.sqrt(point.total_count");
});
it("keeps domestic flow markers compact so nearby China locations stay visible", () => {
const source = readSource();
expect(source).toContain("const isDomestic = !params?.data?.abnormal");
expect(source).toContain("const maxSize = isDomestic ? 12 : 16");
expect(source).toContain("const minSize = isDomestic ? 5 : 7");
expect(source).toContain("scale: 1.7");
expect(source).toContain("scale: 1.5");
expect(source).toContain("symbolSize: 9");
expect(source).not.toContain("scale: 3");
expect(source).not.toContain("scale: 2.4");
expect(source).not.toContain("symbolSize: 14");
});
it("shows a compact flow legend and keeps the server tooltip address-only", () => {
const source = readSource();
expect(source).toContain("source-map-wrap");
expect(source).toContain("fullscreen-map-wrap");
expect(source).toContain("flow-legend");
expect(source).toContain("map-legend");
expect(source).toContain("服务器");
expect(source).toContain("正常访问点");
expect(source).toContain("异常访问点");
expect(source).toContain('class="legend-dot server"');
expect(source).toContain('class="legend-dot normal"');
expect(source).toContain('class="legend-dot abnormal"');
expect(source).toContain('if (row.isServer) return "中国 / 上海";');
expect(source).not.toContain('if (row.isServer) return `${serverLocation.name}<br/>中国 / 上海`;');
expect(source).not.toContain("fullscreen-legend");
});
it("supports fullscreen preview for the current source map", () => {
const source = readSource();
expect(source).toContain("fullscreenVisible");
expect(source).toContain("openFullscreenPreview");
expect(source).toContain("resizeFullscreenChart");
expect(source).toContain("<el-dialog");
expect(source).toContain("fullscreen");
expect(source).toContain("destroy-on-close");
expect(source).toContain(':close-on-click-modal="false"');
expect(source).toContain('aria-label="全屏预览"');
expect(source).toContain("fullscreenMapKey");
expect(source).toContain("fullscreen-source-map");
expect(source).toContain("全屏预览");
expect(source).toContain("退出全屏");
expect(source).toContain(":option=\"sourceMapOption\"");
});
it("raises canvas pixel ratio for sharper fullscreen map rendering", () => {
const source = readSource();
expect(source).toContain("getDevicePixelRatio");
expect(source).toContain("chartInitOptions");
expect(source).toContain("fullscreenChartInitOptions");
expect(source).toContain(":init-options=\"chartInitOptions\"");
expect(source).toContain(":init-options=\"fullscreenChartInitOptions\"");
expect(source).toContain("Math.min(getDevicePixelRatio(), 2)");
expect(source).toContain("Math.min(getDevicePixelRatio() * 1.5, 3)");
});
it("uses a flexible full-page layout so the source map fills the remaining viewport", () => {
const source = readSource();
expect(source).toContain("height: 100%");
expect(source).toContain("min-height: 0");
expect(source).toContain("flex: 1 1 auto");
expect(source).toContain("grid-template-rows: minmax(0, 1fr)");
expect(source).toContain("height: 100%");
expect(source).toContain("overflow-y: auto");
expect(source).not.toContain("height: 320px");
expect(source).not.toContain("min-height: 430px");
});
it("prevents horizontal scrolling in the source ranking panel", () => {
const source = readSource();
expect(source).toContain(".rank-panel");
expect(source).toContain("overflow: hidden");
expect(source).toContain("overflow-x: hidden");
expect(source).toContain("overflow-y: auto");
expect(source).toContain("box-sizing: border-box");
expect(source).toContain("grid-template-columns: 36px minmax(0, 1fr) minmax(72px, max-content)");
expect(source).toContain("max-width: 100%");
expect(source).toContain("text-overflow: ellipsis");
expect(source).toContain("text-align: right");
});
it("recreates the chart when switching map modes to avoid stale geo state", () => {
const source = readSource();
expect(source).toContain(':key="mapView"');
expect(source).toContain(':update-options="chartUpdateOptions"');
expect(source).toContain("const chartUpdateOptions = { notMerge: true }");
});
it("resizes the source map after data load and keeps the chart container full width", () => {
const source = readSource();
expect(source).toContain('ref="sourceChartRef"');
expect(source).toContain("const sourceChartRef = ref<{ resize?: () => void } | null>(null)");
expect(source).toContain("const resizeSourceCharts = async () =>");
expect(source).toContain("sourceChartRef.value?.resize?.()");
expect(source).toContain("await resizeSourceCharts()");
expect(source).toContain("defineExpose({ refresh: loadData, resize: resizeSourceCharts })");
expect(source).not.toContain(".source-map :deep(> div)");
});
it("uses source-analysis copy instead of IP-location tab wording", () => {
const source = readSource();
expect(source).toContain("访问来源分析");
expect(source).toContain("来源分布");
expect(source).toContain("热点来源地");
expect(source).not.toContain("查看访问来源的地理分布");
expect(source).not.toContain("访问来源地理分布热力图");
expect(source).not.toContain("按访问次数排序");
expect(source).not.toContain("IP 属地分析");
expect(source).not.toContain("中国地图");
expect(source).not.toContain("热点属地");
expect(source).not.toContain("用户分布图");
});
it("uses the standard geojson.cn China map data instead of generated rectangles", () => {
const source = readSource();
const mapSource = readMapSource();
expect(source).toContain("../assets/china.json");
expect(mapSource).toContain("geojson.cn/api/china/1.6.3/china.json");
expect(mapSource).not.toContain("ProvinceBox");
expect(mapSource).not.toContain("provinceBoxes");
});
it("removes heat-map visual legends and keeps map zoom interactions disabled", () => {
const source = readSource();
expect(source).not.toContain("visualMap:");
expect(source).not.toContain("VisualMapComponent");
expect(source).not.toContain("hasMapData");
expect(source).not.toContain("maxValue");
expect(source).not.toContain('color: ["#93c5fd", "#60a5fa", "#3b82f6", "#2563eb", "#1d4ed8"]');
expect(source).not.toContain("outOfRange:");
expect(source).toContain("roam: false");
expect(source).not.toContain("scaleLimit");
});
it("uses a stronger base map style so borders remain visible behind flow lines", () => {
const source = readSource();
expect(source).toContain('areaColor: "#e6edf8"');
expect(source).toContain('borderColor: "#aebed2"');
expect(source).toContain("borderWidth: 1");
expect(source).toContain('shadowColor: "rgba(37, 99, 235, 0.08)"');
expect(source).toContain("shadowBlur: 10");
expect(source).toContain("shadowOffsetY: 2");
expect(source).toContain('areaColor: "#dbeafe", borderColor: "#64748b", borderWidth: 1.3');
expect(source).not.toContain('areaColor: "#eef4ff"');
expect(source).not.toContain('borderColor: "#dbe7f7"');
expect(source).not.toContain("borderWidth: 0.8");
});
it("keeps geo hover interaction while avoiding empty white tooltip panels", () => {
const source = readSource();
expect(source).toContain("const formatGeoTooltip = (params: any) =>");
expect(source).toContain('return name || "暂无访问数据";');
expect(source).toContain('trigger: "item"');
expect(source).toContain("confine: true");
expect(source).toContain("formatter: formatGeoTooltip");
expect(source).toContain("tooltip: {\n show: true,\n formatter: formatGeoTooltip,\n }");
expect(source).toContain("formatLineTooltip");
expect(source).toContain("formatPointTooltip");
expect(source).toContain("tooltip: {\n show: true,\n formatter: formatLineTooltip,\n }");
expect(source).toContain("tooltip: {\n show: true,\n formatter: formatPointTooltip,\n }");
expect(source).not.toContain("silent: true");
expect(source).not.toContain("tooltip: { show: false }");
});
it("uses narrow metric cards without helper subtitles", () => {
const source = readSource();
expect(source).toContain("min-height: 64px");
expect(source).toContain("padding: 10px 16px");
expect(source).toContain("right: -34px");
expect(source).toContain("bottom: -42px");
expect(source).toContain("border-radius: 18px");
expect(source).not.toContain("<small>{{ card.hint }}</small>");
expect(source).not.toContain("hint:");
expect(source).not.toContain("权限检查总量");
});
it("removes the duplicated hero copy above the map", () => {
const source = readSource();
expect(source).toContain("ip-locations-toolbar");
expect(source).not.toContain("权限监控 / IP属地");
expect(source).not.toContain("按访问日志聚合省市、用户与来源 IP");
expect(source).not.toContain("悬停省份查看访问次数、访问用户数和来源 IP 数");
expect(source).not.toContain("hero-desc");
expect(source).not.toContain("eyebrow");
});
it("places the period filter toolbar on the right", () => {
const source = readSource();
expect(source).toContain(".ip-hero");
expect(source).toContain("justify-content: space-between");
expect(source).toContain("margin-left: auto");
});
it("keeps non-China source labels visible and lists top 10 regions", () => {
const source = readSource();
expect(source).toContain('row.country && row.country !== "中国" ? row.country : ""');
expect(source).toContain("row.isp");
expect(source).toContain('parts.join(" / ")');
expect(source).toContain(".slice(0, 10)");
});
});