The scene previously returned early when realtime rows were absent and selected map-tier assets for network mode, hiding SCADA markers and station interiors and floors. Use SCADA timestamps as valid frames, render node-aligned monitor markers, and pin the full network context in the manifest regression test. Keep the timeline close action inside its drag header.
111 lines
3.9 KiB
TypeScript
111 lines
3.9 KiB
TypeScript
/** @jest-environment node */
|
|
|
|
import { createHash } from "node:crypto";
|
|
import { existsSync, readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
|
|
const sceneRoot = join(
|
|
process.cwd(),
|
|
"public",
|
|
"three-dimensional",
|
|
"zjb",
|
|
"v29",
|
|
);
|
|
|
|
describe("ZJB three-dimensional runtime assets", () => {
|
|
it("ships every model referenced by the production manifest", () => {
|
|
const manifest = JSON.parse(
|
|
readFileSync(join(sceneRoot, "manifest.json"), "utf8"),
|
|
) as {
|
|
packageId: string;
|
|
renderRevision: number;
|
|
assets: Array<{ file: string; sha256: string }>;
|
|
networkContext: string[];
|
|
networkModel: { file: string; metadata: string; sha256: string };
|
|
sourceCatalogFile?: string;
|
|
bindingsFile?: string;
|
|
};
|
|
|
|
expect(manifest.packageId).toBe("zjb-web-v29");
|
|
expect(manifest.renderRevision).toBe(29);
|
|
expect(manifest.assets).toHaveLength(24);
|
|
expect(manifest.networkContext).toEqual([
|
|
"detail_roof",
|
|
"detail_facade",
|
|
"detail_interior",
|
|
"detail_ceiling",
|
|
"map_platforms",
|
|
"map_railway",
|
|
"map_roads",
|
|
"map_pump_shell",
|
|
]);
|
|
manifest.assets.forEach((asset) => {
|
|
const assetPath = join(sceneRoot, asset.file);
|
|
expect(existsSync(assetPath)).toBe(true);
|
|
expect(createHash("sha256").update(readFileSync(assetPath)).digest("hex")).toBe(
|
|
asset.sha256,
|
|
);
|
|
});
|
|
expect(existsSync(join(sceneRoot, manifest.networkModel.file))).toBe(true);
|
|
expect(existsSync(join(sceneRoot, manifest.networkModel.metadata))).toBe(true);
|
|
expect(manifest.sourceCatalogFile).toBeUndefined();
|
|
expect(manifest.bindingsFile).toBeUndefined();
|
|
|
|
const networkModel = readFileSync(join(sceneRoot, manifest.networkModel.file));
|
|
expect(createHash("sha256").update(networkModel).digest("hex")).toBe(
|
|
manifest.networkModel.sha256,
|
|
);
|
|
});
|
|
|
|
it("includes the offline runtime modules and third-party licenses", () => {
|
|
[
|
|
"preview.html",
|
|
"preview.mjs",
|
|
"appearance.mjs",
|
|
"asset-inspector.mjs",
|
|
"camera-navigation.mjs",
|
|
"network-style.mjs",
|
|
"integration.mjs",
|
|
"render-effects.mjs",
|
|
"vendor/meshopt_decoder.module.js",
|
|
"vendor/meshoptimizer-LICENSE.md",
|
|
"vendor/three/LICENSE",
|
|
"vendor/three/three.module.js",
|
|
"vendor/three/addons/loaders/GLTFLoader.js",
|
|
].forEach((relativePath) => {
|
|
expect(existsSync(join(sceneRoot, relativePath))).toBe(true);
|
|
});
|
|
});
|
|
|
|
it("keeps the embedded viewer on the versioned same-origin host protocol", () => {
|
|
const preview = readFileSync(join(sceneRoot, "preview.mjs"), "utf8");
|
|
const html = readFileSync(join(sceneRoot, "preview.html"), "utf8");
|
|
const inspector = readFileSync(
|
|
join(sceneRoot, "asset-inspector.mjs"),
|
|
"utf8",
|
|
);
|
|
const networkStyle = readFileSync(
|
|
join(sceneRoot, "network-style.mjs"),
|
|
"utf8",
|
|
);
|
|
|
|
expect(preview).toContain("tjwater:zjb-scene");
|
|
expect(preview).toContain("HOST_VERSION=2");
|
|
expect(preview).toContain("event.origin===window.location.origin");
|
|
expect(preview).toContain("event.source===window.parent");
|
|
expect(preview).toContain("postHost('ready'");
|
|
expect(preview).toContain("data.type==='results'");
|
|
expect(preview).toContain("data.type==='clear-results'");
|
|
expect(preview).toContain("data.type!=='command'");
|
|
expect(preview).toContain("postHost('selection-changed'");
|
|
expect(preview).toContain("next==='network'?manifest.networkContext:manifest.mapDefault");
|
|
expect(preview).not.toContain("window.zjbNetwork");
|
|
expect(preview).not.toContain("resultsFile");
|
|
expect(html).not.toContain("绑定运行结果");
|
|
expect(html).not.toContain("resultsFile");
|
|
expect(inspector).not.toContain("document.getElementById");
|
|
expect(networkStyle).toContain("ScadaSensorMarkers");
|
|
expect(networkStyle).toContain("source==='scada'");
|
|
});
|
|
});
|