test: add unit tests for temperature chart data and visibility policy, and document city data sources

This commit is contained in:
2569718930@qq.com
2026-05-26 06:02:47 +08:00
parent e1417f607d
commit 636a81d6df
2 changed files with 84 additions and 1 deletions
+28 -1
View File
@@ -48,7 +48,7 @@
| amsterdam | KNMI 数据平台 | 10 min | 荷兰 |
| taipei | CWA 开放数据 (466920) | ~10 min | 台湾 |
| tel aviv | IMS Lod (225) | 实时 | 以色列 |
| paris | AEROWEB 实况 / AROME HD 15min | 实时/15min | 法国 |
| paris | AEROWEB 实况 / AROME HD | 实时/15min | 法国 (AROME是15分钟临近预报) |
### Tier 4 — 仅 METAR10 分钟缓存)
@@ -107,3 +107,30 @@ ankara, istanbul, helsinki, amsterdam, paris
- **Tier 2 城市**(5 分钟级):修正效果良好,MADIS 更新稳定
- **Tier 3 城市**(10-15 分钟级):修正可用但滞后较大
- **Tier 4 城市**(仅 METAR):修正效果有限,不建议依赖
## 关于网站终端图表的数据曲线展示逻辑
### 1. 实测数据(默认全开,突出核心)
- **跑道全量展示**:北京、上海、广州、成都、重庆、武汉、首尔等城市的跑道实测数据,默认全量开启,无需手动勾选。
- **结算跑道高亮**:系统内置了各大机场的官方结算跑道映射。命中的跑道将被**重点强调**(加粗的青色实线 #009688,线宽 2.8),并标记为“[跑道号] 结算跑道”。具体的跑道映射如下:
- 北京:19/01
- 上海:17L/35R
- 广州:02L/20R
- 成都:02L/20R
- 重庆:20R/02L
- 武汉:04/22
- 首尔:15R/33L
- **辅助跑道弱化**:同一机场下的其他非结算跑道,也会同时展示,但采用较细的虚线(线宽 1.2)以作陪衬区分。
- **其他实测展示**:所有城市的 METAR 报文曲线、官方气象站实测(如 Hong Kong / Lau Fau Shan 的香港天文台曲线)均默认展示。
### 2. 核心预测数据(默认展示)
- **DEB 模型融合**:作为平台核心的高精度智能融合预测曲线,默认始终展示给用户。
### 3. 多模型原始数据(默认隐藏,按需自选)
- **保持整洁**:为了防止图表线缆过于杂乱,各大原始模型(ECMWF, GFS, ICON, GEM 等)的数据曲线在初次加载时**默认隐藏**。
- **特例**:仅针对巴黎(Paris),由于其 AROME HD 是高精度的 15 分钟级临近预报,极具参考价值,因此默认开启。
- **自由交互**:用户可通过图表底部的图例交互按钮,随时自由勾选、叠加或隐藏任意所需的数据曲线。
@@ -13,6 +13,10 @@ function seriesByKey(series: Array<{ key: string }>, key: string) {
return series.find((item) => item.key === key);
}
function runwayKey(rwy: string) {
return `runway_${rwy.split("/").map((part) => part.trim().toUpperCase()).join("_")}`;
}
export function runTests() {
const guangzhou = {
city: "guangzhou",
@@ -95,10 +99,62 @@ export function runTests() {
),
"users should still be able to enable a hidden multi-model curve from the legend",
);
assert(
defaultVisibleSeries.some((item) => item.key === "hourly_forecast"),
"DEB fusion forecast should be visible by default",
);
assert(
__isTemperatureSeriesVisibleByDefaultForTest("paris", "model_curve_AROME HD"),
"Paris AROME HD should be the only default-visible model curve exception",
);
assert(
__getVisibleTemperatureSeriesForTest(
"paris",
[{ key: "model_curve_AROME HD" }, { key: "model_curve_ECMWF" }] as any,
{},
).some((item) => item.key === "model_curve_AROME HD"),
"Paris AROME HD should be active in the default visible series",
);
const settlementRunwayCases = [
["beijing", "19/01"],
["shanghai", "17L/35R"],
["guangzhou", "02L/20R"],
["chengdu", "02L/20R"],
["chongqing", "20R/02L"],
["wuhan", "04/22"],
["seoul", "15R/33L"],
] as const;
settlementRunwayCases.forEach(([city, settlementRwy]) => {
const chart = __buildTemperatureChartDataForTest(
{
city,
local_date: "2026-05-25",
local_time: "10:00",
tz_offset_seconds: 8 * 60 * 60,
runway_plate_history: {
[settlementRwy]: [
{ time: "00:05", temp: 25.1 },
{ time: "00:35", temp: 25.3 },
],
"99/00": [
{ time: "00:05", temp: 24.1 },
{ time: "00:35", temp: 24.3 },
],
},
} as any,
{ localTime: "10:00", times: ["00:00", "00:30"], temps: [25, 26] } as any,
"1D",
);
const highlighted = seriesByKey(chart.series, runwayKey(settlementRwy)) as any;
assert(highlighted, `${city} settlement runway should be present`);
assert(highlighted.label.includes("结算跑道"), `${city} settlement runway should be labeled`);
assert(highlighted.color === "#009688", `${city} settlement runway should use highlight cyan`);
assert(highlighted.featured === true, `${city} settlement runway should be featured`);
assert(!highlighted.dashed, `${city} settlement runway should be solid`);
const auxiliary = seriesByKey(chart.series, "runway_99_00") as any;
assert(auxiliary?.dashed === true, `${city} auxiliary runway should be dashed`);
});
const shenzhen = __buildTemperatureChartDataForTest(
{