@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/src/index.ts
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 1. ATOMIC CORE ENGINE (O Motor)
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
type VoidFn = () => void | Promise<void>;
|
|
6
|
+
type HookType = "beforeAll" | "afterAll" | "beforeEach" | "afterEach";
|
|
7
|
+
|
|
8
|
+
interface SuiteNode {
|
|
9
|
+
name: string;
|
|
10
|
+
tests: { name: string; fn: VoidFn }[];
|
|
11
|
+
hooks: Record<HookType, VoidFn[]>;
|
|
12
|
+
parent?: SuiteNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class AtomicCore {
|
|
16
|
+
private static instance: AtomicCore;
|
|
17
|
+
private rootSuite: SuiteNode = {
|
|
18
|
+
name: "ROOT",
|
|
19
|
+
tests: [],
|
|
20
|
+
hooks: { beforeAll: [], afterAll: [], beforeEach: [], afterEach: [] },
|
|
21
|
+
};
|
|
22
|
+
private currentSuite: SuiteNode = this.rootSuite;
|
|
23
|
+
private suiteStarted = new Set<SuiteNode>();
|
|
24
|
+
|
|
25
|
+
static get() {
|
|
26
|
+
if (!AtomicCore.instance) AtomicCore.instance = new AtomicCore();
|
|
27
|
+
return AtomicCore.instance;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// --- Atomic Actions ---
|
|
31
|
+
|
|
32
|
+
defineGroup(name: string, fn: VoidFn) {
|
|
33
|
+
const parent = this.currentSuite;
|
|
34
|
+
const newSuite: SuiteNode = {
|
|
35
|
+
name,
|
|
36
|
+
tests: [],
|
|
37
|
+
hooks: { beforeAll: [], afterAll: [], beforeEach: [], afterEach: [] },
|
|
38
|
+
parent,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
this.currentSuite = newSuite;
|
|
42
|
+
console.log(`\n📂 [GROUP] ${name}`);
|
|
43
|
+
try {
|
|
44
|
+
fn();
|
|
45
|
+
// Se houve algum afterAll, rodamos no fim do grupo
|
|
46
|
+
newSuite.hooks.afterAll.forEach((h) => h());
|
|
47
|
+
} finally {
|
|
48
|
+
this.currentSuite = parent;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
defineCase(name: string, fn: VoidFn) {
|
|
53
|
+
console.log(` └─ 📝 [CASE] ${name}`);
|
|
54
|
+
this.runTestSafe(this.currentSuite, name, fn);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
addHook(type: HookType, fn: VoidFn) {
|
|
58
|
+
this.currentSuite.hooks[type].push(fn);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// --- Internal Runner Logic ---
|
|
62
|
+
|
|
63
|
+
private async runTestSafe(suite: SuiteNode, name: string, fn: VoidFn) {
|
|
64
|
+
// Run beforeAll if first test in this suite
|
|
65
|
+
if (!this.suiteStarted.has(suite)) {
|
|
66
|
+
suite.hooks.beforeAll.forEach((h) => h());
|
|
67
|
+
this.suiteStarted.add(suite);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
// Run BeforeEach hooks
|
|
72
|
+
suite.hooks.beforeEach.forEach((h) => h());
|
|
73
|
+
|
|
74
|
+
await fn();
|
|
75
|
+
console.log(` ✅ PASS: ${suite.name} › ${name}`);
|
|
76
|
+
|
|
77
|
+
// Run AfterEach hooks
|
|
78
|
+
suite.hooks.afterEach.forEach((h) => h());
|
|
79
|
+
} catch (e) {
|
|
80
|
+
console.error(
|
|
81
|
+
` ❌ FAIL: ${suite.name} › ${name} › ${(e as Error).message}`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
reset() {
|
|
87
|
+
this.rootSuite = {
|
|
88
|
+
name: "ROOT",
|
|
89
|
+
tests: [],
|
|
90
|
+
hooks: { beforeAll: [], afterAll: [], beforeEach: [], afterEach: [] },
|
|
91
|
+
};
|
|
92
|
+
this.currentSuite = this.rootSuite;
|
|
93
|
+
this.suiteStarted.clear();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const core = AtomicCore.get();
|
|
98
|
+
|
|
99
|
+
export const resetAtomicCore = () => core.reset();
|
|
100
|
+
|
|
101
|
+
// ============================================================================
|
|
102
|
+
// 2. UNIVERSAL MOCK (O Ator/Dublê)
|
|
103
|
+
// ============================================================================
|
|
104
|
+
|
|
105
|
+
class UniversalMockHandler {
|
|
106
|
+
public calls: any[][] = [];
|
|
107
|
+
private impl: ((...args: any[]) => any) | null = null;
|
|
108
|
+
private defaultReturn: any = undefined;
|
|
109
|
+
private isResolved: boolean = false;
|
|
110
|
+
private parent: UniversalMockHandler | null = null;
|
|
111
|
+
|
|
112
|
+
constructor(originalImpl?: (...args: any[]) => any) {
|
|
113
|
+
this.impl = originalImpl || null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
setParent(parent: UniversalMockHandler) {
|
|
117
|
+
this.parent = parent;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// O método que é chamado quando alguém invoca o mock
|
|
121
|
+
invoke(...args: any[]) {
|
|
122
|
+
this.calls.push(args);
|
|
123
|
+
// Notifica o pai que houve uma interação (útil para to(obj).wasCalled())
|
|
124
|
+
if (this.parent) this.parent.invoke(...args);
|
|
125
|
+
|
|
126
|
+
if (this.impl) return this.impl(...args);
|
|
127
|
+
if (this.isResolved) return Promise.resolve(this.defaultReturn);
|
|
128
|
+
return this.defaultReturn;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// --- Setup Methods (Aliases Internos) ---
|
|
132
|
+
setReturn(val: any) {
|
|
133
|
+
this.defaultReturn = val;
|
|
134
|
+
this.isResolved = false;
|
|
135
|
+
}
|
|
136
|
+
setResolved(val: any) {
|
|
137
|
+
this.defaultReturn = val;
|
|
138
|
+
this.isResolved = true;
|
|
139
|
+
}
|
|
140
|
+
setImplementation(fn: any) {
|
|
141
|
+
this.impl = fn;
|
|
142
|
+
}
|
|
143
|
+
clear() {
|
|
144
|
+
this.calls = [];
|
|
145
|
+
}
|
|
146
|
+
getDefaultReturn() {
|
|
147
|
+
return this.defaultReturn;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface AtomicMock extends Function {
|
|
152
|
+
(...args: any[]): any;
|
|
153
|
+
_handler: UniversalMockHandler;
|
|
154
|
+
// Jest compatible
|
|
155
|
+
mockReturnValue(v: any): void;
|
|
156
|
+
mockResolvedValue(v: any): void;
|
|
157
|
+
mockImplementation(fn: any): void;
|
|
158
|
+
// Math dialect
|
|
159
|
+
yields(v: any): void;
|
|
160
|
+
mapsTo(v: any): void;
|
|
161
|
+
convergesTo(v: any): void;
|
|
162
|
+
derive(fn: any): void;
|
|
163
|
+
// Narrative dialect
|
|
164
|
+
respondsWith(v: any): void;
|
|
165
|
+
eventuallyGives(v: any): void;
|
|
166
|
+
actsLike(fn: any): void;
|
|
167
|
+
// Imperative dialect
|
|
168
|
+
forceReturn(v: any): void;
|
|
169
|
+
resolveWith(v: any): void;
|
|
170
|
+
executes(fn: any): void;
|
|
171
|
+
// Shared
|
|
172
|
+
clear(): void;
|
|
173
|
+
reset(): void;
|
|
174
|
+
// Support for arbitrary method mocks (Deep Proxy)
|
|
175
|
+
[key: string]: any;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// A função mágica que é ao mesmo tempo executável e configurável
|
|
179
|
+
function createAtomicMock(
|
|
180
|
+
implementation?: (...args: any[]) => any,
|
|
181
|
+
parentHandler?: UniversalMockHandler,
|
|
182
|
+
): AtomicMock {
|
|
183
|
+
const handler = new UniversalMockHandler(implementation);
|
|
184
|
+
if (parentHandler) handler.setParent(parentHandler);
|
|
185
|
+
const subMocks = new Map<string, any>();
|
|
186
|
+
|
|
187
|
+
const mockFn = (...args: any[]) => handler.invoke(...args);
|
|
188
|
+
|
|
189
|
+
// Mapeamento de TODOS os métodos de configuração de mocks
|
|
190
|
+
const config: Record<string, any> = {
|
|
191
|
+
_handler: handler,
|
|
192
|
+
// Jest
|
|
193
|
+
mockReturnValue: (v: any) => handler.setReturn(v),
|
|
194
|
+
mockResolvedValue: (v: any) => handler.setResolved(v),
|
|
195
|
+
mockImplementation: (fn: any) => handler.setImplementation(fn),
|
|
196
|
+
|
|
197
|
+
// Matemático
|
|
198
|
+
yields: (v: any) => handler.setReturn(v),
|
|
199
|
+
mapsTo: (v: any) => handler.setReturn(v),
|
|
200
|
+
convergesTo: (v: any) => handler.setResolved(v),
|
|
201
|
+
derive: (fn: any) => handler.setImplementation(fn),
|
|
202
|
+
|
|
203
|
+
// Narrativo
|
|
204
|
+
respondsWith: (v: any) => handler.setReturn(v),
|
|
205
|
+
eventuallyGives: (v: any) => handler.setResolved(v),
|
|
206
|
+
actsLike: (fn: any) => handler.setImplementation(fn),
|
|
207
|
+
|
|
208
|
+
// Imperativo
|
|
209
|
+
forceReturn: (v: any) => handler.setReturn(v),
|
|
210
|
+
resolveWith: (v: any) => handler.setResolved(v),
|
|
211
|
+
executes: (fn: any) => handler.setImplementation(fn),
|
|
212
|
+
|
|
213
|
+
// Common
|
|
214
|
+
clear: () => {
|
|
215
|
+
handler.clear();
|
|
216
|
+
subMocks.forEach((m) => m.clear());
|
|
217
|
+
},
|
|
218
|
+
reset: () => {
|
|
219
|
+
handler.clear();
|
|
220
|
+
handler.setImplementation(null);
|
|
221
|
+
handler.setReturn(undefined);
|
|
222
|
+
subMocks.clear();
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// Retornamos um Proxy para permitir acesso a propriedades arbitrárias (como métodos)
|
|
227
|
+
return new Proxy(mockFn, {
|
|
228
|
+
get(target, prop: string) {
|
|
229
|
+
// 1. Se for um método de configuração ou propriedade interna, retorna do config
|
|
230
|
+
if (prop in config) return config[prop];
|
|
231
|
+
if (prop === "then") return undefined; // Evita problemas com Promises
|
|
232
|
+
|
|
233
|
+
// 2. Se o mock foi configurado para retornar um objeto, tentamos pegar a propriedade dele
|
|
234
|
+
const currentReturn = handler.getDefaultReturn();
|
|
235
|
+
if (
|
|
236
|
+
currentReturn &&
|
|
237
|
+
typeof currentReturn === "object" &&
|
|
238
|
+
prop in currentReturn
|
|
239
|
+
) {
|
|
240
|
+
return currentReturn[prop];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 3. Se for uma propriedade arbitrária e não temos valor, retornamos um sub-mock (lazy creation)
|
|
244
|
+
if (!subMocks.has(prop)) {
|
|
245
|
+
subMocks.set(prop, createAtomicMock(undefined, handler));
|
|
246
|
+
}
|
|
247
|
+
return subMocks.get(prop);
|
|
248
|
+
},
|
|
249
|
+
// Permite Object.assign e outras operações
|
|
250
|
+
set(target, prop: string, value: any) {
|
|
251
|
+
config[prop] = value;
|
|
252
|
+
return true;
|
|
253
|
+
},
|
|
254
|
+
}) as unknown as AtomicMock;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function createAtomicSpy(obj: any, method: string) {
|
|
258
|
+
const original = obj[method];
|
|
259
|
+
const mock = createAtomicMock(original);
|
|
260
|
+
obj[method] = mock;
|
|
261
|
+
return mock; // Retorna o mock para asserções
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ============================================================================
|
|
265
|
+
// 3. UNIVERSAL ASSERTION (O Juiz)
|
|
266
|
+
// ============================================================================
|
|
267
|
+
|
|
268
|
+
class UniversalAssertion<T> {
|
|
269
|
+
constructor(
|
|
270
|
+
private actual: T,
|
|
271
|
+
private isNegated: boolean = false,
|
|
272
|
+
) {}
|
|
273
|
+
|
|
274
|
+
get not() {
|
|
275
|
+
return new UniversalAssertion(this.actual, !this.isNegated);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private pass(condition: boolean, msg: string) {
|
|
279
|
+
const success = this.isNegated ? !condition : condition;
|
|
280
|
+
if (!success) throw new Error(this.isNegated ? `[NOT] ${msg}` : msg);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// --- Equality & Truthiness ---
|
|
284
|
+
|
|
285
|
+
// Jest / Classic
|
|
286
|
+
toBe(expected: T) {
|
|
287
|
+
this.pass(
|
|
288
|
+
this.actual === expected,
|
|
289
|
+
`Expected ${this.actual} to be ${expected}`,
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
toEqual(expected: T) {
|
|
293
|
+
this.pass(
|
|
294
|
+
JSON.stringify(this.actual) === JSON.stringify(expected),
|
|
295
|
+
`Expected ${this.actual} to equal ${expected}`,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Matemático
|
|
300
|
+
is(expected: T) {
|
|
301
|
+
this.toBe(expected);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Narrativo
|
|
305
|
+
be(expected: T) {
|
|
306
|
+
this.toBe(expected);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Imperativo
|
|
310
|
+
isOk() {
|
|
311
|
+
this.pass(!!this.actual, `Ensure ${this.actual} is truthy`);
|
|
312
|
+
}
|
|
313
|
+
matches(regex: RegExp) {
|
|
314
|
+
if (typeof this.actual !== "string")
|
|
315
|
+
throw new Error("Value must be string");
|
|
316
|
+
this.pass(
|
|
317
|
+
regex.test(this.actual),
|
|
318
|
+
`Ensure '${this.actual}' matches ${regex}`,
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Narrativo
|
|
323
|
+
have(prop: string) {
|
|
324
|
+
this.pass(
|
|
325
|
+
typeof this.actual === "object" &&
|
|
326
|
+
this.actual !== null &&
|
|
327
|
+
prop in (this.actual as any),
|
|
328
|
+
`Intend object to have '${prop}'`,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
uploaded(...args: any[]) {
|
|
332
|
+
this.received(...args);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// --- Mock Assertions ---
|
|
336
|
+
|
|
337
|
+
// Helper para pegar o handler do mock
|
|
338
|
+
private getMockHandler(mockFn: any) {
|
|
339
|
+
if (!mockFn._handler)
|
|
340
|
+
throw new Error(
|
|
341
|
+
"Assertion target is not a registered Mock/Spy function.",
|
|
342
|
+
);
|
|
343
|
+
return mockFn._handler as UniversalMockHandler;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Jest
|
|
347
|
+
toHaveBeenCalled() {
|
|
348
|
+
const h = this.getMockHandler(this.actual);
|
|
349
|
+
this.pass(h.calls.length > 0, "Expected mock to have been called");
|
|
350
|
+
}
|
|
351
|
+
toHaveBeenCalledWith(...args: any[]) {
|
|
352
|
+
const h = this.getMockHandler(this.actual);
|
|
353
|
+
const match = h.calls.some(
|
|
354
|
+
(call) => JSON.stringify(call) === JSON.stringify(args),
|
|
355
|
+
);
|
|
356
|
+
this.pass(match, `Expected mock called with ${JSON.stringify(args)}`);
|
|
357
|
+
}
|
|
358
|
+
toHaveBeenCalledTimes(n: number) {
|
|
359
|
+
const h = this.getMockHandler(this.actual);
|
|
360
|
+
this.pass(
|
|
361
|
+
h.calls.length === n,
|
|
362
|
+
`Expected mock called ${n} times, got ${h.calls.length}`,
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Matemático
|
|
367
|
+
wasEvaluated() {
|
|
368
|
+
this.toHaveBeenCalled();
|
|
369
|
+
}
|
|
370
|
+
appliedTo(...args: any[]) {
|
|
371
|
+
this.toHaveBeenCalledWith(...args);
|
|
372
|
+
}
|
|
373
|
+
get evaluated() {
|
|
374
|
+
const h = this.getMockHandler(this.actual);
|
|
375
|
+
return (n: number) => ({ times: this.toHaveBeenCalledTimes(n) }); // Currying simulado para sintaxe .evaluated(n).times
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Narrativo
|
|
379
|
+
wasCalled() {
|
|
380
|
+
this.toHaveBeenCalled();
|
|
381
|
+
}
|
|
382
|
+
received(...args: any[]) {
|
|
383
|
+
this.toHaveBeenCalledWith(...args);
|
|
384
|
+
}
|
|
385
|
+
get called() {
|
|
386
|
+
const h = this.getMockHandler(this.actual);
|
|
387
|
+
return (n: number) => ({ times: this.toHaveBeenCalledTimes(n) });
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Imperativo
|
|
391
|
+
triggered() {
|
|
392
|
+
this.toHaveBeenCalled();
|
|
393
|
+
}
|
|
394
|
+
calledWith(...args: any[]) {
|
|
395
|
+
this.toHaveBeenCalledWith(...args);
|
|
396
|
+
}
|
|
397
|
+
triggeredCount(n: number) {
|
|
398
|
+
this.toHaveBeenCalledTimes(n);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Factory para assertions
|
|
403
|
+
const assertValue = <T>(val: T) => new UniversalAssertion(val);
|
|
404
|
+
|
|
405
|
+
// ============================================================================
|
|
406
|
+
// 4. DIALECT EXPORTS (A Pedra de Roseta)
|
|
407
|
+
// ============================================================================
|
|
408
|
+
|
|
409
|
+
// --- 📐 MATEMÁTICO (MathDialect) ---
|
|
410
|
+
export const MathDialect = {
|
|
411
|
+
// Structure
|
|
412
|
+
axiom: (n: string, f: VoidFn) => core.defineGroup(n, f),
|
|
413
|
+
proof: (n: string, f: VoidFn) => core.defineCase(n, f),
|
|
414
|
+
implies: assertValue,
|
|
415
|
+
|
|
416
|
+
// Mocks (Creation)
|
|
417
|
+
arbitrary: createAtomicMock,
|
|
418
|
+
lambda: createAtomicMock,
|
|
419
|
+
monitor: createAtomicSpy,
|
|
420
|
+
|
|
421
|
+
// Lifecycle
|
|
422
|
+
postulate: (f: VoidFn) => core.addHook("beforeAll", f),
|
|
423
|
+
conclude: (f: VoidFn) => core.addHook("afterAll", f),
|
|
424
|
+
given: (f: VoidFn) => core.addHook("beforeEach", f),
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// --- 📖 NARRATIVO (NarrativeDialect) ---
|
|
428
|
+
export const NarrativeDialect = {
|
|
429
|
+
// Structure
|
|
430
|
+
intend: (n: string, f: VoidFn) => core.defineGroup(n, f),
|
|
431
|
+
story: (n: string, f: VoidFn) => core.defineGroup(n, f),
|
|
432
|
+
detail: (n: string, f: VoidFn) => core.defineCase(n, f),
|
|
433
|
+
scenario: (n: string, f: VoidFn) => core.defineCase(n, f),
|
|
434
|
+
to: assertValue,
|
|
435
|
+
|
|
436
|
+
// Mocks (Creation)
|
|
437
|
+
dummy: createAtomicMock,
|
|
438
|
+
standIn: createAtomicMock,
|
|
439
|
+
watch: createAtomicSpy,
|
|
440
|
+
shadow: createAtomicSpy,
|
|
441
|
+
|
|
442
|
+
// Lifecycle
|
|
443
|
+
background: (f: VoidFn) => core.addHook("beforeAll", f),
|
|
444
|
+
cleanup: (f: VoidFn) => core.addHook("afterAll", f),
|
|
445
|
+
before: (f: VoidFn) => core.addHook("beforeEach", f),
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// --- 🛡️ IMPERATIVO (ImperativeDialect) ---
|
|
449
|
+
export const ImperativeDialect = {
|
|
450
|
+
// Structure
|
|
451
|
+
ensure: (n: string, f: VoidFn) => core.defineGroup(n, f),
|
|
452
|
+
suite: (n: string, f: VoidFn) => core.defineGroup(n, f),
|
|
453
|
+
check: (n: string, f: VoidFn) => core.defineCase(n, f),
|
|
454
|
+
verify: (n: string, f: VoidFn) => core.defineCase(n, f),
|
|
455
|
+
that: assertValue,
|
|
456
|
+
|
|
457
|
+
// Mocks (Creation)
|
|
458
|
+
stub: createAtomicMock,
|
|
459
|
+
mock: createAtomicMock,
|
|
460
|
+
inspect: createAtomicSpy,
|
|
461
|
+
spy: createAtomicSpy,
|
|
462
|
+
|
|
463
|
+
// Lifecycle
|
|
464
|
+
initAll: (f: VoidFn) => core.addHook("beforeAll", f),
|
|
465
|
+
disposeAll: (f: VoidFn) => core.addHook("afterAll", f),
|
|
466
|
+
reset: (f: VoidFn) => core.addHook("beforeEach", f),
|
|
467
|
+
clear: () => {}, // No-op for global clear
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
// --- 🤡 JEST / CLASSIC ---
|
|
471
|
+
export const ClassicDialect = {
|
|
472
|
+
describe: (n: string, f: VoidFn) => core.defineGroup(n, f),
|
|
473
|
+
it: (n: string, f: VoidFn) => core.defineCase(n, f),
|
|
474
|
+
test: (n: string, f: VoidFn) => core.defineCase(n, f),
|
|
475
|
+
expect: assertValue,
|
|
476
|
+
|
|
477
|
+
// Objeto Jest Global (simulado)
|
|
478
|
+
jest: {
|
|
479
|
+
fn: createAtomicMock,
|
|
480
|
+
spyOn: createAtomicSpy,
|
|
481
|
+
},
|
|
482
|
+
|
|
483
|
+
beforeAll: (f: VoidFn) => core.addHook("beforeAll", f),
|
|
484
|
+
afterAll: (f: VoidFn) => core.addHook("afterAll", f),
|
|
485
|
+
beforeEach: (f: VoidFn) => core.addHook("beforeEach", f),
|
|
486
|
+
afterEach: (f: VoidFn) => core.addHook("afterEach", f),
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
// --- Top-Level Exports for Ease of Use ---
|
|
490
|
+
export const {
|
|
491
|
+
axiom,
|
|
492
|
+
proof,
|
|
493
|
+
implies,
|
|
494
|
+
arbitrary,
|
|
495
|
+
lambda,
|
|
496
|
+
monitor,
|
|
497
|
+
postulate,
|
|
498
|
+
conclude,
|
|
499
|
+
given,
|
|
500
|
+
} = MathDialect;
|
|
501
|
+
export const {
|
|
502
|
+
intend,
|
|
503
|
+
story,
|
|
504
|
+
detail,
|
|
505
|
+
scenario,
|
|
506
|
+
to,
|
|
507
|
+
dummy,
|
|
508
|
+
standIn,
|
|
509
|
+
watch,
|
|
510
|
+
shadow,
|
|
511
|
+
background,
|
|
512
|
+
cleanup,
|
|
513
|
+
before,
|
|
514
|
+
} = NarrativeDialect;
|
|
515
|
+
export const {
|
|
516
|
+
ensure,
|
|
517
|
+
suite,
|
|
518
|
+
check,
|
|
519
|
+
verify,
|
|
520
|
+
that,
|
|
521
|
+
stub,
|
|
522
|
+
mock,
|
|
523
|
+
inspect,
|
|
524
|
+
spy,
|
|
525
|
+
initAll,
|
|
526
|
+
disposeAll,
|
|
527
|
+
reset,
|
|
528
|
+
clear,
|
|
529
|
+
} = ImperativeDialect;
|
|
530
|
+
export const {
|
|
531
|
+
describe,
|
|
532
|
+
it,
|
|
533
|
+
test,
|
|
534
|
+
expect,
|
|
535
|
+
beforeAll,
|
|
536
|
+
afterAll,
|
|
537
|
+
beforeEach,
|
|
538
|
+
afterEach,
|
|
539
|
+
} = ClassicDialect;
|