mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-28 00:35:32 +08:00
fix(provider): distinguish legacy providers from db-only when tolerating live config errors
Change `ProviderMeta.live_config_managed` from `bool` to `Option<bool>` to introduce a three-state semantic: - `Some(true)`: provider has been written to live config - `Some(false)`: explicitly db-only, never written to live config - `None`: legacy data or unknown state (pre-existing providers) Previously, legacy providers defaulted to `live_config_managed = false` via `#[serde(default)]`, which silently swallowed live config parse errors. This could mask genuine configuration issues for providers that had actually been synced to live config before the field was introduced. Now, only providers with an explicit `Some(false)` marker tolerate parse errors; legacy `None` providers surface errors as before, preserving safety for already-managed configurations. Also wrap the `ensureQueryData` call for live provider IDs during duplication in a try/catch so that a malformed config file shows a user-facing toast instead of silently failing. Add tests for both the legacy error propagation path and the frontend duplication failure scenario.
This commit is contained in:
@@ -2,6 +2,7 @@ import { Suspense, type ComponentType } from "react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { render, screen, waitFor, fireEvent } from "@testing-library/react";
|
||||
import { describe, it, expect, beforeEach, vi } from "vitest";
|
||||
import { providersApi } from "@/lib/api/providers";
|
||||
import {
|
||||
resetProviderState,
|
||||
setCurrentProviderId,
|
||||
@@ -282,4 +283,52 @@ describe("App integration with MSW", () => {
|
||||
expect.stringContaining("Provider key is required for openclaw"),
|
||||
);
|
||||
});
|
||||
|
||||
it("shows toast when duplicate cannot load live provider ids", async () => {
|
||||
setProviders("openclaw", {
|
||||
deepseek: {
|
||||
id: "deepseek",
|
||||
name: "DeepSeek",
|
||||
settingsConfig: {
|
||||
baseUrl: "https://api.deepseek.com",
|
||||
apiKey: "test-key",
|
||||
api: "openai-completions",
|
||||
models: [],
|
||||
},
|
||||
category: "custom",
|
||||
sortIndex: 0,
|
||||
createdAt: Date.now(),
|
||||
},
|
||||
});
|
||||
setCurrentProviderId("openclaw", "deepseek");
|
||||
|
||||
const liveIdsSpy = vi
|
||||
.spyOn(providersApi, "getOpenClawLiveProviderIds")
|
||||
.mockRejectedValueOnce(new Error("broken config"));
|
||||
|
||||
const { default: App } = await import("@/App");
|
||||
renderApp(App);
|
||||
|
||||
fireEvent.click(screen.getByText("switch-openclaw"));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId("provider-list").textContent).toContain(
|
||||
"deepseek",
|
||||
),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByText("duplicate"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(toastErrorMock).toHaveBeenCalledWith(
|
||||
expect.stringContaining("读取配置中的供应商标识失败"),
|
||||
);
|
||||
});
|
||||
|
||||
expect(screen.getByTestId("provider-list").textContent).not.toContain(
|
||||
"deepseek-copy",
|
||||
);
|
||||
|
||||
liveIdsSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user