chore(eslint): fix 14 no-explicit-any in tests/mocks (Onda 5 PR 5.2a)#110
Conversation
Reduces ESLint errors from 142 → 128 (-14, -10%) by replacing 'any'
with 'unknown' or specific types in test files and mocks.
**src/test/mocks/supabase.ts (5 fixes):**
- createQueryBuilder params: any → unknown
- builder: removed explicit Record<string, unknown> type (TS infers shape from literal, which is fine for a chainable mock)
- then() resolve callback: typed properly
- createMockSupabase overrides: typed via SupabaseOverrides interface
(auth: Record<string, unknown>, tables: Record<string, {data, error}>)
**src/test/mocks/auth.tsx (3 fixes):**
- mockUser/mockSession/mockProfile cast as any → cast as unknown as
typeof X (eliminates 'any' but keeps the test-flexibility intent)
**src/hooks/useEmailActions.test.ts (2 fixes):**
- '_supabase as any' → 'as unknown as typeof _supabase'
- 'error: { message } as any' → 'as unknown as Error'
**src/hooks/useEmailDraft.test.ts (1 fix):**
- '_supabase as any' → 'as unknown as typeof _supabase'
**src/utils/emailMappers.test.ts (2 fixes):**
- 'null as any' / 'undefined as any' → 'unknown as Parameters<...>[0]'
**src/features/inbox/hooks/__tests__/useMessageQueueE2E.spec.tsx (1 fix):**
- processMessage: any → (...args: unknown[]) => unknown
Validations:
- bun run lint → 128 errors (was 142), 1330 warnings
- bun run build → ✓ built in 1m 3s
- bunx vitest run on touched test files:
• emailMappers.test.ts: 11/11 pass
• useEmailDraft.test.ts: 5/5 pass
• useEmailActions.test.ts: 20/21 pass (1 pre-existing failure
NOT introduced by this PR — confirmed by running same test
on main where it doesn't even start)
All 14 no-explicit-any errors in tests/mocks zeroed.
Backlog remaining for Onda 5:
- PR 5.2b: 10 no-unused-expressions + 7 outros (~17 errors)
- PR 5.3: 108 no-restricted-imports (DDD architecture refactor)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
💤 Files with no reviewable changes (1)
WalkthroughRetipagem em testes e mocks: query builder e overrides do mock Supabase passam de ChangesType Safety Improvements
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d09d36161
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| // Mock component to test the hook | ||
| function QueueTestComponent({ processMessage, contactId }: { processMessage: any, contactId: string }) { | ||
| function QueueTestComponent({ processMessage, contactId }: { processMessage: (...args: unknown[]) => unknown, contactId: string }) { |
There was a problem hiding this comment.
Keep the mock processor Promise-compatible
When this test file is included in npm run typecheck, QueueTestComponent passes processMessage directly to useMessageQueue, whose contract is (item: QueueItem) => Promise<void> in src/features/inbox/hooks/useMessageQueue.ts. Typing the prop as returning unknown makes that argument no longer assignable because unknown is not a Promise, so the test suite fails to type-check even though the runtime mocks are async. Use the hook parameter type or a Promise-returning signature instead.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/features/inbox/hooks/__tests__/useMessageQueueE2E.spec.tsx (1)
6-6: ⚡ Quick winTipo
processMessagenão alinha ao contrato do hook.O teste passa
(...args: unknown[]) => unknownparauseMessageQueue, que espera(item: QueueItem) => Promise<void>. Isso viola a guideline de "unknown sem narrowing posterior". Derivar o tipo diretamente do hook garante alinhamento e evita incompatibilidades futuras.Diff sugerido
+type ProcessMessage = Parameters<typeof useMessageQueue>[0]; + -function QueueTestComponent({ processMessage, contactId }: { processMessage: (...args: unknown[]) => unknown, contactId: string }) { +function QueueTestComponent({ processMessage, contactId }: { processMessage: ProcessMessage; contactId: string }) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/inbox/hooks/__tests__/useMessageQueueE2E.spec.tsx` at line 6, The test's QueueTestComponent declares processMessage as (...args: unknown[]) => unknown which doesn't match useMessageQueue's contract; change the prop type to the exact handler type expected by useMessageQueue (a function accepting a QueueItem and returning Promise<void>) by deriving it from the hook's types (e.g., using the hook's parameter/return type inference) so QueueTestComponent's processMessage signature aligns with useMessageQueue and removes use of unknown.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/features/inbox/hooks/__tests__/useMessageQueueE2E.spec.tsx`:
- Line 6: The test's QueueTestComponent declares processMessage as (...args:
unknown[]) => unknown which doesn't match useMessageQueue's contract; change the
prop type to the exact handler type expected by useMessageQueue (a function
accepting a QueueItem and returning Promise<void>) by deriving it from the
hook's types (e.g., using the hook's parameter/return type inference) so
QueueTestComponent's processMessage signature aligns with useMessageQueue and
removes use of unknown.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 67232a56-8738-4da5-9dfa-4a7a65718c4b
📒 Files selected for processing (6)
src/features/inbox/hooks/__tests__/useMessageQueueE2E.spec.tsxsrc/hooks/useEmailActions.test.tssrc/hooks/useEmailDraft.test.tssrc/test/mocks/auth.tsxsrc/test/mocks/supabase.tssrc/utils/emailMappers.test.ts
Codex flagged that the typing 'processMessage: (...args: unknown[]) => unknown' breaks typecheck because useMessageQueue's actual contract is '(item: QueueItem) => Promise<void>' — unknown is not a Promise, so the arg becomes non-assignable. Fix: import QueueItem type from the hook and use the real signature. - Before: processMessage: (...args: unknown[]) => unknown - After: processMessage: (item: QueueItem) => Promise<void> This both eliminates the no-explicit-any error AND keeps the test file typecheck-clean (correct contract). Validations: - bun run lint → 128 errors (unchanged from previous commit) - bunx vitest run on this file: 1/2 pass (1 pre-existing failure confirmed in main)
There was a problem hiding this comment.
Pull request overview
Reduz o número de violações do ESLint (@typescript-eslint/no-explicit-any) em arquivos de testes/mocks, substituindo usos de any por tipagens mais seguras (unknown, Parameters<>, e asserts mais específicos) para avançar a iniciativa de strict-typing sem impactar código de produção.
Changes:
- Substitui casts
as anyporunknown+ tipos derivados (Parameters<typeof ...>[0]) em testes de mapeadores de e-mail. - Refina tipagem de mocks (Supabase e Auth) para eliminar
anyem helpers compartilhados. - Ajusta tipagem de callbacks em testes E2E de hook (fila de mensagens) para evitar
any.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/emailMappers.test.ts | Remove any ao testar inputs inválidos usando tipo derivado de emailMappers.*. |
| src/test/mocks/supabase.ts | Troca any por unknown, remove builder: any, e define SupabaseOverrides. |
| src/test/mocks/auth.tsx | Substitui as any por double-assertions para remover any no contexto mockado. |
| src/hooks/useEmailDraft.test.ts | Remove as any no supabase importado (mas adiciona workaround via variável tipada). |
| src/hooks/useEmailActions.test.ts | Remove as any no supabase importado e troca error as any por double-assertion. |
| src/features/inbox/hooks/tests/useMessageQueueE2E.spec.tsx | Troca processMessage: any por assinatura baseada em unknown. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const _supabaseTyped = _supabase as unknown as typeof _supabase; | ||
| void _supabaseTyped; |
| const _supabaseTyped = _supabase as unknown as typeof _supabase; | ||
| void _supabaseTyped; |
|
|
||
| // Mock component to test the hook | ||
| function QueueTestComponent({ processMessage, contactId }: { processMessage: any, contactId: string }) { | ||
| function QueueTestComponent({ processMessage, contactId }: { processMessage: (item: QueueItem) => Promise<void>, contactId: string }) { |
| user: mockUser as unknown as typeof mockUser, | ||
| session: mockSession as unknown as typeof mockSession, | ||
| profile: mockProfile as unknown as typeof mockProfile, |
| vi.mocked(safeClient.rpc).mockResolvedValueOnce({ | ||
| data: null, | ||
| error: { message: 'RPC Error' } as any, | ||
| error: { message: 'RPC Error' } as unknown as Error, | ||
| requestId: 'req_123' | ||
| }); |
5 micro-fixes from Copilot review (no scope creep):
1. useEmailDraft.test.ts: removed unused '_supabase' import +
'void _supabaseTyped;' workaround. The supabase symbol was only
referenced by the unused vars hack — it's mocked via vi.mock()
factory which doesn't need the import.
2. useEmailActions.test.ts: same cleanup (removed unused import +
void hack).
3. useEmailActions.test.ts:101: replaced 'as unknown as Error' with
'new Error('RPC Error')' for proper Error shape (has .name, .stack).
No more bypass-style casting.
4. test/mocks/auth.tsx: removed redundant 'as unknown as typeof X'
casts. The values already have type 'typeof mockUser/Session/Profile'
from their declarations — double casting was no-op noise.
Validations:
- bun run lint → 128 errors (unchanged, expected)
- bunx vitest run on touched files: 20/21 pass (1 pre-existing
failure confirmed in main — same as previous commit)
|
@coderabbitai full review 3 commits no PR — 2 últimos respondem feedback:
Estado: 128 errors total (-14 desde base), 0 no-explicit-any restantes, build OK. |
|
✅ Actions performedFull review triggered. |
🎉 Fecha Onda 5: 108 → 0 errors (-108). ESLint TOTAL: 164 → 0 errors em 4 PRs (#109, #110, #111, este). ## Estratégia DDD Regra `no-restricted-imports` (eslint.config.js) bloqueia: 1. Imports cross-feature deep (`@/features/X/...`) — força entry points 2. Imports relativos profundos (`../../...`) 3. INTRA-feature via alias (`@/features/X/Y` quando arquivo está em X) ## Batch A — INTRA-feature (106 fixes em 42 arquivos) Pattern: `@/features/X/Y/Z` → caminho relativo via path.relative() Ex (src/features/inbox/components/chat/ChatHeader.tsx): - ANTES: `@/features/inbox/components/ai-tools/VisionIcon` - DEPOIS: `../ai-tools/VisionIcon` Distribuição: - 92 inbox (52 chat, 12 contact-details, 8 components, 5 hooks, 3 services, 3 virtualized, 3 conversation-list, 2 realtime, 2 templates, 2 search, 1 monitoring, 1 mocks) - 7 auth (5 components, 1 hooks, 1 context) - 3 admin (2 hooks, 1 services) - 3 connections (2 hooks, 1 services) - 1 sla (1 components) Script: /tmp/fix-intra.mjs (Node + path.relative) - 106/106 sucesso, zero falhas - 1 read/write por arquivo (eficiente) - Ordem desc por linha (não invalida índices) ## Batch B — CROSS-feature (2 fixes) Imports de outra feature DEVEM usar entry point (`@/features/X`), não path interno (`@/features/X/hooks/...`). Os barrels já existiam (`auth/index.ts` e `sla/index.ts` fazem `export * from './hooks'`), só não estavam sendo usados: - src/features/inbox/components/ChatPanel.tsx: `@/features/auth/hooks/useUserRole` → `@/features/auth` - src/features/inbox/components/RealtimeInboxView.tsx: `@/features/sla/hooks/useSLAAlerts` → `@/features/sla` ## Validação - bunx eslint . → 0 errors, 1330 warnings (Onda 5 ZERADA) - bunx tsc --noEmit → ✓ sem erros (typecheck pristine) - bun run build → ✓ built in 58.09s (zero regressões) - 44 files changed, 108 insertions(+), 108 deletions(-) ## Stress-test (10 cenários) ✓ path.relative gera `../foo` ou `./foo` corretamente ✓ Sem imports circulares (auth/sla não importam inbox) ✓ Comments inline preservados (replace só no string interno) ✓ BOM/CRLF tratados pelo Node ✓ index.ts implícito resolvido pelo TS path mapping ✓ Build não quebrou — tsconfig path mapping continua funcionando ✓ Typecheck sem regressão ✓ Sem sessão paralela (verificado via git reflog) ✓ Barrels já existiam, useUserRole/useSLAAlerts já re-exportados ✓ Eslint --fix NÃO usado (só explicit replace, sem side effects) ## Pós-Onda 5 Próximo do roadmap pré-deploy: - PR #108 (preserve/faxina) — decidir mergear ou fechar - 8 dependabots — aplicar recomendação A (fechar com TODO pós-deploy) - Fase B10 — patch 9 vulns npm - Fase B5 — ENV_SETUP doc - Fase C — Dockerfile + deploy zapp.atomicabr.com.br
🎉 Fecha Onda 5: 108 → 0 errors (-108). ESLint TOTAL: 164 → 0 errors em 4 PRs (#109, #110, #111, este). ## Estratégia DDD Regra `no-restricted-imports` (eslint.config.js) bloqueia: 1. Imports cross-feature deep (`@/features/X/...`) — força entry points 2. Imports relativos profundos (`../../...`) 3. INTRA-feature via alias (`@/features/X/Y` quando arquivo está em X) ## Batch A — INTRA-feature (106 fixes em 42 arquivos) Pattern: `@/features/X/Y/Z` → caminho relativo via path.relative() Ex (src/features/inbox/components/chat/ChatHeader.tsx): - ANTES: `@/features/inbox/components/ai-tools/VisionIcon` - DEPOIS: `../ai-tools/VisionIcon` Distribuição: - 92 inbox (52 chat, 12 contact-details, 8 components, 5 hooks, 3 services, 3 virtualized, 3 conversation-list, 2 realtime, 2 templates, 2 search, 1 monitoring, 1 mocks) - 7 auth (5 components, 1 hooks, 1 context) - 3 admin (2 hooks, 1 services) - 3 connections (2 hooks, 1 services) - 1 sla (1 components) Script: /tmp/fix-intra.mjs (Node + path.relative) - 106/106 sucesso, zero falhas - 1 read/write por arquivo (eficiente) - Ordem desc por linha (não invalida índices) ## Batch B — CROSS-feature (2 fixes) Imports de outra feature DEVEM usar entry point (`@/features/X`), não path interno (`@/features/X/hooks/...`). Os barrels já existiam (`auth/index.ts` e `sla/index.ts` fazem `export * from './hooks'`), só não estavam sendo usados: - src/features/inbox/components/ChatPanel.tsx: `@/features/auth/hooks/useUserRole` → `@/features/auth` - src/features/inbox/components/RealtimeInboxView.tsx: `@/features/sla/hooks/useSLAAlerts` → `@/features/sla` ## Validação - bunx eslint . → 0 errors, 1330 warnings (Onda 5 ZERADA) - bunx tsc --noEmit → ✓ sem erros (typecheck pristine) - bun run build → ✓ built in 58.09s (zero regressões) - 44 files changed, 108 insertions(+), 108 deletions(-) ## Stress-test (10 cenários) ✓ path.relative gera `../foo` ou `./foo` corretamente ✓ Sem imports circulares (auth/sla não importam inbox) ✓ Comments inline preservados (replace só no string interno) ✓ BOM/CRLF tratados pelo Node ✓ index.ts implícito resolvido pelo TS path mapping ✓ Build não quebrou — tsconfig path mapping continua funcionando ✓ Typecheck sem regressão ✓ Sem sessão paralela (verificado via git reflog) ✓ Barrels já existiam, useUserRole/useSLAAlerts já re-exportados ✓ Eslint --fix NÃO usado (só explicit replace, sem side effects) ## Pós-Onda 5 Próximo do roadmap pré-deploy: - PR #108 (preserve/faxina) — decidir mergear ou fechar - 8 dependabots — aplicar recomendação A (fechar com TODO pós-deploy) - Fase B10 — patch 9 vulns npm - Fase B5 — ENV_SETUP doc - Fase C — Dockerfile + deploy zapp.atomicabr.com.br
…09) (#113) Documenta o estado FINAL após: - Onda 5 completa (164 → 0 errors em 4 PRs: #109, #110, #111, #112) - 8 dependabots resolvidos (3 mergeados, 5 fechados, 1 preservation closed) Estado atual: - HEAD main: f1b3eab - ESLint: 0 errors, 1330 warnings - Branches remotas: 2 (main + preserve) - PRs OPEN: 0 Conteúdo do handoff (718 linhas): - TL;DR + estado atual com métricas - Quem é Joaquim e workflow - Histórico cronológico de TODOS os PRs (Schemas, Faxina pré-Onda, Ondas 1, 2, 5) - Faxina de branches (491 → 2) - Resolução técnica dos 8 dependabots - Decisões técnicas-chave (React 18, Vite reject, Sentry accept, etc) - 20 lições aprendidas - Catálogo de notes em /workspace/notes/ - Pendências pré-deploy (Backup Supabase, RabbitMQ 69GB, Drift, Deploy VPS, FX-DEP-02) - Backlogs de review skipped - Como retomar (instruções pra próximo Claude) - Apêndices: comandos úteis, infra VPS, Vercel, workflow Este doc serve como ponto de retomada pra próxima sessão Claude sem perder contexto.
Resumo
Reduz ESLint errors de 142 → 128 (-14, -10%) eliminando todos os
no-explicit-anyem arquivos de teste/mock.no-explicit-anyEstratégia
Onda 5 fatiada em sub-PRs pra revisão incremental. Este é 5.2a — só toca em arquivos de teste e mocks, risco mínimo (não afeta produção).
Mudanças
src/test/mocks/supabase.ts(5 fixes)createQueryBuilder(resolvedData: any, resolvedError: any)→unknownbuilder(TS infere shape do literal — é o que queremos pra chainable mock)then()resolve callback agora tipadocreateMockSupabase(overrides: Record<string, any>)→ tipo dedicadoSupabaseOverridescomauthetablescorretamente shapeadossrc/test/mocks/auth.tsx(3 fixes)mockUser/mockSession/mockProfile as any→as unknown as typeof X(mantém flexibilidade do mock sem usarany)src/hooks/useEmailActions.test.ts(2 fixes)_supabase as any→as unknown as typeof _supabaseerror: { message } as any→as unknown as Errorsrc/hooks/useEmailDraft.test.ts(1 fix)_supabase as any→as unknown as typeof _supabasesrc/utils/emailMappers.test.ts(2 fixes)null/undefined as any→as unknown as Parameters<typeof emailMappers.X>[0](preserva intent de testar input inválido)src/features/inbox/hooks/__tests__/useMessageQueueE2E.spec.tsx(1 fix)processMessage: any→(...args: unknown[]) => unknownValidação
bun run lint→ 128 errors (era 142)bun run build→ built in 1m 3sbunx vitest runnos arquivos modificados:emailMappers.test.ts: 11/11 passuseEmailDraft.test.ts: 5/5 passuseEmailActions.test.ts: 20/21 pass (1 falha pre-existente, NÃO introduzida por este PR — confirmado rodando mesmo teste emmainonde nem inicia)Backlog Onda 5 (próximos PRs)
no-unused-expressions+ 7 outros (~17 errors em código real)no-restricted-imports(DDD: 106 INTRA-feature codemod + 2 cross-feature barrel)Governance
Summary by CodeRabbit
Versão de Lançamento