@analizza-ai/testspec 0.1.1

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +189 -0
  4. package/bin/cli.js +42 -0
  5. package/package.json +69 -0
  6. package/src/adapters/agents/claude.js +88 -0
  7. package/src/adapters/agents/copilot.js +39 -0
  8. package/src/adapters/agents/index.js +22 -0
  9. package/src/adapters/sdd/index.js +23 -0
  10. package/src/adapters/sdd/openspec.js +58 -0
  11. package/src/adapters/sdd/speckit.js +19 -0
  12. package/src/commands/generate.js +66 -0
  13. package/src/commands/init.js +112 -0
  14. package/src/commands/report.js +60 -0
  15. package/src/commands/validate.js +68 -0
  16. package/src/core/reporter.js +44 -0
  17. package/src/core/spec-parser.js +141 -0
  18. package/src/core/stub-generator.js +92 -0
  19. package/src/core/testcontainers.js +39 -0
  20. package/src/core/tests-builder.js +120 -0
  21. package/src/index.js +10 -0
  22. package/src/utils/config.js +29 -0
  23. package/src/utils/logger.js +13 -0
  24. package/src/utils/sdd-detector.js +23 -0
  25. package/templates/agent-instructions/AGENTS.md +39 -0
  26. package/templates/agent-instructions/CLAUDE.md +48 -0
  27. package/templates/agent-instructions/copilot.md +52 -0
  28. package/templates/agent-instructions/skills/testspec-apply-qa.md +424 -0
  29. package/templates/agent-instructions/skills/testspec-generate.md +138 -0
  30. package/templates/agent-instructions/skills/testspec-run-qa.md +338 -0
  31. package/templates/agent-instructions/skills/testspec-specify-qa.md +535 -0
  32. package/templates/stubs/jest/unit.template.js +17 -0
  33. package/templates/stubs/junit/unit.template.java +27 -0
  34. package/templates/stubs/pytest/unit.template.py +18 -0
  35. package/templates/stubs/testcontainers/node-pg-kafka.template.js +38 -0
  36. package/templates/stubs/testcontainers/node-pg.template.js +32 -0
  37. package/templates/stubs/testcontainers/spring-pg-kafka.template.java +41 -0
  38. package/templates/stubs/vitest/unit.template.js +19 -0
  39. package/templates/tests-md/default.md +43 -0
@@ -0,0 +1,535 @@
1
+ # testspec-specify-qa
2
+
3
+ Inicia a especificação técnica de testes QA para uma feature, buscando o `tests.md` via GitHub MCP, conduzindo um questionário com o QA engineer e gerando os artefatos de especificação e estrutura de pastas no diretório atual do projeto QA.
4
+
5
+ ## Quando usar
6
+
7
+ Após `/testspec-generate` ter gerado o `tests.md` da feature no repositório do app.
8
+
9
+ ---
10
+
11
+ ## Configuração
12
+
13
+ - **App repo:** acessado exclusivamente via GitHub MCP — owner/repo definido em `./testspec/instructions.md` via campo `app_repo` (ex: `diegolirio/sdd-sdt-flow`)
14
+ - **Nunca use caminhos relativos ou locais** para acessar o repositório do app — sempre GitHub MCP
15
+ - **Diretório base de saída:** **sempre o diretório de trabalho atual** (`.`) — nunca use caminhos absolutos ou hardcoded
16
+
17
+ ---
18
+
19
+ ## Instructions
20
+
21
+ ### 0. Garantir e ler arquivos globais do projeto QA (SEMPRE, primeiro passo)
22
+
23
+ **Nunca peça ao usuário para criar arquivos ou diretórios manualmente. Crie tudo que faltar e prossiga.**
24
+
25
+ #### 0a. Garantir estrutura `./testspec/`
26
+
27
+ Se `./testspec/` não existir, crie o diretório.
28
+
29
+ #### 0b. Garantir `./testspec/instructions.md`
30
+
31
+ Se o arquivo não existir, pergunte ao usuário via **AskUserQuestion** (open-ended):
32
+ > "Qual é o repositório GitHub do app? (formato: owner/repo, ex: diegolirio/sdd-sdt-flow)"
33
+
34
+ Com a resposta, crie o arquivo com conteúdo padrão opinativo:
35
+
36
+ ```markdown
37
+ # Instructions — QA Project
38
+
39
+ ## app_repo
40
+ {owner/repo informado pelo usuário}
41
+
42
+ ## Ferramenta de teste padrão
43
+ k6
44
+
45
+ ## Arquitetura
46
+ - Scripts organizados por tipo: e2e/, load/, chaos-engineering/
47
+ - Um script por caso de teste (CT)
48
+ - Run plans .md gerados ao lado de cada script
49
+
50
+ ## Tecnologias
51
+ - k6 (JavaScript) para E2E e load
52
+ - kubectl para coleta de logs k8s
53
+ - Confluence para publicação de relatórios
54
+
55
+ ## Convenções
56
+ - Nomenclatura kebab-case sem acentos
57
+ - Variáveis de ambiente para URLs e credenciais (nunca hardcode)
58
+ - Thresholds: p95 < 500ms, error rate < 1% (load); p95 < 2000ms, error rate < 5% (chaos)
59
+ ```
60
+
61
+ Após criar, leia o arquivo e aplique todas as diretrizes durante a geração — elas têm precedência sobre os defaults da skill.
62
+
63
+ #### 0c. Garantir `./testspec/current-feature.md`
64
+
65
+ Se o arquivo não existir, crie-o vazio e execute o passo 1 normalmente.
66
+ Se existir e contiver um nome de feature válido, use-o diretamente — pule o passo 1.
67
+
68
+ ---
69
+
70
+ ### 1. Identificar a feature
71
+
72
+ O argumento passado pelo usuário pode ser:
73
+ - **Nome da feature** em kebab-case (ex: `kafka-consumer-order-request`)
74
+ - **Nenhum argumento** — siga o passo 1b abaixo
75
+
76
+ > **Atenção:** se `./testspec/current-feature.md` já definiu a feature no passo 0, este passo é ignorado.
77
+
78
+ **Se nenhum argumento foi passado e `current-feature.md` está vazio:**
79
+
80
+ Leia `app_repo` de `./testspec/instructions.md` (ex: `diegolirio/sdd-sdt-flow`).
81
+
82
+ **Prioridade 1 — GitHub MCP**
83
+
84
+ Busque em paralelo via GitHub MCP usando o `app_repo` do `instructions.md`:
85
+ - Features **ativas**: `GET /repos/{app_repo}/contents/openspec/changes` — filtre `type: "dir"`, exclua `archive`
86
+ - Features **arquivadas**: `GET /repos/{app_repo}/contents/openspec/changes/archive` — filtre `type: "dir"`
87
+
88
+ **Prioridade 2 — Fallback: features já em `./testspec/`**
89
+
90
+ Se o GitHub MCP falhar (sem token, sem acesso), liste os diretórios em `./testspec/` excluindo `instructions.md` e `current-feature.md`. Prefixe com `[local]`.
91
+
92
+ Se nenhuma fonte retornar features, informe e encerre:
93
+ ```
94
+ Nenhuma feature encontrada em {app_repo} via GitHub MCP nem em ./testspec/.
95
+ Verifique o token GitHub ou adicione features ao repositório.
96
+ ```
97
+
98
+ a. Monte a lista completa e pergunte ao usuário via **AskUserQuestion** (single select):
99
+ > "Qual feature deseja especificar os testes QA?"
100
+
101
+ - Prefixe: `[ativa]`, `[arquivada]` ou `[local]`
102
+ - Exiba o nome exato do diretório
103
+
104
+ b. Registre: nome da feature e sua origem.
105
+
106
+ ### 1.1 Fixar a feature em `current-feature.md`
107
+
108
+ Independentemente de como a feature foi identificada (argumento, seleção ou `current-feature.md` já preenchido), **sempre escreva** o nome da feature no arquivo:
109
+
110
+ ```
111
+ ./testspec/current-feature.md
112
+ ```
113
+
114
+ Conteúdo do arquivo (apenas o nome, sem formatação extra):
115
+ ```
116
+ {feature-name}
117
+ ```
118
+
119
+ Isso garante que `/testspec-apply-qa` e outras skills da sessão usem a mesma feature sem precisar perguntar novamente.
120
+
121
+ ---
122
+
123
+ ### 2. Ler o `tests.md`
124
+
125
+ Leia via GitHub MCP usando `app_repo` de `instructions.md`:
126
+ - Feature **ativa**: path `openspec/changes/{feature-name}/tests.md`
127
+ - Feature **arquivada**: path `openspec/changes/archive/{feature-name}/tests.md`
128
+
129
+ O conteúdo virá em base64 — decodifique antes de usar.
130
+
131
+ **Fallback — feature `[local]`** (veio de `./testspec/`):
132
+
133
+ Se a feature foi encontrada apenas em `./testspec/` e o GitHub MCP está inacessível, verifique se `spec.qa.md` já existe em `./testspec/{feature-name}/`:
134
+ - Se existe: pergunte via **AskUserQuestion**:
135
+ > "Encontrei `spec.qa.md` existente para esta feature. Como deseja prosseguir?"
136
+ - **Refazer** — ignora o existente e segue o questionário normalmente
137
+ - **Usar o existente** — pula para o passo 8
138
+ - Se não existe: encerre informando:
139
+ ```
140
+ tests.md não encontrado via GitHub MCP.
141
+ Verifique o token GitHub ou execute /testspec-generate no repositório do app.
142
+ ```
143
+
144
+ ---
145
+
146
+ ### 3. Analisar o `tests.md` em profundidade
147
+
148
+ Extraia e internalize **todos** os seguintes dados antes de avançar:
149
+
150
+ - **Nome legível da feature** — título `# Testes —`
151
+ - **Protocolo de entrada** — HTTP, Kafka, gRPC (derivado de `## Contexto` e `## Estrutura`)
152
+ - **Método HTTP e path** — se protocolo HTTP
153
+ - **Schema do body de entrada** — campos, tipos, obrigatoriedade
154
+ - **Schema da resposta de sucesso** — status HTTP, headers (especialmente `Location`), body
155
+ - **Tabela(s) de banco de dados** — mencionadas em `## Validações de Banco de Dados`
156
+ - **Todos os `### CT-NN`** — número, nome, entrada, critérios de aceite, tipo (sucesso/rejeição)
157
+ - **Regras de negócio implícitas** — ex: "COUNT não muda", "campo preenchido com valor X"
158
+
159
+ ---
160
+
161
+ ### 4. Conduzir o questionário
162
+
163
+ Faça as perguntas **em sequência**, uma de cada vez — não agrupe em uma só mensagem.
164
+
165
+ ---
166
+
167
+ #### Pergunta A — Ferramenta de testes
168
+
169
+ **AskUserQuestion** (single select):
170
+ > "Qual ferramenta será usada para implementar os scripts de teste?"
171
+
172
+ | Opção | Descrição |
173
+ |---|---|
174
+ | **K6** | JavaScript, ideal para E2E e load; extensão `.js` |
175
+ | **Gatling** | Scala/Java, foco em load e relatórios detalhados; extensão `.scala` |
176
+ | **Outro** | Abre campo livre para descrever ferramenta e extensão de arquivo |
177
+
178
+ Se "Outro": pergunte em seguida (open-ended) o nome da ferramenta e a extensão dos arquivos.
179
+
180
+ Registre: `{tool}` (ex: `k6`, `gatling`) e `{ext}` (ex: `.js`, `.scala`).
181
+
182
+ ---
183
+
184
+ #### Pergunta B — Tipos de teste
185
+
186
+ **AskUserQuestion** (multi select):
187
+ > "Quais tipos de teste deseja implementar para esta feature?"
188
+
189
+ | Opção | Escopo |
190
+ |---|---|
191
+ | **E2E Funcional** | Um script por CT — valida contrato e regras de negócio |
192
+ | **Teste de Carga (Load)** | Scripts de throughput por estágio de RPS — apenas CTs de sucesso |
193
+ | **Chaos Engineering** | Scripts de resiliência sob falha — apenas CTs de sucesso |
194
+
195
+ Registre os tipos selecionados — eles controlam quais seções e arquivos são gerados.
196
+
197
+ ---
198
+
199
+ #### Pergunta C — Especificação técnica detalhada
200
+
201
+ **AskUserQuestion** (open-ended):
202
+ > "Descreva tecnicamente o que deseja testar. Preencha o JSON abaixo com o que souber — quanto mais detalhe, mais precisa a especificação gerada."
203
+
204
+ Apresente o template:
205
+
206
+ ```json
207
+ {
208
+ "request": {
209
+ "httpMethod": "POST",
210
+ "path": "/resource",
211
+ "headers": {},
212
+ "requestBody": {}
213
+ },
214
+ "rules": [
215
+ { "description": "Regra de negócio ou comportamento esperado" },
216
+ { "classes": { "entity": ["field1", "field2"] }, "description": "Campos que devem ser persistidos" },
217
+ { "sequenceDescription": "Sequência de operações que o sistema deve executar" }
218
+ ],
219
+ "response": {
220
+ "status": 201,
221
+ "headers": {
222
+ "Location": "/resource/{id}"
223
+ },
224
+ "body": {}
225
+ },
226
+ "database": {
227
+ "table": "table_name",
228
+ "assertedFields": ["field1", "field2"]
229
+ },
230
+ "loadProfile": {
231
+ "stages": [
232
+ { "rps": 100, "duration": "5m" },
233
+ { "rps": 1000, "duration": "5m" }
234
+ ]
235
+ },
236
+ "chaosScenarios": [
237
+ { "type": "shutdown-pods", "description": "Desliga pods durante o teste" }
238
+ ]
239
+ }
240
+ ```
241
+
242
+ ---
243
+
244
+ ### 5. Análise profunda — extrair detalhes técnicos
245
+
246
+ Com `tests.md` + respostas do questionário, analise **antes de gerar qualquer arquivo**:
247
+
248
+ **Do `request`:**
249
+ - Quais campos são obrigatórios vs opcionais?
250
+ - Há tipos especiais: UUID, enum, nested object, null explícito?
251
+ - Há headers necessários: Authorization, Content-Type, X-Correlation-Id?
252
+
253
+ **Das `rules`:**
254
+ - Quais rules implicam asserções de banco (persistência, lock, update parcial)?
255
+ - Há `sequenceDescription`? → gere critério de ordem de operações nos CTs correspondentes
256
+ - Há campos cujo valor no banco difere do enviado na request (ex: campo calculado)?
257
+
258
+ **Da `response`:**
259
+ - Há `Location` header? → todo script de sucesso deve extrair o ID e usá-lo em asserções
260
+ - O body tem campos derivados (código gerado, timestamps)? → defina como validá-los
261
+ - Qual é o código HTTP exato para cada CT de rejeição?
262
+
263
+ **Do `loadProfile`:**
264
+ - VUs estimados por estágio: `VUs ≈ RPS × latência_média_em_segundos` (use 0.2s como default se desconhecida)
265
+ - Há necessidade de warmup antes do platô?
266
+
267
+ **Do `chaosScenarios`:**
268
+ - O mecanismo de caos requer kubectl, toxiproxy ou outra ferramenta?
269
+
270
+ Se qualquer ponto estiver ambíguo, **faça uma pergunta de esclarecimento** antes de prosseguir.
271
+
272
+ ---
273
+
274
+ ### 6. Verificar existência de `testspec/{feature-name}/`
275
+
276
+ Verifique se `./testspec/{feature-name}/` já existe no diretório atual.
277
+
278
+ Se existir, pergunte via **AskUserQuestion** (single select):
279
+ - **Sobrescrever** — apaga e recria os arquivos
280
+ - **Cancelar** — encerra sem alterações
281
+
282
+ ---
283
+
284
+ ### 7. Criar estrutura de diretórios
285
+
286
+ Crie **todos** os diretórios abaixo relativos ao diretório atual (`.`):
287
+
288
+ ```
289
+ ./testspec/{feature-name}/
290
+
291
+ ./src/test/features/{feature-name}/e2e/
292
+ ./src/test/features/{feature-name}/load/ ← somente se Load selecionado
293
+ ./src/test/features/{feature-name}/chaos-engineering/ ← somente se Chaos selecionado
294
+ ```
295
+
296
+ ---
297
+
298
+ ### 8. Gerar `./testspec/{feature-name}/spec.qa.md`
299
+
300
+ Siga o **Formato spec.qa.md** abaixo.
301
+
302
+ ### 9. Gerar `./testspec/{feature-name}/tasks.qa.md`
303
+
304
+ Siga o **Formato tasks.qa.md** abaixo.
305
+
306
+ ---
307
+
308
+ ### 10. Exibir confirmação final
309
+
310
+ ```
311
+ Especificação QA gerada para '{feature-name}':
312
+
313
+ Ferramenta: {K6 | Gatling | Outro}
314
+ Testes: {E2E} {Load} {Chaos}
315
+
316
+ Artefatos criados em ./testspec/{feature-name}/
317
+ spec.qa.md
318
+ tasks.qa.md
319
+
320
+ Estrutura de pastas criada em ./src/test/features/{feature-name}/
321
+ e2e/ ({N} scripts mapeados)
322
+ load/ ({N} scripts mapeados) ← omitir se não selecionado
323
+ chaos-engineering/ ({N} scripts) ← omitir se não selecionado
324
+
325
+ Próximo passo: /testspec-apply-qa para implementar os scripts.
326
+ ```
327
+
328
+ ---
329
+
330
+ ## Formato spec.qa.md
331
+
332
+ ```markdown
333
+ # Tests Spec — {Nome Legível da Feature}
334
+
335
+ > Especificação técnica dos scripts de teste derivada do tests.md + questionário QA.
336
+ > Ferramenta: {K6 | Gatling | Outro}
337
+
338
+ ---
339
+
340
+ ## Contexto
341
+
342
+ {Resumo da feature: protocolo de entrada, operação, regras de negócio relevantes para os testes. 3-5 linhas.}
343
+
344
+ ---
345
+
346
+ ## Contrato Técnico
347
+
348
+ ### Request
349
+
350
+ ```
351
+ {HTTP_METHOD} {path}
352
+ Content-Type: application/json
353
+ {outros headers relevantes com exemplo de valor}
354
+
355
+ Body:
356
+ {
357
+ "{campo}": <Tipo>, -- {obrigatório|opcional} — {descrição}
358
+ ...
359
+ }
360
+ ```
361
+
362
+ ### Response (Sucesso)
363
+
364
+ ```
365
+ HTTP Status: {código}
366
+ Location: {path}/{id} ← incluir somente se presente
367
+
368
+ Body:
369
+ {
370
+ "{campo}": <Tipo>, -- {descrição}
371
+ }
372
+ ```
373
+
374
+ ### Regras de Negócio para Testes
375
+
376
+ {Derivadas das `rules` do questionário e dos critérios do tests.md}
377
+ - {regra 1}
378
+ - {regra 2}
379
+ - {regra N}
380
+
381
+ ---
382
+
383
+ ## Cobertura de Testes
384
+
385
+ ### E2E
386
+
387
+ | CT | Arquivo | Cenário | Tipo |
388
+ |-------|-----------------------------------------------|---------------------|----------|
389
+ | CT-01 | {tool}-e2e-{acao}-{cenario}{ext} | {nome do cenário} | Sucesso |
390
+ | CT-NN | {tool}-e2e-{acao}-{cenario}{ext} | {nome do cenário} | Rejeição |
391
+
392
+ ### Load ← incluir somente se Load selecionado
393
+
394
+ | Cenário | Arquivo | VUs est. | Duração | RPS alvo |
395
+ |---------|------------------------------------------------------|----------|---------|----------|
396
+ | CT-01 | {tool}-load-{acao}-{cenario}-100-rps-5min{ext} | ~20 | 5min | 100 |
397
+ | CT-01 | {tool}-load-{acao}-{cenario}-1000-rps-5min{ext} | ~200 | 5min | 1000 |
398
+
399
+ ### Chaos Engineering ← incluir somente se Chaos selecionado
400
+
401
+ | Cenário | Arquivo | Tipo de caos | Mecanismo |
402
+ |---------|------------------------------------------------------|---------------|---------------|
403
+ | CT-01 | {tool}-dr-{acao}-{cenario}-shutdown-pods{ext} | Pod shutdown | kubectl delete|
404
+
405
+ ---
406
+
407
+ ## Estrutura de Pastas
408
+
409
+ ```
410
+ src/test/features/{feature-name}/
411
+ e2e/
412
+ {tool}-e2e-{acao}-{cenario}{ext}
413
+ {tool}-e2e-{acao}-{cenario}.md ← run plan gerado pelo /testspec-apply-qa
414
+ load/ ← somente se Load selecionado
415
+ {tool}-load-{acao}-{cenario}-{rps}-rps-{duracao}{ext}
416
+ {tool}-load-{acao}-{cenario}-{rps}-rps-{duracao}.md ← run plan
417
+ chaos-engineering/ ← somente se Chaos selecionado
418
+ {tool}-dr-{acao}-{cenario}-{tipo-caos}{ext}
419
+ {tool}-dr-{acao}-{cenario}-{tipo-caos}.md ← run plan
420
+ ```
421
+
422
+ ## Convenção de Nomenclatura
423
+
424
+ | Tipo | Padrão |
425
+ |-------|-----------------------------------------------------|
426
+ | E2E | `{tool}-e2e-{acao}-{cenario}{ext}` |
427
+ | Load | `{tool}-load-{acao}-{cenario}-{rps}-rps-{dur}{ext}` |
428
+ | Chaos | `{tool}-dr-{acao}-{cenario}-{tipo-caos}{ext}` |
429
+
430
+ Onde:
431
+ - `{acao}`: verbo da operação em kebab-case (ex: `create-order`, `consume-message`)
432
+ - `{cenario}`: resultado esperado em kebab-case (ex: `success`, `bad-request-zero-value`)
433
+ - `{rps}`: número inteiro de requisições por segundo alvo
434
+ - `{dur}`: duração do estágio (ex: `5min`, `10min`)
435
+ - `{tipo-caos}`: tipo de falha em kebab-case (ex: `shutdown-pods`, `network-latency`)
436
+
437
+ ---
438
+
439
+ ## Casos de Teste — Mapeamento Detalhado
440
+
441
+ ### CT-01 — {Nome do Cenário}
442
+
443
+ **Arquivo E2E:** `src/test/features/{feature-name}/e2e/{tool}-e2e-{...}{ext}`
444
+ **Tipo:** Sucesso
445
+
446
+ **Entrada:**
447
+ ```json
448
+ {payload completo extraído do tests.md e do questionário, com valores de exemplo reais}
449
+ ```
450
+
451
+ **Critérios de Aceite para o script:**
452
+ - Verificar status HTTP {código}
453
+ - {Se Location header presente}: Extrair `{id}` do header `Location` e usar em asserções subsequentes
454
+ - Verificar campo `{campo}` no body de resposta igual a `{valor}`
455
+ - {Se persistência}: Consultar tabela `{tabela}` e verificar `{campo}` = `{valor}` após a operação
456
+ - {Se sequenceDescription}: Verificar que `{operação A}` ocorre antes de `{operação B}`
457
+
458
+ ---
459
+
460
+ ### CT-NN — {Nome do Cenário}
461
+
462
+ **Arquivo E2E:** `src/test/features/{feature-name}/e2e/{tool}-e2e-{...}{ext}`
463
+ **Tipo:** Rejeição
464
+
465
+ **Entrada:**
466
+ ```json
467
+ {payload inválido com o campo problemático destacado}
468
+ ```
469
+
470
+ **Critérios de Aceite para o script:**
471
+ - Verificar status HTTP {código de erro — ex: 400, 422}
472
+ - Verificar que COUNT na tabela `{tabela}` permanece igual ao valor anterior à requisição
473
+ - {Se body de erro padronizado}: Verificar estrutura do body de erro
474
+ ```
475
+
476
+ ---
477
+
478
+ ## Formato tasks.qa.md
479
+
480
+ ```markdown
481
+ # Tasks — QA {Nome Legível da Feature}
482
+
483
+ > Tarefas de implementação derivadas do spec.qa.md.
484
+ > Ferramenta: {K6 | Gatling | Outro}
485
+
486
+ ---
487
+
488
+ ## 1. E2E Tests
489
+
490
+ - [ ] 1.1 Criar `src/test/features/{feature-name}/e2e/{tool}-e2e-{...}{ext}` — CT-01: {nome}
491
+ - [ ] 1.2 Criar `src/test/features/{feature-name}/e2e/{tool}-e2e-{...}.md` — run plan CT-01
492
+ - [ ] 1.N Criar `src/test/features/{feature-name}/e2e/{tool}-e2e-{...}{ext}` — CT-NN: {nome}
493
+ - [ ] 1.N+1 Criar `src/test/features/{feature-name}/e2e/{tool}-e2e-{...}.md` — run plan CT-NN
494
+
495
+ ## 2. Load Tests ← incluir somente se Load selecionado
496
+
497
+ - [ ] 2.1 Criar `src/test/features/{feature-name}/load/{tool}-load-{...}-100-rps-5min{ext}` — CT-01, 100 RPS
498
+ - [ ] 2.2 Criar `src/test/features/{feature-name}/load/{tool}-load-{...}-100-rps-5min.md` — run plan
499
+ - [ ] 2.3 Criar `src/test/features/{feature-name}/load/{tool}-load-{...}-1000-rps-5min{ext}` — CT-01, 1000 RPS
500
+ - [ ] 2.4 Criar `src/test/features/{feature-name}/load/{tool}-load-{...}-1000-rps-5min.md` — run plan
501
+
502
+ ## 3. Chaos Engineering ← incluir somente se Chaos selecionado
503
+
504
+ - [ ] 3.1 Criar `src/test/features/{feature-name}/chaos-engineering/{tool}-dr-{...}-shutdown-pods{ext}` — CT-01, pod failure
505
+ - [ ] 3.2 Criar `src/test/features/{feature-name}/chaos-engineering/{tool}-dr-{...}-shutdown-pods.md` — run plan
506
+
507
+ ## 4. Verificação
508
+
509
+ - [ ] 4.1 Validar sintaxe de todos os scripts E2E (dry-run ou lint da ferramenta escolhida)
510
+ - [ ] 4.2 Revisar thresholds de load com SRE/produto antes de executar
511
+ - [ ] 4.3 Confirmar mecanismo de caos disponível no ambiente (kubectl, toxiproxy, etc.)
512
+ ```
513
+
514
+ ---
515
+
516
+ ## Guardrails
517
+
518
+ - **Nunca peça ao usuário para criar arquivos ou diretórios** — se `./testspec/`, `instructions.md` ou `current-feature.md` não existirem, crie-os imediatamente com conteúdo padrão e prossiga
519
+ - **`instructions.md` criado automaticamente** com valores opinativos sensatos (`app_repo_local_path: ../development-flow-sdd-sdt`, k6 como ferramenta padrão, thresholds default)
520
+ - **`instructions.md` tem precedência** sobre qualquer default da skill após criado — se o usuário personalizou, siga o arquivo
521
+ - **`current-feature.md` elimina a pergunta de seleção** — se contiver um nome de feature, use-o diretamente sem perguntar ao usuário
522
+ - **Diretório de saída:** sempre `./testspec/` e `./src/test/features/` relativos ao diretório atual — nunca use paths absolutos ou hardcoded
523
+ - **GitHub MCP é a única fonte do app repo** — nunca use caminhos relativos ou locais (`../`) para acessar o repositório do app
524
+ - **`app_repo` em `instructions.md`** define o `owner/repo` usado em todas as chamadas GitHub MCP — sempre leia dali, nunca hardcode
525
+ - **Seleção de feature obrigatória quando `current-feature.md` está vazio:** sempre listar features do GitHub MCP e perguntar — nunca assumir
526
+ - **Questionário obrigatório:** não gere nenhum arquivo antes de concluir as Perguntas A, B e C (spec técnica)
527
+ - **Nomenclatura:** sempre kebab-case, sem acentos, sem espaços, sem caracteres especiais
528
+ - **`tasks.qa.md`:** usa exclusivamente `- [ ]` — nunca bullets simples
529
+ - **Load e Chaos:** SOMENTE para CTs de sucesso (happy path) — CTs de rejeição ficam apenas em E2E
530
+ - **Seções condicionais:** omitir Load e Chaos inteiramente se não foram selecionados em Pergunta B
531
+ - **Protocolo Kafka:** se o protocolo for Kafka (não HTTP), omitir seções HTTP, adaptar `{acao}` para `consume-{recurso}`, omitir `Location` header
532
+ - **Location header:** se presente na resposta, SEMPRE incluir instrução de extração do ID nos critérios de aceite do CT de sucesso
533
+ - **sequenceDescription:** se presente nas rules, SEMPRE gerar critério de ordem de operações no CT correspondente
534
+ - **Próximo passo:** sempre referenciar `/testspec-apply-qa`
535
+ - **Run plans:** sempre gerados pelo `/testspec-apply-qa` junto com cada script — não pergunte ao usuário, não condicione
@@ -0,0 +1,17 @@
1
+ /**
2
+ * {{CT_ID}} — {{TITLE}}
3
+ * Feature: {{FEATURE}}
4
+ * Auto-generated by testspec. Fill in arrange/act/assert.
5
+ */
6
+
7
+ describe('{{CT_ID}} — {{TITLE}}', () => {
8
+ beforeEach(() => {
9
+ // arrange: set up state from spec precondition
10
+ });
11
+
12
+ it('should {{TITLE}}', async () => {
13
+ // Input: (from CT input field)
14
+ // Expected output: (from CT expected output field)
15
+ expect(true).toBe(true); // replace with real assertion
16
+ });
17
+ });
@@ -0,0 +1,27 @@
1
+ /**
2
+ * {{CT_ID}} — {{TITLE}}
3
+ * Feature: {{FEATURE}}
4
+ * Auto-generated by testspec. Fill in arrange/act/assert.
5
+ */
6
+
7
+ import org.junit.jupiter.api.BeforeEach;
8
+ import org.junit.jupiter.api.DisplayName;
9
+ import org.junit.jupiter.api.Test;
10
+ import static org.assertj.core.api.Assertions.assertThat;
11
+
12
+ @DisplayName("{{CT_ID}} — {{TITLE}}")
13
+ class {{CT_ID_CAMEL}}Test {
14
+
15
+ @BeforeEach
16
+ void setUp() {
17
+ // arrange: set up state from spec precondition
18
+ }
19
+
20
+ @Test
21
+ @DisplayName("should {{TITLE}}")
22
+ void should{{CT_ID_CAMEL}}() {
23
+ // Input: (from CT input field)
24
+ // Expected output: (from CT expected output field)
25
+ assertThat(true).isTrue(); // replace with real assertion
26
+ }
27
+ }
@@ -0,0 +1,18 @@
1
+ """
2
+ {{CT_ID}} — {{TITLE}}
3
+ Feature: {{FEATURE}}
4
+ Auto-generated by testspec. Fill in arrange/act/assert.
5
+ """
6
+
7
+ import pytest
8
+
9
+
10
+ class Test{{CT_ID}}:
11
+ def setup_method(self):
12
+ # arrange: set up state from spec precondition
13
+ pass
14
+
15
+ def test_{{CT_ID_LOWER}}(self):
16
+ # Input: (from CT input field)
17
+ # Expected output: (from CT expected output field)
18
+ assert True # replace with real assertion
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Integration test stub — {{FEATURE}} (change: {{CHANGE}})
3
+ * Stack: Node.js + PostgreSQL + Kafka (Testcontainers)
4
+ * Auto-generated by testspec. Fill in HTTP calls and DB/Kafka assertions.
5
+ */
6
+
7
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
8
+ import { PostgreSqlContainer } from '@testcontainers/postgresql';
9
+ import { KafkaContainer } from '@testcontainers/kafka';
10
+
11
+ describe('{{FEATURE}} — integration', () => {
12
+ let pgContainer, kafkaContainer;
13
+ let connectionString, brokerUrl;
14
+
15
+ beforeAll(async () => {
16
+ [pgContainer, kafkaContainer] = await Promise.all([
17
+ new PostgreSqlContainer('postgres:16-alpine').start(),
18
+ new KafkaContainer('confluentinc/cp-kafka:7.4.0').start(),
19
+ ]);
20
+ connectionString = pgContainer.getConnectionUri();
21
+ brokerUrl = `${kafkaContainer.getHost()}:${kafkaContainer.getMappedPort(9093)}`;
22
+ // run migrations here if needed
23
+ }, 90_000);
24
+
25
+ afterAll(async () => {
26
+ await Promise.all([pgContainer.stop(), kafkaContainer.stop()]);
27
+ });
28
+
29
+ {{SCENARIOS}}
30
+
31
+ it('CT-placeholder — replace with real CT', async () => {
32
+ // Input: (from tests.md CT input field)
33
+ // Expected output: (from tests.md CT expected output field)
34
+ // DB validation: (from tests.md CT DB validation field)
35
+ expect(connectionString).toBeTruthy();
36
+ expect(brokerUrl).toBeTruthy();
37
+ });
38
+ });
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Integration test stub — {{FEATURE}} (change: {{CHANGE}})
3
+ * Stack: Node.js + PostgreSQL (Testcontainers)
4
+ * Auto-generated by testspec. Fill in HTTP calls and DB assertions.
5
+ */
6
+
7
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
8
+ import { PostgreSqlContainer } from '@testcontainers/postgresql';
9
+
10
+ describe('{{FEATURE}} — integration', () => {
11
+ let container;
12
+ let connectionString;
13
+
14
+ beforeAll(async () => {
15
+ container = await new PostgreSqlContainer('postgres:16-alpine').start();
16
+ connectionString = container.getConnectionUri();
17
+ // run migrations here if needed
18
+ }, 60_000);
19
+
20
+ afterAll(async () => {
21
+ await container.stop();
22
+ });
23
+
24
+ {{SCENARIOS}}
25
+
26
+ it('CT-placeholder — replace with real CT', async () => {
27
+ // Input: (from tests.md CT input field)
28
+ // Expected output: (from tests.md CT expected output field)
29
+ // DB validation: (from tests.md CT DB validation field)
30
+ expect(connectionString).toBeTruthy();
31
+ });
32
+ });