@vibe2founder/tests2dialects 0.1.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/CHANGELOG.md +73 -0
- package/bun.lock +22 -0
- package/bunfig.toml +2 -0
- package/critica.md +77 -0
- package/docs/4-ideias.md +66 -0
- package/docs/api-api.md +93 -0
- package/docs/api-imperativo.md +125 -0
- package/docs/api-matematico.md +145 -0
- package/docs/api-narrativo.md +181 -0
- package/docs/guia-rapido.md +189 -0
- package/docs/whitepaper.md +21 -0
- package/examples/imperative.spec.ts +58 -0
- package/examples/math.spec.ts +52 -0
- package/examples/narrative.spec.ts +61 -0
- package/examples/polyglot-shopping-cart.spec.ts +212 -0
- package/examples/sanity.spec.ts +54 -0
- package/examples/showcase-api.spec.ts +70 -0
- package/examples/test-api.ts +36 -0
- package/infograficos/detalhado.png +0 -0
- package/infograficos/mobile.png +0 -0
- package/infograficos/normal.png +0 -0
- package/landing-page/README.md +38 -0
- package/landing-page/bun.lock +609 -0
- package/landing-page/eslint.config.js +23 -0
- package/landing-page/index.html +17 -0
- package/landing-page/package-lock.json +2962 -0
- package/landing-page/package.json +34 -0
- package/landing-page/postcss.config.js +6 -0
- package/landing-page/public/vite.svg +1 -0
- package/landing-page/src/App.tsx +358 -0
- package/landing-page/src/assets/react.svg +1 -0
- package/landing-page/src/index.css +34 -0
- package/landing-page/src/main.tsx +10 -0
- package/landing-page/tailwind.config.js +59 -0
- package/landing-page/tsconfig.app.json +28 -0
- package/landing-page/tsconfig.json +7 -0
- package/landing-page/tsconfig.node.json +26 -0
- package/landing-page/vite.config.ts +7 -0
- package/logo.png +0 -0
- package/output.log +60 -0
- package/package.json +36 -0
- package/packages/api-test-dialect/README.md +30 -0
- package/packages/api-test-dialect/index.ts +132 -0
- package/packages/api-test-dialect/openapi.json +64 -0
- package/packages/reqify/README.md +33 -0
- package/packages/reqify/index.ts +48 -0
- package/podcast/O_Matem/303/241tico,_o_Narrador_e_o_Engenheiro.json +0 -0
- package/podcast/O_Matem/303/241tico,_o_Narrador_e_o_Engenheiro.md +0 -0
- package/podcast/critica-Dialetos_de_teste__inova/303/247/303/243o_ou_fragmenta/303/247/303/243o_.json +0 -0
- package/podcast/critica-Dialetos_de_teste__inova/303/247/303/243o_ou_fragmenta/303/247/303/243o_.md +0 -0
- package/podcast/critica-Unificar_filosofia_e_pr/303/241tica_na_documenta/303/247/303/243o_(7_words__covers_t.md +1 -0
- package/podcast/critica-Unificar_filosofia_e_pr/303/241tica_na_documenta/303/247/303/243o__7_words__covers_t.ogg +0 -0
- package/podcast/critica2-Sil/303/252ncio_estrat/303/251gico_e_sobrecarga_em_READMEs.ogg +0 -0
- package/podcast/critica2.json +3191 -0
- package/podcast/critica2.md +1 -0
- package/podcast/debate-Dialetos_de_teste__inova/303/247/303/243o_ou_fragmenta/303/247/303/243o_.json +0 -0
- package/podcast/debate-Dialetos_de_teste__inova/303/247/303/243o_ou_fragmenta/303/247/303/243o_.md +0 -0
- package/readme.md +58 -0
- package/reports/01-01-2026_00-45.md +40 -0
- package/reports/01-01-2026_02-30.md +37 -0
- package/reports/03-02-2026_10-55.md +8 -0
- package/reports/03-02-2026_11-45.md +13 -0
- package/reports/03-02-2026_11-50.md +10 -0
- package/reports/26-01-2026_16-25.md +31 -0
- package/reports/26-01-2026_19-20.md +27 -0
- package/reports/31-12-2025_22-35.md +25 -0
- package/reports/31-12-2025_22-45.md +15 -0
- package/slides/Dialetos_de_Teste_Um_Executor_M/303/272ltiplos_Vocabul/303/241rios.pdf +0 -0
- package/src/cli.ts +445 -0
- package/src/index.ts +539 -0
- package/tabela.html +350 -0
- package/tsconfig.json +22 -0
- package/types/api-types.ts +11 -0
- package/www/index.html +1344 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Release] v0.4.1
|
|
6
|
+
|
|
7
|
+
### What's Changed
|
|
8
|
+
|
|
9
|
+
- :memo: **docs**: Added explicit "Running API Tests" section to README for clarity on execution steps.
|
|
10
|
+
- :sparkles: **feat**: Created `examples/showcase-api.spec.ts` demonstrating all API dialect features (GET, POST, PUT, DELETE, Headers, Schema).
|
|
11
|
+
|
|
12
|
+
## [0.4.0]
|
|
13
|
+
|
|
14
|
+
### What's Changed
|
|
15
|
+
|
|
16
|
+
- :recycle: **refactor**: Renomeado projeto para `@vibe2founder/tests2dialects`.
|
|
17
|
+
- :bug: **fix**: Corrigidas extensões de importação ESM para `.js` em todo o projeto.
|
|
18
|
+
- :bug: **fix**: Implementado isolamento de estado no CLI entre arquivos de teste via `resetAtomicCore()`.
|
|
19
|
+
- :zap: **perf**: Melhorada a precisão do report do CLI com logs de caminho completo de suites.
|
|
20
|
+
- :label: **types**: Adicionada interface `AtomicMock` para resolver lints de Proxy dinâmico.
|
|
21
|
+
|
|
22
|
+
## [0.3.0]
|
|
23
|
+
|
|
24
|
+
### What's Changed
|
|
25
|
+
|
|
26
|
+
- :sparkles: **feat**: Criado o novo Dialeto de Testes de API (`@vibe2founder/api-test-dialect`).
|
|
27
|
+
- :sparkles: **feat**: Implementado `@vibe2founder/request2http` nativo/local utilizando Fetch API.
|
|
28
|
+
- :label: **types**: Adicionada tipagem semântica nominal para todos os parâmetros de rede em `types/api-types.ts`.
|
|
29
|
+
- :memo: **docs**: Adicionados READMEs detalhados para os novos pacotes e relatório técnico em `reports/`.
|
|
30
|
+
- :white_check_mark: **test**: Criado exemplo operacional em `examples/test-api.ts`.
|
|
31
|
+
|
|
32
|
+
## [0.2.0]
|
|
33
|
+
|
|
34
|
+
### What's Changed
|
|
35
|
+
|
|
36
|
+
- :rocket: **release**: Version bump to 0.2.0.
|
|
37
|
+
- :wrench: **chore**: Added `testall` as a CLI binary alias in `package.json`.
|
|
38
|
+
- :art: **style**: Standardized `readme.md` headings to sentence case (only first word capitalized).
|
|
39
|
+
- :sparkles: **feat**: Implemented `critica2.md` suggestions with visual proofs of coexistence and strategic sections for leadership.
|
|
40
|
+
- :zap: **perf**: Enhanced core engine with Deep Proxies for mocks, supporting automatic method mocking.
|
|
41
|
+
- :recycle: **refactor**: Implemented "Call Bubbling" in mocks to allow verifying object interactions via parent mocks.
|
|
42
|
+
- :bug: **fix**: Fixed `beforeAll` and `afterAll` hook execution in the test runner.
|
|
43
|
+
- :white_check_mark: **test**: Verified and fixed all examples, achieving 100% pass rate on the polyglot test suite.
|
|
44
|
+
|
|
45
|
+
## [0.1.0]
|
|
46
|
+
|
|
47
|
+
### What's Changed
|
|
48
|
+
|
|
49
|
+
- :memo: **docs**: Expanded README with detailed philosophies for each test dialect.
|
|
50
|
+
- :memo: **docs**: Added complete, realistic code examples for Math, Narrative, and Imperative dialects.
|
|
51
|
+
- :recycle: **refactor**: Updated `src/index.ts` to export dialect functions as top-level exports, simplifying imports.
|
|
52
|
+
- :wrench: **chore**: Standardized package naming in documentation to `@vibe2founder/tests2dialects`.
|
|
53
|
+
- :art: **style**: Converted comparison table in README from HTML to Markdown for better portability.
|
|
54
|
+
- :sparkles: **feat**: Complete README restructure following podcast feedback:
|
|
55
|
+
- Added "Cansado de Descrever?" hook connecting philosophy to practice
|
|
56
|
+
- Added "Quick Start" section for 5-minute first test victory
|
|
57
|
+
- Added visual dialect chooser flowchart
|
|
58
|
+
- Added "A Dor Que Resolvemos" pain-point sections before each dialect
|
|
59
|
+
- Moved advanced topics (Rosetta Table, Polyglot Mode) to the end
|
|
60
|
+
- Added gradual adoption/migration guide
|
|
61
|
+
- :sparkles: **feat**: Complete CLI rewrite with Vitest-style output:
|
|
62
|
+
- ANSI color palette (green/red/yellow/cyan)
|
|
63
|
+
- Spinner animation during test execution
|
|
64
|
+
- Per-file timer showing elapsed time
|
|
65
|
+
- Grouped test results with indentation
|
|
66
|
+
- Summary statistics (files, tests, duration)
|
|
67
|
+
- Exit codes based on test results
|
|
68
|
+
- :sparkles: **feat**: README restructure following critica2.md podcast:
|
|
69
|
+
- Visual proof of legacy coexistence (Jest + dialeto) at the very top
|
|
70
|
+
- New "Por Que Adotar no Seu Time?" section for tech leads/managers
|
|
71
|
+
- Progressive disclosure: API summaries in README, full docs linked separately
|
|
72
|
+
- Created `/docs/api-imperativo.md`, `/docs/api-matematico.md`, `/docs/api-narrativo.md`
|
|
73
|
+
- Reordered sections: Trust → Strategy → Quick Start → Choose Dialect
|
package/bun.lock
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"workspaces": {
|
|
4
|
+
"": {
|
|
5
|
+
"name": "@vibe2founder/tests2dialects",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@types/node": "latest",
|
|
8
|
+
"undici-types": "~7.16.0",
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"typescript": "latest",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
"packages": {
|
|
16
|
+
"@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="],
|
|
17
|
+
|
|
18
|
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
19
|
+
|
|
20
|
+
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
|
21
|
+
}
|
|
22
|
+
}
|
package/bunfig.toml
ADDED
package/critica.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Crítica e Esclarecimento: A Filosofia Aditiva do tests2dialects Tester
|
|
2
|
+
|
|
3
|
+
Uma crítica comum a novos frameworks é a sensação de que "precisamos jogar tudo fora e reaprender a programar". Este documento existe para esclarecer que o **tests2dialects Tester** foi desenhado com uma filosofia oposta: a **Filosofia Aditiva**.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Não é uma Negação do Passado
|
|
8
|
+
|
|
9
|
+
A maior preocupação de qualquer equipe é o **código legado**. Se você tem 5.000 testes escritos em Jest padrão (`describe`, `it`, `expect`), o tests2dialects Tester **não exige que você reescreva uma linha sequer**.
|
|
10
|
+
|
|
11
|
+
O framework funciona como um **superset** (superconjunto). Ele entende nativamente a sintaxe do Jest.
|
|
12
|
+
|
|
13
|
+
> **Resumo:** Seus testes antigos continuam passando. Seu conhecimento de Jest continua válido.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. O Mito da "Torre de Babel"
|
|
18
|
+
|
|
19
|
+
Quando dizemos "tests2dialects", **não esperamos que cada desenvolvedor seja fluente em todos os dialetos**. Isso seria ineficiente e aumentaria a carga cognitiva.
|
|
20
|
+
|
|
21
|
+
A proposta é a **Especialização por Contexto**:
|
|
22
|
+
|
|
23
|
+
- O **Cientista de Dados** só precisa aprender o `MathDialect`. Ele não precisa saber o que é um `scenario` ou `looks`.
|
|
24
|
+
- O **Designer/Frontend** foca no `VisualDialect`. Ele ignora completamente a existência dos axiomas matemáticos.
|
|
25
|
+
- O **Engenheiro de Backend** usa o `ImperativeDialect`.
|
|
26
|
+
|
|
27
|
+
> **Você não precisa aprender 4 idiomas.** Você escolhe um que se adapta ao seu projeto e ignora o resto. O framework é poliglota; você não precisa ser.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 3. Um Executor para Todos (One Runner)
|
|
32
|
+
|
|
33
|
+
Tecnicamente, não há "mágica" pesada rodando por trás. O tests2dialects Tester **unifica a execução**. Isso significa que você não precisa de pipelines de CI/CD separados para "Testes Jest Antigos" e "Testes Novos".
|
|
34
|
+
|
|
35
|
+
Um único comando:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm test
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Executará:
|
|
42
|
+
|
|
43
|
+
- ✅ Seus arquivos `.spec.ts` antigos (Jest Clássico).
|
|
44
|
+
- ✅ Seus novos arquivos de regras de negócio (`MathDialect`).
|
|
45
|
+
- ✅ Seus novos testes de componentes (`VisualDialect`).
|
|
46
|
+
|
|
47
|
+
Todos aparecem no mesmo relatório, com a mesma cobertura de código, na mesma janela de terminal.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 4. Exemplo Prático de Coexistência
|
|
52
|
+
|
|
53
|
+
Imagine um arquivo de teste que está sendo migrado ou refatorado. O código abaixo é **100% válido** e executável pelo tests2dialects Tester:
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
// Legado: Ninguém quer mexer nisso agora
|
|
57
|
+
describe("Módulo de Login (Legacy)", () => {
|
|
58
|
+
it("deve validar senha", () => {
|
|
59
|
+
expect(validar("123")).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Novo: Nova funcionalidade de criptografia adicionada hoje
|
|
64
|
+
import { axiom, implies } from "@vibe2founder/tests2dialects";
|
|
65
|
+
|
|
66
|
+
axiom("Nova Criptografia SHA-256", () => {
|
|
67
|
+
// Usamos o dialeto novo apenas para a feature nova
|
|
68
|
+
// Não quebramos nada do anterior
|
|
69
|
+
implies(hash("123")).matches(/^[a-f0-9]{64}$/);
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Conclusão
|
|
76
|
+
|
|
77
|
+
O **tests2dialects Tester** não veio para destruir o Jest ou o Mocha. Ele veio para **dar vocabulário onde o vocabulário padrão falha em expressar a intenção**. É uma ferramenta de **adição**, não de substituição.
|
package/docs/4-ideias.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
4 Ideias Contraintuitivas do tests2dialects que Vão Mudar a Forma Como Você Escreve Testes
|
|
2
|
+
|
|
3
|
+
Adotar um novo framework de testes muitas vezes vem com um custo alto: a sensação de que precisamos "jogar tudo fora e reaprender a programar". É um processo que paralisa equipes e desvaloriza o código construído ao longo de anos. O framework tests2dialects chega com uma filosofia surpreendentemente diferente, a "Filosofia Aditiva" — uma abordagem que respeita seu tempo e seu código. Neste post, vamos explorar as quatro ideias mais impactantes e contraintuitivas por trás dessa nova forma de pensar que promete expandir, e não substituir, seu ecossistema de testes.
|
|
4
|
+
|
|
5
|
+
1. Você não precisa reescrever uma linha de código legado
|
|
6
|
+
|
|
7
|
+
A primeira e mais radical ideia do tests2dialects é o respeito absoluto pelo seu trabalho existente. A "Filosofia Aditiva" significa que o framework funciona como um superset (superconjunto) do Jest. Ele não exige a reescrita de testes antigos.
|
|
8
|
+
|
|
9
|
+
Isso quer dizer que os milhares de testes describe/it/expect que sua equipe já possui continuarão funcionando perfeitamente, com um único comando de execução. Não há migração forçada, nem quebra de compatibilidade.
|
|
10
|
+
|
|
11
|
+
O tests2dialects Tester não veio para destruir o Jest ou o Mocha. Ele veio para dar vocabulário onde o vocabulário padrão falha em expressar a intenção. É uma ferramenta de adição, não de substituição.
|
|
12
|
+
|
|
13
|
+
Essa abordagem é crucial porque reduz drasticamente o risco de adoção. Ela respeita o trabalho já feito pela equipe e permite que novas funcionalidades e conceitos sejam introduzidos de forma gradual e segura, sem a necessidade de um "big bang" ou de uma refatoração massiva.
|
|
14
|
+
|
|
15
|
+
2. A linguagem do seu teste deveria refletir a do seu problema
|
|
16
|
+
|
|
17
|
+
A frustração central que o tests2dialects resolve é o desalinhamento semântico. A linguagem padrão de testes, com describe e it, foi projetada para descrever comportamentos de componentes, mas se torna inadequada em outros contextos, como provar a correção de um algoritmo ou verificar a conformidade de um contrato de API.
|
|
18
|
+
|
|
19
|
+
Veja como a linguagem padrão soa "errada" e informal ao testar uma função de criptografia pura: describe("SHA-256", () => { it("should produce a valid hash"...) })
|
|
20
|
+
|
|
21
|
+
Em contraste, o Dialeto Matemático do framework reflete o rigor necessário com uma sintaxe de prova axiomática, alinhada à natureza do problema:
|
|
22
|
+
|
|
23
|
+
axiom("Teoria de Hash SHA-256", () => {
|
|
24
|
+
proof("Hash de string vazia converge para constante conhecida", () => {
|
|
25
|
+
implies(sha256("")).is("e3b0c44...");
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
A linguagem importa. Ela molda o pensamento.
|
|
30
|
+
|
|
31
|
+
Utilizar a semântica correta aumenta fundamentalmente a clareza, o rigor e, mais importante, a intenção do teste. A equipe não está mais descrevendo um comportamento; está, de fato, provando uma verdade universal, o que alinha a mentalidade do desenvolvedor com o rigor matemático do problema. O código passa a comunicar o que está fazendo de forma muito mais precisa.
|
|
32
|
+
|
|
33
|
+
3. O framework é poliglota para que você não precise ser
|
|
34
|
+
|
|
35
|
+
A ideia de múltiplos "dialetos" de teste pode soar como um convite ao caos, o chamado "Mito da Torre de Babel". No entanto, a proposta do tests2dialects é o oposto: a ideia não é que cada desenvolvedor aprenda todos os dialetos, mas que cada especialista use a ferramenta mais afiada para sua tarefa, adotando a mentalidade certa para o trabalho.
|
|
36
|
+
|
|
37
|
+
O conceito é a Especialização por Contexto:
|
|
38
|
+
|
|
39
|
+
- Cientista de Dados: Foca no MathDialect, adotando uma mentalidade científica e axiomática para provar a correção de algoritmos.
|
|
40
|
+
- Product Manager e Designer: Utilizam o NarrativeDialect para descrever fluxos de usuário de forma legível, focando na experiência humana e no comportamento do sistema.
|
|
41
|
+
- Engenheiro de Backend/Sistemas: Usa o ImperativeDialect para garantir a conformidade de APIs, adotando uma mentalidade rigorosa de engenharia de sistemas.
|
|
42
|
+
|
|
43
|
+
A mensagem é clara: "Você não precisa aprender 4 idiomas. Você escolhe um que se adapta ao seu projeto e ignora o resto." Essa abordagem reduz a carga cognitiva, permitindo que as equipes trabalhem com ferramentas especializadas e de alta precisão sem nunca sair do mesmo ecossistema de testes.
|
|
44
|
+
|
|
45
|
+
4. Seus testes podem virar a documentação que seu time de produto entende
|
|
46
|
+
|
|
47
|
+
Uma das barreiras mais comuns no desenvolvimento de software é a comunicação entre a equipe de produto e a de engenharia. Os testes, que deveriam ser a fonte da verdade sobre o comportamento do sistema, são frequentemente ilegíveis para pessoas não-técnicas.
|
|
48
|
+
|
|
49
|
+
O Dialeto Narrativo do tests2dialects foi criado para destruir essa barreira. Veja a diferença:
|
|
50
|
+
|
|
51
|
+
// Antes (Ilegível para não-técnicos)
|
|
52
|
+
it("should return 403", () => { /_ ... _/ });
|
|
53
|
+
|
|
54
|
+
// Depois (Claro para todos)
|
|
55
|
+
scenario("Usuário sem permissão tenta acessar o painel de Admin", () => {
|
|
56
|
+
const response = attemptAccessAsUnauthorizedUser();
|
|
57
|
+
to(response.status).be(403);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
Essa mudança transforma os testes em um "contrato vivo" e uma "documentação viva". Product Managers e Designers podem agora ler os testes e validar se as regras de negócio foram implementadas conforme o esperado. Os testes se tornam a fonte única de verdade para as regras de negócio, quebrando a barreira clássica entre produto e engenharia e garantindo que o produto construído é, de fato, o produto desejado.
|
|
61
|
+
|
|
62
|
+
Conclusão
|
|
63
|
+
|
|
64
|
+
O tests2dialects não se apresenta como um substituto revolucionário, mas como uma evolução inteligente. Sua filosofia é adicionar poder de expressão ao ecossistema que já conhecemos, uma ferramenta que lhe devolve o poder de escolher a palavra certa para o problema certo. Ele nos dá o vocabulário para alinhar a linguagem do teste à natureza do problema.
|
|
65
|
+
|
|
66
|
+
Depois de ver essa abordagem, a pergunta que fica é: será que a forma como sempre escrevemos testes tem limitado a forma como pensamos sobre nossos próprios sistemas?
|
package/docs/api-api.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# 🌐 Dialeto de API - API Completa
|
|
2
|
+
|
|
3
|
+
> **Filosofia:** Design by Contract e Fluent Interface.
|
|
4
|
+
>
|
|
5
|
+
> **Vibe:** Declarativa, Precisa, Conectada.
|
|
6
|
+
>
|
|
7
|
+
> **Ideal para:** Backend Engineers, QA Automation, validação de contratos, testes de integração e microserviços.
|
|
8
|
+
|
|
9
|
+
## Estrutura
|
|
10
|
+
|
|
11
|
+
| Função | Descrição | Equivalente Supertest/Axios |
|
|
12
|
+
| :----------------------- | :------------------------------------------- | :---------------------------------- |
|
|
13
|
+
| `ApiSpec.define(name)` | Inicia a definição de um novo teste de API | `describe` / `it` |
|
|
14
|
+
| `.from(url)` | Define a URL base para a requisição | `request(app)` / `axios.create` |
|
|
15
|
+
| `.get(path)` | Configura uma requisição GET | `.get(path)` |
|
|
16
|
+
| `.post(path, body)` | Configura uma requisição POST com corpo | `.post(path).send(body)` |
|
|
17
|
+
| `.put(path, body)` | Configura uma requisição PUT com corpo | `.put(path).send(body)` |
|
|
18
|
+
| `.delete(path)` | Configura uma requisição DELETE | `.delete(path)` |
|
|
19
|
+
| `.method(verb, path)` | Define um método HTTP arbitrário | `.request({method, url})` |
|
|
20
|
+
|
|
21
|
+
## Configuração da Requisição
|
|
22
|
+
|
|
23
|
+
| Função | Descrição | Equivalente |
|
|
24
|
+
| :-------------------- | :-------------------------------------------- | :-------------------------------------- |
|
|
25
|
+
| `.header(key, val)` | Adiciona um cabeçalho à requisição | `.set(key, val)` |
|
|
26
|
+
| `.withBody(body)` | Define ou sobrescreve o corpo da requisição | `.send(body)` |
|
|
27
|
+
| `.withAuth(token)` | Atalho para Header Authorization Bearer | `.set('Authorization', 'Bearer ...')` |
|
|
28
|
+
|
|
29
|
+
## Asserções
|
|
30
|
+
|
|
31
|
+
| Função | Descrição | Equivalente Jest/Chai |
|
|
32
|
+
| :----------------------------------------------- | :----------------------------------------------------------- | :----------------------------------------- |
|
|
33
|
+
| `.shouldReturn(status)` | Verifica o Status Code HTTP retornado | `expect(res.status).toBe(status)` |
|
|
34
|
+
| `.matchingSchema(schema)` | Valida se a resposta corresponde ao schema (tipagem nominal) | `expect(res.body).toMatchSchema(schema)` |
|
|
35
|
+
|
|
36
|
+
## Execução
|
|
37
|
+
|
|
38
|
+
| Função | Descrição | O que faz |
|
|
39
|
+
| :--------- | :--------------------------------------- | :--------------------------------------------------------------- |
|
|
40
|
+
| `.run()` | Executa a requisição e as validações | Dispara o fetch, valida status, valida schema e loga o resultado |
|
|
41
|
+
|
|
42
|
+
## Exemplo Completo
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { ApiSpec } from "@vibe2founder/tests2dialects";
|
|
46
|
+
|
|
47
|
+
// Definindo o teste de forma fluída e declarativa
|
|
48
|
+
await ApiSpec.define("Ciclo de Vida do Usuário")
|
|
49
|
+
.from("https://api.empresa.com/v1")
|
|
50
|
+
|
|
51
|
+
// Passo 1: Criar Usuário
|
|
52
|
+
.post("/users", {
|
|
53
|
+
name: "Antigravity",
|
|
54
|
+
email: "ag@vibe2founder.codes",
|
|
55
|
+
role: "admin"
|
|
56
|
+
})
|
|
57
|
+
.header("X-Project-ID", "one-spec-4-all")
|
|
58
|
+
.shouldReturn(201)
|
|
59
|
+
.matchingSchema({
|
|
60
|
+
id: "number",
|
|
61
|
+
name: "string",
|
|
62
|
+
createdAt: "string"
|
|
63
|
+
})
|
|
64
|
+
.run();
|
|
65
|
+
|
|
66
|
+
// Passo 2: Validar se o usuário existe
|
|
67
|
+
await ApiSpec.define("Buscar Usuário Criado")
|
|
68
|
+
.from("https://api.empresa.com/v1")
|
|
69
|
+
.get("/users/1")
|
|
70
|
+
.shouldReturn(200)
|
|
71
|
+
.run();
|
|
72
|
+
|
|
73
|
+
// Passo 3: Remover Usuário
|
|
74
|
+
await ApiSpec.define("Remover Usuário")
|
|
75
|
+
.from("https://api.empresa.com/v1")
|
|
76
|
+
.delete("/users/1")
|
|
77
|
+
.shouldReturn(204)
|
|
78
|
+
.run();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Quando Usar
|
|
82
|
+
|
|
83
|
+
- ✅ Testes de integração de APIs REST.
|
|
84
|
+
- ✅ Verificação de contratos e schemas de resposta.
|
|
85
|
+
- ✅ Validação de Status Codes HTTP.
|
|
86
|
+
- ✅ Cenários que dependem de rede real ou mocks de rede.
|
|
87
|
+
- ✅ Testes E2E de backend.
|
|
88
|
+
|
|
89
|
+
## Quando NÃO Usar
|
|
90
|
+
|
|
91
|
+
- ❌ Testes unitários de funções puras → Use o [Dialeto Matemático](./api-matematico.md)
|
|
92
|
+
- ❌ Fluxos de UI complexas ou Narrativas de negócio → Use o [Dialeto Narrativo](./api-narrativo.md)
|
|
93
|
+
- ❌ Lógica de negócios interna sem I/O direto → Use o [Dialeto Imperativo](./api-imperativo.md)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# 🛡️ Dialeto Imperativo - API Completa
|
|
2
|
+
|
|
3
|
+
> **Filosofia:** Design by Contract e Engenharia de Sistemas.
|
|
4
|
+
>
|
|
5
|
+
> **Vibe:** Técnica, Rigorosa, "Crachá de Engenheiro".
|
|
6
|
+
>
|
|
7
|
+
> **Ideal para:** Engenheiros de backend, DevOps, validação de APIs, conformidade (compliance).
|
|
8
|
+
|
|
9
|
+
## Estrutura
|
|
10
|
+
|
|
11
|
+
| Função | Descrição | Equivalente Jest |
|
|
12
|
+
| ------------------ | ------------------------------- | ---------------- |
|
|
13
|
+
| `ensure(name, fn)` | Garante um requisito de sistema | `describe` |
|
|
14
|
+
| `suite(name, fn)` | Uma suite de verificações | `describe` |
|
|
15
|
+
| `check(name, fn)` | Uma checagem pontual | `test` / `it` |
|
|
16
|
+
| `verify(name, fn)` | Verificação de conformidade | `test` / `it` |
|
|
17
|
+
|
|
18
|
+
## Asserções
|
|
19
|
+
|
|
20
|
+
| Função | Descrição | Equivalente Jest |
|
|
21
|
+
| ----------------------------- | --------------------- | ---------------------------------------- |
|
|
22
|
+
| `that(val).is(expected)` | "Que o valor é..." | `expect(val).toBe(expected)` |
|
|
23
|
+
| `that(val).isOk()` | Verifica "truthiness" | `expect(val).toBeTruthy()` |
|
|
24
|
+
| `that(val).matches(regex)` | Validação de padrão | `expect(val).toMatch(regex)` |
|
|
25
|
+
| `that(val).triggered()` | Verifica disparo | `expect(val).toHaveBeenCalled()` |
|
|
26
|
+
| `that(val).calledWith(args)` | Verifica payload | `expect(val).toHaveBeenCalledWith(args)` |
|
|
27
|
+
| `that(val).triggeredCount(n)` | Contagem exata | `expect(val).toHaveBeenCalledTimes(n)` |
|
|
28
|
+
|
|
29
|
+
## Mocks
|
|
30
|
+
|
|
31
|
+
| Função | Descrição | Equivalente Jest |
|
|
32
|
+
| ---------------------- | -------------------------------- | ------------------------- |
|
|
33
|
+
| `stub()` | Cria um stub de infraestrutura | `jest.fn()` |
|
|
34
|
+
| `mock()` | Alias para stub | `jest.fn()` |
|
|
35
|
+
| `inspect(obj, method)` | Inspeciona um método interno | `jest.spyOn(obj, method)` |
|
|
36
|
+
| `spy(obj, method)` | Alias clássico | `jest.spyOn(obj, method)` |
|
|
37
|
+
| `s.forceReturn(val)` | Força um retorno imediato | `mockReturnValue(val)` |
|
|
38
|
+
| `s.resolveWith(val)` | Resolve promessa (network) | `mockResolvedValue(val)` |
|
|
39
|
+
| `s.executes(fn)` | Executa implementação substituta | `mockImplementation(fn)` |
|
|
40
|
+
|
|
41
|
+
## Lifecycle
|
|
42
|
+
|
|
43
|
+
| Função | Descrição | Equivalente Jest |
|
|
44
|
+
| ---------------- | ------------------------------- | ---------------- |
|
|
45
|
+
| `initAll(fn)` | Inicialização de sistema | `beforeAll(fn)` |
|
|
46
|
+
| `reset(fn)` | Reset de estado (antes de cada) | `beforeEach(fn)` |
|
|
47
|
+
| `disposeAll(fn)` | Descarte de recursos | `afterAll(fn)` |
|
|
48
|
+
|
|
49
|
+
## Exemplo Completo
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
import {
|
|
53
|
+
ensure,
|
|
54
|
+
check,
|
|
55
|
+
verify,
|
|
56
|
+
that,
|
|
57
|
+
stub,
|
|
58
|
+
initAll,
|
|
59
|
+
reset,
|
|
60
|
+
} from "@vibe2founder/tests2dialects";
|
|
61
|
+
|
|
62
|
+
ensure("Conformidade do Gateway de Pagamento", () => {
|
|
63
|
+
let apiGateway;
|
|
64
|
+
let transactionLogger;
|
|
65
|
+
|
|
66
|
+
initAll(() => {
|
|
67
|
+
apiGateway = stub();
|
|
68
|
+
transactionLogger = stub();
|
|
69
|
+
|
|
70
|
+
apiGateway.forceReturn({
|
|
71
|
+
status: 200,
|
|
72
|
+
transactionId: "tx_abc123",
|
|
73
|
+
timestamp: "2026-01-01T00:00:00Z",
|
|
74
|
+
});
|
|
75
|
+
transactionLogger.forceReturn(true);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
reset(() => {
|
|
79
|
+
// Limpa estado entre testes se necessário
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
check("Transação bem-sucedida retorna status 200", () => {
|
|
83
|
+
const response = apiGateway.process({
|
|
84
|
+
amount: 99.9,
|
|
85
|
+
currency: "BRL",
|
|
86
|
+
cardToken: "tok_visa_xxxx",
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
that(response.status).is(200);
|
|
90
|
+
that(response.transactionId).matches(/^tx_[a-z0-9]+$/);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
verify("TransactionId segue padrão RFC do contrato", () => {
|
|
94
|
+
const response = apiGateway.process({ amount: 50 });
|
|
95
|
+
|
|
96
|
+
that(response.transactionId).matches(/^tx_[a-z0-9]{6,}$/);
|
|
97
|
+
that(response.timestamp).matches(/^\d{4}-\d{2}-\d{2}T/);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
check("Toda transação deve ser logada para auditoria", () => {
|
|
101
|
+
apiGateway.process({ amount: 100 });
|
|
102
|
+
transactionLogger.log({ event: "PAYMENT_PROCESSED" });
|
|
103
|
+
|
|
104
|
+
that(transactionLogger).triggered();
|
|
105
|
+
that(transactionLogger).calledWith({ event: "PAYMENT_PROCESSED" });
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
verify("Gateway deve ser acionado exatamente uma vez por request", () => {
|
|
109
|
+
that(apiGateway).triggeredCount(1);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Quando Usar
|
|
115
|
+
|
|
116
|
+
- ✅ Integrações de API
|
|
117
|
+
- ✅ Drivers de banco de dados
|
|
118
|
+
- ✅ Validação de contratos RFC
|
|
119
|
+
- ✅ Conformidade com regulamentos (PCI-DSS, LGPD, etc.)
|
|
120
|
+
- ✅ Testes de infraestrutura
|
|
121
|
+
|
|
122
|
+
## Quando NÃO Usar
|
|
123
|
+
|
|
124
|
+
- ❌ Algoritmos matemáticos puros → Use o [Dialeto Matemático](./api-matematico.md)
|
|
125
|
+
- ❌ Fluxos de usuário legíveis por PMs → Use o [Dialeto Narrativo](./api-narrativo.md)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# 📐 Dialeto Matemático - API Completa
|
|
2
|
+
|
|
3
|
+
> **Filosofia:** Lógica Formal e Programação Funcional.
|
|
4
|
+
>
|
|
5
|
+
> **Vibe:** Científica, Imutável, Axiomática.
|
|
6
|
+
>
|
|
7
|
+
> **Ideal para:** Cientistas de dados, engenheiros de algoritmos, bibliotecas de utilitários, cálculos financeiros.
|
|
8
|
+
|
|
9
|
+
## Estrutura
|
|
10
|
+
|
|
11
|
+
| Função | Descrição | Equivalente Jest |
|
|
12
|
+
| ----------------- | ---------------------------------------- | ---------------- |
|
|
13
|
+
| `axiom(name, fn)` | Define um grupo de verdades fundamentais | `describe` |
|
|
14
|
+
| `proof(name, fn)` | Uma prova individual de um caso | `test` / `it` |
|
|
15
|
+
| `lemma(name, fn)` | Uma prova auxiliar (menor) | `test` / `it` |
|
|
16
|
+
|
|
17
|
+
## Asserções
|
|
18
|
+
|
|
19
|
+
| Função | Descrição | Equivalente Jest |
|
|
20
|
+
| --------------------------------- | ----------------------------------- | ---------------------------------------- |
|
|
21
|
+
| `implies(val).is(expected)` | "O valor implica ser..." | `expect(val).toBe(expected)` |
|
|
22
|
+
| `implies(val).wasEvaluated()` | Verifica se a função foi computada | `expect(val).toHaveBeenCalled()` |
|
|
23
|
+
| `implies(val).appliedTo(args)` | Verifica os argumentos da aplicação | `expect(val).toHaveBeenCalledWith(args)` |
|
|
24
|
+
| `implies(val).evaluated(n).times` | Frequência de avaliação | `expect(val).toHaveBeenCalledTimes(n)` |
|
|
25
|
+
| `implies(val).matches(regex)` | Corresponde a um padrão | `expect(val).toMatch(regex)` |
|
|
26
|
+
|
|
27
|
+
## Mocks
|
|
28
|
+
|
|
29
|
+
| Função | Descrição | Equivalente Jest |
|
|
30
|
+
| ---------------------- | ---------------------------------------- | ------------------------- |
|
|
31
|
+
| `arbitrary()` | Cria uma função genérica para teste | `jest.fn()` |
|
|
32
|
+
| `lambda()` | Alias para arbitrary | `jest.fn()` |
|
|
33
|
+
| `monitor(obj, method)` | Monitora uma função existente | `jest.spyOn(obj, method)` |
|
|
34
|
+
| `f.yields(val)` | Define o resultado produzido pela função | `mockReturnValue(val)` |
|
|
35
|
+
| `f.mapsTo(val)` | Alias para yields | `mockReturnValue(val)` |
|
|
36
|
+
| `f.convergesTo(val)` | Define o resultado assíncrono (limite) | `mockResolvedValue(val)` |
|
|
37
|
+
| `f.derive(fn)` | Define a implementação lógica | `mockImplementation(fn)` |
|
|
38
|
+
|
|
39
|
+
## Lifecycle
|
|
40
|
+
|
|
41
|
+
| Função | Descrição | Equivalente Jest |
|
|
42
|
+
| --------------- | ----------------------------------- | ---------------- |
|
|
43
|
+
| `postulate(fn)` | Define premissas iniciais globais | `beforeAll(fn)` |
|
|
44
|
+
| `setup(fn)` | Alias para postulate | `beforeAll(fn)` |
|
|
45
|
+
| `given(fn)` | "Dado que..." (antes de cada prova) | `beforeEach(fn)` |
|
|
46
|
+
| `conclude(fn)` | Conclusões finais / limpeza | `afterAll(fn)` |
|
|
47
|
+
|
|
48
|
+
## Exemplo Completo
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
import {
|
|
52
|
+
axiom,
|
|
53
|
+
proof,
|
|
54
|
+
lemma,
|
|
55
|
+
implies,
|
|
56
|
+
arbitrary,
|
|
57
|
+
monitor,
|
|
58
|
+
postulate,
|
|
59
|
+
given,
|
|
60
|
+
conclude,
|
|
61
|
+
} from "@vibe2founder/tests2dialects";
|
|
62
|
+
|
|
63
|
+
axiom("Teoria de Juros Compostos", () => {
|
|
64
|
+
let calcInterest;
|
|
65
|
+
let applyTax;
|
|
66
|
+
const logger = arbitrary();
|
|
67
|
+
|
|
68
|
+
postulate(() => {
|
|
69
|
+
// Premissas globais para todos os teoremas deste axioma
|
|
70
|
+
console.log("Estabelecendo premissas...");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
given(() => {
|
|
74
|
+
// Definimos as funções puras a serem testadas a cada ciclo
|
|
75
|
+
calcInterest = (p, r, t) => Math.floor(p * Math.pow(1 + r, t));
|
|
76
|
+
applyTax = (subtotal, rate) =>
|
|
77
|
+
Math.round(subtotal * (1 + rate) * 100) / 100;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
proof("Capital de 1000 a 5% por 2 anos implica montante de 1102", () => {
|
|
81
|
+
const result = calcInterest(1000, 0.05, 2);
|
|
82
|
+
implies(result).is(1102);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
proof("Taxa zero implica preservação do capital", () => {
|
|
86
|
+
const result = calcInterest(500, 0, 10);
|
|
87
|
+
implies(result).is(500);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
proof("Desconto de 100% anula o preço", () => {
|
|
91
|
+
const calcDiscount = (price, percent) => price - price * (percent / 100);
|
|
92
|
+
implies(calcDiscount(500, 100)).is(0);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
lemma("Imposto de 10% sobre R$100 resulta em R$110", () => {
|
|
96
|
+
implies(applyTax(100, 0.1)).is(110);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
proof("Logger arbitrário registra cálculo", () => {
|
|
100
|
+
logger.yields(true);
|
|
101
|
+
logger("calc_start");
|
|
102
|
+
|
|
103
|
+
implies(logger).wasEvaluated();
|
|
104
|
+
implies(logger).appliedTo("calc_start");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
conclude(() => {
|
|
108
|
+
console.log("Teoremas provados com sucesso.");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
axiom("Teoria de Fibonacci", () => {
|
|
113
|
+
const fib = arbitrary();
|
|
114
|
+
|
|
115
|
+
given(() => {
|
|
116
|
+
// Definição recursiva de Fibonacci
|
|
117
|
+
fib.derive((n) => (n <= 1 ? n : fib(n - 1) + fib(n - 2)));
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
proof("Fibonacci(0) implica 0", () => {
|
|
121
|
+
implies(fib(0)).is(0);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
proof("Fibonacci(1) implica 1", () => {
|
|
125
|
+
implies(fib(1)).is(1);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
proof("Fibonacci(10) implica 55", () => {
|
|
129
|
+
implies(fib(10)).is(55);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Quando Usar
|
|
135
|
+
|
|
136
|
+
- ✅ Algoritmos matemáticos puros
|
|
137
|
+
- ✅ Funções de criptografia
|
|
138
|
+
- ✅ Cálculos financeiros
|
|
139
|
+
- ✅ Regras de negócio determinísticas
|
|
140
|
+
- ✅ Bibliotecas de utilitários
|
|
141
|
+
|
|
142
|
+
## Quando NÃO Usar
|
|
143
|
+
|
|
144
|
+
- ❌ Integrações de API com contratos → Use o [Dialeto Imperativo](./api-imperativo.md)
|
|
145
|
+
- ❌ Fluxos de usuário legíveis por PMs → Use o [Dialeto Narrativo](./api-narrativo.md)
|