feat: productize landing and chart education
This commit is contained in:
+66
@@ -0,0 +1,66 @@
|
||||
import * as Chart from "@/components/dashboard/scan-terminal/LiveTemperatureThresholdChart";
|
||||
|
||||
function assert(condition: unknown, message: string): asserts condition {
|
||||
if (!condition) throw new Error(message);
|
||||
}
|
||||
|
||||
export function runTests() {
|
||||
const buildItems = (Chart as any).__buildAdvancedWeatherVariableItemsForTest;
|
||||
assert(typeof buildItems === "function", "advanced weather variable item builder should be exported for tests");
|
||||
const buildCadence = (Chart as any).__buildSourceCadenceSummaryForTest;
|
||||
assert(typeof buildCadence === "function", "source cadence summary builder should be exported for tests");
|
||||
|
||||
const items = buildItems(
|
||||
{
|
||||
metar_context: {
|
||||
airport_wind_speed_kt: 7,
|
||||
airport_wind_dir: 220,
|
||||
airport_humidity: 68,
|
||||
},
|
||||
},
|
||||
{
|
||||
current: { dewpoint: 18.2 },
|
||||
airportPrimary: {
|
||||
wind_speed_kt: 9,
|
||||
wind_dir: 240,
|
||||
humidity: 64,
|
||||
pressure_hpa: 1009.4,
|
||||
source_label: "MADIS HFMETAR",
|
||||
},
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
assert(items.length === 5, `expected five advanced variable items, got ${items.length}`);
|
||||
assert(items.some((item: any) => item.key === "wind_dir" && item.value === "240°"), "wind direction should prefer airport-primary detail data");
|
||||
assert(items.some((item: any) => item.key === "wind_speed" && item.value === "9 kt"), "wind speed should include kt units");
|
||||
assert(items.some((item: any) => item.key === "dewpoint" && item.value === "18.2°C"), "dew point should render from current conditions");
|
||||
assert(items.some((item: any) => item.key === "humidity" && item.value === "64%"), "humidity should render as a percentage");
|
||||
assert(items.some((item: any) => item.key === "pressure" && item.value === "1009.4 hPa"), "pressure should render as hPa");
|
||||
|
||||
const emptyItems = buildItems({}, {}, true);
|
||||
assert(emptyItems.length === 0, "advanced variables should stay hidden when no source fields exist");
|
||||
|
||||
const backendCadence = buildCadence(
|
||||
{},
|
||||
{
|
||||
airportPrimary: {
|
||||
source_code: "custom_source",
|
||||
source_label: "Custom Feed",
|
||||
freshness: { native_update_interval_sec: 420, freshness_status: "fresh" },
|
||||
},
|
||||
},
|
||||
true,
|
||||
);
|
||||
assert(backendCadence?.cadence === "420s", "source cadence should prefer backend native_update_interval_sec");
|
||||
assert(backendCadence?.label.includes("Custom Feed"), "source cadence should include the source label");
|
||||
|
||||
const amscCadence = buildCadence({}, { airportPrimary: { source: "amsc_awos" } }, false);
|
||||
assert(amscCadence?.cadence === "180s", "AMSC AWOS should fall back to 180s source cadence");
|
||||
|
||||
const amosCadence = buildCadence({}, { airportPrimary: { source_label: "AMOS runway" } }, false);
|
||||
assert(amosCadence?.cadence === "60s", "AMOS should fall back to 60s source cadence");
|
||||
|
||||
const madisCadence = buildCadence({}, { airportPrimary: { source_code: "madis_hfmetar" } }, false);
|
||||
assert(madisCadence?.cadence === "300s", "MADIS should fall back to 300s source cadence");
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { getDocsPage } from "@/content/docs/docs";
|
||||
|
||||
function assert(condition: unknown, message: string): asserts condition {
|
||||
if (!condition) throw new Error(message);
|
||||
}
|
||||
|
||||
function pageText(slug: string, locale: "zh-CN" | "en-US") {
|
||||
const page = getDocsPage(slug);
|
||||
assert(page, `${slug} docs page should exist`);
|
||||
return [
|
||||
page.content[locale].title,
|
||||
page.content[locale].description,
|
||||
...page.content[locale].sections.flatMap((section) => [
|
||||
section.title,
|
||||
...section.blocks.flatMap((block) => {
|
||||
if (block.type === "paragraph" || block.type === "callout") return [block.text];
|
||||
if (block.type === "bullets" || block.type === "steps") return block.items;
|
||||
if (block.type === "link") return [block.label, block.caption || ""];
|
||||
if (block.type === "image") return [block.alt, block.caption || ""];
|
||||
return [];
|
||||
}),
|
||||
]),
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
export function runTests() {
|
||||
const introZh = pageText("intro", "zh-CN");
|
||||
assert(
|
||||
introZh.includes("结算源优先") && introZh.includes("实时实测终端"),
|
||||
"intro should position PolyWeather as a settlement-source-first live terminal",
|
||||
);
|
||||
|
||||
const chartGuideZh = pageText("chart-guide", "zh-CN");
|
||||
assert(chartGuideZh.includes("如何读 PolyWeather 图表"), "chart guide title should be present");
|
||||
assert(chartGuideZh.includes("高级气象变量") && chartGuideZh.includes("默认隐藏"), "chart guide should explain advanced variables as hidden-by-default context");
|
||||
assert(chartGuideZh.includes("不要把概率温度带当成实测曲线"), "chart guide should warn against reading probability as observation");
|
||||
|
||||
const realtimeSourcesZh = pageText("realtime-sources", "zh-CN");
|
||||
assert(realtimeSourcesZh.includes("AMSC 180s"), "realtime sources should document the AMSC 180s cadence");
|
||||
assert(realtimeSourcesZh.includes("AMOS 60s"), "realtime sources should document the AMOS 60s cadence");
|
||||
assert(realtimeSourcesZh.includes("SSE patch"), "realtime sources should document the SSE patch path");
|
||||
|
||||
const settlementSourcesZh = pageText("settlement-sources", "zh-CN");
|
||||
assert(settlementSourcesZh.includes("结算站点"), "settlement source guide should exist");
|
||||
assert(settlementSourcesZh.includes("机场 METAR") && settlementSourcesZh.includes("官方结算站点"), "settlement source guide should distinguish airport and official station settlement");
|
||||
|
||||
assert(
|
||||
getDocsPage("chart-guide")?.group === "getting-started" &&
|
||||
getDocsPage("realtime-sources")?.group === "settlement" &&
|
||||
getDocsPage("settlement-sources")?.group === "settlement",
|
||||
"docs navigation should expose chart, realtime source, and settlement source guides in the right groups",
|
||||
);
|
||||
|
||||
const chartGuideEn = pageText("chart-guide", "en-US");
|
||||
assert(chartGuideEn.includes("How To Read PolyWeather Charts"), "English chart guide should exist");
|
||||
assert(chartGuideEn.includes("hidden by default"), "English chart guide should describe hidden-by-default advanced variables");
|
||||
}
|
||||
Reference in New Issue
Block a user