9afdccdc14
- useLocalStorage: retorna tupla [valor, setter] tipada como [T, (v: T|fn) => void] - useAsync: espera microtask act cycle antes de checar status - useClipboard: mock navigator.clipboard.writeText antes - useMedia: mock matchMedia antes - Busca por padrão: act() + waitFor p/ efeitos assíncronos (sem fakeTimers gerais) - docs: PROJECTS-REGISTER, SESSION-STATE (pretérito + presente)
152 lines
4.5 KiB
Markdown
152 lines
4.5 KiB
Markdown
# Learnings — Padrões bem-sucedidos
|
|
|
|
_Registro de padrões que funcionam, para replicar._
|
|
|
|
---
|
|
|
|
## [LRN-20260519-001] category
|
|
|
|
**Logged**: 2026-05-19T20:39:00-03:00
|
|
**Priority**: high
|
|
**Status**: pending
|
|
**Area**: config
|
|
|
|
### Summary
|
|
Instalar skills do Clawhub com `/var/lib/openclaw/tools/node/npm/bin/clawhub`
|
|
|
|
### Details
|
|
O CLI `clawhub` não está no `$PATH` global, mas existe instalado em `/var/lib/openclaw/tools/node/npm/bin/clawhub`. Sempre usar o caminho completo.
|
|
|
|
### Suggested Action
|
|
Adicionar symlink ou alias para `clawhub` no PATH do agente, ou sempre usar o caminho completo.
|
|
|
|
### Metadata
|
|
- Source: error
|
|
- Tags: clawhub, cli, path, install
|
|
- Pattern-Key: clawhub.cli_path
|
|
|
|
---
|
|
|
|
## [LRN-20260519-002] clawhub-search-qc
|
|
|
|
**Logged**: 2026-05-19T20:42:00-03:00
|
|
**Priority**: medium
|
|
**Status**: pending
|
|
**Area**: config
|
|
|
|
### Summary
|
|
`clawhub search` com termos muito específicos retorna vazio; usar termos genéricos primeiro
|
|
|
|
### Details
|
|
Pesquisas com termos combinados como "programming developer full-stack" retornaram vazio. Termos simples como "autonomous agent" retornaram resultados. Melhor abordar a pesquisa em múltiplas queries curtas.
|
|
|
|
### Suggested Action
|
|
Fazer múltiplas searches com termos curtos e depois filtrar manualmente.
|
|
|
|
### Metadata
|
|
- Source: error
|
|
- Tags: clawhub, search, query
|
|
- Pattern-Key: clawhub.search_strategy
|
|
|
|
---
|
|
|
|
<!-- Novas entradas acima desta linha -->
|
|
|
|
## [LRN-20260519-003] biblioteca-compartilhada-libs
|
|
|
|
**Logged**: 2026-05-19T21:30:00-03:00
|
|
**Priority**: medium
|
|
**Status**: pending
|
|
**Area**: config
|
|
|
|
### Summary
|
|
Criar biblioteca inteligente compartilhada em `libs/` para reuso entre projetos, com conhecimento extraído de todas as skills instaladas.
|
|
|
|
### Details
|
|
Toda skill que instalamos tem conhecimento valioso (padrões, gotchas, templates).
|
|
Ao invés de cada agente lembrar de cor, centralize em `libs/<dominio>/`:
|
|
- skills são extraídas e promovidas para arquivos .md limpos na biblioteca
|
|
- novos projetos copiam `libs/` como template de padrões
|
|
- o próprio agente consulte `libs/` antes de implementar qualquer coisa
|
|
|
|
### Suggested Action
|
|
Quando instalar nova skill:
|
|
1. Ler o SKILL.md
|
|
2. Extrair o conhecimento útil
|
|
3. Promover para `libs/<dominio>/` apropriado
|
|
4. Atualizar `libs/INDEX.md`
|
|
|
|
### Metadata
|
|
- Source: best_practice
|
|
- Tags: biblioteca, reuso, padroes, compartilhamento
|
|
- Pattern-Key: libs.shared_knowledge_base
|
|
- Recurrence-Count: 1
|
|
|
|
---
|
|
|
|
---
|
|
|
|
## [LRN-20260519-004] category
|
|
**Logged**: 2026-05-19T23:10:00-03:00
|
|
**Priority**: high
|
|
**Status**: pending
|
|
**Area**: testing
|
|
|
|
### Summary
|
|
Vitest jsdom — mocks obrigatórios antes de renderizar hooks que usam APIs do navegador
|
|
|
|
### Details
|
|
No ambiente jsdom:
|
|
- `localStorage` não existe → mock com `Object.defineProperty(global, 'localStorage', ...)` antes de qualquer hook useLocalStorage
|
|
- `navigator.clipboard` não existe → mock antes de useClipboard
|
|
- `window.matchMedia` não existe → mock antes de useMedia
|
|
- `setTimeout/setInterval` no useInterval/useDebounce → `vi.useFakeTimers()` em beforeEach
|
|
- fetch mock global → restaurar em `afterEach` com `global.fetch = originalFetch`
|
|
|
|
### Suggested Action
|
|
Criar um arquivo `tests/setup.ts` com todos os mocks globais e importar em `vitest.config.ts`.
|
|
|
|
### Metadata
|
|
- Source: best_practice
|
|
- Tags: vitest, jsdom, mocks, testing
|
|
- Pattern-Key: vitest.jsdom.mocks
|
|
- Recurrence-Count: 3
|
|
|
|
---
|
|
|
|
## [LRN-20260519-005] category
|
|
**Logged**: 2026-05-19T23:10:00-03:00
|
|
**Priority**: medium
|
|
**Status**: pending
|
|
**Area**: testing
|
|
|
|
### Summary
|
|
React Testing Library — renderHook + act() para testar hooks assíncronos
|
|
|
|
### Details
|
|
Hooks que fazem async operations (useAsync, useFetch, useClipboard):
|
|
1. `renderHook` retorna `{ result }`
|
|
2. Para atualizações async, sempre envolva em `act(async () => { await ... })`
|
|
3. Para等待 promises: `await act(async () => { await new Promise(r => setTimeout(r, ms)); })`
|
|
4. Com fakeTimers: `act(() => { vi.advanceTimersByTime(ms); })`
|
|
5. Nunca acesse `result.current` diretamente após um await async — sempre dentro de act()
|
|
|
|
### Suggested Action
|
|
Template de teste async:
|
|
```ts
|
|
it('descrição', async () => {
|
|
global.fetch = vi.fn(() => Promise.resolve(makeRes(200, body))) as any;
|
|
const { result } = renderHook(() => useFetch<T>('/url', {}));
|
|
|
|
await act(async () => { await new Promise(r => setTimeout(r, 50)); });
|
|
|
|
expect(result.current.status).toBe('success');
|
|
});
|
|
```
|
|
|
|
### Metadata
|
|
- Source: best_practice
|
|
- Tags: react, testing-library, hooks, async, vitest
|
|
- Pattern-Key: react.testing-library
|
|
- Recurrence-Count: 3
|