// @vitest-environment jsdom // SPEC: PJ2026-010405 云端控制台. // Implementation reference: draft-2026-07-13-p0-cloud-console. // Responsibility: 验证 OpenCode frame URL 换票完成后仍等待 iframe load,并提供失败、超时与重试状态。 import { flushPromises, mount } from "@vue/test-utils"; import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; import OpenCodeFrameView from "./OpenCodeFrameView.vue"; vi.mock("@/config/runtime", () => ({ opencodeFrameUrl: () => "https://opencode.example.test" })); function successfulFrameUrlResponse(): Response { return new Response(JSON.stringify({ url: "/opencode/proxy/?ticket=redacted" }), { status: 200, headers: { "content-type": "application/json" } }); } describe("OpenCodeFrameView", () => { beforeEach(() => { vi.stubGlobal("fetch", vi.fn(async () => successfulFrameUrlResponse())); }); afterEach(() => { vi.useRealTimers(); vi.unstubAllGlobals(); }); test("waits for iframe load before reporting ready", async () => { const wrapper = mount(OpenCodeFrameView); await flushPromises(); expect(wrapper.get('[data-testid="opencode-load-state"]').text()).toBe("loading"); expect(wrapper.get("iframe").attributes("src")).toBe("/opencode/proxy/?ticket=redacted"); expect(wrapper.get("[role='status']").text()).toContain("OpenCode 加载中"); await wrapper.get("iframe").trigger("load"); expect(wrapper.get('[data-testid="opencode-load-state"]').text()).toBe("ready"); expect(wrapper.find("[role='status']").exists()).toBe(false); wrapper.unmount(); }); test("shows a retry after iframe error and starts a fresh bounded load", async () => { const wrapper = mount(OpenCodeFrameView); await flushPromises(); await wrapper.get("iframe").trigger("error"); expect(wrapper.get('[data-testid="opencode-load-state"]').text()).toBe("error"); expect(wrapper.get("[role='status']").text()).toContain("iframe 加载失败"); expect(wrapper.find("iframe").exists()).toBe(false); await wrapper.get("button").trigger("click"); await flushPromises(); expect(fetch).toHaveBeenCalledTimes(2); expect(wrapper.get('[data-testid="opencode-load-state"]').text()).toBe("loading"); expect(wrapper.find("iframe").exists()).toBe(true); wrapper.unmount(); }); test("fails a frame that does not load within the bounded timeout", async () => { vi.useFakeTimers(); const wrapper = mount(OpenCodeFrameView); await flushPromises(); await vi.advanceTimersByTimeAsync(15_000); expect(wrapper.get('[data-testid="opencode-load-state"]').text()).toBe("error"); expect(wrapper.get("[role='status']").text()).toContain("iframe 加载超时"); expect(wrapper.find("iframe").exists()).toBe(false); wrapper.unmount(); }); });