@maestro-ai/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -0
- package/content/guides/Cat/303/241logo de Stacks para Cloud Moderna.md" +119 -0
- package/content/guides/Cat/303/241logo de Stacks para Hospedagem Compartilhada.md" +147 -0
- package/content/guides/Checklist Mestre de Entrega.md +68 -0
- package/content/guides/Gates de Qualidade.md +209 -0
- package/content/guides/Guia de Adi/303/247/303/243o de Novas Funcionalidades.md" +355 -0
- package/content/guides/Guia de Chaos Engineering.md +267 -0
- package/content/guides/Guia de Debugging com IA.md +135 -0
- package/content/guides/Guia de Estrat/303/251gias de Cache.md" +352 -0
- package/content/guides/Guia de Migrations Zero-Downtime.md +311 -0
- package/content/guides/Guia de Multi-tenancy.md +368 -0
- package/content/guides/Guia de Otimiza/303/247/303/243o de Custos Cloud.md" +195 -0
- package/content/guides/Guia de Refatora/303/247/303/243o de C/303/263digo Legado com IA.md" +162 -0
- package/content/guides/Guia de SLOs e Error Budgets.md +315 -0
- package/content/guides/M/303/251tricas de Efici/303/252ncia do Desenvolvimento com IA.md" +93 -0
- package/content/guides/Rules base.md +90 -0
- package/content/prompts/README.md +203 -0
- package/content/prompts/acessibilidade/analise-acessibilidade.md +257 -0
- package/content/prompts/apis/design-api-rest.md +303 -0
- package/content/prompts/apis/idempotencia.md +254 -0
- package/content/prompts/apis/versionamento.md +313 -0
- package/content/prompts/arquitetura/arquitetura-c4-completo.md +190 -0
- package/content/prompts/arquitetura/clean-architecture.md +151 -0
- package/content/prompts/arquitetura/ddd-bounded-contexts.md +183 -0
- package/content/prompts/arquitetura/ddd-cqrs.md +176 -0
- package/content/prompts/arquitetura/modelo-dominio.md +207 -0
- package/content/prompts/arquitetura/multi-tenancy.md +235 -0
- package/content/prompts/database/migrations-zero-downtime.md +192 -0
- package/content/prompts/database/otimizacao-queries.md +296 -0
- package/content/prompts/desenvolvimento/code-review.md +301 -0
- package/content/prompts/desenvolvimento/gerar-servico.md +271 -0
- package/content/prompts/devops/docker-compose.md +336 -0
- package/content/prompts/devops/feature-flags.md +374 -0
- package/content/prompts/devops/kubernetes-deploy.md +460 -0
- package/content/prompts/devops/pipeline-cicd.md +358 -0
- package/content/prompts/devops/terraform-iac.md +502 -0
- package/content/prompts/escalabilidade/analise-performance.md +240 -0
- package/content/prompts/escalabilidade/analise-performance.txt +94 -0
- package/content/prompts/escalabilidade/caching.md +255 -0
- package/content/prompts/observabilidade/chaos-testing.md +237 -0
- package/content/prompts/observabilidade/estrategia-observabilidade.md +263 -0
- package/content/prompts/observabilidade/estrategia-observabilidade.txt +134 -0
- package/content/prompts/observabilidade/slos.md +215 -0
- package/content/prompts/produto/discovery-inicial.md +203 -0
- package/content/prompts/produto/discovery-inicial.txt +33 -0
- package/content/prompts/requisitos/refinar-requisitos.md +232 -0
- package/content/prompts/requisitos/refinar-requisitos.txt +40 -0
- package/content/prompts/seguranca/analise-seguranca.md +243 -0
- package/content/prompts/seguranca/pentest-checklist.md +333 -0
- package/content/prompts/seguranca/rate-limiting.md +356 -0
- package/content/prompts/seguranca/revisao-lgpd.md +227 -0
- package/content/prompts/seguranca/threat-modeling.md +224 -0
- package/content/prompts/testes/contract-testing.md +340 -0
- package/content/prompts/testes/gerar-testes-unitarios.md +474 -0
- package/content/prompts/testes/testes-e2e.md +460 -0
- package/content/prompts/testes/testes-integracao.md +418 -0
- package/content/prompts/testes/testes-performance.md +458 -0
- package/content/prompts/ux/gerar-ui-stitch.md +151 -0
- package/content/skills/api-patterns/SKILL.md +81 -0
- package/content/skills/api-patterns/api-style.md +42 -0
- package/content/skills/api-patterns/auth.md +24 -0
- package/content/skills/api-patterns/documentation.md +26 -0
- package/content/skills/api-patterns/graphql.md +41 -0
- package/content/skills/api-patterns/rate-limiting.md +31 -0
- package/content/skills/api-patterns/response.md +37 -0
- package/content/skills/api-patterns/rest.md +40 -0
- package/content/skills/api-patterns/scripts/api_validator.py +211 -0
- package/content/skills/api-patterns/security-testing.md +122 -0
- package/content/skills/api-patterns/trpc.md +41 -0
- package/content/skills/api-patterns/versioning.md +22 -0
- package/content/skills/app-builder/SKILL.md +75 -0
- package/content/skills/app-builder/agent-coordination.md +71 -0
- package/content/skills/app-builder/feature-building.md +53 -0
- package/content/skills/app-builder/project-detection.md +34 -0
- package/content/skills/app-builder/scaffolding.md +118 -0
- package/content/skills/app-builder/tech-stack.md +40 -0
- package/content/skills/app-builder/templates/SKILL.md +39 -0
- package/content/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
- package/content/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
- package/content/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
- package/content/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
- package/content/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
- package/content/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
- package/content/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
- package/content/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +82 -0
- package/content/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +100 -0
- package/content/skills/app-builder/templates/nextjs-static/TEMPLATE.md +106 -0
- package/content/skills/app-builder/templates/nuxt-app/TEMPLATE.md +101 -0
- package/content/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
- package/content/skills/app-builder/templates/react-native-app/TEMPLATE.md +93 -0
- package/content/skills/architecture/SKILL.md +55 -0
- package/content/skills/architecture/context-discovery.md +43 -0
- package/content/skills/architecture/examples.md +94 -0
- package/content/skills/architecture/pattern-selection.md +68 -0
- package/content/skills/architecture/patterns-reference.md +50 -0
- package/content/skills/architecture/trade-off-analysis.md +77 -0
- package/content/skills/bash-linux/SKILL.md +199 -0
- package/content/skills/behavioral-modes/SKILL.md +242 -0
- package/content/skills/brainstorming/SKILL.md +163 -0
- package/content/skills/brainstorming/dynamic-questioning.md +350 -0
- package/content/skills/clean-code/SKILL.md +201 -0
- package/content/skills/code-review-checklist/SKILL.md +109 -0
- package/content/skills/database-design/SKILL.md +52 -0
- package/content/skills/database-design/database-selection.md +43 -0
- package/content/skills/database-design/indexing.md +39 -0
- package/content/skills/database-design/migrations.md +48 -0
- package/content/skills/database-design/optimization.md +36 -0
- package/content/skills/database-design/orm-selection.md +30 -0
- package/content/skills/database-design/schema-design.md +56 -0
- package/content/skills/database-design/scripts/schema_validator.py +172 -0
- package/content/skills/deployment-procedures/SKILL.md +241 -0
- package/content/skills/doc.md +177 -0
- package/content/skills/documentation-templates/SKILL.md +194 -0
- package/content/skills/frontend-design/SKILL.md +396 -0
- package/content/skills/frontend-design/animation-guide.md +331 -0
- package/content/skills/frontend-design/color-system.md +311 -0
- package/content/skills/frontend-design/decision-trees.md +418 -0
- package/content/skills/frontend-design/motion-graphics.md +306 -0
- package/content/skills/frontend-design/scripts/accessibility_checker.py +183 -0
- package/content/skills/frontend-design/scripts/ux_audit.py +722 -0
- package/content/skills/frontend-design/typography-system.md +345 -0
- package/content/skills/frontend-design/ux-psychology.md +541 -0
- package/content/skills/frontend-design/visual-effects.md +383 -0
- package/content/skills/game-development/2d-games/SKILL.md +119 -0
- package/content/skills/game-development/3d-games/SKILL.md +135 -0
- package/content/skills/game-development/SKILL.md +167 -0
- package/content/skills/game-development/game-art/SKILL.md +185 -0
- package/content/skills/game-development/game-audio/SKILL.md +190 -0
- package/content/skills/game-development/game-design/SKILL.md +129 -0
- package/content/skills/game-development/mobile-games/SKILL.md +108 -0
- package/content/skills/game-development/multiplayer/SKILL.md +132 -0
- package/content/skills/game-development/pc-games/SKILL.md +144 -0
- package/content/skills/game-development/vr-ar/SKILL.md +123 -0
- package/content/skills/game-development/web-games/SKILL.md +150 -0
- package/content/skills/geo-fundamentals/SKILL.md +156 -0
- package/content/skills/geo-fundamentals/scripts/geo_checker.py +289 -0
- package/content/skills/i18n-localization/SKILL.md +154 -0
- package/content/skills/i18n-localization/scripts/i18n_checker.py +241 -0
- package/content/skills/intelligent-routing/SKILL.md +334 -0
- package/content/skills/lint-and-validate/SKILL.md +45 -0
- package/content/skills/lint-and-validate/scripts/lint_runner.py +172 -0
- package/content/skills/lint-and-validate/scripts/type_coverage.py +173 -0
- package/content/skills/mcp-builder/SKILL.md +176 -0
- package/content/skills/mobile-design/SKILL.md +394 -0
- package/content/skills/mobile-design/decision-trees.md +516 -0
- package/content/skills/mobile-design/mobile-backend.md +491 -0
- package/content/skills/mobile-design/mobile-color-system.md +420 -0
- package/content/skills/mobile-design/mobile-debugging.md +122 -0
- package/content/skills/mobile-design/mobile-design-thinking.md +357 -0
- package/content/skills/mobile-design/mobile-navigation.md +458 -0
- package/content/skills/mobile-design/mobile-performance.md +767 -0
- package/content/skills/mobile-design/mobile-testing.md +356 -0
- package/content/skills/mobile-design/mobile-typography.md +433 -0
- package/content/skills/mobile-design/platform-android.md +666 -0
- package/content/skills/mobile-design/platform-ios.md +561 -0
- package/content/skills/mobile-design/scripts/mobile_audit.py +670 -0
- package/content/skills/mobile-design/touch-psychology.md +537 -0
- package/content/skills/nextjs-best-practices/SKILL.md +203 -0
- package/content/skills/nodejs-best-practices/SKILL.md +333 -0
- package/content/skills/parallel-agents/SKILL.md +175 -0
- package/content/skills/performance-profiling/SKILL.md +143 -0
- package/content/skills/performance-profiling/scripts/lighthouse_audit.py +76 -0
- package/content/skills/plan-writing/SKILL.md +152 -0
- package/content/skills/powershell-windows/SKILL.md +167 -0
- package/content/skills/python-patterns/SKILL.md +441 -0
- package/content/skills/react-patterns/SKILL.md +198 -0
- package/content/skills/red-team-tactics/SKILL.md +199 -0
- package/content/skills/seo-fundamentals/SKILL.md +129 -0
- package/content/skills/seo-fundamentals/scripts/seo_checker.py +219 -0
- package/content/skills/server-management/SKILL.md +161 -0
- package/content/skills/systematic-debugging/SKILL.md +109 -0
- package/content/skills/tailwind-patterns/SKILL.md +269 -0
- package/content/skills/tdd-workflow/SKILL.md +149 -0
- package/content/skills/testing-patterns/SKILL.md +178 -0
- package/content/skills/testing-patterns/scripts/test_runner.py +219 -0
- package/content/skills/vulnerability-scanner/SKILL.md +276 -0
- package/content/skills/vulnerability-scanner/checklists.md +121 -0
- package/content/skills/vulnerability-scanner/scripts/security_scan.py +458 -0
- package/content/skills/webapp-testing/SKILL.md +187 -0
- package/content/skills/webapp-testing/scripts/playwright_runner.py +173 -0
- package/content/specialists/Especialista em Acessibilidade.md +266 -0
- package/content/specialists/Especialista em An/303/241lise de Testes.md" +434 -0
- package/content/specialists/Especialista em Arquitetura Avan/303/247ada.md" +358 -0
- package/content/specialists/Especialista em Arquitetura de Software.md +177 -0
- package/content/specialists/Especialista em Banco de Dados.md +260 -0
- package/content/specialists/Especialista em Contrato de API.md +172 -0
- package/content/specialists/Especialista em Dados e Analytics com IA.md +246 -0
- package/content/specialists/Especialista em Debugging e Troubleshooting.md +191 -0
- package/content/specialists/Especialista em Desenvolvimento Frontend.md +477 -0
- package/content/specialists/Especialista em Desenvolvimento Mobile.md +241 -0
- package/content/specialists/Especialista em Desenvolvimento e Vibe Coding Estruturado.md +417 -0
- package/content/specialists/Especialista em DevOps e Infraestrutura.md +294 -0
- package/content/specialists/Especialista em Documenta/303/247/303/243o T/303/251cnica.md" +227 -0
- package/content/specialists/Especialista em Engenharia de Requisitos com IA.md +299 -0
- package/content/specialists/Especialista em Explora/303/247/303/243o de Codebase.md" +179 -0
- package/content/specialists/Especialista em Gest/303/243o de Produto.md" +179 -0
- package/content/specialists/Especialista em Migra/303/247/303/243o e Moderniza/303/247/303/243o.md" +410 -0
- package/content/specialists/Especialista em Modelagem e Arquitetura de Dom/303/255nio com IA.md" +248 -0
- package/content/specialists/Especialista em Observabilidade.md +415 -0
- package/content/specialists/Especialista em Performance e Escalabilidade.md +373 -0
- package/content/specialists/Especialista em Plano de Execu/303/247/303/243o com IA.md" +341 -0
- package/content/specialists/Especialista em Prototipagem R/303/241pida com Google Stitch.md" +419 -0
- package/content/specialists/Especialista em Seguran/303/247a da Informa/303/247/303/243o.md" +508 -0
- package/content/specialists/Especialista em UX Design.md +453 -0
- package/content/specialists/INDEX.md +43 -0
- package/content/templates/PRD.md +165 -0
- package/content/templates/README.md +65 -0
- package/content/templates/adr.md +103 -0
- package/content/templates/arquitetura.md +279 -0
- package/content/templates/backlog.md +185 -0
- package/content/templates/checklist-seguranca.md +180 -0
- package/content/templates/contexto.md +120 -0
- package/content/templates/criterios-aceite.md +99 -0
- package/content/templates/design-banco.md +270 -0
- package/content/templates/design-doc.md +240 -0
- package/content/templates/feature.md +88 -0
- package/content/templates/historia-backend.md +84 -0
- package/content/templates/historia-frontend.md +75 -0
- package/content/templates/historia-usuario.md +125 -0
- package/content/templates/mapa-navegacao.md +133 -0
- package/content/templates/matriz-rastreabilidade.md +121 -0
- package/content/templates/modelo-dominio.md +219 -0
- package/content/templates/plano-testes.md +199 -0
- package/content/templates/prototipo-stitch.md +138 -0
- package/content/templates/requisitos.md +162 -0
- package/content/templates/slo-sli.md +197 -0
- package/content/workflows/README-MCP.md +363 -0
- package/content/workflows/brainstorm.md +113 -0
- package/content/workflows/create.md +59 -0
- package/content/workflows/debug.md +103 -0
- package/content/workflows/deploy.md +176 -0
- package/content/workflows/enhance.md +63 -0
- package/content/workflows/mcp-debug.md +506 -0
- package/content/workflows/mcp-feature.md +385 -0
- package/content/workflows/mcp-gate.md +413 -0
- package/content/workflows/mcp-next.md +388 -0
- package/content/workflows/mcp-refactor.md +600 -0
- package/content/workflows/mcp-start.md +304 -0
- package/content/workflows/mcp-status.md +400 -0
- package/content/workflows/orchestrate.md +237 -0
- package/content/workflows/plan.md +89 -0
- package/content/workflows/preview.md +81 -0
- package/content/workflows/status.md +86 -0
- package/content/workflows/test.md +144 -0
- package/content/workflows/ui-ux-pro-max.md +296 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.js +138 -0
- package/dist/commands/update.d.ts +5 -0
- package/dist/commands/update.js +50 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +21 -0
- package/package.json +48 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
# Prompt: Gerar Testes Unitários
|
|
2
|
+
|
|
3
|
+
> **Quando usar**: Após implementar uma classe/função, para criar testes
|
|
4
|
+
> **Especialista**: [Análise de Testes](../../02-especialistas/Especialista%20em%20Análise%20de%20Testes.md)
|
|
5
|
+
> **Nível**: Simples a Médio
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Fluxo de Contexto
|
|
10
|
+
|
|
11
|
+
Antes de usar este prompt, tenha em mãos:
|
|
12
|
+
- Código da classe/função a ser testada
|
|
13
|
+
- Entendimento das regras de negócio
|
|
14
|
+
|
|
15
|
+
Após gerar, salve os testes em:
|
|
16
|
+
- `src/__tests__/` ou `tests/` conforme convenção do projeto
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Prompt Completo
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
Atue como engenheiro de qualidade especializado em testes automatizados.
|
|
24
|
+
|
|
25
|
+
## Contexto do Projeto
|
|
26
|
+
|
|
27
|
+
[COLE BREVE CONTEXTO - O que o sistema faz]
|
|
28
|
+
|
|
29
|
+
## Código a Testar
|
|
30
|
+
|
|
31
|
+
```[LINGUAGEM]
|
|
32
|
+
[COLE O CÓDIGO DA CLASSE/FUNÇÃO]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Stack de Testes
|
|
36
|
+
|
|
37
|
+
Framework: [Jest/Pytest/JUnit/xUnit/Vitest/etc]
|
|
38
|
+
Linguagem: [TypeScript/Python/Java/C#/etc]
|
|
39
|
+
Mocking: [jest.mock/unittest.mock/Mockito/etc]
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Sua Missão
|
|
44
|
+
|
|
45
|
+
Gere testes unitários completos seguindo boas práticas:
|
|
46
|
+
|
|
47
|
+
### 1. Estrutura dos Testes
|
|
48
|
+
|
|
49
|
+
Use o padrão AAA (Arrange, Act, Assert):
|
|
50
|
+
- **Arrange**: Preparar dados e mocks
|
|
51
|
+
- **Act**: Executar a ação
|
|
52
|
+
- **Assert**: Verificar resultado
|
|
53
|
+
|
|
54
|
+
### 2. Cenários Obrigatórios
|
|
55
|
+
|
|
56
|
+
Para cada método público, cubra:
|
|
57
|
+
|
|
58
|
+
#### Happy Path
|
|
59
|
+
- Fluxo de sucesso com dados válidos
|
|
60
|
+
- Retorno esperado correto
|
|
61
|
+
|
|
62
|
+
#### Edge Cases (Casos de Borda)
|
|
63
|
+
- Valores mínimos/máximos
|
|
64
|
+
- Listas vazias
|
|
65
|
+
- Strings vazias
|
|
66
|
+
- Null/undefined (se aplicável)
|
|
67
|
+
- Zero, números negativos
|
|
68
|
+
|
|
69
|
+
#### Error Cases
|
|
70
|
+
- Entradas inválidas
|
|
71
|
+
- Exceções esperadas
|
|
72
|
+
- Mensagens de erro corretas
|
|
73
|
+
|
|
74
|
+
#### Validation Cases
|
|
75
|
+
- Cada regra de validação testada
|
|
76
|
+
- Combinações de validações
|
|
77
|
+
|
|
78
|
+
### 3. Mocking
|
|
79
|
+
|
|
80
|
+
Para cada dependência (repositório, serviço externo):
|
|
81
|
+
- Mock da dependência
|
|
82
|
+
- Configurar retornos para cada cenário
|
|
83
|
+
- Verificar que foi chamado corretamente
|
|
84
|
+
|
|
85
|
+
### 4. Formato do Teste
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
describe('[NomeClasse]', () => {
|
|
89
|
+
describe('[nomeMetodo]', () => {
|
|
90
|
+
it('deve [fazer algo] quando [condição]', () => {
|
|
91
|
+
// Arrange
|
|
92
|
+
// Act
|
|
93
|
+
// Assert
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 5. Comentários
|
|
100
|
+
|
|
101
|
+
Para cada teste, inclua:
|
|
102
|
+
- Comentário de 1 linha explicando o que garante
|
|
103
|
+
- Anotação se é happy path, edge case ou error case
|
|
104
|
+
|
|
105
|
+
### 6. Coverage Mínimo
|
|
106
|
+
|
|
107
|
+
- Todas as branches (if/else)
|
|
108
|
+
- Todos os catches de exceção
|
|
109
|
+
- Todos os retornos possíveis
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Exemplo de Uso
|
|
115
|
+
|
|
116
|
+
```text
|
|
117
|
+
Atue como engenheiro de qualidade especializado em testes automatizados.
|
|
118
|
+
|
|
119
|
+
## Contexto do Projeto
|
|
120
|
+
|
|
121
|
+
Sistema de agendamento para salões de beleza.
|
|
122
|
+
|
|
123
|
+
## Código a Testar
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
@Injectable()
|
|
127
|
+
export class AgendamentoService {
|
|
128
|
+
constructor(
|
|
129
|
+
private readonly repository: AgendamentoRepository,
|
|
130
|
+
private readonly notificacao: NotificacaoService,
|
|
131
|
+
) {}
|
|
132
|
+
|
|
133
|
+
async criar(dto: CriarAgendamentoDto): Promise<Agendamento> {
|
|
134
|
+
if (dto.dataHora < new Date()) {
|
|
135
|
+
throw new BadRequestException('Não é possível agendar no passado');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const conflito = await this.repository.findByHorario(dto.dataHora);
|
|
139
|
+
if (conflito) {
|
|
140
|
+
throw new ConflictException('Horário já ocupado');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const agendamento = await this.repository.create({
|
|
144
|
+
...dto,
|
|
145
|
+
status: StatusAgendamento.PENDENTE,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
await this.notificacao.enviarConfirmacao(agendamento);
|
|
149
|
+
return agendamento;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async cancelar(id: string): Promise<void> {
|
|
153
|
+
const agendamento = await this.repository.findById(id);
|
|
154
|
+
|
|
155
|
+
const limite = new Date(agendamento.dataHora);
|
|
156
|
+
limite.setHours(limite.getHours() - 2);
|
|
157
|
+
|
|
158
|
+
if (new Date() > limite) {
|
|
159
|
+
throw new BadRequestException('Cancelamento só até 2h antes');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
await this.repository.updateStatus(id, StatusAgendamento.CANCELADO);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Stack de Testes
|
|
168
|
+
|
|
169
|
+
Framework: Jest
|
|
170
|
+
Linguagem: TypeScript
|
|
171
|
+
Mocking: jest.mock
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Resposta Esperada
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { Test, TestingModule } from '@nestjs/testing';
|
|
180
|
+
import { AgendamentoService } from './agendamento.service';
|
|
181
|
+
import { AgendamentoRepository } from './agendamento.repository';
|
|
182
|
+
import { NotificacaoService } from '../notificacao/notificacao.service';
|
|
183
|
+
import { BadRequestException, ConflictException } from '@nestjs/common';
|
|
184
|
+
import { StatusAgendamento } from './enums/status-agendamento.enum';
|
|
185
|
+
|
|
186
|
+
describe('AgendamentoService', () => {
|
|
187
|
+
let service: AgendamentoService;
|
|
188
|
+
let repository: jest.Mocked<AgendamentoRepository>;
|
|
189
|
+
let notificacao: jest.Mocked<NotificacaoService>;
|
|
190
|
+
|
|
191
|
+
// Factory para criar DTOs de teste
|
|
192
|
+
const criarDto = (overrides = {}) => ({
|
|
193
|
+
clienteId: 'cliente-123',
|
|
194
|
+
servicoId: 'servico-456',
|
|
195
|
+
dataHora: new Date(Date.now() + 86400000), // amanhã
|
|
196
|
+
...overrides,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Factory para criar entidade mock
|
|
200
|
+
const criarAgendamento = (overrides = {}) => ({
|
|
201
|
+
id: 'agendamento-789',
|
|
202
|
+
...criarDto(),
|
|
203
|
+
status: StatusAgendamento.PENDENTE,
|
|
204
|
+
criadoEm: new Date(),
|
|
205
|
+
...overrides,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
beforeEach(async () => {
|
|
209
|
+
// Arrange: Setup dos mocks
|
|
210
|
+
const module: TestingModule = await Test.createTestingModule({
|
|
211
|
+
providers: [
|
|
212
|
+
AgendamentoService,
|
|
213
|
+
{
|
|
214
|
+
provide: AgendamentoRepository,
|
|
215
|
+
useValue: {
|
|
216
|
+
findById: jest.fn(),
|
|
217
|
+
findByHorario: jest.fn(),
|
|
218
|
+
create: jest.fn(),
|
|
219
|
+
updateStatus: jest.fn(),
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
provide: NotificacaoService,
|
|
224
|
+
useValue: {
|
|
225
|
+
enviarConfirmacao: jest.fn(),
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
}).compile();
|
|
230
|
+
|
|
231
|
+
service = module.get<AgendamentoService>(AgendamentoService);
|
|
232
|
+
repository = module.get(AgendamentoRepository);
|
|
233
|
+
notificacao = module.get(NotificacaoService);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('criar', () => {
|
|
237
|
+
// ========== HAPPY PATH ==========
|
|
238
|
+
|
|
239
|
+
// Garante que agendamento válido é criado com sucesso
|
|
240
|
+
it('deve criar agendamento quando horário está disponível', async () => {
|
|
241
|
+
// Arrange
|
|
242
|
+
const dto = criarDto();
|
|
243
|
+
const agendamentoCriado = criarAgendamento();
|
|
244
|
+
repository.findByHorario.mockResolvedValue(null);
|
|
245
|
+
repository.create.mockResolvedValue(agendamentoCriado);
|
|
246
|
+
notificacao.enviarConfirmacao.mockResolvedValue(undefined);
|
|
247
|
+
|
|
248
|
+
// Act
|
|
249
|
+
const resultado = await service.criar(dto);
|
|
250
|
+
|
|
251
|
+
// Assert
|
|
252
|
+
expect(resultado).toEqual(agendamentoCriado);
|
|
253
|
+
expect(resultado.status).toBe(StatusAgendamento.PENDENTE);
|
|
254
|
+
expect(repository.create).toHaveBeenCalledWith({
|
|
255
|
+
...dto,
|
|
256
|
+
status: StatusAgendamento.PENDENTE,
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Garante que notificação é enviada após criar
|
|
261
|
+
it('deve enviar notificação após criar agendamento', async () => {
|
|
262
|
+
// Arrange
|
|
263
|
+
const dto = criarDto();
|
|
264
|
+
const agendamentoCriado = criarAgendamento();
|
|
265
|
+
repository.findByHorario.mockResolvedValue(null);
|
|
266
|
+
repository.create.mockResolvedValue(agendamentoCriado);
|
|
267
|
+
|
|
268
|
+
// Act
|
|
269
|
+
await service.criar(dto);
|
|
270
|
+
|
|
271
|
+
// Assert
|
|
272
|
+
expect(notificacao.enviarConfirmacao).toHaveBeenCalledWith(agendamentoCriado);
|
|
273
|
+
expect(notificacao.enviarConfirmacao).toHaveBeenCalledTimes(1);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// ========== ERROR CASES ==========
|
|
277
|
+
|
|
278
|
+
// Garante que data no passado é rejeitada
|
|
279
|
+
it('deve lançar BadRequestException quando data é no passado', async () => {
|
|
280
|
+
// Arrange
|
|
281
|
+
const dto = criarDto({
|
|
282
|
+
dataHora: new Date('2020-01-01'), // data no passado
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Act & Assert
|
|
286
|
+
await expect(service.criar(dto)).rejects.toThrow(BadRequestException);
|
|
287
|
+
await expect(service.criar(dto)).rejects.toThrow('Não é possível agendar no passado');
|
|
288
|
+
expect(repository.create).not.toHaveBeenCalled();
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// Garante que conflito de horário é tratado
|
|
292
|
+
it('deve lançar ConflictException quando horário já está ocupado', async () => {
|
|
293
|
+
// Arrange
|
|
294
|
+
const dto = criarDto();
|
|
295
|
+
const agendamentoExistente = criarAgendamento();
|
|
296
|
+
repository.findByHorario.mockResolvedValue(agendamentoExistente);
|
|
297
|
+
|
|
298
|
+
// Act & Assert
|
|
299
|
+
await expect(service.criar(dto)).rejects.toThrow(ConflictException);
|
|
300
|
+
await expect(service.criar(dto)).rejects.toThrow('Horário já ocupado');
|
|
301
|
+
expect(repository.create).not.toHaveBeenCalled();
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// ========== EDGE CASES ==========
|
|
305
|
+
|
|
306
|
+
// Garante que data exatamente no momento atual é rejeitada
|
|
307
|
+
it('deve rejeitar agendamento com data igual ao momento atual', async () => {
|
|
308
|
+
// Arrange
|
|
309
|
+
const agora = new Date();
|
|
310
|
+
const dto = criarDto({ dataHora: agora });
|
|
311
|
+
|
|
312
|
+
// Act & Assert
|
|
313
|
+
await expect(service.criar(dto)).rejects.toThrow(BadRequestException);
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
describe('cancelar', () => {
|
|
318
|
+
// ========== HAPPY PATH ==========
|
|
319
|
+
|
|
320
|
+
// Garante que cancelamento funciona quando dentro do limite
|
|
321
|
+
it('deve cancelar agendamento quando falta mais de 2h', async () => {
|
|
322
|
+
// Arrange
|
|
323
|
+
const treHorasDepois = new Date(Date.now() + 3 * 60 * 60 * 1000);
|
|
324
|
+
const agendamento = criarAgendamento({ dataHora: treHorasDepois });
|
|
325
|
+
repository.findById.mockResolvedValue(agendamento);
|
|
326
|
+
|
|
327
|
+
// Act
|
|
328
|
+
await service.cancelar('agendamento-789');
|
|
329
|
+
|
|
330
|
+
// Assert
|
|
331
|
+
expect(repository.updateStatus).toHaveBeenCalledWith(
|
|
332
|
+
'agendamento-789',
|
|
333
|
+
StatusAgendamento.CANCELADO,
|
|
334
|
+
);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// ========== ERROR CASES ==========
|
|
338
|
+
|
|
339
|
+
// Garante que cancelamento tardio é rejeitado
|
|
340
|
+
it('deve lançar BadRequestException quando falta menos de 2h', async () => {
|
|
341
|
+
// Arrange
|
|
342
|
+
const umaHoraDepois = new Date(Date.now() + 1 * 60 * 60 * 1000);
|
|
343
|
+
const agendamento = criarAgendamento({ dataHora: umaHoraDepois });
|
|
344
|
+
repository.findById.mockResolvedValue(agendamento);
|
|
345
|
+
|
|
346
|
+
// Act & Assert
|
|
347
|
+
await expect(service.cancelar('agendamento-789')).rejects.toThrow(
|
|
348
|
+
BadRequestException,
|
|
349
|
+
);
|
|
350
|
+
await expect(service.cancelar('agendamento-789')).rejects.toThrow(
|
|
351
|
+
'Cancelamento só até 2h antes',
|
|
352
|
+
);
|
|
353
|
+
expect(repository.updateStatus).not.toHaveBeenCalled();
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// ========== EDGE CASES ==========
|
|
357
|
+
|
|
358
|
+
// Garante que exatamente 2h antes ainda permite cancelar
|
|
359
|
+
it('deve permitir cancelamento exatamente 2h antes', async () => {
|
|
360
|
+
// Arrange
|
|
361
|
+
const exatamenteDuasHoras = new Date(Date.now() + 2 * 60 * 60 * 1000 + 1000);
|
|
362
|
+
const agendamento = criarAgendamento({ dataHora: exatamenteDuasHoras });
|
|
363
|
+
repository.findById.mockResolvedValue(agendamento);
|
|
364
|
+
|
|
365
|
+
// Act
|
|
366
|
+
await service.cancelar('agendamento-789');
|
|
367
|
+
|
|
368
|
+
// Assert
|
|
369
|
+
expect(repository.updateStatus).toHaveBeenCalled();
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Variações por Framework
|
|
378
|
+
|
|
379
|
+
### Python + Pytest
|
|
380
|
+
|
|
381
|
+
```python
|
|
382
|
+
import pytest
|
|
383
|
+
from unittest.mock import Mock, AsyncMock
|
|
384
|
+
from datetime import datetime, timedelta
|
|
385
|
+
from app.services.agendamento_service import AgendamentoService
|
|
386
|
+
from app.exceptions import BadRequestError, ConflictError
|
|
387
|
+
|
|
388
|
+
class TestAgendamentoService:
|
|
389
|
+
@pytest.fixture
|
|
390
|
+
def repository(self):
|
|
391
|
+
return Mock()
|
|
392
|
+
|
|
393
|
+
@pytest.fixture
|
|
394
|
+
def service(self, repository):
|
|
395
|
+
return AgendamentoService(repository)
|
|
396
|
+
|
|
397
|
+
# Garante que agendamento válido é criado
|
|
398
|
+
async def test_criar_agendamento_sucesso(self, service, repository):
|
|
399
|
+
# Arrange
|
|
400
|
+
dto = {"data_hora": datetime.now() + timedelta(days=1)}
|
|
401
|
+
repository.find_by_horario.return_value = None
|
|
402
|
+
repository.create.return_value = {"id": "123", **dto}
|
|
403
|
+
|
|
404
|
+
# Act
|
|
405
|
+
resultado = await service.criar(dto)
|
|
406
|
+
|
|
407
|
+
# Assert
|
|
408
|
+
assert resultado["id"] == "123"
|
|
409
|
+
repository.create.assert_called_once()
|
|
410
|
+
|
|
411
|
+
# Garante que data passada é rejeitada
|
|
412
|
+
async def test_criar_agendamento_data_passada(self, service):
|
|
413
|
+
# Arrange
|
|
414
|
+
dto = {"data_hora": datetime(2020, 1, 1)}
|
|
415
|
+
|
|
416
|
+
# Act & Assert
|
|
417
|
+
with pytest.raises(BadRequestError):
|
|
418
|
+
await service.criar(dto)
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Java + JUnit
|
|
422
|
+
|
|
423
|
+
```java
|
|
424
|
+
@ExtendWith(MockitoExtension.class)
|
|
425
|
+
class AgendamentoServiceTest {
|
|
426
|
+
|
|
427
|
+
@Mock
|
|
428
|
+
private AgendamentoRepository repository;
|
|
429
|
+
|
|
430
|
+
@InjectMocks
|
|
431
|
+
private AgendamentoService service;
|
|
432
|
+
|
|
433
|
+
// Garante que agendamento válido é criado
|
|
434
|
+
@Test
|
|
435
|
+
void deveCriarAgendamentoQuandoHorarioDisponivel() {
|
|
436
|
+
// Arrange
|
|
437
|
+
var dto = new CriarAgendamentoDto(LocalDateTime.now().plusDays(1));
|
|
438
|
+
when(repository.findByHorario(any())).thenReturn(Optional.empty());
|
|
439
|
+
when(repository.create(any())).thenReturn(new Agendamento());
|
|
440
|
+
|
|
441
|
+
// Act
|
|
442
|
+
var resultado = service.criar(dto);
|
|
443
|
+
|
|
444
|
+
// Assert
|
|
445
|
+
assertNotNull(resultado);
|
|
446
|
+
verify(repository).create(any());
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Garante que data passada é rejeitada
|
|
450
|
+
@Test
|
|
451
|
+
void deveLancarExcecaoQuandoDataPassada() {
|
|
452
|
+
// Arrange
|
|
453
|
+
var dto = new CriarAgendamentoDto(LocalDateTime.of(2020, 1, 1, 10, 0));
|
|
454
|
+
|
|
455
|
+
// Act & Assert
|
|
456
|
+
assertThrows(BadRequestException.class, () -> service.criar(dto));
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Checklist Pós-Geração
|
|
464
|
+
|
|
465
|
+
- [ ] Todos os métodos públicos têm pelo menos 1 teste
|
|
466
|
+
- [ ] Happy path testado para cada método
|
|
467
|
+
- [ ] Error cases testados (exceções)
|
|
468
|
+
- [ ] Edge cases testados (limites, vazios, nulls)
|
|
469
|
+
- [ ] Mocks configurados corretamente
|
|
470
|
+
- [ ] Padrão AAA seguido (Arrange, Act, Assert)
|
|
471
|
+
- [ ] Cada teste tem comentário explicando o que garante
|
|
472
|
+
- [ ] Factories criadas para dados de teste
|
|
473
|
+
- [ ] Nenhum teste depende de outro (isolamento)
|
|
474
|
+
- [ ] Rodar testes e verificar que passam
|