import { describe, expect, it } from "vitest"; import type { ApplyConfigurationResult, PingServerResponse, } from "../api/tauriCommands"; import type { ComponentStatus } from "../domain/types"; import { connectionCheckView, noticeFromConfigurationApply, pingSummary, routeChainSegments, } from "./viewModel"; const runningProxiFyre: ComponentStatus = { id: "proxyfier", name: "ProxiFyre", state: "running", installed: true, running: true, path: "C:\\Tools\\ProxiFyre\\ProxiFyre.exe", problems: [], actions: [], }; describe("App view helpers", () => { it("describes the external SOCKS5 route without Local sing-box", () => { const segments = routeChainSegments({ routeMode: "external", proxyInput: "proxy.example.test:1080", proxyfier: runningProxiFyre, singbox: undefined, singBoxStatus: null, selectedServer: null, appCount: 2, isDetectingComponents: false, }); expect(segments.map((segment) => segment.id)).toEqual([ "apps", "proxifyre", "endpoint", "exit", ]); expect(segments[2]).toMatchObject({ value: "proxy.example.test:1080", tone: "ok", }); expect(segments[3].details).toContain( "Local sing-box не нужен для этого маршрута.", ); }); it("summarizes the fastest successful ping", () => { const results = [ { tag: "slow", ok: true, latency: 90 }, { tag: "failed", ok: false }, { tag: "fast", ok: true, latency: 20 }, ] as PingServerResponse[]; expect(pingSummary(results)).toBe("Ответили 2/3; быстрее fast: 20 ms."); }); it("builds an expandable route-check result from every backend probe", () => { const view = connectionCheckView({ routeMode: "external", proxyInput: "192.168.50.111:8080", proxyCheck: { tag: "external", server: "192.168.50.111", serverPort: 8080, ok: true, latency: 14, probes: [ { id: "cloudflare-trace", name: "Cloudflare Trace", url: "https://cloudflare.com/cdn-cgi/trace", ok: true, status: 200, latency: 21, ip: "203.0.113.10", }, { id: "ipify", name: "ipify", url: "https://api.ipify.org", ok: false, error: "timeout", }, ], }, singbox: undefined, singBoxStatus: null, selectedServer: null, isDetectingComponents: false, isProxyChecking: false, }); expect(view).toMatchObject({ checked: true, endpoint: "192.168.50.111:8080", tone: "warning", }); expect(view.probes.map((probe) => probe.id)).toEqual([ "tcp", "cloudflare-trace", "ipify", ]); expect(view.details).toContainEqual({ label: "Cloudflare Trace", value: "IP 203.0.113.10 · HTTP 200 · 21 ms", }); expect(view.probes[1]).toMatchObject({ ip: "203.0.113.10", latency: "21 ms", status: "Доступна", }); }); it("shows the result surface while the route check is running", () => { const view = connectionCheckView({ routeMode: "external", proxyInput: "192.168.50.111:8080", proxyCheck: null, singbox: undefined, singBoxStatus: null, selectedServer: null, isDetectingComponents: false, isProxyChecking: true, }); expect(view).toMatchObject({ checked: false, loading: true }); }); it("distinguishes rolled-back and partial apply failures", () => { const base: ApplyConfigurationResult = { success: false, changed: false, partialState: false, message: "Helper failed; previous files restored.", generatedConfigPath: "C:\\ProgramData\\ProxyWarden\\generated\\proxifyre-app-config.json", restartRequired: [], phases: [], }; expect(noticeFromConfigurationApply(base).title).toBe("Изменения отменены"); expect( noticeFromConfigurationApply({ ...base, partialState: true }).title, ).toBe("Проверь состояние файлов"); }); });