feat(web): parité layout AppImage desktop + switch TUI naïf/CLI custom — #208
This commit is contained in:
107
frontend/src/features/web/WebDesktopWorkspace.test.tsx
Normal file
107
frontend/src/features/web/WebDesktopWorkspace.test.tsx
Normal file
@ -0,0 +1,107 @@
|
||||
import { beforeEach, describe, it, expect } from "vitest";
|
||||
import { fireEvent, render, screen, within } from "@testing-library/react";
|
||||
|
||||
import type { Gateways } from "@/ports";
|
||||
import { DIProvider } from "@/app/di";
|
||||
import { createMockGateways, MockWorkStateGateway } from "@/adapters/mock";
|
||||
import { WebSession } from "@/adapters/http";
|
||||
import type { FetchLike } from "@/adapters/http/httpInvoker";
|
||||
import type { FlagStore } from "@/adapters/http/webSession";
|
||||
import { WebApp } from "./WebApp";
|
||||
|
||||
function memStore(): FlagStore {
|
||||
const map = new Map<string, string>();
|
||||
return {
|
||||
getItem: (k) => map.get(k) ?? null,
|
||||
setItem: (k, v) => void map.set(k, v),
|
||||
removeItem: (k) => void map.delete(k),
|
||||
};
|
||||
}
|
||||
|
||||
const okFetch: FetchLike = async () => ({
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => ({ ok: true }),
|
||||
text: async () => "{}",
|
||||
});
|
||||
|
||||
async function seededGateways(): Promise<Gateways> {
|
||||
const gateways = createMockGateways();
|
||||
const project = await gateways.project.createProject("Demo", "/srv/demo");
|
||||
(gateways.workState as MockWorkStateGateway)._setProjectWorkState(project.id, {
|
||||
agents: [
|
||||
{ agentId: "a1", name: "Archi", profileId: "p1", busy: { state: "idle" }, tickets: [] },
|
||||
],
|
||||
conversations: [],
|
||||
});
|
||||
return gateways;
|
||||
}
|
||||
|
||||
function renderPairedWebApp(gateways: Gateways) {
|
||||
const session = new WebSession({ baseUrl: "https://h", fetchImpl: okFetch, store: memStore() });
|
||||
session.markPaired();
|
||||
return render(
|
||||
<DIProvider gateways={gateways}>
|
||||
<WebApp session={session} />
|
||||
</DIProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
window.localStorage.clear();
|
||||
window.innerWidth = 1280;
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
});
|
||||
|
||||
describe("WebWorkspace desktop layout", () => {
|
||||
it("mounts the desktop AppImage-style shell with LayoutTabs/LayoutGrid and no detached action", async () => {
|
||||
renderPairedWebApp(await seededGateways());
|
||||
|
||||
expect(
|
||||
(await screen.findByTestId("web-workspace")).getAttribute("data-shell"),
|
||||
).toBe(
|
||||
"desktop-layout",
|
||||
);
|
||||
expect(screen.queryByTestId("web-mobile-task-canvas")).toBeNull();
|
||||
|
||||
fireEvent.click(await screen.findByText("Demo"));
|
||||
|
||||
expect(await screen.findByTestId("layout-tabs")).toBeTruthy();
|
||||
expect(await screen.findByTestId("layout-grid")).toBeTruthy();
|
||||
expect(screen.getByLabelText("right dock")).toBeTruthy();
|
||||
expect(screen.queryByRole("button", { name: /detach/i })).toBeNull();
|
||||
expect(screen.queryByText(/Fenêtre/)).toBeNull();
|
||||
});
|
||||
|
||||
it("opens panels as floating or docked from the desktop menu bar without a detached web mode", async () => {
|
||||
renderPairedWebApp(await seededGateways());
|
||||
fireEvent.click(await screen.findByText("Demo"));
|
||||
await screen.findByTestId("layout-grid");
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Panneaux" }));
|
||||
const menu = await screen.findByRole("menu", { name: "Panneaux" });
|
||||
|
||||
fireEvent.click(within(menu).getByRole("button", { name: "Tickets" }));
|
||||
const submenu = await screen.findByRole("menu", { name: "Tickets" });
|
||||
fireEvent.click(within(submenu).getByRole("button", { name: "Flottant" }));
|
||||
|
||||
expect(await screen.findByRole("dialog", { name: "Tickets" })).toBeTruthy();
|
||||
expect(screen.queryByRole("button", { name: /detached/i })).toBeNull();
|
||||
});
|
||||
|
||||
it("can dock a panel to the left from the menu bar while keeping the grid in the main area", async () => {
|
||||
renderPairedWebApp(await seededGateways());
|
||||
fireEvent.click(await screen.findByText("Demo"));
|
||||
await screen.findByTestId("layout-grid");
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Panneaux" }));
|
||||
const menu = await screen.findByRole("menu", { name: "Panneaux" });
|
||||
fireEvent.click(within(menu).getByRole("button", { name: "Project context" }));
|
||||
const submenu = await screen.findByRole("menu", { name: "Project context" });
|
||||
fireEvent.click(within(submenu).getByRole("button", { name: "Ancré à gauche" }));
|
||||
|
||||
expect(await screen.findByLabelText("left dock")).toBeTruthy();
|
||||
expect(await screen.findByLabelText("Project context panel")).toBeTruthy();
|
||||
expect(screen.getByTestId("layout-grid")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user