diff --git a/src/App.test.ts b/src/App.test.tsx similarity index 58% rename from src/App.test.ts rename to src/App.test.tsx index 0285702..fd4d244 100644 --- a/src/App.test.ts +++ b/src/App.test.tsx @@ -1,7 +1,15 @@ -import { describe, expect, it } from "vitest"; +import { cleanup, render, waitFor } from "@testing-library/react"; +import { afterEach, describe, expect, it } from "vitest"; import { initialState } from "./data/sampleData"; import type { QOfficeState } from "./types"; -import { qofficeWindowTitle } from "./App"; +import { App, qofficeWindowTitle } from "./App"; + +afterEach(() => { + cleanup(); + window.localStorage.clear(); + window.history.pushState({}, "", "/"); + window.document.title = ""; +}); describe("qofficeWindowTitle", () => { it("uses the current artifact name for standalone application title bars", () => { @@ -32,4 +40,28 @@ describe("qofficeWindowTitle", () => { expect(qofficeWindowTitle(state, "slides")).toBe("Презентация1 - QPowerPoint"); expect(qofficeWindowTitle(state, "mail")).toBe("Почта - QOutlook"); }); + + it("syncs the browser document title with the active standalone application", async () => { + const originalResizeObserver = globalThis.ResizeObserver; + const originalRequestAnimationFrame = window.requestAnimationFrame; + + globalThis.ResizeObserver = class { + observe() {} + disconnect() {} + } as unknown as typeof ResizeObserver; + window.requestAnimationFrame = ((callback: FrameRequestCallback) => { + callback(0); + return 1; + }) as typeof window.requestAnimationFrame; + window.history.pushState({}, "", "/qword"); + + try { + render(); + + await waitFor(() => expect(window.document.title).toBe(qofficeWindowTitle(initialState, "word"))); + } finally { + globalThis.ResizeObserver = originalResizeObserver; + window.requestAnimationFrame = originalRequestAnimationFrame; + } + }); }); diff --git a/src/App.tsx b/src/App.tsx index 9894863..1fccdbb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { useCallback, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { BookOpen, Columns2, FileText, Minus, Plus, Rows3 } from "lucide-react"; import { AppShell } from "./components/AppShell"; import { QOutlook } from "./features/qoutlook/QOutlook"; @@ -125,6 +125,10 @@ export function App() { const activeApp = activeAppFromLocation(window.location); const windowTitle = qofficeWindowTitle(state, activeApp); + useEffect(() => { + window.document.title = windowTitle; + }, [windowTitle]); + const updateWordStatus = useCallback((nextStatus: QWordStatus) => { setWordStatus((current) => current.currentPage === nextStatus.currentPage && current.pageCount === nextStatus.pageCount && current.wordCount === nextStatus.wordCount ? current : nextStatus