fix: pre-release fixes for code formatting, i18n, and test suite

- Run cargo fmt to fix Rust code formatting (lib.rs)
- Add missing i18n keys: migration.success, agents.title (zh/en/ja)
- Replace hardcoded strings "Agents" and "MCP" with t() calls in App.tsx
- Fix test mocks and assertions:
  - Add providersApi.updateTrayMenu to useSettings.test.tsx mock
  - Update SettingsPage mock path in App.test.tsx
  - Fix toast message assertion in integration/SettingsDialog.test.tsx
  - Add autoSaveSettings to SettingsDialog component test mock
  - Fix loading state test to check spinner instead of title
  - Update import button name matching for selected file state
  - Fix save button test to switch to advanced tab first
  - Remove obsolete cancel button test (button no longer exists)

Test results improved from 99 passed / 17 failed to 104 passed / 11 failed
This commit is contained in:
Jason
2025-11-28 15:53:25 +08:00
parent 00f78e4546
commit 3878a16c4f
9 changed files with 46 additions and 31 deletions
+4 -2
View File
@@ -71,7 +71,8 @@ impl TrayTexts {
},
"ja" => Self {
show_main: "メインウィンドウを開く",
no_provider_hint: " (プロバイダーがまだありません。メイン画面から追加してください)",
no_provider_hint:
" (プロバイダーがまだありません。メイン画面から追加してください)",
quit: "終了",
},
_ => Self {
@@ -521,7 +522,8 @@ pub fn run() {
unsafe {
use objc2::msg_send;
let _: () = msg_send![&*ns_window, setBackgroundColor: &*bg_color];
let _: () =
msg_send![&*ns_window, setBackgroundColor: &*bg_color];
}
} else {
log::warn!("Failed to retain NSWindow reference");
+2 -2
View File
@@ -391,7 +391,7 @@ function App() {
t("prompts.title", { appName: t(`apps.${activeApp}`) })}
{currentView === "skills" && t("skills.title")}
{currentView === "mcp" && t("mcp.unifiedPanel.title")}
{currentView === "agents" && "Agents"}
{currentView === "agents" && t("agents.title")}
</h1>
</div>
) : (
@@ -512,7 +512,7 @@ function App() {
size="sm"
onClick={() => setCurrentView("mcp")}
className="text-muted-foreground hover:text-foreground hover:bg-black/5 dark:hover:bg-white/5"
title="MCP"
title={t("mcp.title")}
>
<Server className="h-4 w-4" />
</Button>
+6
View File
@@ -833,5 +833,11 @@
"colorLabel": "Icon Color",
"selectIcon": "Select Icon",
"preview": "Preview"
},
"migration": {
"success": "Configuration migrated successfully"
},
"agents": {
"title": "Agents"
}
}
+6
View File
@@ -833,5 +833,11 @@
"colorLabel": "アイコンカラー",
"selectIcon": "アイコンを選択",
"preview": "プレビュー"
},
"migration": {
"success": "設定の移行が完了しました"
},
"agents": {
"title": "エージェント"
}
}
+6
View File
@@ -833,5 +833,11 @@
"colorLabel": "图标颜色",
"selectIcon": "选择图标",
"preview": "预览"
},
"migration": {
"success": "配置迁移成功"
},
"agents": {
"title": "智能体"
}
}
+15 -24
View File
@@ -35,6 +35,7 @@ interface SettingsMock {
resetDirectory: ReturnType<typeof vi.fn>;
resetAppConfigDir: ReturnType<typeof vi.fn>;
saveSettings: ReturnType<typeof vi.fn>;
autoSaveSettings: ReturnType<typeof vi.fn>;
resetSettings: ReturnType<typeof vi.fn>;
acknowledgeRestart: ReturnType<typeof vi.fn>;
}
@@ -66,6 +67,7 @@ const createSettingsMock = (overrides: Partial<SettingsMock> = {}) => {
resetDirectory: vi.fn(),
resetAppConfigDir: vi.fn(),
saveSettings: vi.fn().mockResolvedValue({ requiresRestart: false }),
autoSaveSettings: vi.fn().mockResolvedValue({ requiresRestart: false }),
resetSettings: vi.fn(),
acknowledgeRestart: vi.fn(),
};
@@ -247,7 +249,8 @@ describe("SettingsPage Component", () => {
render(<SettingsPage open={true} onOpenChange={vi.fn()} />);
expect(screen.queryByText("language:zh")).not.toBeInTheDocument();
expect(screen.getByText("settings.title")).toBeInTheDocument();
// 加载状态下显示 spinner 而不是表单内容
expect(document.querySelector(".animate-spin")).toBeInTheDocument();
});
it("should reset import/export status when dialog transitions to open", () => {
@@ -264,6 +267,7 @@ describe("SettingsPage Component", () => {
it("should render general and advanced tabs and trigger child callbacks", () => {
const onOpenChange = vi.fn();
// 设置 selectedFile 后,按钮显示 settings.import(可执行导入)
importExportMock = createImportExportMock({
selectedFile: "/tmp/config.json",
});
@@ -284,21 +288,20 @@ describe("SettingsPage Component", () => {
});
fireEvent.click(screen.getByText("settings.tabAdvanced"));
fireEvent.click(
screen.getByRole("button", { name: "settings.selectConfigFile" }),
);
expect(importExportMock.selectImportFile).toHaveBeenCalled();
// 有文件时,点击导入按钮执行 importConfig
fireEvent.click(
screen.getByRole("button", { name: /settings\.import/ }),
);
expect(importExportMock.importConfig).toHaveBeenCalled();
fireEvent.click(
screen.getByRole("button", { name: "settings.exportConfig" }),
);
expect(importExportMock.exportConfig).toHaveBeenCalled();
fireEvent.click(screen.getByRole("button", { name: "settings.import" }));
expect(importExportMock.importConfig).toHaveBeenCalled();
fireEvent.click(screen.getByRole("button", { name: "common.clear" }));
// 清除选择按钮
fireEvent.click(screen.getByRole("button", { name: "Clear selection" }));
expect(importExportMock.clearSelection).toHaveBeenCalled();
});
@@ -330,7 +333,9 @@ describe("SettingsPage Component", () => {
render(<SettingsPage open={true} onOpenChange={onOpenChange} />);
fireEvent.click(screen.getByText("common.save"));
// 保存按钮在 advanced tab 中
fireEvent.click(screen.getByText("settings.tabAdvanced"));
fireEvent.click(screen.getByRole("button", { name: /common\.save/ }));
await waitFor(() => {
expect(settingsMock.saveSettings).toHaveBeenCalledTimes(1);
@@ -341,20 +346,6 @@ describe("SettingsPage Component", () => {
});
});
it("should reset settings and close dialog when clicking cancel", () => {
const onOpenChange = vi.fn();
render(<SettingsPage open={true} onOpenChange={onOpenChange} />);
fireEvent.click(screen.getByText("common.cancel"));
expect(settingsMock.resetSettings).toHaveBeenCalledTimes(1);
expect(settingsMock.acknowledgeRestart).toHaveBeenCalledTimes(1);
expect(importExportMock.clearSelection).toHaveBeenCalledTimes(1);
expect(importExportMock.resetStatus).toHaveBeenCalledTimes(2);
expect(onOpenChange).toHaveBeenCalledWith(false);
});
it("should show restart prompt and allow immediate restart after save", async () => {
settingsMock = createSettingsMock({
requiresRestart: true,
+4
View File
@@ -8,6 +8,7 @@ const useSettingsQueryMock = vi.fn();
const setAppConfigDirOverrideMock = vi.fn();
const applyClaudePluginConfigMock = vi.fn();
const syncCurrentProvidersLiveMock = vi.fn();
const updateTrayMenuMock = vi.fn();
const toastErrorMock = vi.fn();
const toastSuccessMock = vi.fn();
@@ -52,6 +53,9 @@ vi.mock("@/lib/api", () => ({
syncCurrentProvidersLive: (...args: unknown[]) =>
syncCurrentProvidersLiveMock(...args),
},
providersApi: {
updateTrayMenu: (...args: unknown[]) => updateTrayMenuMock(...args),
},
}));
const createSettingsFormMock = (overrides: Record<string, unknown> = {}) => ({
+2 -2
View File
@@ -109,8 +109,8 @@ vi.mock("@/components/ConfirmDialog", () => ({
) : null,
}));
vi.mock("@/components/settings/SettingsDialog", () => ({
SettingsDialog: ({ open, onOpenChange, onImportSuccess }: any) =>
vi.mock("@/components/settings/SettingsPage", () => ({
SettingsPage: ({ open, onOpenChange, onImportSuccess }: any) =>
open ? (
<div data-testid="settings-dialog">
<button onClick={() => onImportSuccess?.()}>
+1 -1
View File
@@ -264,7 +264,7 @@ describe("SettingsPage integration", () => {
await waitFor(() => expect(toastErrorMock).toHaveBeenCalled());
const cancelMessage = toastErrorMock.mock.calls.at(-1)?.[0] as string;
expect(cancelMessage).toMatch(
/settings\.selectFileFailed|选择保存位置失败/,
/settings\.selectFileFailed|选择.*保存路径/,
);
toastErrorMock.mockClear();