Le transport est figé au build par Vite : un seul `dist` ne peut pas servir
à la fois le desktop (IPC Tauri) et le navigateur (HTTP+WS). Le serveur
embarqué servait donc un bundle desktop, d'où `__TAURI_INTERNALS__ is
undefined` côté navigateur.
- `vite.config.ts` devient une factory `({ mode })` : le mode par défaut émet
le bundle desktop (`dist`), `--mode web` lit `.env.web` et émet le bundle
navigateur (`dist-web`).
- `.env.web` porte `VITE_TRANSPORT=http` dans un fichier de mode plutôt qu'en
préfixe de commande, syntaxe qui n'existe pas sous Windows (bundle NSIS).
- `transport.ts` extrait le prédicat `transportFromEnv()`, partagé par l'app et
la config de build : le constant `__IDEA_TRANSPORT__` et le transport résolu
dérivent de la même variable via le même prédicat, ils ne peuvent pas diverger.
- `main.tsx` publie `__IDEA_TRANSPORT__` sur `window` : l'affectation est un
effet de bord, elle survit à la minification et rend un bundle identifiable
sans grep d'un symbole minifié. Les deux jeux d'adapters étant présents dans
les deux bundles, leur présence ne prouve rien.
Le chemin desktop est inchangé : le web reste opt-in.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
125 lines
4.0 KiB
TypeScript
125 lines
4.0 KiB
TypeScript
/**
|
|
* L1 — the DI provider resolves real vs mock gateways from `VITE_USE_MOCK`,
|
|
* and `useGateways` exposes the injected set (and guards against misuse).
|
|
*/
|
|
import { describe, it, expect, afterEach, vi } from "vitest";
|
|
import { render, screen, renderHook } from "@testing-library/react";
|
|
|
|
import { MockSystemGateway } from "@/adapters/mock";
|
|
import { HttpSystemGateway } from "@/adapters/http/streamGateways";
|
|
import { TauriSystemGateway } from "@/adapters";
|
|
import {
|
|
DIProvider,
|
|
useGateways,
|
|
resolveGateways,
|
|
resolveTransport,
|
|
shouldUseMock,
|
|
shouldUseHttp,
|
|
} from "./di";
|
|
import { transportFromEnv } from "./transport";
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllEnvs();
|
|
});
|
|
|
|
describe("shouldUseMock / resolveGateways", () => {
|
|
it("returns mock gateways when VITE_USE_MOCK=1", () => {
|
|
vi.stubEnv("VITE_USE_MOCK", "1");
|
|
expect(shouldUseMock()).toBe(true);
|
|
expect(resolveGateways().system).toBeInstanceOf(MockSystemGateway);
|
|
});
|
|
|
|
it("returns mock gateways when VITE_USE_MOCK=true", () => {
|
|
vi.stubEnv("VITE_USE_MOCK", "true");
|
|
expect(shouldUseMock()).toBe(true);
|
|
});
|
|
|
|
it("returns real (non-mock) gateways otherwise", () => {
|
|
vi.stubEnv("VITE_USE_MOCK", "");
|
|
vi.stubEnv("VITE_TRANSPORT", "");
|
|
expect(shouldUseMock()).toBe(false);
|
|
// Real adapter is not the mock implementation.
|
|
expect(resolveGateways().system).not.toBeInstanceOf(MockSystemGateway);
|
|
});
|
|
});
|
|
|
|
describe("resolveTransport / web (HTTP+WS) selection (ticket #13, F1)", () => {
|
|
it("selects the HTTP transport when VITE_TRANSPORT=http", () => {
|
|
vi.stubEnv("VITE_USE_MOCK", "");
|
|
vi.stubEnv("VITE_TRANSPORT", "http");
|
|
expect(shouldUseHttp()).toBe(true);
|
|
expect(resolveTransport()).toBe("http");
|
|
expect(resolveGateways().system).toBeInstanceOf(HttpSystemGateway);
|
|
});
|
|
|
|
it("keeps Tauri as the default when no transport env is set", () => {
|
|
vi.stubEnv("VITE_USE_MOCK", "");
|
|
vi.stubEnv("VITE_TRANSPORT", "");
|
|
expect(resolveTransport()).toBe("tauri");
|
|
expect(resolveGateways().system).toBeInstanceOf(TauriSystemGateway);
|
|
});
|
|
|
|
it("lets mock win over the web transport", () => {
|
|
vi.stubEnv("VITE_USE_MOCK", "1");
|
|
vi.stubEnv("VITE_TRANSPORT", "http");
|
|
expect(resolveTransport()).toBe("mock");
|
|
expect(resolveGateways().system).toBeInstanceOf(MockSystemGateway);
|
|
});
|
|
});
|
|
|
|
describe("transportFromEnv (ticket #74, F1)", () => {
|
|
// The build config derives `__IDEA_TRANSPORT__` from this same predicate, so
|
|
// pinning it here pins both the runtime transport and the build constant.
|
|
it("selects http only for the exact opt-in value", () => {
|
|
expect(transportFromEnv("http")).toBe("http");
|
|
});
|
|
|
|
it.each([undefined, "", "tauri", "HTTP", "http ", "web"])(
|
|
"falls back to tauri for %o",
|
|
(value) => {
|
|
expect(transportFromEnv(value)).toBe("tauri");
|
|
},
|
|
);
|
|
|
|
it("agrees with shouldUseHttp for the value the build reads", () => {
|
|
vi.stubEnv("VITE_TRANSPORT", "http");
|
|
expect(shouldUseHttp()).toBe(transportFromEnv("http") === "http");
|
|
vi.stubEnv("VITE_TRANSPORT", "");
|
|
expect(shouldUseHttp()).toBe(transportFromEnv("") === "http");
|
|
});
|
|
});
|
|
|
|
describe("DIProvider / useGateways", () => {
|
|
it("provides explicit gateways to consumers", () => {
|
|
const gateways = resolveGatewaysMock();
|
|
const { result } = renderHook(() => useGateways(), {
|
|
wrapper: ({ children }) => (
|
|
<DIProvider gateways={gateways}>{children}</DIProvider>
|
|
),
|
|
});
|
|
expect(result.current).toBe(gateways);
|
|
});
|
|
|
|
it("renders children inside the provider", () => {
|
|
render(
|
|
<DIProvider gateways={resolveGatewaysMock()}>
|
|
<span>ok</span>
|
|
</DIProvider>,
|
|
);
|
|
expect(screen.getByText("ok")).toBeTruthy();
|
|
});
|
|
|
|
it("throws when useGateways is used outside a provider", () => {
|
|
expect(() => renderHook(() => useGateways())).toThrow(
|
|
/must be used within a <DIProvider>/,
|
|
);
|
|
});
|
|
});
|
|
|
|
function resolveGatewaysMock() {
|
|
vi.stubEnv("VITE_USE_MOCK", "1");
|
|
const g = resolveGateways();
|
|
vi.unstubAllEnvs();
|
|
return g;
|
|
}
|