东方财富题材列表存在 securityCode 为 null 的题材(如"铟"01726), getStockBoard(null) 调用 startsWith 抛 TypeError,React 渲染崩溃, 页面被错误边界接管。修复 getStockBoard 使其对空值兜底返回主板, 同时保护全部 8 处调用方;ThemeItem.securityCode/securityName 类型 如实标注为 string|null。新增最小回归脚本复现并验证修复。 Co-Authored-By: Claude <noreply@anthropic.com>
64 lines
2.1 KiB
JavaScript
64 lines
2.1 KiB
JavaScript
// 最小复现/验证脚本:直接编译 src/lib/stock-api.ts 真实源码,
|
||
// 调用 getStockBoard(null),复现「Cannot read properties of null (reading 'startsWith')」。
|
||
// 无测试框架,node 直接运行:node tests/get-stock-board-repro.mjs
|
||
import fs from "node:fs";
|
||
import path from "node:path";
|
||
import Module from "node:module";
|
||
import ts from "typescript";
|
||
|
||
const srcPath = path.resolve("src/lib/stock-api.ts");
|
||
const source = fs.readFileSync(srcPath, "utf8");
|
||
|
||
const js = ts.transpileModule(source, {
|
||
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020, esModuleInterop: true },
|
||
}).outputText;
|
||
|
||
const mod = new Module(srcPath);
|
||
mod.filename = srcPath;
|
||
mod.paths = Module._nodeModulePaths(path.dirname(srcPath));
|
||
|
||
// 拦截 @/lib/api-client 别名导入(getStockBoard 本身不依赖它)
|
||
const origResolve = Module._resolveFilename;
|
||
Module._resolveFilename = function (request, ...args) {
|
||
if (request === "@/lib/api-client") return path.resolve("tests/_stub-api-client.cjs");
|
||
return origResolve.call(this, request, ...args);
|
||
};
|
||
|
||
try {
|
||
mod._compile(js, srcPath);
|
||
} finally {
|
||
Module._resolveFilename = origResolve;
|
||
}
|
||
|
||
const { getStockBoard } = mod.exports;
|
||
|
||
// ---- 断言 ----
|
||
function assertThrows(fn, label) {
|
||
try {
|
||
fn();
|
||
console.log(`✗ ${label}: 未抛错`);
|
||
process.exitCode = 1;
|
||
} catch (e) {
|
||
console.log(`✓ ${label}: 抛错 -> ${e.message}`);
|
||
}
|
||
}
|
||
|
||
function assertNoThrow(fn, label) {
|
||
try {
|
||
const r = fn();
|
||
console.log(`✓ ${label}: 未抛错 -> ${JSON.stringify(r)}`);
|
||
return r;
|
||
} catch (e) {
|
||
console.log(`✗ ${label}: 抛错 -> ${e.message}`);
|
||
process.exitCode = 1;
|
||
}
|
||
}
|
||
|
||
// 正常代码
|
||
assertNoThrow(() => getStockBoard("600000"), "正常代码 getStockBoard('600000')");
|
||
// 崩盘场景:securityCode 为 null(East Money 题材列表实测存在),修复后应兜底返回主板
|
||
assertNoThrow(() => getStockBoard(null), "null securityCode");
|
||
assertNoThrow(() => getStockBoard(undefined), "undefined securityCode");
|
||
// 空串不崩
|
||
assertNoThrow(() => getStockBoard(""), "空串 getStockBoard('')");
|