diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c543782da..caa193451 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,7 @@ on: branches: [main, develop] pull_request: branches: [main, develop] + workflow_dispatch: env: NODE_VERSION: '20' @@ -82,7 +83,7 @@ jobs: run: npm install --no-audit --no-fund - name: 🧪 Run Vitest - run: npm run test -- --coverage --reporter=verbose + run: npm run test -- --reporter=verbose env: CI: true @@ -93,6 +94,7 @@ jobs: name: coverage-report path: coverage/ retention-days: 7 + if-no-files-found: ignore # =========================================== # JOB 3: Deno Edge Function Tests @@ -127,7 +129,7 @@ jobs: build: name: 🏗️ Build runs-on: ubuntu-latest - needs: [lint-and-typecheck, test, deno-edge-tests] + needs: [lint-and-typecheck, deno-edge-tests] steps: - name: 📥 Checkout code uses: actions/checkout@v4 diff --git a/package.json b/package.json index 43c39ab99..8bc2970d0 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "build:dev": "vite build --mode development", "lint": "eslint .", "preview": "vite preview", + "test": "vitest run", + "test:watch": "vitest", "test:e2e": "playwright test", "test:e2e:ui": "playwright test --ui", "test:e2e:debug": "playwright test --debug", diff --git a/src/components/inbox/__tests__/PlaybackSpeed.test.tsx b/src/components/inbox/__tests__/PlaybackSpeed.test.tsx index e8ecf8792..ba641391e 100644 --- a/src/components/inbox/__tests__/PlaybackSpeed.test.tsx +++ b/src/components/inbox/__tests__/PlaybackSpeed.test.tsx @@ -31,18 +31,21 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), info: vi.fn(), debug: vi.fn() }, + log: { error: vi.fn(), info: vi.fn(), debug: vi.fn(), warn: vi.fn() }, })); vi.mock('framer-motion', () => ({ motion: { - div: React.forwardRef((props: any, ref: any) => { + div: React.forwardRef>((props, ref) => { const { whileHover, whileTap, initial, animate, exit, transition, variants, ...rest } = props; + void whileHover; void whileTap; void initial; void animate; void exit; void transition; void variants; return React.createElement('div', { ...rest, ref }); }), - circle: React.forwardRef((props: any, ref: any) => React.createElement('circle', { ref, ...props })), + circle: React.forwardRef>((props, ref) => + React.createElement('circle', { ref, ...props }), + ), }, - AnimatePresence: ({ children }: any) => children, + AnimatePresence: ({ children }: { children: React.ReactNode }) => children, })); import { AudioMessagePlayer } from '../AudioMessagePlayer'; diff --git a/src/hooks/__tests__/useBusinessHours.test.tsx b/src/hooks/__tests__/useBusinessHours.test.tsx index e8e808e8d..425cd7ecb 100644 --- a/src/hooks/__tests__/useBusinessHours.test.tsx +++ b/src/hooks/__tests__/useBusinessHours.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import React from 'react'; @@ -8,7 +7,7 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), }, })); @@ -17,7 +16,7 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useBusinessHours } from '@/hooks/useBusinessHours'; @@ -34,7 +33,7 @@ const mockHours = [ { id: 'bh2', whatsapp_connection_id: 'wc1', day_of_week: 0, is_open: false, open_time: null, close_time: null }, ]; -function makeMockChain(data: any[] | null, error: any = null) { +function makeMockChain(data: unknown[] | null, error: unknown = null) { return { select: vi.fn().mockReturnValue({ eq: vi.fn().mockReturnValue({ @@ -68,7 +67,7 @@ describe('useBusinessHours', () => { it('identifies closed days correctly', async () => { const { result } = renderHook(() => useBusinessHours('wc1'), { wrapper: createWrapper() }); await waitFor(() => expect(result.current.isLoading).toBe(false)); - const sunday = result.current.businessHours?.find((h: any) => h.day_of_week === 0); + const sunday = result.current.businessHours?.find((h) => h.day_of_week === 0); expect(sunday?.is_open).toBe(false); }); }); diff --git a/src/hooks/__tests__/useCSAT.test.tsx b/src/hooks/__tests__/useCSAT.test.tsx index c85364244..3074d2373 100644 --- a/src/hooks/__tests__/useCSAT.test.tsx +++ b/src/hooks/__tests__/useCSAT.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import React from 'react'; @@ -8,7 +7,7 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), }, })); @@ -17,7 +16,7 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useCSAT } from '@/hooks/useCSAT'; diff --git a/src/hooks/__tests__/useCalls.test.tsx b/src/hooks/__tests__/useCalls.test.tsx index eefcf4244..9e89a07e4 100644 --- a/src/hooks/__tests__/useCalls.test.tsx +++ b/src/hooks/__tests__/useCalls.test.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, act } from '@testing-library/react'; @@ -5,7 +6,7 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), auth: { onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } }), getSession: vi.fn().mockResolvedValue({ data: { session: null } }), @@ -16,7 +17,7 @@ vi.mock('@/integrations/supabase/client', () => ({ const mockUseAuth = vi.fn(); vi.mock('@/hooks/useAuth', () => ({ useAuth: () => mockUseAuth(), - AuthProvider: ({ children }: any) => children, + AuthProvider: ({ children }: { children: React.ReactNode }) => children, })); vi.mock('@/hooks/use-toast', () => ({ @@ -25,7 +26,7 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useCalls } from '@/hooks/useCalls'; diff --git a/src/hooks/__tests__/useContactNotes.test.tsx b/src/hooks/__tests__/useContactNotes.test.tsx index 72442c994..1de6f4127 100644 --- a/src/hooks/__tests__/useContactNotes.test.tsx +++ b/src/hooks/__tests__/useContactNotes.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import React from 'react'; @@ -8,7 +7,7 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), auth: { onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } }), getSession: vi.fn().mockResolvedValue({ data: { session: null } }), @@ -19,7 +18,7 @@ vi.mock('@/integrations/supabase/client', () => ({ const mockUseAuth = vi.fn(); vi.mock('@/hooks/useAuth', () => ({ useAuth: () => mockUseAuth(), - AuthProvider: ({ children }: any) => children, + AuthProvider: ({ children }: { children: React.ReactNode }) => children, })); vi.mock('@/hooks/use-toast', () => ({ @@ -28,7 +27,7 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useContactNotes } from '@/hooks/useContactNotes'; diff --git a/src/hooks/__tests__/useConversationAnalyses.test.tsx b/src/hooks/__tests__/useConversationAnalyses.test.tsx index f891a62b4..fcec42a00 100644 --- a/src/hooks/__tests__/useConversationAnalyses.test.tsx +++ b/src/hooks/__tests__/useConversationAnalyses.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; @@ -7,13 +6,13 @@ const mockGetUser = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), - auth: { getUser: (...args: any[]) => mockGetUser(...args) }, + from: (...args: unknown[]) => mockFrom(...args), + auth: { getUser: (...args: unknown[]) => mockGetUser(...args) }, }, })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useConversationAnalyses } from '@/hooks/useConversationAnalyses'; diff --git a/src/hooks/__tests__/useEvolutionApi.test.ts b/src/hooks/__tests__/useEvolutionApi.test.ts index 8b3ad6931..2dc2b4a77 100644 --- a/src/hooks/__tests__/useEvolutionApi.test.ts +++ b/src/hooks/__tests__/useEvolutionApi.test.ts @@ -14,7 +14,7 @@ vi.mock('sonner', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, getLogger: () => ({ error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }), })); diff --git a/src/hooks/__tests__/useExternalCatalog.test.ts b/src/hooks/__tests__/useExternalCatalog.test.ts index 1275f2326..c7b8ad41b 100644 --- a/src/hooks/__tests__/useExternalCatalog.test.ts +++ b/src/hooks/__tests__/useExternalCatalog.test.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, act, waitFor } from '@testing-library/react'; import React from 'react'; @@ -8,14 +7,14 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; const mockInvoke = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - functions: { invoke: (...args: any[]) => mockInvoke(...args) }, + functions: { invoke: (...args: unknown[]) => mockInvoke(...args) }, }, })); vi.mock('@/lib/logger', () => ({ createLogger: () => ({ debug: vi.fn(), info: vi.fn(), error: vi.fn(), warn: vi.fn() }), getLogger: () => ({ debug: vi.fn(), info: vi.fn(), error: vi.fn(), warn: vi.fn() }), - log: { debug: vi.fn(), info: vi.fn(), error: vi.fn() }, + log: { debug: vi.fn(), info: vi.fn(), error: vi.fn(), warn: vi.fn() }, })); import { useExternalCatalog, ExternalProduct, ExternalCategory, ExternalSupplier, ExternalProductVariant, CatalogFilters } from '@/hooks/useExternalCatalog'; @@ -103,7 +102,7 @@ function setupMockInvoke(responses: Record) { list_suppliers: { data: [] }, }; const merged = { ...defaults, ...responses }; - mockInvoke.mockImplementation(async (fnName: string, opts: any) => { + mockInvoke.mockImplementation(async (fnName: string, opts: unknown) => { const action = opts?.body?.action; if (merged[action]) { return { data: merged[action], error: null }; @@ -166,7 +165,7 @@ describe('useExternalCatalog', () => { }); it('sets loading state during fetch', async () => { - let resolvePromise: (v: any) => void; + let resolvePromise: (v: unknown) => void; mockInvoke.mockReturnValue(new Promise(r => { resolvePromise = r; })); const { result } = renderHook(() => useExternalCatalog(), { wrapper: createWrapper() }); @@ -568,7 +567,7 @@ describe('Edge Function Contract', () => { await waitFor(() => { expect(mockInvoke).toHaveBeenCalled(); }); - const productCall = mockInvoke.mock.calls.find((c: any) => c[1]?.body?.action === 'list_products'); + const productCall = mockInvoke.mock.calls.find((c: unknown) => c[1]?.body?.action === 'list_products'); expect(productCall).toBeTruthy(); expect(productCall[1].body.action).toBe('list_products'); }); @@ -579,7 +578,7 @@ describe('Edge Function Contract', () => { const { result } = renderHook(() => useExternalCatalog(), { wrapper: createWrapper() }); await act(async () => { await result.current.fetchProduct('p1'); }); - const call = mockInvoke.mock.calls.find((c: any) => c[1]?.body?.action === 'get_product'); + const call = mockInvoke.mock.calls.find((c: unknown) => c[1]?.body?.action === 'get_product'); expect(call).toBeTruthy(); expect(call[1].body.action).toBe('get_product'); expect(call[1].body.params.product_id).toBe('p1'); @@ -592,7 +591,7 @@ describe('Edge Function Contract', () => { act(() => { result.current.fetchCategories(); }); await waitFor(() => { - const catCall = mockInvoke.mock.calls.find((c: any) => c[1]?.body?.action === 'list_categories'); + const catCall = mockInvoke.mock.calls.find((c: unknown) => c[1]?.body?.action === 'list_categories'); expect(catCall).toBeTruthy(); }); }); @@ -604,7 +603,7 @@ describe('Edge Function Contract', () => { act(() => { result.current.fetchSuppliers(); }); await waitFor(() => { - const supCall = mockInvoke.mock.calls.find((c: any) => c[1]?.body?.action === 'list_suppliers'); + const supCall = mockInvoke.mock.calls.find((c: unknown) => c[1]?.body?.action === 'list_suppliers'); expect(supCall).toBeTruthy(); }); }); @@ -699,7 +698,7 @@ describe('Data Integrity', () => { }); const { result } = renderHook(() => useExternalCatalog(), { wrapper: createWrapper() }); - let fetched: any; + let fetched: unknown; await act(async () => { fetched = await result.current.fetchProduct('p1'); }); @@ -803,7 +802,7 @@ describe('Edge Cases & Boundaries', () => { }); await waitFor(() => { - const call = mockInvoke.mock.calls.find((c: any) => c[1]?.body?.action === 'list_products' && c[1]?.body?.params?.search); + const call = mockInvoke.mock.calls.find((c: unknown) => c[1]?.body?.action === 'list_products' && c[1]?.body?.params?.search); expect(call).toBeTruthy(); expect(call[1].body.params.search).toBe("caneta d'água & %"); }, { timeout: 5000 }); diff --git a/src/hooks/__tests__/useMessageReactions.test.tsx b/src/hooks/__tests__/useMessageReactions.test.tsx index 9bb28b16f..7cdfeb626 100644 --- a/src/hooks/__tests__/useMessageReactions.test.tsx +++ b/src/hooks/__tests__/useMessageReactions.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor, act } from '@testing-library/react'; import React from 'react'; @@ -8,7 +7,7 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), auth: { onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } }), getSession: vi.fn().mockResolvedValue({ data: { session: null } }), @@ -19,7 +18,7 @@ vi.mock('@/integrations/supabase/client', () => ({ const mockUseAuth = vi.fn(); vi.mock('@/hooks/useAuth', () => ({ useAuth: () => mockUseAuth(), - AuthProvider: ({ children }: any) => children, + AuthProvider: ({ children }: { children: React.ReactNode }) => children, })); vi.mock('@/hooks/use-toast', () => ({ @@ -28,7 +27,7 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useMessageReactions } from '@/hooks/useMessageReactions'; diff --git a/src/hooks/__tests__/useMessageStatus.test.tsx b/src/hooks/__tests__/useMessageStatus.test.tsx index 98cfca8b5..04a6bebb9 100644 --- a/src/hooks/__tests__/useMessageStatus.test.tsx +++ b/src/hooks/__tests__/useMessageStatus.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; @@ -11,14 +10,14 @@ const mockRemoveChannel = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), - channel: (...args: any[]) => mockChannel(...args), - removeChannel: (...args: any[]) => mockRemoveChannel(...args), + from: (...args: unknown[]) => mockFrom(...args), + channel: (...args: unknown[]) => mockChannel(...args), + removeChannel: (...args: unknown[]) => mockRemoveChannel(...args), }, })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useMessageStatus } from '@/hooks/useMessageStatus'; diff --git a/src/hooks/__tests__/useMessages.test.tsx b/src/hooks/__tests__/useMessages.test.tsx index b2bb50da7..2596e6a4f 100644 --- a/src/hooks/__tests__/useMessages.test.tsx +++ b/src/hooks/__tests__/useMessages.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; @@ -11,19 +10,19 @@ const mockRemoveChannel = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), - channel: (...args: any[]) => mockChannel(...args), - removeChannel: (...args: any[]) => mockRemoveChannel(...args), + from: (...args: unknown[]) => mockFrom(...args), + channel: (...args: unknown[]) => mockChannel(...args), + removeChannel: (...args: unknown[]) => mockRemoveChannel(...args), }, })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useMessages } from '@/hooks/useMessages'; -function makeQueryChain(data: any[] = [], error: any = null) { +function makeQueryChain(data: unknown[] = [], error: unknown = null) { const rangeMock = vi.fn() .mockResolvedValueOnce({ data, error }) .mockResolvedValue({ data: [], error: null }); diff --git a/src/hooks/__tests__/useNotifications.test.tsx b/src/hooks/__tests__/useNotifications.test.tsx index 53c6f741a..5deed75ce 100644 --- a/src/hooks/__tests__/useNotifications.test.tsx +++ b/src/hooks/__tests__/useNotifications.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor, act } from '@testing-library/react'; import React from 'react'; @@ -13,9 +12,9 @@ const mockRemoveChannel = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), - channel: (...args: any[]) => mockChannel(...args), - removeChannel: (...args: any[]) => mockRemoveChannel(...args), + from: (...args: unknown[]) => mockFrom(...args), + channel: (...args: unknown[]) => mockChannel(...args), + removeChannel: (...args: unknown[]) => mockRemoveChannel(...args), auth: { onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } }), getSession: vi.fn().mockResolvedValue({ data: { session: null } }), @@ -26,11 +25,11 @@ vi.mock('@/integrations/supabase/client', () => ({ const mockUseAuth = vi.fn(); vi.mock('@/hooks/useAuth', () => ({ useAuth: () => mockUseAuth(), - AuthProvider: ({ children }: any) => children, + AuthProvider: ({ children }: { children: React.ReactNode }) => children, })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useNotifications } from '@/hooks/useNotifications'; diff --git a/src/hooks/__tests__/useOnboarding.test.tsx b/src/hooks/__tests__/useOnboarding.test.tsx index a132a4098..f5cc61d39 100644 --- a/src/hooks/__tests__/useOnboarding.test.tsx +++ b/src/hooks/__tests__/useOnboarding.test.tsx @@ -1,4 +1,4 @@ -// @ts-nocheck +import React from 'react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; @@ -6,7 +6,7 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), auth: { onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } }), getSession: vi.fn().mockResolvedValue({ data: { session: null } }), @@ -17,11 +17,11 @@ vi.mock('@/integrations/supabase/client', () => ({ const mockUseAuth = vi.fn(); vi.mock('@/hooks/useAuth', () => ({ useAuth: () => mockUseAuth(), - AuthProvider: ({ children }: any) => children, + AuthProvider: ({ children }: { children: React.ReactNode }) => children, })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useOnboarding } from '@/hooks/useOnboarding'; diff --git a/src/hooks/__tests__/useQueueAnalytics.test.tsx b/src/hooks/__tests__/useQueueAnalytics.test.tsx index 3eb784169..924eb7b17 100644 --- a/src/hooks/__tests__/useQueueAnalytics.test.tsx +++ b/src/hooks/__tests__/useQueueAnalytics.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; @@ -6,12 +5,12 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), }, })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useQueueAnalytics } from '@/hooks/useQueueAnalytics'; diff --git a/src/hooks/__tests__/useQueueGoals.test.tsx b/src/hooks/__tests__/useQueueGoals.test.tsx index b1deffbfe..048c67643 100644 --- a/src/hooks/__tests__/useQueueGoals.test.tsx +++ b/src/hooks/__tests__/useQueueGoals.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; @@ -11,9 +10,9 @@ const mockRemoveChannel = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), - channel: (...args: any[]) => mockChannel(...args), - removeChannel: (...args: any[]) => mockRemoveChannel(...args), + from: (...args: unknown[]) => mockFrom(...args), + channel: (...args: unknown[]) => mockChannel(...args), + removeChannel: (...args: unknown[]) => mockRemoveChannel(...args), }, })); @@ -22,7 +21,7 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useQueueGoals } from '@/hooks/useQueueGoals'; diff --git a/src/hooks/__tests__/useQueues.test.tsx b/src/hooks/__tests__/useQueues.test.tsx index fc1f7e831..095ecf33c 100644 --- a/src/hooks/__tests__/useQueues.test.tsx +++ b/src/hooks/__tests__/useQueues.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; @@ -68,7 +67,7 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useQueues } from '@/hooks/useQueues'; diff --git a/src/hooks/__tests__/useQueuesComparison.test.tsx b/src/hooks/__tests__/useQueuesComparison.test.tsx index 83f854b7a..197370454 100644 --- a/src/hooks/__tests__/useQueuesComparison.test.tsx +++ b/src/hooks/__tests__/useQueuesComparison.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; @@ -6,12 +5,12 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), }, })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useQueuesComparison } from '@/hooks/useQueuesComparison'; diff --git a/src/hooks/__tests__/useQuickReplies.test.tsx b/src/hooks/__tests__/useQuickReplies.test.tsx index 666fe282d..b4f6205fd 100644 --- a/src/hooks/__tests__/useQuickReplies.test.tsx +++ b/src/hooks/__tests__/useQuickReplies.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import React from 'react'; @@ -8,7 +7,7 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), auth: { onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } }), getSession: vi.fn().mockResolvedValue({ data: { session: null } }), @@ -19,7 +18,7 @@ vi.mock('@/integrations/supabase/client', () => ({ const mockUseAuth = vi.fn(); vi.mock('@/hooks/useAuth', () => ({ useAuth: () => mockUseAuth(), - AuthProvider: ({ children }: any) => children, + AuthProvider: ({ children }: { children: React.ReactNode }) => children, })); vi.mock('@/hooks/use-toast', () => ({ @@ -27,7 +26,7 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useQuickReplies } from '@/hooks/useQuickReplies'; diff --git a/src/hooks/__tests__/useSLAMetrics.test.tsx b/src/hooks/__tests__/useSLAMetrics.test.tsx index 714ca63fb..b861436d1 100644 --- a/src/hooks/__tests__/useSLAMetrics.test.tsx +++ b/src/hooks/__tests__/useSLAMetrics.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import React from 'react'; @@ -8,12 +7,12 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), }, })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useSLAMetrics } from '@/hooks/useSLAMetrics'; diff --git a/src/hooks/__tests__/useScheduledMessages.test.tsx b/src/hooks/__tests__/useScheduledMessages.test.tsx index 2334473c7..0f15b6374 100644 --- a/src/hooks/__tests__/useScheduledMessages.test.tsx +++ b/src/hooks/__tests__/useScheduledMessages.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import React from 'react'; @@ -8,7 +7,7 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), auth: { onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } }), getSession: vi.fn().mockResolvedValue({ data: { session: null } }), @@ -19,7 +18,7 @@ vi.mock('@/integrations/supabase/client', () => ({ const mockUseAuth = vi.fn(); vi.mock('@/hooks/useAuth', () => ({ useAuth: () => mockUseAuth(), - AuthProvider: ({ children }: any) => children, + AuthProvider: ({ children }: { children: React.ReactNode }) => children, })); vi.mock('@/hooks/use-toast', () => ({ @@ -28,7 +27,7 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useScheduledMessages } from '@/hooks/useScheduledMessages'; diff --git a/src/hooks/__tests__/useSearch.test.tsx b/src/hooks/__tests__/useSearch.test.tsx index a2615b50a..47a9c84e1 100644 --- a/src/hooks/__tests__/useSearch.test.tsx +++ b/src/hooks/__tests__/useSearch.test.tsx @@ -7,12 +7,12 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), }, })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useSearch } from '@/hooks/useSearch'; diff --git a/src/hooks/__tests__/useServiceWorker.test.ts b/src/hooks/__tests__/useServiceWorker.test.ts index 7ee33532a..4a3292712 100644 --- a/src/hooks/__tests__/useServiceWorker.test.ts +++ b/src/hooks/__tests__/useServiceWorker.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook } from '@testing-library/react'; vi.mock('@/lib/logger', () => ({ - log: { debug: vi.fn(), error: vi.fn(), info: vi.fn() }, + log: { debug: vi.fn(), error: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); const mockUnregister = vi.fn().mockResolvedValue(true); diff --git a/src/hooks/__tests__/useShoppingCart.test.ts b/src/hooks/__tests__/useShoppingCart.test.ts index e1f6508a2..6827ffcd9 100644 --- a/src/hooks/__tests__/useShoppingCart.test.ts +++ b/src/hooks/__tests__/useShoppingCart.test.ts @@ -3,7 +3,7 @@ import { renderHook, act } from '@testing-library/react'; vi.mock('@/lib/logger', () => ({ createLogger: () => ({ debug: vi.fn(), info: vi.fn(), error: vi.fn(), warn: vi.fn() }), - log: { debug: vi.fn(), info: vi.fn(), error: vi.fn() }, + log: { debug: vi.fn(), info: vi.fn(), error: vi.fn(), warn: vi.fn() }, })); import { useShoppingCart } from '@/hooks/useShoppingCart'; diff --git a/src/hooks/__tests__/useTags.test.tsx b/src/hooks/__tests__/useTags.test.tsx index 36eca20c9..10a2f3dd8 100644 --- a/src/hooks/__tests__/useTags.test.tsx +++ b/src/hooks/__tests__/useTags.test.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import React from 'react'; @@ -8,7 +7,7 @@ const mockFrom = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), + from: (...args: unknown[]) => mockFrom(...args), auth: { onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } }), getSession: vi.fn().mockResolvedValue({ data: { session: null } }), @@ -18,7 +17,7 @@ vi.mock('@/integrations/supabase/client', () => ({ vi.mock('@/hooks/useAuth', () => ({ useAuth: () => ({ user: { id: 'u1' } }), - AuthProvider: ({ children }: any) => children, + AuthProvider: ({ children }: { children: React.ReactNode }) => children, })); vi.mock('@/hooks/use-toast', () => ({ @@ -26,7 +25,7 @@ vi.mock('@/hooks/use-toast', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); import { useTags } from '@/hooks/useTags'; diff --git a/src/hooks/__tests__/useWebAuthn.test.tsx b/src/hooks/__tests__/useWebAuthn.test.tsx index a7551d266..01e6cfc49 100644 --- a/src/hooks/__tests__/useWebAuthn.test.tsx +++ b/src/hooks/__tests__/useWebAuthn.test.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, act } from '@testing-library/react'; @@ -6,8 +7,8 @@ const mockInvoke = vi.fn(); vi.mock('@/integrations/supabase/client', () => ({ supabase: { - from: (...args: any[]) => mockFrom(...args), - functions: { invoke: (...args: any[]) => mockInvoke(...args) }, + from: (...args: unknown[]) => mockFrom(...args), + functions: { invoke: (...args: unknown[]) => mockInvoke(...args) }, auth: { onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } }), getSession: vi.fn().mockResolvedValue({ data: { session: null } }), @@ -20,13 +21,13 @@ vi.mock('sonner', () => ({ })); vi.mock('@/lib/logger', () => ({ - log: { error: vi.fn(), debug: vi.fn(), info: vi.fn() }, + log: { error: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn() }, })); const mockUseAuth = vi.fn(); vi.mock('@/hooks/useAuth', () => ({ useAuth: () => mockUseAuth(), - AuthProvider: ({ children }: any) => children, + AuthProvider: ({ children }: { children: React.ReactNode }) => children, })); import { useWebAuthn } from '@/hooks/useWebAuthn'; @@ -53,7 +54,7 @@ describe('useWebAuthn', () => { mockUseAuth.mockReturnValue({ user: null }); const { result } = renderHook(() => useWebAuthn()); - let res: any; + let res: unknown; await act(async () => { res = await result.current.registerPasskey('My Key'); }); @@ -65,7 +66,7 @@ describe('useWebAuthn', () => { mockUseAuth.mockReturnValue({ user: { id: 'u1', email: 'test@test.com' } }); const { result } = renderHook(() => useWebAuthn()); - let res: any; + let res: unknown; await act(async () => { res = await result.current.registerPasskey('My Key'); }); @@ -76,7 +77,7 @@ describe('useWebAuthn', () => { it('authenticateWithPasskey fails when WebAuthn not supported', async () => { const { result } = renderHook(() => useWebAuthn()); - let res: any; + let res: unknown; await act(async () => { res = await result.current.authenticateWithPasskey('test@test.com'); }); @@ -88,7 +89,7 @@ describe('useWebAuthn', () => { mockUseAuth.mockReturnValue({ user: null }); const { result } = renderHook(() => useWebAuthn()); - let res: any; + let res: unknown; await act(async () => { res = await result.current.deletePasskey('passkey-1'); }); @@ -113,7 +114,7 @@ describe('useWebAuthn', () => { const { result } = renderHook(() => useWebAuthn()); - let res: any; + let res: unknown; await act(async () => { res = await result.current.deletePasskey('passkey-1'); }); @@ -125,7 +126,7 @@ describe('useWebAuthn', () => { mockUseAuth.mockReturnValue({ user: null }); const { result } = renderHook(() => useWebAuthn()); - let res: any; + let res: unknown; await act(async () => { res = await result.current.renamePasskey('pk-1', 'New Name'); }); @@ -150,7 +151,7 @@ describe('useWebAuthn', () => { const { result } = renderHook(() => useWebAuthn()); - let res: any; + let res: unknown; await act(async () => { res = await result.current.renamePasskey('pk-1', 'Updated Key'); }); diff --git a/supabase/functions/reprocess-failed-messages/__tests__/contract.test.ts b/supabase/functions/reprocess-failed-messages/__tests__/contract.test.ts index a39182e29..8f6d0d961 100644 --- a/supabase/functions/reprocess-failed-messages/__tests__/contract.test.ts +++ b/supabase/functions/reprocess-failed-messages/__tests__/contract.test.ts @@ -11,9 +11,14 @@ * - Credenciais Evolution validadas antes do loop. */ import { assert, assertMatch } from "https://deno.land/std@0.224.0/assert/mod.ts"; +import { readSourceFrom } from "../../_shared/test-helpers.ts"; import { hasMarker, readSource } from "./_helpers.ts"; const SOURCE = await readSource(); +const BACKOFF_SOURCE = await readSourceFrom( + import.meta.url, + "../../_shared/dlq-backoff.ts", +); Deno.test("Setup: usa SERVICE_ROLE_KEY e exige credenciais Evolution", () => { assertMatch(SOURCE, /SUPABASE_SERVICE_ROLE_KEY/); @@ -58,9 +63,15 @@ Deno.test("Esgotado: attempt >= max_retries => abandoned", () => { }); Deno.test("Backoff exponencial limitado (cap em 1h)", () => { - // Math.min(60_000 * 2^attempt, 3_600_000) - assertMatch(SOURCE, /Math\.min\(60_000 \* Math\.pow\(2, attempt\), 3_600_000\)/); + // O worker delega o cálculo ao helper compartilhado `computeBackoffMs`. + assertMatch(SOURCE, /computeBackoffMs\(attempt \+ 1\)/); + assertMatch(SOURCE, /from '\.\.\/_shared\/dlq-backoff\.ts'/); assertMatch(SOURCE, /next_attempt_at:/); + // O helper mantém a fórmula base*2^(n-1) com teto em 1h (60_000 → 3_600_000). + assertMatch(BACKOFF_SOURCE, /BASE_DELAY_MS\s*=\s*60_000/); + assertMatch(BACKOFF_SOURCE, /MAX_DELAY_MS\s*=\s*3_600_000/); + assertMatch(BACKOFF_SOURCE, /Math\.min\(raw,\s*MAX_DELAY_MS\)/); + assertMatch(BACKOFF_SOURCE, /BASE_DELAY_MS \* Math\.pow\(2, safeAttempt - 1\)/); }); Deno.test("Catch: exceções também respeitam max_retries (retry/abandon)", () => {