Files
Test User 1b12ad8451
CI / Frontend test and build (push) Has been cancelled
CI / Rust test (push) Has been cancelled
CI / Docker build (push) Has been cancelled
Add font package profiling
2026-07-04 16:21:10 +08:00

176 lines
6.3 KiB
JavaScript

import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { normalizeAnalytics } from "../src/analytics.mjs";
import { detectUiLanguage, getMessages, translateFact } from "../src/i18n.mjs";
describe("ui language", () => {
it("uses Chinese when the browser language list contains zh", () => {
assert.equal(detectUiLanguage(["zh-CN", "en-US"]), "zh");
assert.match(getMessages("zh").requestDescription, /IP 数据库/);
});
it("falls back to English for non-Chinese browsers", () => {
assert.equal(detectUiLanguage(["fr-FR", "en-US"]), "en");
assert.match(getMessages("en").requestDescription, /IP database/);
});
it("respects browser language priority order", () => {
assert.equal(detectUiLanguage(["en-US", "zh-CN"]), "en");
});
it("includes English copy for network diagnostics and regional signals", () => {
const copy = getMessages("en");
assert.equal(copy.network.title, "Network exposure check");
assert.equal(copy.network.serverTitle, "Address seen by the server");
assert.equal(copy.network.metrics.public, "Public");
assert.equal(copy.network.candidateCategories.private, "Private/local");
assert.equal(copy.signalCatalog.timezone.name, "System timezone");
assert.match(copy.signalCatalog.fonts.detail, /Canvas/);
});
it("localizes analytics bucket labels for public dashboard keys", () => {
const zh = getMessages("zh");
assert.equal(zh.categoryDistribution, "画像线索类别");
assert.equal(zh.analyticsBucketLabels.identity, "身份与区域");
assert.equal(zh.analyticsBucketLabels.device, "设备环境");
assert.equal(zh.analyticsBucketLabels.privacy, "隐私与存储");
assert.equal(zh.analyticsBucketLabels.preferences, "显示偏好");
assert.equal(zh.analyticsBucketLabels.automation, "自动化痕迹");
assert.equal(zh.analyticsBucketLabels.graphics, "图形栈");
assert.equal(zh.analyticsBucketLabels.audio, "音频栈");
assert.equal(zh.analyticsBucketLabels["profile-local-summary"], "本地画像摘要");
assert.equal(zh.analyticsBucketLabels["network-server"], "服务端网络摘要");
});
it("translates common staged facts for the selected language", () => {
const fact = translateFact(
{
id: "timezone",
label: "系统时区",
value: "Asia/Shanghai",
inference: "可推断所在时区和常见地区。",
sensitivity: "medium",
},
getMessages("en"),
);
assert.equal(fact.label, "System timezone");
assert.equal(fact.inference, "Can reveal timezone and likely region.");
});
it("translates common fact values and units", () => {
const fact = translateFact(
{
id: "touch",
label: "触控能力",
value: "0 点触控",
inference: "可推断是否为移动或触屏设备。",
sensitivity: "low",
},
getMessages("en"),
);
assert.equal(fact.value, "0 touch points");
});
it("translates permission-state facts without Chinese fallbacks", () => {
const fact = translateFact(
{
id: "permission-state-geolocation",
label: "定位权限状态",
value: "prompt",
inference: "只查询状态,不会弹出授权请求。",
sensitivity: "low",
},
getMessages("en"),
);
assert.equal(fact.label, "Location permission state");
assert.equal(fact.value, "Ask every time");
assert.equal(fact.inference, "This only checks the passive permission state and does not open a permission prompt.");
});
it("translates font-package facts for the staged profile report", () => {
const fact = translateFact(
{
id: "font-packages",
label: "字体包画像",
value: "中文/CJK=2 开发字体=1",
inference: "常见字体包会暴露系统、语言环境和工具链线索。",
sensitivity: "high",
},
getMessages("en"),
);
assert.equal(fact.label, "Font package profile");
assert.equal(fact.inference, "Installed font families can reveal OS, language environment, and toolchain clues.");
});
});
describe("analytics normalization", () => {
it("builds dashboard buckets with percentages", () => {
const analytics = normalizeAnalytics({
totalScans: 4,
averageScore: 51.25,
bandCounts: { high: 2 },
localeCounts: [
{ label: "zh-CN", count: 3 },
{ label: "en-US", count: 1 },
],
timezoneCounts: [{ label: "Asia/Shanghai", count: 2 }],
timezoneOffsetCounts: [{ label: "UTC+08:00", count: 3 }],
userAgentCounts: [{ label: "Chrome", count: 4 }],
scoreBuckets: [
{ label: "0-20", count: 1 },
{ label: "61-80", count: 3 },
],
stageCounts: [
{ label: "local", count: 4 },
{ label: "request", count: 2 },
],
categoryCounts: [{ label: "network", count: 6 }],
sensitivityTotals: {
low: 10,
medium: 8,
high: 4,
critical: 2,
},
networkExposure: {
webrtcSamples: 4,
webrtcCandidates: 7,
webrtcPublic: 2,
webrtcPrivate: 3,
webrtcMdns: 2,
serverSamples: 4,
serverObserved: 3,
forwardedFor: 2,
cfConnectingIp: 1,
realIpHeader: 1,
connectionSamples: 3,
saveData: 1,
averageRttMs: 86.4,
},
connectionTypeCounts: [{ label: "4g", count: 2 }],
topSignals: [{ id: "timezone", hits: 3 }],
updatedAt: "2026-07-03T10:00:00Z",
});
assert.equal(analytics.total, 4);
assert.equal(analytics.highCount, 2);
assert.equal(analytics.distributions[0].buckets[0].percent, 75);
assert.equal(analytics.riskBuckets[1].percent, 75);
assert.equal(analytics.stageBuckets[0].label, "local");
assert.equal(analytics.categoryBuckets[0].count, 6);
assert.equal(analytics.sensitivityBuckets[2].label, "high");
assert.equal(analytics.sensitivityBuckets[2].percent, 17);
assert.equal(analytics.networkExposure.webrtcPublic, 2);
assert.equal(analytics.networkExposure.proxyHeaders, 4);
assert.equal(analytics.networkExposure.averageRttMs, 86.4);
assert.equal(analytics.connectionTypeBuckets[0].percent, 67);
assert.equal(analytics.topSignals[0].label, "timezone");
assert.equal(analytics.topSignals[0].percent, 75);
});
});