diff --git a/src/components/SiteHeader.tsx b/src/components/SiteHeader.tsx index 18f273b..38752c2 100644 --- a/src/components/SiteHeader.tsx +++ b/src/components/SiteHeader.tsx @@ -1,6 +1,8 @@ import Image from "next/image"; import Link from "next/link"; +import { TerminalNavLink } from "~/components/TerminalNavLink"; + export function SiteHeader() { return (
@@ -16,6 +18,7 @@ export function SiteHeader() { Labs + { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("defaults to the same-origin WeTTY path", () => { + vi.spyOn(globalThis, "fetch").mockRejectedValue(new Error("not found")); + + render(); + + expect(screen.getByRole("link", { name: "Terminal" })).toHaveAttribute( + "href", + LAB3_DEFAULT_TERMINAL_PATH, + ); + }); + + it("loads the terminal link from runtime config", async () => { + const fetchMock = vi.spyOn(globalThis, "fetch").mockResolvedValue( + new Response( + JSON.stringify({ + lab3TerminalUrl: "http://127.0.0.1:7681/wetty", + }), + { status: 200 }, + ), + ); + + render(); + + await waitFor(() => { + expect(screen.getByRole("link", { name: "Terminal" })).toHaveAttribute( + "href", + "http://localhost:7681/wetty", + ); + }); + expect(fetchMock).toHaveBeenCalledWith(COURSEWARE_RUNTIME_CONFIG_PATH, { + cache: "no-store", + }); + }); +}); diff --git a/src/components/TerminalNavLink.tsx b/src/components/TerminalNavLink.tsx new file mode 100644 index 0000000..605b3cf --- /dev/null +++ b/src/components/TerminalNavLink.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { useEffect, useState } from "react"; + +import { + LAB3_DEFAULT_TERMINAL_PATH, + fetchCoursewareRuntimeConfig, +} from "~/lib/courseware-runtime"; + +export function TerminalNavLink() { + const [terminalPath, setTerminalPath] = useState(LAB3_DEFAULT_TERMINAL_PATH); + + useEffect(() => { + let isCancelled = false; + + void fetchCoursewareRuntimeConfig() + .then((runtimeConfig) => { + if (isCancelled) return; + setTerminalPath(runtimeConfig.lab3TerminalUrl); + }) + .catch(() => { + if (isCancelled) return; + setTerminalPath(LAB3_DEFAULT_TERMINAL_PATH); + }); + + return () => { + isCancelled = true; + }; + }, []); + + return ( + + Terminal + + ); +}