Production typecheck (tsconfig.json + tsconfig.app.json) was already
clean, but a third config that includes test files surfaced 661 errors
across 60+ test files — accumulated drift between mock fixtures and
production types. Six parallel typescript-pro agents fixed every one
without touching production code.
Per-scope before/after (errors → 0):
ChatView 183
Mailbox + Agent suite (5 files) 156
Task / Modal suite (6 files) 127
App + small components (12 files) 96
Hooks + api/auth (8 files) 48
Long tail (32 files) 51
-----------------------------------------------------------------
Total 661
Major fix categories:
- Untyped state objects inferring `never[]` / `null` literals (root
cause of ~120 errors in ChatView alone — added a single
`UseChatReturn` annotation)
- Mock objects missing fields that became required: `WorkflowStep.mode`,
`ChatMessage.thinkingOutput / metadata`, `ChatSession.projectId`,
`Task.log`, `ProjectHealth` fields, `PtyTerminalSessionInfo.createdAt`,
`Agent.metadata`, `InboxResponse.total`, etc.
- Mock objects with stale fields that no longer exist:
`AgentBudgetStatus.budgetPeriod`, `truncated` on log responses,
`OutboxResponse.unreadCount`, `MergeResult.source/target/details`
- Modal props that became required (e.g. `PlanningModeModal.onTasksCreated`)
- String literals not in narrowed unions (`Column`, `WorkflowStepPhase`,
`InsightStatus`, `AgentLogType`, etc.)
- `querySelector` returning `Element` cast to `HTMLElement` for
`@testing-library/react`'s `within()`
- Vitest mock typing: `.mock.calls` access needing `vi.mocked(...)`,
zero-param tuple handling, generic `vi.fn(() => [])` inferring
`never[]`
Helpers introduced in test files (no shared infra):
- `makeSettings(overrides)` in ModelSelectorTab.test.tsx
- `makePromptOverrides(overrides)` in AgentPromptsManager.test.tsx
- `FileBrowserTestOverrides` type alias in FileBrowser.test.tsx
- `makeInboxResponse / makeOutboxResponse` in MailboxView.test.tsx
Verification:
- tsc -p tsconfig.json: exit 0
- tsc -p tsconfig.app.json: exit 0
- tsc -p tsconfig.test-check.json (new — includes test files): exit 0
- vitest run: 9639 / 9641 (2 pre-existing failures
in terminal-mobile-keyboard-layout.test.ts
unrelated to this work; verified via
`git stash` + run on clean HEAD)
Adds packages/dashboard/tsconfig.test-check.json to keep this regression
guard available locally — same as tsconfig.app.json minus the test
exclude.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
533 lines
17 KiB
TypeScript
533 lines
17 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
import { renderHook, waitFor } from "@testing-library/react";
|
|
import { useRemoteNodeData } from "../useRemoteNodeData";
|
|
import * as apiNodeModule from "../../api-node";
|
|
|
|
vi.mock("../../api-node", () => ({
|
|
fetchRemoteNodeHealth: vi.fn(),
|
|
fetchRemoteNodeProjects: vi.fn(),
|
|
fetchRemoteNodeTasks: vi.fn(),
|
|
fetchRemoteNodeProjectHealth: vi.fn(),
|
|
}));
|
|
|
|
const mockFetchRemoteNodeHealth = vi.mocked(apiNodeModule.fetchRemoteNodeHealth);
|
|
const mockFetchRemoteNodeProjects = vi.mocked(apiNodeModule.fetchRemoteNodeProjects);
|
|
const mockFetchRemoteNodeTasks = vi.mocked(apiNodeModule.fetchRemoteNodeTasks);
|
|
const mockFetchRemoteNodeProjectHealth = vi.mocked(apiNodeModule.fetchRemoteNodeProjectHealth);
|
|
|
|
describe("useRemoteNodeData search query propagation", () => {
|
|
beforeEach(() => {
|
|
mockFetchRemoteNodeHealth.mockReset();
|
|
mockFetchRemoteNodeProjects.mockReset();
|
|
mockFetchRemoteNodeTasks.mockReset();
|
|
mockFetchRemoteNodeProjectHealth.mockReset();
|
|
|
|
// Default mock setup for successful fetch
|
|
mockFetchRemoteNodeHealth.mockResolvedValueOnce({
|
|
status: "online",
|
|
version: "1.0.0",
|
|
nodeId: "node_abc",
|
|
});
|
|
mockFetchRemoteNodeProjects.mockResolvedValueOnce([]);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("forwards searchQuery to fetchRemoteNodeTasks when provided", async () => {
|
|
const mockTasks = [
|
|
{
|
|
id: "FN-001",
|
|
title: "Test Task",
|
|
description: "Test description",
|
|
column: "todo" as const,
|
|
dependencies: [],
|
|
steps: [],
|
|
currentStep: 0,
|
|
size: "M" as const,
|
|
reviewLevel: 1,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
|
log: [],
|
|
},
|
|
];
|
|
mockFetchRemoteNodeTasks.mockResolvedValueOnce(mockTasks);
|
|
|
|
const { result } = renderHook(() =>
|
|
useRemoteNodeData("node_abc", { projectId: "proj_001", searchQuery: "test" }),
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledWith("node_abc", "proj_001", "test");
|
|
expect(result.current.tasks).toEqual(mockTasks);
|
|
});
|
|
|
|
it("does not forward searchQuery when undefined", async () => {
|
|
mockFetchRemoteNodeTasks.mockResolvedValueOnce([]);
|
|
|
|
const { result } = renderHook(() =>
|
|
useRemoteNodeData("node_abc", { projectId: "proj_001" }),
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledWith("node_abc", "proj_001", undefined);
|
|
});
|
|
|
|
it("refetches tasks when searchQuery changes", async () => {
|
|
const initialTasks = [
|
|
{
|
|
id: "FN-001",
|
|
title: "Initial Task",
|
|
description: "Initial description",
|
|
column: "todo" as const,
|
|
dependencies: [],
|
|
steps: [],
|
|
currentStep: 0,
|
|
size: "M" as const,
|
|
reviewLevel: 1,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
|
log: [],
|
|
},
|
|
];
|
|
const filteredTasks = [
|
|
{
|
|
id: "FN-002",
|
|
title: "Filtered Task",
|
|
description: "Filtered description",
|
|
column: "todo" as const,
|
|
dependencies: [],
|
|
steps: [],
|
|
currentStep: 0,
|
|
size: "M" as const,
|
|
reviewLevel: 1,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
|
log: [],
|
|
},
|
|
];
|
|
|
|
mockFetchRemoteNodeTasks
|
|
.mockResolvedValueOnce(initialTasks)
|
|
.mockResolvedValueOnce(filteredTasks);
|
|
|
|
const { result, rerender } = renderHook(
|
|
({ searchQuery }: { searchQuery?: string }) =>
|
|
useRemoteNodeData("node_abc", { projectId: "proj_001", searchQuery }),
|
|
{ initialProps: { searchQuery: undefined as string | undefined } },
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", undefined);
|
|
expect(result.current.tasks).toEqual(initialTasks);
|
|
|
|
// Update searchQuery
|
|
rerender({ searchQuery: "filtered" });
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(2);
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", "filtered");
|
|
expect(result.current.tasks).toEqual(filteredTasks);
|
|
});
|
|
|
|
it("refetches tasks when searchQuery is cleared", async () => {
|
|
const filteredTasks = [
|
|
{
|
|
id: "FN-001",
|
|
title: "Filtered Task",
|
|
description: "Filtered description",
|
|
column: "todo" as const,
|
|
dependencies: [],
|
|
steps: [],
|
|
currentStep: 0,
|
|
size: "M" as const,
|
|
reviewLevel: 1,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
|
log: [],
|
|
},
|
|
];
|
|
const allTasks = [
|
|
{
|
|
id: "FN-001",
|
|
title: "Filtered Task",
|
|
description: "Filtered description",
|
|
column: "todo" as const,
|
|
dependencies: [],
|
|
steps: [],
|
|
currentStep: 0,
|
|
size: "M" as const,
|
|
reviewLevel: 1,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
|
log: [],
|
|
},
|
|
{
|
|
id: "FN-002",
|
|
title: "Other Task",
|
|
description: "Other description",
|
|
column: "todo" as const,
|
|
dependencies: [],
|
|
steps: [],
|
|
currentStep: 0,
|
|
size: "M" as const,
|
|
reviewLevel: 1,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
|
log: [],
|
|
},
|
|
];
|
|
|
|
mockFetchRemoteNodeTasks
|
|
.mockResolvedValueOnce(filteredTasks)
|
|
.mockResolvedValueOnce(allTasks);
|
|
|
|
const { result, rerender } = renderHook(
|
|
({ searchQuery }: { searchQuery?: string }) =>
|
|
useRemoteNodeData("node_abc", { projectId: "proj_001", searchQuery }),
|
|
{ initialProps: { searchQuery: "filtered" } },
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", "filtered");
|
|
expect(result.current.tasks).toEqual(filteredTasks);
|
|
|
|
// Clear searchQuery
|
|
rerender({ searchQuery: "" });
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(2);
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", "");
|
|
expect(result.current.tasks).toEqual(allTasks);
|
|
});
|
|
|
|
it("refresh function re-fetches with current searchQuery", async () => {
|
|
const mockTasks = [
|
|
{
|
|
id: "FN-001",
|
|
title: "Test Task",
|
|
description: "Test description",
|
|
column: "todo" as const,
|
|
dependencies: [],
|
|
steps: [],
|
|
currentStep: 0,
|
|
size: "M" as const,
|
|
reviewLevel: 1,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
|
log: [],
|
|
},
|
|
];
|
|
|
|
mockFetchRemoteNodeTasks
|
|
.mockResolvedValueOnce(mockTasks)
|
|
.mockResolvedValueOnce(mockTasks);
|
|
|
|
const { result } = renderHook(() =>
|
|
useRemoteNodeData("node_abc", { projectId: "proj_001", searchQuery: "test" }),
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", "test");
|
|
|
|
// Call refresh
|
|
result.current.refresh();
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(2);
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenLastCalledWith("node_abc", "proj_001", "test");
|
|
});
|
|
});
|
|
|
|
describe("useRemoteNodeData", () => {
|
|
beforeEach(() => {
|
|
mockFetchRemoteNodeHealth.mockReset();
|
|
mockFetchRemoteNodeProjects.mockReset();
|
|
mockFetchRemoteNodeTasks.mockReset();
|
|
mockFetchRemoteNodeProjectHealth.mockReset();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe("when nodeId is null", () => {
|
|
it("returns empty state without fetching", () => {
|
|
const { result } = renderHook(() => useRemoteNodeData(null));
|
|
|
|
expect(result.current.projects).toEqual([]);
|
|
expect(result.current.tasks).toEqual([]);
|
|
expect(result.current.health).toBe(null);
|
|
expect(result.current.loading).toBe(false);
|
|
expect(result.current.error).toBe(null);
|
|
|
|
// No API calls should have been made
|
|
expect(mockFetchRemoteNodeHealth).not.toHaveBeenCalled();
|
|
expect(mockFetchRemoteNodeProjects).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("returns empty state with projectId option but no nodeId", () => {
|
|
const { result } = renderHook(() => useRemoteNodeData(null, { projectId: "proj_001" }));
|
|
|
|
expect(result.current.projects).toEqual([]);
|
|
expect(result.current.tasks).toEqual([]);
|
|
expect(result.current.loading).toBe(false);
|
|
expect(result.current.error).toBe(null);
|
|
|
|
// No API calls should have been made
|
|
expect(mockFetchRemoteNodeHealth).not.toHaveBeenCalled();
|
|
expect(mockFetchRemoteNodeTasks).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("when nodeId is provided", () => {
|
|
it("fetches health and projects on mount", async () => {
|
|
const mockHealth = { status: "online", version: "1.0.0", nodeId: "node_abc" };
|
|
const mockProjects = [
|
|
{
|
|
id: "proj_001",
|
|
name: "Test Project",
|
|
path: "/test/path",
|
|
status: "active" as const,
|
|
isolationMode: "in-process" as const,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
},
|
|
];
|
|
|
|
mockFetchRemoteNodeHealth.mockResolvedValueOnce(mockHealth);
|
|
mockFetchRemoteNodeProjects.mockResolvedValueOnce(mockProjects);
|
|
|
|
const { result } = renderHook(() => useRemoteNodeData("node_abc"));
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeHealth).toHaveBeenCalledTimes(1);
|
|
expect(mockFetchRemoteNodeHealth).toHaveBeenCalledWith("node_abc");
|
|
expect(mockFetchRemoteNodeProjects).toHaveBeenCalledTimes(1);
|
|
expect(mockFetchRemoteNodeProjects).toHaveBeenCalledWith("node_abc");
|
|
expect(result.current.health).toEqual(mockHealth);
|
|
expect(result.current.projects).toEqual(mockProjects);
|
|
});
|
|
|
|
it("fetches tasks and project health when projectId option is provided", async () => {
|
|
const mockHealth = { status: "online", version: "1.0.0", nodeId: "node_abc" };
|
|
const mockProjects = [
|
|
{
|
|
id: "proj_001",
|
|
name: "Test Project",
|
|
path: "/test/path",
|
|
status: "active" as const,
|
|
isolationMode: "in-process" as const,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
},
|
|
];
|
|
const mockTasks = [
|
|
{
|
|
id: "FN-001",
|
|
title: "Test Task",
|
|
description: "Test description",
|
|
column: "todo" as const,
|
|
dependencies: [],
|
|
steps: [],
|
|
currentStep: 0,
|
|
size: "M" as const,
|
|
reviewLevel: 1,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
columnMovedAt: "2026-01-01T00:00:00.000Z",
|
|
log: [],
|
|
},
|
|
];
|
|
const mockProjectHealth = {
|
|
projectId: "proj_001",
|
|
activeTaskCount: 5,
|
|
inFlightAgentCount: 2,
|
|
status: "active" as const,
|
|
totalTasksCompleted: 0,
|
|
totalTasksFailed: 0,
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
};
|
|
|
|
mockFetchRemoteNodeHealth.mockResolvedValueOnce(mockHealth);
|
|
mockFetchRemoteNodeProjects.mockResolvedValueOnce(mockProjects);
|
|
mockFetchRemoteNodeTasks.mockResolvedValueOnce(mockTasks);
|
|
mockFetchRemoteNodeProjectHealth.mockResolvedValueOnce(mockProjectHealth);
|
|
|
|
const { result } = renderHook(() =>
|
|
useRemoteNodeData("node_abc", { projectId: "proj_001" }),
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledTimes(1);
|
|
expect(mockFetchRemoteNodeTasks).toHaveBeenCalledWith("node_abc", "proj_001", undefined);
|
|
expect(mockFetchRemoteNodeProjectHealth).toHaveBeenCalledTimes(1);
|
|
expect(mockFetchRemoteNodeProjectHealth).toHaveBeenCalledWith("node_abc", "proj_001");
|
|
expect(result.current.tasks).toEqual(mockTasks);
|
|
});
|
|
|
|
it("handles errors gracefully", async () => {
|
|
mockFetchRemoteNodeHealth.mockResolvedValueOnce({
|
|
status: "online",
|
|
version: "1.0.0",
|
|
nodeId: "node_abc",
|
|
});
|
|
mockFetchRemoteNodeProjects.mockRejectedValueOnce(new Error("Failed to fetch projects"));
|
|
|
|
const { result } = renderHook(() => useRemoteNodeData("node_abc"));
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(result.current.error).toContain("Failed to fetch projects");
|
|
});
|
|
|
|
it("handles health fetch errors", async () => {
|
|
mockFetchRemoteNodeHealth.mockRejectedValueOnce(new Error("Health check failed"));
|
|
|
|
const { result } = renderHook(() => useRemoteNodeData("node_abc"));
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(result.current.error).toContain("Health check failed");
|
|
});
|
|
|
|
it("refresh function re-fetches data", async () => {
|
|
const initialHealth = { status: "online", version: "1.0.0", nodeId: "node_abc" };
|
|
const initialProjects = [
|
|
{
|
|
id: "proj_001",
|
|
name: "Test Project",
|
|
path: "/test/path",
|
|
status: "active" as const,
|
|
isolationMode: "in-process" as const,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
},
|
|
];
|
|
|
|
mockFetchRemoteNodeHealth.mockResolvedValueOnce(initialHealth);
|
|
mockFetchRemoteNodeProjects.mockResolvedValueOnce(initialProjects);
|
|
|
|
const { result } = renderHook(() => useRemoteNodeData("node_abc"));
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(result.current.health).toEqual(initialHealth);
|
|
|
|
// Set up new responses for refresh
|
|
const refreshedHealth = { status: "online", version: "1.1.0", nodeId: "node_abc" };
|
|
const refreshedProjects = [
|
|
{
|
|
id: "proj_002",
|
|
name: "New Project",
|
|
path: "/new/path",
|
|
status: "active" as const,
|
|
isolationMode: "in-process" as const,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
},
|
|
];
|
|
mockFetchRemoteNodeHealth.mockResolvedValueOnce(refreshedHealth);
|
|
mockFetchRemoteNodeProjects.mockResolvedValueOnce(refreshedProjects);
|
|
|
|
// Call refresh
|
|
result.current.refresh();
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.health).toEqual(refreshedHealth);
|
|
});
|
|
|
|
expect(result.current.projects).toEqual(refreshedProjects);
|
|
});
|
|
|
|
it("refetches when nodeId changes", async () => {
|
|
const mockHealth = { status: "online", version: "1.0.0", nodeId: "node_abc" };
|
|
const mockProjects = [
|
|
{
|
|
id: "proj_001",
|
|
name: "Test Project",
|
|
path: "/test/path",
|
|
status: "active" as const,
|
|
isolationMode: "in-process" as const,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
},
|
|
];
|
|
|
|
mockFetchRemoteNodeHealth.mockResolvedValue(mockHealth);
|
|
mockFetchRemoteNodeProjects.mockResolvedValue(mockProjects);
|
|
|
|
const { result, rerender } = renderHook(
|
|
({ nodeId }: { nodeId: string | null }) => useRemoteNodeData(nodeId),
|
|
{ initialProps: { nodeId: "node_abc" } },
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
expect(mockFetchRemoteNodeHealth).toHaveBeenCalledTimes(1);
|
|
|
|
// Change nodeId
|
|
rerender({ nodeId: "node_xyz" });
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
// Should have fetched for the new nodeId
|
|
expect(mockFetchRemoteNodeHealth).toHaveBeenCalledTimes(2);
|
|
expect(mockFetchRemoteNodeHealth).toHaveBeenLastCalledWith("node_xyz");
|
|
});
|
|
});
|
|
});
|