feat(frontend): adapter web HTTP+WebSocket derrière les ports (#13)
Lot F1 du chantier server/client mode : nouvel adaptateur web branché derrière les ports d'invocation et de flux live, permettant au frontend de dialoguer avec le backend via HTTP + WebSocket en mode client/serveur. Le mode desktop (Tauri IPC) reste inchangé. - frontend/src/adapters/http : invoker HTTP, client live WebSocket, gateways request/response et stream, frames, garde unsupported (7 fichiers + 2 tests). - frontend/src/app : câblage DI (di.tsx) et son test, typage vite-env.d.ts. Validé : build vert, garde no-direct-invoke verte, 724 tests verts, desktop inchangé. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -6,7 +6,16 @@ import { describe, it, expect, afterEach, vi } from "vitest";
|
||||
import { render, screen, renderHook } from "@testing-library/react";
|
||||
|
||||
import { MockSystemGateway } from "@/adapters/mock";
|
||||
import { DIProvider, useGateways, resolveGateways, shouldUseMock } from "./di";
|
||||
import { HttpSystemGateway } from "@/adapters/http/streamGateways";
|
||||
import { TauriSystemGateway } from "@/adapters";
|
||||
import {
|
||||
DIProvider,
|
||||
useGateways,
|
||||
resolveGateways,
|
||||
resolveTransport,
|
||||
shouldUseMock,
|
||||
shouldUseHttp,
|
||||
} from "./di";
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
@ -26,12 +35,37 @@ describe("shouldUseMock / resolveGateways", () => {
|
||||
|
||||
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("DIProvider / useGateways", () => {
|
||||
it("provides explicit gateways to consumers", () => {
|
||||
const gateways = resolveGatewaysMock();
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
/**
|
||||
* Dependency-injection provider for the UI ports.
|
||||
*
|
||||
* Chooses real Tauri adapters vs mocks based on `VITE_USE_MOCK` (any truthy
|
||||
* value → mocks). Components consume gateways via {@link useGateways} and never
|
||||
* construct adapters or call `invoke()` themselves.
|
||||
* Chooses one of three transport implementations (ticket #13): the mock adapters
|
||||
* (`VITE_USE_MOCK`), the web HTTP+WS adapters (`VITE_TRANSPORT="http"`), or the
|
||||
* default Tauri desktop adapters. Components consume gateways via
|
||||
* {@link useGateways} and never construct adapters or call `invoke()` themselves.
|
||||
*/
|
||||
|
||||
import {
|
||||
@ -16,18 +17,45 @@ import {
|
||||
import type { Gateways } from "@/ports";
|
||||
import { createTauriGateways } from "@/adapters";
|
||||
import { createMockGateways } from "@/adapters/mock";
|
||||
import { createHttpWsGateways } from "@/adapters/http";
|
||||
|
||||
const GatewaysContext = createContext<Gateways | null>(null);
|
||||
|
||||
/** The selected transport backing the gateways. */
|
||||
export type Transport = "mock" | "http" | "tauri";
|
||||
|
||||
/** Whether the mock adapters should be used (env-driven, overridable in tests). */
|
||||
export function shouldUseMock(): boolean {
|
||||
const flag = import.meta.env.VITE_USE_MOCK;
|
||||
return flag === "1" || flag === "true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the web (client/server) HTTP+WS adapters should be used. Selected
|
||||
* explicitly via `VITE_TRANSPORT="http"` so the desktop path stays the default
|
||||
* and is never affected (ticket #13, lot F1).
|
||||
*/
|
||||
export function shouldUseHttp(): boolean {
|
||||
return import.meta.env.VITE_TRANSPORT === "http";
|
||||
}
|
||||
|
||||
/** Resolves which transport to use. Mock wins, then explicit web, else Tauri. */
|
||||
export function resolveTransport(): Transport {
|
||||
if (shouldUseMock()) return "mock";
|
||||
if (shouldUseHttp()) return "http";
|
||||
return "tauri";
|
||||
}
|
||||
|
||||
/** Resolves the gateway set for the current environment. */
|
||||
export function resolveGateways(): Gateways {
|
||||
return shouldUseMock() ? createMockGateways() : createTauriGateways();
|
||||
switch (resolveTransport()) {
|
||||
case "mock":
|
||||
return createMockGateways();
|
||||
case "http":
|
||||
return createHttpWsGateways();
|
||||
case "tauri":
|
||||
return createTauriGateways();
|
||||
}
|
||||
}
|
||||
|
||||
interface DIProviderProps {
|
||||
|
||||
Reference in New Issue
Block a user