200 lines · 6.9 KB · TypeScript
RawDownload
import {  DEFAULT_CLIENT_SETTINGS,  EnvironmentId,  FILL_PREVIEW_VIEWPORT,  ThreadId,  type ClientSettings,  type DesktopPreviewBridge,} from "@t3tools/contracts";import { act } from "react";import { create, type ReactTestRenderer } from "react-test-renderer";import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test"; const mocks = vi.hoisted(() => ({  getClientSettings: vi.fn<() => Promise<ClientSettings | null>>(),  setClientSettings: vi.fn<(settings: ClientSettings) => Promise<void>>(),  createTab: vi.fn<DesktopPreviewBridge["createTab"]>(),  closeTab: vi.fn<DesktopPreviewBridge["closeTab"]>(),  registerWebview: vi.fn<DesktopPreviewBridge["registerWebview"]>(),  getPreviewConfig: vi.fn<DesktopPreviewBridge["getPreviewConfig"]>(),  activeRecordings: new Set<string>(),})); vi.mock("~/localApi", () => ({  ensureLocalApi: () => ({ persistence: mocks }),})); vi.mock("~/components/preview/previewBridge", () => ({  previewBridge: {    createTab: mocks.createTab,    closeTab: mocks.closeTab,    registerWebview: mocks.registerWebview,    getPreviewConfig: mocks.getPreviewConfig,  },})); vi.mock("~/components/preview/usePreviewBridge", () => ({  usePreviewBridge: () => undefined,})); vi.mock("./browserRecording", () => ({  useActiveBrowserRecordingTabIds: () => mocks.activeRecordings,  stopBrowserRecording: async () => null,})); import {  __resetClientSettingsPersistenceForTests,  ensureClientSettingsHydrated,} from "~/hooks/useSettings";import { useBrowserSurfaceStore } from "./browserSurfaceStore";import * as desktopTabLifetime from "./desktopTabLifetime";import { HostedBrowserWebview } from "./HostedBrowserWebview"; let renderer: ReactTestRenderer | undefined; function deferred<A>() {  let resolve!: (value: A) => void;  let reject!: (error: unknown) => void;  const promise = new Promise<A>((resolvePromise, rejectPromise) => {    resolve = resolvePromise;    reject = rejectPromise;  });  return { promise, resolve, reject };} beforeEach(() => {  __resetClientSettingsPersistenceForTests();  useBrowserSurfaceStore.setState({ activityByTabId: {}, byTabId: {} });  mocks.getClientSettings.mockReset();  mocks.setClientSettings.mockReset().mockResolvedValue(undefined);  mocks.createTab.mockReset().mockResolvedValue(undefined);  mocks.closeTab.mockReset().mockResolvedValue(undefined);  mocks.registerWebview.mockReset().mockResolvedValue(undefined);  mocks.getPreviewConfig.mockReset().mockResolvedValue({    partition: "persist:t3-preview-work",    webPreferences: "contextIsolation=yes",    preloadUrl: null,  });  vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);  vi.stubGlobal("window", globalThis);  vi.stubGlobal("navigator", { platform: "Linux" });  vi.stubGlobal(    "requestAnimationFrame",    vi.fn(() => 0),  );  vi.stubGlobal("cancelAnimationFrame", vi.fn());  vi.spyOn(console, "error").mockImplementation(() => undefined);}); afterEach(async () => {  vi.useFakeTimers();  await act(() => renderer?.unmount());  renderer = undefined;  await vi.advanceTimersByTimeAsync(0);  vi.useRealTimers();  __resetClientSettingsPersistenceForTests();  useBrowserSurfaceStore.setState({ activityByTabId: {}, byTabId: {} });  vi.restoreAllMocks();  vi.unstubAllGlobals();}); describe("HostedBrowserWebview settings hydration", () => {  it("starts a retained background tab only after a settings read succeeds on retry", async () => {    const firstRead = deferred<ClientSettings | null>();    const retryRead = deferred<ClientSettings | null>();    const tabCreation = deferred<void>();    mocks.getClientSettings      .mockReturnValueOnce(firstRead.promise)      .mockReturnValueOnce(retryRead.promise);    mocks.createTab.mockReturnValueOnce(tabCreation.promise);    const acquire = vi.spyOn(desktopTabLifetime, "acquireDesktopTab");    const createGuest = vi.fn((_attributes: unknown) =>      Object.assign(new EventTarget(), { getWebContentsId: () => 41 }),    );    const threadRef = {      environmentId: EnvironmentId.make("host-settings-retry"),      threadId: ThreadId.make("thread-settings-retry"),    };    const runtimeTabId = "retained-background-tab";    useBrowserSurfaceStore.getState().acquireActivity(runtimeTabId);     await act(() => {      renderer = create(        <HostedBrowserWebview          threadRef={threadRef}          tabId="server-tab"          runtimeTabId={runtimeTabId}          initialUrl="https://example.com"          viewport={FILL_PREVIEW_VIEWPORT}          pictureInPicture={false}          profileId="work"          zoomFactor={1.25}        />,        {          createNodeMock: (element) =>            element.type === "webview"              ? createGuest(element.props)              : { scrollLeft: 0, scrollTop: 0, scrollTo: () => undefined },        },      );    });     expect(mocks.getClientSettings).toHaveBeenCalledOnce();    expect(acquire).not.toHaveBeenCalled();    expect(createGuest).not.toHaveBeenCalled();    expect(mocks.createTab).not.toHaveBeenCalled();     const failure = new Error("Saved settings are unavailable");    await act(async () => {      const hydration = ensureClientSettingsHydrated();      firstRead.reject(failure);      await expect(hydration).rejects.toBe(failure);    });    expect(acquire).not.toHaveBeenCalled();    expect(createGuest).not.toHaveBeenCalled();    expect(mocks.createTab).not.toHaveBeenCalled();     let retry!: Promise<void>;    await act(() => {      retry = ensureClientSettingsHydrated();    });    expect(mocks.getClientSettings).toHaveBeenCalledTimes(2);    expect(acquire).not.toHaveBeenCalled();    expect(createGuest).not.toHaveBeenCalled();    expect(mocks.createTab).not.toHaveBeenCalled();     await act(async () => {      retryRead.resolve({        ...DEFAULT_CLIENT_SETTINGS,        browserDefaultZoomFactor: 1.25,        browserDefaultAppearance: "dark",        browserProfiles: [{ id: "work", name: "Work", kind: "persistent" }],        browserDefaultProfileId: "work",      });      await retry;    });     expect(acquire).toHaveBeenCalledExactlyOnceWith(runtimeTabId);    expect(mocks.getPreviewConfig).toHaveBeenCalledExactlyOnceWith(threadRef.environmentId, "work");    expect(createGuest).toHaveBeenCalledOnce();    expect(createGuest).toHaveBeenCalledWith(      expect.objectContaining({        partition: "persist:t3-preview-work",        src: "https://example.com",      }),    );    expect(mocks.createTab).toHaveBeenCalledExactlyOnceWith(runtimeTabId, {      zoomFactor: 1.25,      colorScheme: "dark",    });    expect(mocks.registerWebview).not.toHaveBeenCalled();     await act(async () => {      tabCreation.resolve();      await tabCreation.promise;    });    expect(mocks.registerWebview).toHaveBeenCalledExactlyOnceWith(runtimeTabId, 41);    expect(mocks.closeTab).not.toHaveBeenCalled();    expect(mocks.setClientSettings).not.toHaveBeenCalled();  });});