fix(dashboard-tests): green Full Suite after chat tags, TaskForm meta, remote lifecycle
- Replace undefined --space-2xs in ChatView tag menu with calc(--space-xs / 2) - Stub fetchChatTags/create/rename/delete on streaming-thread api mock for useChat mount - Expect TaskForm model/tracking callbacks with TaskFormValueChangeMeta source - Drive remote tunnel lifecycle via one stop then error status (no double Stop race)
This commit is contained in:
@@ -2788,5 +2788,10 @@ Queued-message banners stack above the composer input with a capped scroll area,
|
||||
.chat-tag-create-row .input { min-width: 0; }
|
||||
@media (max-width: 768px) {
|
||||
.chat-session-tags { max-height: calc(var(--space-lg) * 2); }
|
||||
.chat-tag-menu-item { gap: var(--space-2xs); }
|
||||
/*
|
||||
FNXC:ChatTags 2026-07-24-23:05:
|
||||
Compact mobile tag-menu gap must use a defined token. --space-2xs is intentionally
|
||||
undefined (space-token-defined hygiene); half of --space-xs matches the prior intent.
|
||||
*/
|
||||
.chat-tag-menu-item { gap: calc(var(--space-xs) / 2); }
|
||||
}
|
||||
|
||||
@@ -16,6 +16,12 @@ vi.mock("../../sse-bus", () => ({
|
||||
subscribeSse: vi.fn(() => () => {}),
|
||||
}));
|
||||
|
||||
/*
|
||||
FNXC:ChatTags 2026-07-24-23:05:
|
||||
useChat loads tags on mount via fetchChatTags/createChatTag/renameChatTag/deleteChatTag.
|
||||
Partial ../../api factories must stub those exports or CI fails with
|
||||
"No fetchChatTags export is defined on the mock" once tag APIs ship.
|
||||
*/
|
||||
vi.mock("../../api", () => ({
|
||||
fetchSettings: vi.fn().mockResolvedValue({}),
|
||||
fetchChatSessions: vi.fn(),
|
||||
@@ -27,6 +33,10 @@ vi.mock("../../api", () => ({
|
||||
streamChatResponse: vi.fn(),
|
||||
attachChatStream: vi.fn(),
|
||||
cancelChatResponse: vi.fn(),
|
||||
fetchChatTags: vi.fn().mockResolvedValue({ tags: [] }),
|
||||
createChatTag: vi.fn().mockResolvedValue({ tag: { id: "tag-1", name: "t", createdAt: "2026-04-08T00:00:00.000Z" } }),
|
||||
renameChatTag: vi.fn().mockResolvedValue({ tag: { id: "tag-1", name: "t", createdAt: "2026-04-08T00:00:00.000Z" } }),
|
||||
deleteChatTag: vi.fn().mockResolvedValue({ success: true }),
|
||||
fetchAgents: vi.fn().mockResolvedValue([
|
||||
{ id: "agent-001", name: "Alpha", role: "executor", state: "idle", icon: undefined, createdAt: "2026-04-08T00:00:00.000Z", updatedAt: "2026-04-08T00:00:00.000Z", metadata: {} },
|
||||
]),
|
||||
|
||||
@@ -587,11 +587,17 @@ describe("SettingsModal", () => {
|
||||
});
|
||||
|
||||
it("shows lifecycle state changes for start and stop actions, including error state", async () => {
|
||||
/*
|
||||
FNXC:SettingsRemote 2026-07-24-23:05:
|
||||
Full Suite flake: a second Stop Tunnel click races loadRemoteData after the first stop.
|
||||
Product UI only shows Stop while state is running/starting; after stop refresh returns
|
||||
error, the control is Start Tunnel. Drive start → running → one stop → error message
|
||||
instead of double-stop, and keep running stable across start-poll ticks.
|
||||
*/
|
||||
mockFetchRemoteStatus
|
||||
.mockResolvedValueOnce({ provider: null, state: "stopped", url: null, lastError: null })
|
||||
.mockResolvedValueOnce({ provider: "tailscale", state: "starting", url: null, lastError: null })
|
||||
.mockResolvedValueOnce({ provider: "tailscale", state: "running", url: "https://tail.example", lastError: null })
|
||||
.mockResolvedValueOnce({ provider: "tailscale", state: "error", url: null, lastError: "Tunnel crashed" });
|
||||
.mockResolvedValue({ provider: "tailscale", state: "running", url: "https://tail.example", lastError: null });
|
||||
|
||||
await renderModalSection("remote", "Remote Access");
|
||||
|
||||
@@ -607,15 +613,18 @@ describe("SettingsModal", () => {
|
||||
|
||||
expect(await screen.findByRole("button", { name: "Stop Tunnel" })).toBeInTheDocument();
|
||||
|
||||
mockFetchRemoteStatus.mockResolvedValue({
|
||||
provider: "tailscale",
|
||||
state: "error",
|
||||
url: null,
|
||||
lastError: "Tunnel crashed",
|
||||
});
|
||||
await settingsModalUser.click(screen.getByRole("button", { name: "Stop Tunnel" }));
|
||||
await waitFor(() => {
|
||||
expect(mockStopRemoteTunnel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
await settingsModalUser.click(screen.getByRole("button", { name: "Stop Tunnel" }));
|
||||
await waitFor(() => {
|
||||
expect(mockStopRemoteTunnel).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
expect(await screen.findByText("Tunnel crashed")).toBeInTheDocument();
|
||||
expect(screen.getByRole("button", { name: "Start Tunnel" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows external tunnel panel with actions when external tunnel is detected", async () => {
|
||||
|
||||
@@ -1038,8 +1038,9 @@ describe("TaskForm preset selection (FN-819)", () => {
|
||||
|
||||
expect(onPresetModeChange).toHaveBeenCalledWith("preset");
|
||||
expect(onSelectedPresetIdChange).toHaveBeenCalledWith("fast");
|
||||
expect(onExecutorModelChange).toHaveBeenCalledWith("anthropic/claude-sonnet-4-5");
|
||||
expect(onValidatorModelChange).toHaveBeenCalledWith("openai/gpt-4o");
|
||||
// FNXC:TaskForm 2026-07-24-23:05: model/preset handlers pass TaskFormValueChangeMeta so NewTaskModal can ignore initialization seeds vs user picks.
|
||||
expect(onExecutorModelChange).toHaveBeenCalledWith("anthropic/claude-sonnet-4-5", { source: "user" });
|
||||
expect(onValidatorModelChange).toHaveBeenCalledWith("openai/gpt-4o", { source: "user" });
|
||||
});
|
||||
|
||||
it("switching to default clears preset and model overrides", async () => {
|
||||
@@ -1080,8 +1081,8 @@ describe("TaskForm preset selection (FN-819)", () => {
|
||||
|
||||
expect(onPresetModeChange).toHaveBeenCalledWith("default");
|
||||
expect(onSelectedPresetIdChange).toHaveBeenCalledWith("");
|
||||
expect(onExecutorModelChange).toHaveBeenCalledWith("");
|
||||
expect(onValidatorModelChange).toHaveBeenCalledWith("");
|
||||
expect(onExecutorModelChange).toHaveBeenCalledWith("", { source: "user" });
|
||||
expect(onValidatorModelChange).toHaveBeenCalledWith("", { source: "user" });
|
||||
});
|
||||
|
||||
it("switching to custom clears preset ID", async () => {
|
||||
@@ -1564,7 +1565,8 @@ describe("TaskForm focus behavior (FN-1459)", () => {
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onGithubTrackingEnabledChange).toHaveBeenCalledWith(true);
|
||||
// FNXC:TaskForm 2026-07-24-23:05: settings-default seed marks source initialization so create flow can avoid treating it as a user edit.
|
||||
expect(onGithubTrackingEnabledChange).toHaveBeenCalledWith(true, { source: "initialization" });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user