117 lines · 4.3 KB · TypeScript
RawDownload
import type { AtomCommandResult } from "@t3tools/client-runtime/state/runtime";import type { PreviewSessionSnapshot, ScopedThreadRef } from "@t3tools/contracts";import * as Cause from "effect/Cause";import { AsyncResult } from "effect/unstable/reactivity";import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test"; import { readThreadPreviewState, resetPreviewStateForTests } from "~/previewStateStore";import { selectThreadRightPanelState, useRightPanelStore } from "~/rightPanelStore"; import {  BrowserPreviewUnavailableError,  isBrowserPreviewAssetUrlInvalidError,  type OpenPreviewMutation,  openFileInPreview,  openUrlInPreview,} from "./openFileInPreview"; const threadRef = {  environmentId: "environment-1" as ScopedThreadRef["environmentId"],  threadId: "thread-1" as ScopedThreadRef["threadId"],}; const snapshot = (tabId: string, url: string): PreviewSessionSnapshot => ({  threadId: threadRef.threadId,  tabId,  navStatus: { _tag: "Success", url, title: "" },  canGoBack: false,  canGoForward: false,  updatedAt: "2026-06-21T00:00:00.000Z",}); beforeEach(() => {  resetPreviewStateForTests();  useRightPanelStore.setState({ byThreadKey: {} });}); afterEach(() => vi.unstubAllGlobals()); describe("openFileInPreview", () => {  it("uses the fixed unavailable-runtime message", () => {    expect(new BrowserPreviewUnavailableError().message).toBe(      "The integrated browser is unavailable in this runtime.",    );  });   it("reports invalid asset URLs with safe context and the exact parser cause", async () => {    vi.stubGlobal("window", { desktopBridge: { preview: {} } });    const parserCause = new TypeError("invalid URL");    const InvalidUrl = vi.fn(function InvalidUrl() {      throw parserCause;    });    vi.stubGlobal("URL", InvalidUrl);    const openPreview = vi.fn();    const httpBaseUrl = "not a URL";    const relativeUrl = "/api/assets/signed-secret-token/docs/report.pdf";    const expiresAt = Date.now();     const result = await openFileInPreview({      threadRef,      filePath: "docs/report.pdf",      httpBaseUrl,      createAssetUrl: async () => AsyncResult.success({ relativeUrl, expiresAt }),      openPreview,    });    const error = result._tag === "Failure" ? Cause.squash(result.cause) : undefined;     expect(isBrowserPreviewAssetUrlInvalidError(error)).toBe(true);    if (!isBrowserPreviewAssetUrlInvalidError(error)) {      throw new Error("Expected BrowserPreviewAssetUrlInvalidError");    }    expect(error).toMatchObject({      environmentId: "environment-1",      threadId: "thread-1",      filePath: "docs/report.pdf",      httpBaseUrlLength: httpBaseUrl.length,      relativeUrlLength: relativeUrl.length,      expiresAt,    });    expect(error.cause).toBe(parserCause);    expect(error.message).toBe("The environment returned an invalid asset URL.");    expect(error).not.toHaveProperty("httpBaseUrl");    expect(error).not.toHaveProperty("relativeUrl");    expect(JSON.stringify(error)).not.toContain("signed-secret-token");    expect(openPreview).not.toHaveBeenCalled();  });}); it("does not apply an older preview response after another caller starts a newer request", async () => {  const firstSnapshot = snapshot("tab-1", "https://assets.test/first.png");  const secondSnapshot = snapshot("tab-2", "https://assets.test/second.png");  let resolveFirst!: (result: AtomCommandResult<PreviewSessionSnapshot, never>) => void;  const openPreview: OpenPreviewMutation<never> = ({ input }) =>    input.url === "https://assets.test/first.png"      ? new Promise<AtomCommandResult<PreviewSessionSnapshot, never>>((resolve) => {          resolveFirst = resolve;        })      : Promise.resolve(AsyncResult.success(secondSnapshot));   const firstRequest = openUrlInPreview({    threadRef,    url: "https://assets.test/first.png",    openPreview,  });   await openUrlInPreview({    threadRef,    url: "https://assets.test/second.png",    openPreview,  });  resolveFirst(AsyncResult.success(firstSnapshot));  await firstRequest;   expect(readThreadPreviewState(threadRef).snapshot).toEqual(secondSnapshot);  expect(    selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, threadRef).surfaces,  ).toEqual([{ id: "browser:tab-2", kind: "preview", resourceId: "tab-2" }]);});