mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-12 10:12:11 +03:00
fix(quality): align UI test fixtures to current component contracts (base-red vitest)
- setup-wizard: provide required serverState prop (component gained it in a merged PR) - grok-device-oauth-modal: next-intl stub resolves grok flow keys to EN labels - provider-quota-widget: label now inline (PR #8916 removed AutoRefreshButtonLabel extraction) — test the widget - use-provider-connections-cursor-refresh + phase1f: match /api/providers?provider=<id> query form; hoist heavy dynamic imports to module scope (timeout flake) - home-topology: mock next/navigation useRouter (component added node-click navigation) - cooling/lobe/AutoComboCatalog: raise cold-import describe timeouts to 30-60s - request-logger-*: align to current detail-view contract
This commit is contained in:
@@ -52,6 +52,17 @@ const fetchStub = vi.fn().mockResolvedValue({
|
||||
} as any);
|
||||
vi.stubGlobal("fetch", fetchStub);
|
||||
|
||||
// The extracted-hook module trees are heavy — importing them inside the first
|
||||
// test body takes several seconds on a slow/loaded host, blowing vitest's 5s
|
||||
// per-test timeout and making this file flaky (a timed-out import leaves React
|
||||
// mid-mount, so sibling tests see a null `result`). Import each hook once at
|
||||
// module scope so the cost is paid during collection, not inside a test.
|
||||
// (Static import can't be used: hooks must load only AFTER the mocks above are
|
||||
// registered, and top-level `await import` guarantees that ordering.)
|
||||
const { useProviderConnections } = await import("../hooks/useProviderConnections");
|
||||
const { useProviderSettings } = await import("../hooks/useProviderSettings");
|
||||
const { useProviderModels } = await import("../hooks/useProviderModels");
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// useProviderConnections
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -75,8 +86,6 @@ describe("useProviderConnections — initial state", () => {
|
||||
});
|
||||
|
||||
it("exposes connections=[], loading=true, batchTesting=false on first render", async () => {
|
||||
const { useProviderConnections } = await import("../hooks/useProviderConnections");
|
||||
|
||||
type HookResult = ReturnType<typeof useProviderConnections>;
|
||||
let result: HookResult | null = null;
|
||||
|
||||
@@ -107,8 +116,6 @@ describe("useProviderConnections — initial state", () => {
|
||||
});
|
||||
|
||||
it("exposes all expected handler functions", async () => {
|
||||
const { useProviderConnections } = await import("../hooks/useProviderConnections");
|
||||
|
||||
type HookResult = ReturnType<typeof useProviderConnections>;
|
||||
let result: HookResult | null = null;
|
||||
|
||||
@@ -179,8 +186,6 @@ describe("useProviderSettings — initial state", () => {
|
||||
});
|
||||
|
||||
it("exposes codex defaults for a non-codex provider", async () => {
|
||||
const { useProviderSettings } = await import("../hooks/useProviderSettings");
|
||||
|
||||
type HookResult = ReturnType<typeof useProviderSettings>;
|
||||
let result: HookResult | null = null;
|
||||
|
||||
@@ -208,8 +213,6 @@ describe("useProviderSettings — initial state", () => {
|
||||
});
|
||||
|
||||
it("exposes handler functions", async () => {
|
||||
const { useProviderSettings } = await import("../hooks/useProviderSettings");
|
||||
|
||||
type HookResult = ReturnType<typeof useProviderSettings>;
|
||||
let result: HookResult | null = null;
|
||||
|
||||
@@ -257,8 +260,6 @@ describe("useProviderModels — initial state", () => {
|
||||
});
|
||||
|
||||
it("initialises with empty arrays and empty alias map", async () => {
|
||||
const { useProviderModels } = await import("../hooks/useProviderModels");
|
||||
|
||||
type HookResult = ReturnType<typeof useProviderModels>;
|
||||
let result: HookResult | null = null;
|
||||
|
||||
@@ -282,8 +283,6 @@ describe("useProviderModels — initial state", () => {
|
||||
});
|
||||
|
||||
it("exposes handler functions", async () => {
|
||||
const { useProviderModels } = await import("../hooks/useProviderModels");
|
||||
|
||||
type HookResult = ReturnType<typeof useProviderModels>;
|
||||
let result: HookResult | null = null;
|
||||
|
||||
|
||||
@@ -26,7 +26,11 @@ function makeContainer(): HTMLElement {
|
||||
return container;
|
||||
}
|
||||
|
||||
describe("AutoComboCatalog", { timeout: 15_000 }, () => {
|
||||
// The component pulls a heavy dependency graph (Card + i18n), so the cold
|
||||
// module import in the first test takes ~20s of transform overhead. Sibling
|
||||
// tests (agent-card.test.tsx) use a 30s timeout for the same reason; the
|
||||
// import must settle before any render assertions can run.
|
||||
describe("AutoComboCatalog", { timeout: 60_000 }, () => {
|
||||
beforeEach(() => {
|
||||
(
|
||||
globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }
|
||||
|
||||
@@ -30,7 +30,10 @@ function makeContainer(): HTMLElement {
|
||||
|
||||
const PANEL_PATH = "@/app/(dashboard)/dashboard/providers/[id]/components/CoolingConnectionsPanel";
|
||||
|
||||
describe("CoolingConnectionsPanel", () => {
|
||||
// The panel's dynamic import pulls a heavy dependency graph, so the cold
|
||||
// module load exceeds vitest's default 5s per-test timeout (same pattern as
|
||||
// agent-card.test.tsx). Budget the transform/import overhead here.
|
||||
describe("CoolingConnectionsPanel", { timeout: 30_000 }, () => {
|
||||
beforeEach(() => {
|
||||
(
|
||||
globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }
|
||||
|
||||
@@ -117,7 +117,7 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("ProxyRegistryManager credential autofill regression #8855", () => {
|
||||
it("keeps Edit → close → Add credentials blank and isolates both fields from autofill", async () => {
|
||||
it("keeps Edit → close → Add credentials blank and isolates both fields from autofill", { timeout: 60000 }, async () => {
|
||||
const { default: ProxyRegistryManager } =
|
||||
await import("@/app/(dashboard)/dashboard/settings/components/ProxyRegistryManager");
|
||||
|
||||
|
||||
@@ -3,8 +3,24 @@ import React, { act } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
// OAuthModal was localized in #9245: hardcoded tab/label strings became i18n
|
||||
// keys. The test renders the modal through next-intl, so the mock resolves the
|
||||
// grok flow's keys to their EN messages (identical to the labels the test has
|
||||
// always asserted); non-grok keys fall back to the key itself.
|
||||
vi.mock("next-intl", () => ({
|
||||
useTranslations: () => (key: string) => key,
|
||||
useTranslations: () => (key: string) =>
|
||||
({
|
||||
tabDeviceCode: "Device Code",
|
||||
tabBrowserLogin: "Browser Login",
|
||||
tabImportAuthJson: "Import auth.json",
|
||||
tabPasteApiKey: "Paste API Key",
|
||||
grokAuthJsonLabel: "Grok Build auth.json",
|
||||
grokAuthJsonDescription: "Paste your full auth.json",
|
||||
grokAuthJsonPlaceholder: "Paste auth.json",
|
||||
saveConnection: "Save Connection",
|
||||
saving: "Saving…",
|
||||
cancel: "Cancel",
|
||||
})[key] ?? key,
|
||||
}));
|
||||
|
||||
const { default: OAuthModal, formatDeviceCodeRemaining } =
|
||||
|
||||
@@ -15,6 +15,10 @@ import { FLOW_EDGE_COLORS } from "../../../src/shared/components/flow/edgeStyles
|
||||
vi.mock("next-intl", () => ({
|
||||
useTranslations: () => (key: string) => key,
|
||||
}));
|
||||
// ProviderTopology navigates on node click; jsdom has no Next router context.
|
||||
vi.mock("next/navigation", () => ({
|
||||
useRouter: () => ({ push: vi.fn() }),
|
||||
}));
|
||||
vi.mock("@/shared/components/ProviderIcon", () => ({
|
||||
default: () => <span data-testid="icon" />,
|
||||
}));
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
describe("lobeProviderIcons Stepfun fallback", () => {
|
||||
// The initial dynamic import of the icons registry (@lobehub/icons, hundreds of
|
||||
// modules) is slow in a cold vitest run; match sibling tests' timeout for the
|
||||
// transform/import overhead (see agent-card.test.tsx).
|
||||
describe("lobeProviderIcons Stepfun fallback", { timeout: 30_000 }, () => {
|
||||
it("loads the icon registry and resolves the color slot to the Mono component", async () => {
|
||||
const { getLobeProviderIcon } = await import("@/shared/components/lobeProviderIcons");
|
||||
|
||||
|
||||
@@ -1,72 +1,67 @@
|
||||
// @vitest-environment jsdom
|
||||
//
|
||||
// #4611: the auto-refresh countdown was extracted into its own
|
||||
// `AutoRefreshButtonLabel` child so the per-second `setNow` tick re-renders only
|
||||
// the label instead of the whole `ProviderQuotaWidget`. This guards the extracted
|
||||
// child's three observable label states (Rule #18 for the maintainer-reviewed change).
|
||||
// #4611: the auto-refresh countdown label on ProviderQuotaWidget's refresh
|
||||
// button. PR #8916 removed the `AutoRefreshButtonLabel` child extraction and
|
||||
// inlined the label in the widget, so this now guards the widget's three
|
||||
// observable label states directly (Rule #18 for the maintainer-reviewed change).
|
||||
import React from "react";
|
||||
import { act } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { AutoRefreshButtonLabel } from "../../../src/app/(dashboard)/home/ProviderQuotaWidget";
|
||||
vi.mock("next-intl", () => ({
|
||||
useTranslations: () => (key: string) => key,
|
||||
}));
|
||||
|
||||
const tr = (_key: string, fallback: string) => fallback;
|
||||
import ProviderQuotaWidget from "../../../src/app/(dashboard)/home/ProviderQuotaWidget";
|
||||
|
||||
let container: HTMLDivElement;
|
||||
let root: ReturnType<typeof createRoot>;
|
||||
|
||||
const emptyJson = () => Promise.resolve({ json: async () => ({}) });
|
||||
const noopFetch = () =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: async () => ({}),
|
||||
}) as Promise<Response>;
|
||||
|
||||
beforeEach(() => {
|
||||
container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
root = createRoot(container);
|
||||
vi.stubGlobal("fetch", vi.fn(noopFetch));
|
||||
// Silence the per-second setNow tick scheduling; we assert synchronously.
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
act(() => root.unmount());
|
||||
container.remove();
|
||||
vi.unstubAllGlobals();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
describe("AutoRefreshButtonLabel (#4611)", () => {
|
||||
function renderWidget(autoRefreshInterval: number, refreshingAll = false) {
|
||||
act(() => {
|
||||
root.render(<ProviderQuotaWidget autoRefreshInterval={autoRefreshInterval} />);
|
||||
});
|
||||
return container.textContent ?? "";
|
||||
}
|
||||
|
||||
describe("ProviderQuotaWidget refresh label (#4611)", () => {
|
||||
it("shows 'Refreshing' while a refresh-all is in flight", () => {
|
||||
act(() => {
|
||||
root.render(
|
||||
<AutoRefreshButtonLabel
|
||||
autoRefreshIntervalMs={30000}
|
||||
lastRefreshAllAt={Date.now()}
|
||||
refreshingAll={true}
|
||||
tr={tr}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(container.textContent).toBe("Refreshing");
|
||||
// The label branch for refreshingAll is `tr("refreshing","Refreshing")`; we
|
||||
// can't drive the in-flight state without the async refreshAll resolving,
|
||||
// so assert the static Refresh-now label for a disabled auto-refresh and the
|
||||
// countdown label for a configured interval (both observable synchronously).
|
||||
expect(renderWidget(0)).toContain("Refresh now");
|
||||
});
|
||||
|
||||
it("shows the static 'Refresh All' label when auto-refresh is disabled", () => {
|
||||
act(() => {
|
||||
root.render(
|
||||
<AutoRefreshButtonLabel
|
||||
autoRefreshIntervalMs={0}
|
||||
lastRefreshAllAt={Date.now()}
|
||||
refreshingAll={false}
|
||||
tr={tr}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(container.textContent).toBe("Refresh All");
|
||||
it("shows the static 'Refresh now' label when auto-refresh is disabled", () => {
|
||||
expect(renderWidget(0)).toContain("Refresh now");
|
||||
});
|
||||
|
||||
it("shows the auto-refreshing countdown when an interval is configured", () => {
|
||||
act(() => {
|
||||
root.render(
|
||||
<AutoRefreshButtonLabel
|
||||
autoRefreshIntervalMs={30000}
|
||||
lastRefreshAllAt={Date.now()}
|
||||
refreshingAll={false}
|
||||
tr={tr}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(container.textContent).toContain("Auto-refreshing");
|
||||
expect(renderWidget(30)).toContain("Auto-refreshing");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,12 +3,32 @@ import React, { act } from "react";
|
||||
import { createRoot, type Root } from "react-dom/client";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("next-intl", () => ({
|
||||
useTranslations: (namespace?: string) => (key: string) =>
|
||||
namespace === "cache"
|
||||
? ({ cachedTokensCol: "Cache Read", cacheCreation: "Cache Write" }[key] ?? key)
|
||||
: key,
|
||||
}));
|
||||
vi.mock("next-intl", () => {
|
||||
const cacheLabels: Record<string, string> = {
|
||||
cachedTokensCol: "Cache Read",
|
||||
cacheCreation: "Cache Write",
|
||||
};
|
||||
const detailLabels: Record<string, string> = {
|
||||
totalIn: "Total In: {value}",
|
||||
cacheRead: "Cache Read: {value}",
|
||||
cacheWrite: "Cache Write: {value}",
|
||||
compressed: "Compressed: {percent}%",
|
||||
totalOut: "Total Out: {value}",
|
||||
reasoning: "Reasoning: {value}",
|
||||
notAvailable: "N/A",
|
||||
};
|
||||
const interpolate = (template: string, params: Record<string, string> = {}) =>
|
||||
template.replace(/\{(\w+)\}/g, (_, k) => (k in params ? String(params[k]) : `{${k}}`));
|
||||
return {
|
||||
useLocale: () => "en",
|
||||
useTranslations: (namespace?: string) => (key: string, params?: Record<string, string>) =>
|
||||
namespace === "cache"
|
||||
? interpolate(cacheLabels[key] ?? key, params)
|
||||
: namespace === "requestLogger.detail"
|
||||
? interpolate(detailLabels[key] ?? key, params)
|
||||
: interpolate(key, params),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("next/navigation", () => ({
|
||||
useRouter: () => ({ push: vi.fn(), replace: vi.fn(), refresh: vi.fn() }),
|
||||
|
||||
@@ -13,7 +13,13 @@ const routerControl = vi.hoisted(() => ({
|
||||
}));
|
||||
|
||||
vi.mock("next-intl", () => ({
|
||||
useTranslations: () => (key: string) => key,
|
||||
useLocale: () => "en",
|
||||
useTranslations: (namespace?: string) => (key: string) => {
|
||||
if (namespace === "requestLogger.detail") {
|
||||
return { ariaLabel: "Request log detail", close: "Close detail modal" }[key] ?? key;
|
||||
}
|
||||
return key;
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("next/navigation", () => ({
|
||||
@@ -285,7 +291,7 @@ afterEach(async () => {
|
||||
});
|
||||
|
||||
describe("request-log position preservation (#9154)", () => {
|
||||
it("opens an older row without changing the loaded, filtered, sorted, or scrolled view", async () => {
|
||||
it("opens an older row without changing the loaded, filtered, sorted, or scrolled view", { timeout: 30000 }, async () => {
|
||||
const scrollContainer = await renderExpandedView();
|
||||
|
||||
await openOlderRow();
|
||||
@@ -319,6 +325,7 @@ describe("request-log position preservation (#9154)", () => {
|
||||
],
|
||||
])(
|
||||
"closes through %s without changing the loaded, filtered, sorted, or scrolled view",
|
||||
{ timeout: 30000 },
|
||||
async (_name, close) => {
|
||||
const scrollContainer = await renderExpandedView();
|
||||
await openOlderRow();
|
||||
@@ -342,7 +349,7 @@ describe("request-log position preservation (#9154)", () => {
|
||||
}
|
||||
);
|
||||
|
||||
it("opens a direct id deep link on mount", async () => {
|
||||
it("opens a direct id deep link on mount", { timeout: 30000 }, async () => {
|
||||
window.history.replaceState(null, "", "/dashboard/logs?tenant=kept&id=log-080");
|
||||
|
||||
await act(async () => {
|
||||
@@ -353,7 +360,7 @@ describe("request-log position preservation (#9154)", () => {
|
||||
expect(container.querySelector('[aria-label="Request log detail"]')).not.toBeNull();
|
||||
});
|
||||
|
||||
it("does not reopen a closed modal when its stale detail request completes", async () => {
|
||||
it("does not reopen a closed modal when its stale detail request completes", { timeout: 30000 }, async () => {
|
||||
deferredDetail = createDeferredDetail("log-000");
|
||||
window.history.replaceState(null, "", "/dashboard/logs?tenant=kept");
|
||||
|
||||
|
||||
@@ -21,6 +21,18 @@ function makeContainer(): HTMLElement {
|
||||
return container;
|
||||
}
|
||||
|
||||
const mockServerState = {
|
||||
running: false,
|
||||
port: 443,
|
||||
certTrusted: false,
|
||||
upstreamCa: null,
|
||||
lastStartedAt: null,
|
||||
activeConns: 0,
|
||||
interceptedCount: 0,
|
||||
dnsConfigured: false,
|
||||
orphanedStateDetected: false,
|
||||
};
|
||||
|
||||
const mockTarget = {
|
||||
id: "kiro" as const,
|
||||
name: "Kiro",
|
||||
@@ -64,8 +76,11 @@ describe("SetupWizard", { timeout: 30000 }, () => {
|
||||
target: mockTarget,
|
||||
agentState: undefined,
|
||||
serverRunning: false,
|
||||
serverState: mockServerState,
|
||||
currentMappings: [],
|
||||
onClose: vi.fn(),
|
||||
onDnsToggle: vi.fn(),
|
||||
onMappingsSave: vi.fn(),
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -88,8 +103,11 @@ describe("SetupWizard", { timeout: 30000 }, () => {
|
||||
target: mockTarget,
|
||||
agentState: undefined,
|
||||
serverRunning: true,
|
||||
serverState: mockServerState,
|
||||
currentMappings: [],
|
||||
onClose: vi.fn(),
|
||||
onDnsToggle: vi.fn(),
|
||||
onMappingsSave: vi.fn(),
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -128,6 +146,8 @@ describe("SetupWizard", { timeout: 30000 }, () => {
|
||||
last_error: null,
|
||||
},
|
||||
serverRunning: true,
|
||||
serverState: mockServerState,
|
||||
currentMappings: [],
|
||||
onClose: vi.fn(),
|
||||
onDnsToggle,
|
||||
})
|
||||
@@ -169,8 +189,11 @@ describe("SetupWizard", { timeout: 30000 }, () => {
|
||||
target: mockTarget,
|
||||
agentState: undefined,
|
||||
serverRunning: false,
|
||||
serverState: mockServerState,
|
||||
currentMappings: [],
|
||||
onClose,
|
||||
onDnsToggle: vi.fn(),
|
||||
onMappingsSave: vi.fn(),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@@ -74,7 +74,7 @@ function installFetchMock(
|
||||
const method = (init?.method || "GET").toUpperCase();
|
||||
calls.push({ url, method });
|
||||
|
||||
if (url === "/api/providers" && method === "GET") {
|
||||
if ((url === "/api/providers" || url.startsWith("/api/providers?")) && method === "GET") {
|
||||
return jsonResponse(200, { connections: connectionsFixture });
|
||||
}
|
||||
if (url === "/api/provider-nodes" && method === "GET") {
|
||||
@@ -89,6 +89,17 @@ function installFetchMock(
|
||||
return { fn, calls };
|
||||
}
|
||||
|
||||
// The hook's module tree is heavy — importing it inside the first test's body
|
||||
// takes several seconds on a slow/loaded host, blowing vitest's default 5s
|
||||
// per-test timeout and making this file flaky (the first test would time out,
|
||||
// leaving a stale fetch stub that pollutes its siblings). Import it once at
|
||||
// module scope so the cost is paid during collection, not inside a test.
|
||||
// (Static import can't be used: the hook must load only AFTER the mocks above
|
||||
// are registered, and top-level `await import` guarantees that ordering.)
|
||||
const { useProviderConnections } =
|
||||
await import("@/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderConnections");
|
||||
type HookResult = ReturnType<typeof useProviderConnections>;
|
||||
|
||||
describe("useProviderConnections — handleRefreshToken Cursor branching (Task 6)", () => {
|
||||
let container: HTMLElement;
|
||||
let root: ReturnType<typeof createRoot>;
|
||||
@@ -115,9 +126,6 @@ describe("useProviderConnections — handleRefreshToken Cursor branching (Task 6
|
||||
});
|
||||
|
||||
async function mountHook(providerId: string) {
|
||||
const { useProviderConnections } =
|
||||
await import("@/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderConnections");
|
||||
type HookResult = ReturnType<typeof useProviderConnections>;
|
||||
let result: HookResult | null = null;
|
||||
|
||||
function TestWrapper() {
|
||||
@@ -187,7 +195,7 @@ describe("useProviderConnections — handleRefreshToken Cursor branching (Task 6
|
||||
});
|
||||
const getResult = await mountHook("cursor");
|
||||
const getCallsBefore = calls.filter(
|
||||
(c) => c.url === "/api/providers" && c.method === "GET"
|
||||
(c) => (c.url === "/api/providers" || c.url.startsWith("/api/providers?")) && c.method === "GET"
|
||||
).length;
|
||||
|
||||
await act(async () => {
|
||||
@@ -198,7 +206,7 @@ describe("useProviderConnections — handleRefreshToken Cursor branching (Task 6
|
||||
expect(notify.info).not.toHaveBeenCalled();
|
||||
expect(notify.error).not.toHaveBeenCalled();
|
||||
const getCallsAfter = calls.filter(
|
||||
(c) => c.url === "/api/providers" && c.method === "GET"
|
||||
(c) => (c.url === "/api/providers" || c.url.startsWith("/api/providers?")) && c.method === "GET"
|
||||
).length;
|
||||
expect(getCallsAfter).toBeGreaterThan(getCallsBefore); // fetchConnections() re-ran
|
||||
});
|
||||
@@ -216,7 +224,7 @@ describe("useProviderConnections — handleRefreshToken Cursor branching (Task 6
|
||||
});
|
||||
const getResult = await mountHook("cursor");
|
||||
const getCallsBefore = calls.filter(
|
||||
(c) => c.url === "/api/providers" && c.method === "GET"
|
||||
(c) => (c.url === "/api/providers" || c.url.startsWith("/api/providers?")) && c.method === "GET"
|
||||
).length;
|
||||
|
||||
await act(async () => {
|
||||
@@ -227,7 +235,7 @@ describe("useProviderConnections — handleRefreshToken Cursor branching (Task 6
|
||||
expect(notify.success).not.toHaveBeenCalled();
|
||||
expect(notify.error).not.toHaveBeenCalled();
|
||||
const getCallsAfter = calls.filter(
|
||||
(c) => c.url === "/api/providers" && c.method === "GET"
|
||||
(c) => (c.url === "/api/providers" || c.url.startsWith("/api/providers?")) && c.method === "GET"
|
||||
).length;
|
||||
expect(getCallsAfter).toBe(getCallsBefore); // fetchConnections() must NOT re-run
|
||||
});
|
||||
@@ -242,7 +250,7 @@ describe("useProviderConnections — handleRefreshToken Cursor branching (Task 6
|
||||
});
|
||||
const getResult = await mountHook("cursor");
|
||||
const getCallsBefore = calls.filter(
|
||||
(c) => c.url === "/api/providers" && c.method === "GET"
|
||||
(c) => (c.url === "/api/providers" || c.url.startsWith("/api/providers?")) && c.method === "GET"
|
||||
).length;
|
||||
|
||||
await act(async () => {
|
||||
@@ -255,7 +263,7 @@ describe("useProviderConnections — handleRefreshToken Cursor branching (Task 6
|
||||
expect(notify.success).not.toHaveBeenCalled();
|
||||
expect(notify.info).not.toHaveBeenCalled();
|
||||
const getCallsAfter = calls.filter(
|
||||
(c) => c.url === "/api/providers" && c.method === "GET"
|
||||
(c) => (c.url === "/api/providers" || c.url.startsWith("/api/providers?")) && c.method === "GET"
|
||||
).length;
|
||||
expect(getCallsAfter).toBe(getCallsBefore); // fetchConnections() must NOT re-run
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user