From 85db76e5ef0fdea80eca4ff534bf7838cb99e452 Mon Sep 17 00:00:00 2001 From: Molecule AI Core-UIUX Date: Tue, 12 May 2026 13:29:32 +0000 Subject: [PATCH] test(settings): add AddKeyForm + OrgTokensTab + SecretRow + SecretsTab coverage Cherry-picked from test/settings-tab-coverage (PRs #708/#726). - AddKeyForm: 340 lines, form validation + submission tests - OrgTokensTab: 407 lines, org token CRUD + display tests - SecretRow: 291 lines, secret display + reveal/copy/delete actions - SecretsTab: 308 lines, secrets list + empty state + add form Makes #704 a true superset of all settings test coverage. Co-Authored-By: Claude Opus 4.7 --- .../settings/__tests__/AddKeyForm.test.tsx | 340 +++++++++++++++ .../settings/__tests__/OrgTokensTab.test.tsx | 407 ++++++++++++++++++ .../settings/__tests__/SecretRow.test.tsx | 291 +++++++++++++ .../settings/__tests__/SecretsTab.test.tsx | 308 +++++++++++++ 4 files changed, 1346 insertions(+) create mode 100644 canvas/src/components/settings/__tests__/AddKeyForm.test.tsx create mode 100644 canvas/src/components/settings/__tests__/OrgTokensTab.test.tsx create mode 100644 canvas/src/components/settings/__tests__/SecretRow.test.tsx create mode 100644 canvas/src/components/settings/__tests__/SecretsTab.test.tsx diff --git a/canvas/src/components/settings/__tests__/AddKeyForm.test.tsx b/canvas/src/components/settings/__tests__/AddKeyForm.test.tsx new file mode 100644 index 00000000..bd5e1d79 --- /dev/null +++ b/canvas/src/components/settings/__tests__/AddKeyForm.test.tsx @@ -0,0 +1,340 @@ +// @vitest-environment jsdom +/** + * Tests for AddKeyForm — inline form for adding a new API key. + * + * Covers: + * - Header + key name + value fields rendered + * - Key name auto-uppercased on input + * - Validation: UPPER_SNAKE_CASE required, duplicate name blocked + * - Provider hint shown for known providers (GitHub, Anthropic, OpenRouter) + * - Provider hint hidden for custom key names + * - Debounced value validation + * - Save button disabled when form invalid / saving + * - createSecret called on save with correct args + * - onCancel called on Cancel click + * - Save error shown on failure + * - TestConnectionButton shown when value is format-valid and provider supports it + */ +import React from "react"; +import { render, screen, fireEvent, cleanup, act, waitFor } from "@testing-library/react"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { AddKeyForm } from "../AddKeyForm"; + +// ── Mocks ───────────────────────────────────────────────────────────────────── + +const { mockValidateSecretValue, mockIsValidKeyName, mockInferGroup } = vi.hoisted(() => ({ + mockValidateSecretValue: vi.fn((value: string) => { + // Return error for "bad-value" to test ValidationHint display + if (value === "bad-value") return "Invalid format"; + return null; + }), + mockIsValidKeyName: vi.fn((name: string) => /^[A-Z][A-Z0-9_]*$/.test(name)), + mockInferGroup: vi.fn((name: string) => { + const u = name.toUpperCase(); + if (u.includes("GITHUB")) return "github" as const; + if (u.includes("ANTHROPIC")) return "anthropic" as const; + if (u.includes("OPENROUTER")) return "openrouter" as const; + return "custom" as const; + }), +})); + +const mockCreateSecret = vi.fn(); + +vi.mock("@/stores/secrets-store", () => ({ + useSecretsStore: Object.assign( + vi.fn((selector?: (s: { createSecret: typeof mockCreateSecret }) => unknown) => + selector ? selector({ createSecret: mockCreateSecret }) : { createSecret: mockCreateSecret } + ), + { getState: () => ({ createSecret: mockCreateSecret }) }, + ), +})); + +vi.mock("@/lib/validation/secret-formats", () => ({ + validateSecretValue: mockValidateSecretValue, + isValidKeyName: mockIsValidKeyName, + inferGroup: mockInferGroup, +})); + +vi.mock("@/lib/services", () => ({ + SERVICES: { + github: { label: "GitHub", icon: "github", keyNames: [], docsUrl: "https://github.com", testSupported: true }, + anthropic: { label: "Anthropic", icon: "anthropic", keyNames: [], docsUrl: "https://anthropic.com", testSupported: true }, + openrouter: { label: "OpenRouter", icon: "openrouter", keyNames: [], docsUrl: "https://openrouter.ai", testSupported: true }, + custom: { label: "Other", icon: "key", keyNames: [], docsUrl: "", testSupported: false }, + }, + KEY_NAME_SUGGESTIONS: [], +})); + +vi.mock("@/components/ui/KeyValueField", () => ({ + KeyValueField: ({ value, onChange, disabled }: { value: string; onChange: (v: string) => void; disabled?: boolean }) => ( +