diff --git a/src/components/admin/connections/SecretField.utils.ts b/src/components/admin/connections/SecretField.utils.ts index 015feae88..57d0f2bd1 100644 --- a/src/components/admin/connections/SecretField.utils.ts +++ b/src/components/admin/connections/SecretField.utils.ts @@ -1,4 +1,4 @@ -import type { ConnectionType } from "@/hooks/intelligence"; +import type { ConnectionType } from '@/hooks/intelligence'; /** * Mapeia o `connectionId` (curto, usado nas abas) para a `ConnectionType` @@ -7,13 +7,13 @@ import type { ConnectionType } from "@/hooks/intelligence"; */ export function mapConnectionToTester( connectionId: string | undefined, -): { type: ConnectionType; envKey?: "promobrind" | "crm" } | null { +): { type: ConnectionType; envKey?: 'promobrind' | 'crm' } | null { if (!connectionId) return null; - if (connectionId === "n8n") return { type: "n8n" }; - if (connectionId === "bitrix24") return { type: "bitrix24" }; - if (connectionId === "mcp") return { type: "mcp" }; - if (connectionId === "promobrind" || connectionId === "crm") { - return { type: "supabase", envKey: connectionId }; + if (connectionId === 'n8n') return { type: 'n8n' }; + if (connectionId === 'bitrix24') return { type: 'bitrix24' }; + if (connectionId === 'mcp') return { type: 'mcp' }; + if (connectionId === 'promobrind' || connectionId === 'crm') { + return { type: 'supabase', envKey: connectionId }; } return null; } @@ -21,9 +21,9 @@ export function mapConnectionToTester( export function formatRelative(iso: string): string { const then = new Date(iso).getTime(); const diffMs = Date.now() - then; - if (Number.isNaN(then)) return ""; + if (Number.isNaN(then)) return ''; const sec = Math.floor(diffMs / 1000); - if (sec < 60) return "agora"; + if (sec < 60) return 'agora'; const min = Math.floor(sec / 60); if (min < 60) return `há ${min}m`; const hr = Math.floor(min / 60); @@ -38,14 +38,14 @@ export function formatRelative(iso: string): string { export function formatFullPtBr(iso: string): string { const date = new Date(iso); if (Number.isNaN(date.getTime())) return iso; - const fmt = new Intl.DateTimeFormat("pt-BR", { - day: "2-digit", - month: "2-digit", - year: "numeric", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - timeZoneName: "short", + const fmt = new Intl.DateTimeFormat('pt-BR', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + timeZoneName: 'short', }); return fmt.format(date); } @@ -56,19 +56,19 @@ export function formatFullPtBr(iso: string): string { export function buildUpdatedTooltip( updatedAt: string | null | undefined, updatedByEmail: string | null | undefined, - updatedById?: string | null | undefined, + updatedBy?: string | null | undefined, ): string | undefined { if (!updatedAt) return undefined; - + const dateStr = formatFullPtBr(updatedAt); const relative = formatRelative(updatedAt); - - let author = "sistema (sem autor registrado)"; + + let author = 'sistema (sem autor registrado)'; if (updatedByEmail) { author = updatedByEmail; - } else if (updatedById) { - author = `equipe (#${updatedById.substring(0, 8)})`; + } else if (updatedBy) { + author = `equipe (#${updatedBy.substring(0, 8)})`; } - + return `Atualizado ${relative}\n${dateStr}\npor ${author}`; } diff --git a/tests/components/admin/SecretField.a11y.test.tsx b/tests/components/admin/SecretField.a11y.test.tsx index 74912b2f1..d8ca5bc4e 100644 --- a/tests/components/admin/SecretField.a11y.test.tsx +++ b/tests/components/admin/SecretField.a11y.test.tsx @@ -7,16 +7,29 @@ import { axe } from "../../a11y/axe-helper"; const setSecretMock = vi.fn(); const rotateSecretMock = vi.fn(); const getRotationHistoryMock = vi.fn().mockResolvedValue([]); -vi.mock("@/hooks/useSecretsManager", () => ({ - useSecretsManager: () => ({ - setSecret: setSecretMock, - rotateSecret: rotateSecretMock, - getRotationHistory: getRotationHistoryMock, - }), -})); -vi.mock("@/hooks/useConnectionTestDetails", () => ({ - useConnectionTestDetails: () => ({ details: null, loading: false, error: null, refresh: vi.fn() }), -})); +vi.mock("@/hooks/admin", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + useSecretsManager: () => ({ + setSecret: setSecretMock, + rotateSecret: rotateSecretMock, + getRotationHistory: getRotationHistoryMock, + isLoading: false, + secrets: [], + listError: null, + list: vi.fn(), + refreshCache: vi.fn(), + }), + }; +}); +vi.mock("@/hooks/intelligence", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + useConnectionTestDetails: () => ({ details: null, loading: false, error: null, refetch: vi.fn() }), + }; +}); vi.mock("@/components/admin/connections/CredentialsSourceFilterContext", async (importOriginal) => { const actual = await importOriginal(); return { diff --git a/tests/components/admin/SecretField.test.tsx b/tests/components/admin/SecretField.test.tsx index 1560acb96..838509a38 100644 --- a/tests/components/admin/SecretField.test.tsx +++ b/tests/components/admin/SecretField.test.tsx @@ -7,18 +7,31 @@ import { render, screen, fireEvent } from "@testing-library/react"; const setSecretMock = vi.fn(); const rotateSecretMock = vi.fn(); const getRotationHistoryMock = vi.fn().mockResolvedValue([]); -vi.mock("@/hooks/useSecretsManager", () => ({ - useSecretsManager: () => ({ - setSecret: setSecretMock, - rotateSecret: rotateSecretMock, - getRotationHistory: getRotationHistoryMock, - }), -})); +vi.mock("@/hooks/admin", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + useSecretsManager: () => ({ + setSecret: setSecretMock, + rotateSecret: rotateSecretMock, + getRotationHistory: getRotationHistoryMock, + isLoading: false, + secrets: [], + listError: null, + list: vi.fn(), + refreshCache: vi.fn(), + }), + }; +}); // O hook de detalhes de teste de conexão dispara queries — neutralizamos. -vi.mock("@/hooks/useConnectionTestDetails", () => ({ - useConnectionTestDetails: () => ({ details: null, loading: false, error: null, refresh: vi.fn() }), -})); +vi.mock("@/hooks/intelligence", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + useConnectionTestDetails: () => ({ details: null, loading: false, error: null, refetch: vi.fn() }), + }; +}); // Filtro de fonte de credencial usa contexto — sobrescreve só o hook, // preservando exports auxiliares (`resolveSource`, etc) usados pelo @@ -208,6 +221,7 @@ describe("SecretField — handler de salvar nunca chama API com sufixo <4 chars" it("modo rotate: status com has_value → botão Rotacionar abre input, e Salvar com 3 chars NÃO chama rotateSecret", () => { renderField({ status: { + name: "MCP_SHARED_SECRET", has_value: true, length: 32, masked_suffix: "abcd", @@ -215,7 +229,7 @@ describe("SecretField — handler de salvar nunca chama API com sufixo <4 chars" env_fallback_active: false, updated_at: new Date().toISOString(), updated_by_email: null, - } as any, + }, }); // Entra em modo rotate via botão "Rotacionar". diff --git a/tests/components/admin/pluralization.test.tsx b/tests/components/admin/pluralization.test.tsx index cd8eb8528..343fed389 100644 --- a/tests/components/admin/pluralization.test.tsx +++ b/tests/components/admin/pluralization.test.tsx @@ -6,12 +6,29 @@ import { render, screen, fireEvent } from "@testing-library/react"; const setSecretMock = vi.fn(); const rotateSecretMock = vi.fn(); const getRotationHistoryMock = vi.fn().mockResolvedValue([]); -vi.mock("@/hooks/useSecretsManager", () => ({ - useSecretsManager: () => ({ setSecret: setSecretMock, rotateSecret: rotateSecretMock, getRotationHistory: getRotationHistoryMock }), -})); -vi.mock("@/hooks/useConnectionTestDetails", () => ({ - useConnectionTestDetails: () => ({ details: null, loading: false, error: null, refresh: vi.fn() }), -})); +vi.mock("@/hooks/admin", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + useSecretsManager: () => ({ + setSecret: setSecretMock, + rotateSecret: rotateSecretMock, + getRotationHistory: getRotationHistoryMock, + isLoading: false, + secrets: [], + listError: null, + list: vi.fn(), + refreshCache: vi.fn(), + }), + }; +}); +vi.mock("@/hooks/intelligence", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + useConnectionTestDetails: () => ({ details: null, loading: false, error: null, refetch: vi.fn() }), + }; +}); vi.mock("@/components/admin/connections/CredentialsSourceFilterContext", async (importOriginal) => { const actual = await importOriginal(); return {