Persist versioned models and validated network metadata in IndexedDB. Show scene download progress and recoverable errors with the existing frosted material. Connect existing skeletons to pending navigation and route boundaries while preserving the map. Previously only dynamic imports showed fallbacks, and rejected model promises prevented retries. Verified: 32 focused unit tests; 4 navigation and scene browser checks; 7 cache browser checks including invalid-metadata recovery; isolated production build and type checks.
79 lines
3.9 KiB
TypeScript
79 lines
3.9 KiB
TypeScript
import { fireEvent, render, screen } from "@testing-library/react";
|
|
|
|
import {
|
|
MapNavigationContent,
|
|
NavigationFeedbackProvider,
|
|
PageNavigationContent,
|
|
useNavigationFeedback,
|
|
} from "./NavigationFeedback";
|
|
import { mapSkeletonForPath } from "./PageLoadingSkeleton";
|
|
import { MAP_SKELETON_VARIANTS } from "./mapComponentSkeletonConfig";
|
|
|
|
let mockPathname = "/network-simulation";
|
|
jest.mock("next/navigation", () => ({ usePathname: () => mockPathname }));
|
|
|
|
function Harness() {
|
|
const { reportPending } = useNavigationFeedback();
|
|
return (
|
|
<>
|
|
<button onClick={() => reportPending("first", "/scada-data-cleaning", true)}>清洗</button>
|
|
<button onClick={() => reportPending("second", "/audit-logs", true)}>审计</button>
|
|
<button onClick={() => reportPending("first", "/scada-data-cleaning", false)}>取消旧导航</button>
|
|
<button onClick={() => reportPending("second", "/audit-logs", false)}>结束导航</button>
|
|
<PageNavigationContent>
|
|
<div data-testid="map">原有地图</div>
|
|
<MapNavigationContent><input aria-label="页面草稿" defaultValue="保留输入" /></MapNavigationContent>
|
|
</PageNavigationContent>
|
|
</>
|
|
);
|
|
}
|
|
|
|
describe("page navigation feedback", () => {
|
|
beforeEach(() => { mockPathname = "/network-simulation"; });
|
|
|
|
it("shows the destination skeleton while preserving the map and a cancelled page's draft", () => {
|
|
render(<NavigationFeedbackProvider><Harness /></NavigationFeedbackProvider>);
|
|
const map = screen.getByTestId("map");
|
|
const draft = screen.getByRole("textbox", { name: "页面草稿" });
|
|
fireEvent.click(screen.getByText("清洗"));
|
|
expect(screen.getByRole("status", { name: "正在加载数据清洗" })).toBeVisible();
|
|
expect(screen.getByTestId("map")).toBe(map);
|
|
expect(map).toBeVisible();
|
|
expect(draft).not.toBeVisible();
|
|
fireEvent.click(screen.getByText("取消旧导航"));
|
|
expect(draft).toBeVisible();
|
|
expect(draft).toHaveValue("保留输入");
|
|
expect(screen.queryByRole("progressbar", { name: "正在切换页面" })).not.toBeInTheDocument();
|
|
});
|
|
|
|
it("does not dismiss a newer destination when the previous link settles", () => {
|
|
render(<NavigationFeedbackProvider><Harness /></NavigationFeedbackProvider>);
|
|
fireEvent.click(screen.getByText("清洗"));
|
|
fireEvent.click(screen.getByText("审计"));
|
|
fireEvent.click(screen.getByText("取消旧导航"));
|
|
expect(screen.getByRole("status", { name: "正在加载审计日志" })).toBeVisible();
|
|
expect(screen.getByRole("progressbar", { name: "正在切换页面" })).toBeVisible();
|
|
fireEvent.click(screen.getByText("结束导航"));
|
|
expect(screen.queryByRole("status", { name: "正在加载审计日志" })).not.toBeInTheDocument();
|
|
});
|
|
|
|
it("hands off to route/component loading boundaries as soon as history commits", () => {
|
|
const { rerender } = render(<NavigationFeedbackProvider><Harness /></NavigationFeedbackProvider>);
|
|
fireEvent.click(screen.getByText("清洗"));
|
|
expect(screen.getByRole("progressbar", { name: "正在切换页面" })).toBeVisible();
|
|
mockPathname = "/scada-data-cleaning";
|
|
rerender(<NavigationFeedbackProvider><Harness /></NavigationFeedbackProvider>);
|
|
expect(screen.queryByRole("progressbar", { name: "正在切换页面" })).not.toBeInTheDocument();
|
|
expect(screen.getByRole("textbox", { name: "页面草稿" })).toBeVisible();
|
|
});
|
|
|
|
it("connects every existing map skeleton to its exact public route", () => {
|
|
const paths = [
|
|
"/network-simulation", "/scada-data-cleaning", "/health-risk-analysis", "/monitoring-place-optimization",
|
|
...["burst-detection", "burst-location", "burst-simulation", "contaminant-simulation", "dma-leak-detection", "flushing-analysis"].map((name) => "/hydraulic-simulation/" + name),
|
|
];
|
|
expect(paths.map(mapSkeletonForPath).sort()).toEqual([...MAP_SKELETON_VARIANTS].sort());
|
|
expect(mapSkeletonForPath("/system-admin")).toBeUndefined();
|
|
});
|
|
});
|