bun-sticky 1.0.4 → 1.0.5

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.
@@ -1,966 +0,0 @@
1
- /**
2
- * 🏎️ WJTTC Championship Test Suite for bun-sticky
3
- *
4
- * F1-Inspired Software Testing Philosophy:
5
- * "When brakes must work flawlessly, so must our code."
6
- *
7
- * This test suite demonstrates EVERY Bun test API feature combined
8
- * with the WJTTC (Wolfejam Test Track Championship) methodology.
9
- *
10
- * Bun Test Features Used:
11
- * - test, describe, it (core)
12
- * - test.each (parametrized)
13
- * - test.concurrent (parallel)
14
- * - test.skip, test.todo (documentation)
15
- * - beforeAll, beforeEach, afterEach, afterAll (lifecycle)
16
- * - mock, spyOn (mocking)
17
- * - expect matchers (full suite)
18
- * - snapshots
19
- * - retry, repeats (reliability)
20
- *
21
- * @author wolfejam
22
- * @license MIT
23
- */
24
-
25
- import {
26
- test,
27
- expect,
28
- describe,
29
- it,
30
- beforeAll,
31
- beforeEach,
32
- afterEach,
33
- afterAll,
34
- mock,
35
- spyOn,
36
- } from "bun:test";
37
-
38
- import { parseYaml, getNestedValue, hasValue } from "../lib/parser";
39
- import { calculateScore, SLOTS, ProjectType } from "../lib/scorer";
40
- import { getTier, TIERS } from "../lib/tier";
41
-
42
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
43
- // WJTTC RACE 1: SLOT DEFINITIONS (The Foundation)
44
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
45
-
46
- describe("🏁 WJTTC Race 1: Slot Definitions", () => {
47
- describe("slot counts", () => {
48
- test("project has exactly 3 slots", () => {
49
- expect(SLOTS.project).toHaveLength(3);
50
- });
51
-
52
- test("frontend has exactly 4 slots", () => {
53
- expect(SLOTS.frontend).toHaveLength(4);
54
- });
55
-
56
- test("backend has exactly 5 slots", () => {
57
- expect(SLOTS.backend).toHaveLength(5);
58
- });
59
-
60
- test("universal has exactly 3 slots", () => {
61
- expect(SLOTS.universal).toHaveLength(3);
62
- });
63
-
64
- test("human has exactly 6 slots", () => {
65
- expect(SLOTS.human).toHaveLength(6);
66
- });
67
-
68
- test("total slots equals 21 (Wolfejam specification)", () => {
69
- const total =
70
- SLOTS.project.length +
71
- SLOTS.frontend.length +
72
- SLOTS.backend.length +
73
- SLOTS.universal.length +
74
- SLOTS.human.length;
75
- expect(total).toBe(21);
76
- });
77
- });
78
-
79
- describe("slot naming convention", () => {
80
- test.each(SLOTS.project)("project slot %s uses dot notation", (slot) => {
81
- expect(slot).toMatch(/^project\./);
82
- });
83
-
84
- test.each(SLOTS.human)("human slot %s uses dot notation", (slot) => {
85
- expect(slot).toMatch(/^human_context\./);
86
- });
87
-
88
- test.each(SLOTS.frontend)("frontend slot %s uses stack prefix", (slot) => {
89
- expect(slot).toMatch(/^stack\./);
90
- });
91
-
92
- test.each(SLOTS.backend)("backend slot %s uses stack prefix", (slot) => {
93
- expect(slot).toMatch(/^stack\./);
94
- });
95
- });
96
-
97
- describe("required fields exist", () => {
98
- test("project.name is a slot", () => {
99
- expect(SLOTS.project).toContain("project.name");
100
- });
101
-
102
- test("project.goal is a slot", () => {
103
- expect(SLOTS.project).toContain("project.goal");
104
- });
105
-
106
- test("project.main_language is a slot", () => {
107
- expect(SLOTS.project).toContain("project.main_language");
108
- });
109
-
110
- test("human_context.who (5W1H) is a slot", () => {
111
- expect(SLOTS.human).toContain("human_context.who");
112
- });
113
-
114
- test("human_context.what is a slot", () => {
115
- expect(SLOTS.human).toContain("human_context.what");
116
- });
117
-
118
- test("human_context.why is a slot", () => {
119
- expect(SLOTS.human).toContain("human_context.why");
120
- });
121
-
122
- test("human_context.where is a slot", () => {
123
- expect(SLOTS.human).toContain("human_context.where");
124
- });
125
-
126
- test("human_context.when is a slot", () => {
127
- expect(SLOTS.human).toContain("human_context.when");
128
- });
129
-
130
- test("human_context.how is a slot", () => {
131
- expect(SLOTS.human).toContain("human_context.how");
132
- });
133
- });
134
- });
135
-
136
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
137
- // WJTTC RACE 2: PROJECT TYPE DETECTION
138
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
139
-
140
- describe("🏁 WJTTC Race 2: Project Type Detection", () => {
141
- // Parametrized tests using test.each - Bun's powerful feature
142
- const typeTestCases: Array<[string, string, ProjectType]> = [
143
- ["cli", "type: cli", "cli"],
144
- ["CLI uppercase", "type: CLI", "cli"],
145
- ["library", "type: library", "library"],
146
- ["lib short", "type: lib", "library"],
147
- ["package", "type: package", "library"],
148
- ["api", "type: api", "api"],
149
- ["backend", "type: backend", "api"],
150
- ["webapp", "type: webapp", "webapp"],
151
- ["web", "type: web", "webapp"],
152
- ["frontend", "type: frontend", "webapp"],
153
- ["fullstack", "type: fullstack", "fullstack"],
154
- ["full", "type: full", "fullstack"],
155
- ["mobile", "type: mobile", "mobile"],
156
- ["app", "type: app", "mobile"],
157
- ];
158
-
159
- test.each(typeTestCases)(
160
- "detects %s type from '%s'",
161
- (name, content, expected) => {
162
- const faf = parseYaml(`project:\n ${content}`);
163
- const result = calculateScore(faf);
164
- expect(result.projectType).toBe(expected);
165
- }
166
- );
167
-
168
- describe("type inference from stack", () => {
169
- test("infers fullstack when both frontend and backend exist", () => {
170
- const faf = parseYaml(`
171
- stack:
172
- frontend: React
173
- backend: Node
174
- `);
175
- const result = calculateScore(faf);
176
- expect(result.projectType).toBe("fullstack");
177
- });
178
-
179
- test("infers webapp when only frontend exists", () => {
180
- const faf = parseYaml(`
181
- stack:
182
- frontend: React
183
- `);
184
- const result = calculateScore(faf);
185
- expect(result.projectType).toBe("webapp");
186
- });
187
-
188
- test("infers api when only backend exists", () => {
189
- const faf = parseYaml(`
190
- stack:
191
- backend: Express
192
- `);
193
- const result = calculateScore(faf);
194
- expect(result.projectType).toBe("api");
195
- });
196
-
197
- test("infers api from database presence", () => {
198
- const faf = parseYaml(`
199
- stack:
200
- database: PostgreSQL
201
- `);
202
- const result = calculateScore(faf);
203
- expect(result.projectType).toBe("api");
204
- });
205
-
206
- test("defaults to unknown when no type info", () => {
207
- const faf = parseYaml(`
208
- project:
209
- name: Mystery
210
- `);
211
- const result = calculateScore(faf);
212
- expect(result.projectType).toBe("unknown");
213
- });
214
- });
215
- });
216
-
217
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
218
- // WJTTC RACE 3: SCORE CALCULATIONS
219
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
220
-
221
- describe("🏁 WJTTC Race 3: Score Calculations", () => {
222
- describe("Wolfejam formula verification", () => {
223
- test("score = (filled / applicable) × 100", () => {
224
- const faf = parseYaml(`
225
- project:
226
- name: Test
227
- goal: Testing
228
- main_language: TypeScript
229
- type: cli
230
- human_context:
231
- who: Developers
232
- what: A CLI tool
233
- `);
234
- const result = calculateScore(faf);
235
- // 5 filled / 9 applicable = 55.55% → rounds to 56%
236
- expect(result.filled).toBe(5);
237
- expect(result.total).toBe(9);
238
- expect(result.score).toBe(56);
239
- });
240
- });
241
-
242
- describe("type-aware slot counting", () => {
243
- const slotCountCases: Array<[ProjectType, number]> = [
244
- ["cli", 9],
245
- ["library", 9],
246
- ["api", 17],
247
- ["webapp", 16],
248
- ["fullstack", 21],
249
- ["mobile", 9],
250
- ["unknown", 9],
251
- ];
252
-
253
- test.each(slotCountCases)(
254
- "%s type has %d applicable slots",
255
- (type, expected) => {
256
- const faf = parseYaml(`
257
- project:
258
- type: ${type}
259
- `);
260
- const result = calculateScore(faf);
261
- expect(result.total).toBe(expected);
262
- }
263
- );
264
- });
265
-
266
- describe("100% score scenarios", () => {
267
- test("CLI with all 9 slots filled = 100%", () => {
268
- const faf = parseYaml(`
269
- project:
270
- name: PerfectCLI
271
- goal: Achieve perfection
272
- main_language: Zig
273
- type: cli
274
- human_context:
275
- who: Developers
276
- what: A CLI tool
277
- why: For testing
278
- where: Terminal
279
- when: 2025
280
- how: Run it
281
- `);
282
- const result = calculateScore(faf);
283
- expect(result.score).toBe(100);
284
- expect(result.filled).toBe(9);
285
- expect(result.total).toBe(9);
286
- });
287
-
288
- test("Fullstack with all 21 slots filled = 100%", () => {
289
- const faf = parseYaml(`
290
- project:
291
- name: FullApp
292
- goal: Complete solution
293
- main_language: TypeScript
294
- type: fullstack
295
- stack:
296
- frontend: React
297
- css_framework: Tailwind
298
- ui_library: shadcn
299
- state_management: zustand
300
- backend: Node
301
- api_type: REST
302
- runtime: Bun
303
- database: PostgreSQL
304
- connection: prisma
305
- hosting: Vercel
306
- build: vite
307
- cicd: GitHub Actions
308
- human_context:
309
- who: Users
310
- what: Full application
311
- why: Complete solution
312
- where: Web
313
- when: 2025
314
- how: npm start
315
- `);
316
- const result = calculateScore(faf);
317
- expect(result.score).toBe(100);
318
- expect(result.filled).toBe(21);
319
- expect(result.total).toBe(21);
320
- });
321
- });
322
-
323
- describe("partial score scenarios", () => {
324
- const partialCases: Array<[string, number, number, number]> = [
325
- // [description, filled, total, expectedScore]
326
- // Note: Math.round(x/9 * 100) - some round up!
327
- ["1/9 CLI slots", 1, 9, 11],
328
- ["4/9 CLI slots", 4, 9, 44],
329
- ["5/9 CLI slots", 5, 9, 56], // 55.55 rounds to 56
330
- ["7/9 CLI slots", 7, 9, 78], // 77.77 rounds to 78
331
- ["8/9 CLI slots", 8, 9, 89], // 88.88 rounds to 89
332
- ];
333
-
334
- test.each(partialCases)(
335
- "%s = %d%",
336
- (desc, filled, total, expectedScore) => {
337
- const score = Math.round((filled / total) * 100);
338
- expect(score).toBe(expectedScore);
339
- }
340
- );
341
- });
342
-
343
- describe("empty and edge cases", () => {
344
- test("empty object returns 0 score", () => {
345
- const faf = {};
346
- const result = calculateScore(faf);
347
- expect(result.score).toBe(0);
348
- });
349
-
350
- test("missing sections don't crash", () => {
351
- const faf = parseYaml(`
352
- project:
353
- name: Minimal
354
- `);
355
- expect(() => calculateScore(faf)).not.toThrow();
356
- });
357
- });
358
- });
359
-
360
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
361
- // WJTTC RACE 4: TIER SYSTEM
362
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
363
-
364
- describe("🏁 WJTTC Race 4: Tier System", () => {
365
- describe("tier definitions", () => {
366
- test("7 tiers are defined", () => {
367
- expect(TIERS).toHaveLength(7);
368
- });
369
-
370
- test("all tiers have required properties", () => {
371
- for (const tier of TIERS) {
372
- expect(tier).toHaveProperty("name");
373
- expect(tier).toHaveProperty("emoji");
374
- expect(tier).toHaveProperty("color");
375
- // Note: minScore handled by getTier() function, not stored in TIERS
376
- }
377
- });
378
- });
379
-
380
- describe("tier boundaries (exact thresholds)", () => {
381
- const boundaryTests: Array<[number, string]> = [
382
- [100, "Trophy"],
383
- [99, "Gold"],
384
- [95, "Silver"],
385
- [85, "Bronze"],
386
- [70, "Green"],
387
- [55, "Yellow"],
388
- [54, "Red"],
389
- [0, "Empty"],
390
- ];
391
-
392
- test.each(boundaryTests)("score %d = %s tier", (score, expectedName) => {
393
- const tier = getTier(score);
394
- expect(tier.name).toBe(expectedName);
395
- });
396
- });
397
-
398
- describe("tier emoji verification", () => {
399
- test("Trophy has trophy emoji", () => {
400
- expect(getTier(100).emoji).toBe("🏆");
401
- });
402
-
403
- test("Gold has gold medal emoji", () => {
404
- expect(getTier(99).emoji).toBe("🥇");
405
- });
406
-
407
- test("Silver has silver medal emoji", () => {
408
- expect(getTier(95).emoji).toBe("🥈");
409
- });
410
-
411
- test("Bronze has bronze medal emoji", () => {
412
- expect(getTier(85).emoji).toBe("🥉");
413
- });
414
-
415
- test("Green has green circle emoji", () => {
416
- expect(getTier(70).emoji).toBe("🟢");
417
- });
418
-
419
- test("Yellow has yellow circle emoji", () => {
420
- expect(getTier(55).emoji).toBe("🟡");
421
- });
422
-
423
- test("Red has red circle emoji", () => {
424
- expect(getTier(50).emoji).toBe("🔴");
425
- });
426
- });
427
-
428
- describe("tier color coding", () => {
429
- test("high tiers use green-ish colors", () => {
430
- const trophy = getTier(100);
431
- const gold = getTier(99);
432
- expect(trophy.color).toContain("\x1b[");
433
- expect(gold.color).toContain("\x1b[");
434
- });
435
-
436
- test("Red tier uses red ANSI code", () => {
437
- const red = getTier(50);
438
- expect(red.color).toBe("\x1b[31m");
439
- });
440
- });
441
- });
442
-
443
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
444
- // WJTTC RACE 5: YAML PARSER
445
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
446
-
447
- describe("🏁 WJTTC Race 5: YAML Parser", () => {
448
- describe("parseYaml basic parsing", () => {
449
- test("parses simple key-value", () => {
450
- const result = parseYaml("name: test");
451
- expect(result).toHaveProperty("name", "test");
452
- });
453
-
454
- test("parses nested objects", () => {
455
- const result = parseYaml(`
456
- project:
457
- name: test
458
- goal: testing
459
- `);
460
- expect(result.project).toHaveProperty("name", "test");
461
- expect(result.project).toHaveProperty("goal", "testing");
462
- });
463
-
464
- test("handles empty lines", () => {
465
- const result = parseYaml(`
466
- name: test
467
-
468
- goal: testing
469
- `);
470
- expect(result).toHaveProperty("name", "test");
471
- expect(result).toHaveProperty("goal", "testing");
472
- });
473
-
474
- test("ignores comments", () => {
475
- const result = parseYaml(`
476
- # This is a comment
477
- name: test
478
- `);
479
- expect(result).toHaveProperty("name", "test");
480
- expect(result).not.toHaveProperty("#");
481
- });
482
- });
483
-
484
- describe("getNestedValue", () => {
485
- const testObj = {
486
- project: {
487
- name: "test",
488
- details: {
489
- version: "1.0.0",
490
- },
491
- },
492
- };
493
-
494
- test("gets top-level value", () => {
495
- expect(getNestedValue(testObj, "project")).toBeDefined();
496
- });
497
-
498
- test("gets nested value", () => {
499
- expect(getNestedValue(testObj, "project.name")).toBe("test");
500
- });
501
-
502
- test("gets deeply nested value", () => {
503
- expect(getNestedValue(testObj, "project.details.version")).toBe("1.0.0");
504
- });
505
-
506
- test("returns undefined for missing path", () => {
507
- expect(getNestedValue(testObj, "missing.path")).toBeUndefined();
508
- });
509
- });
510
-
511
- describe("hasValue", () => {
512
- test("returns true for existing value", () => {
513
- const obj = { name: "test" };
514
- expect(hasValue(obj, "name")).toBe(true);
515
- });
516
-
517
- test("returns false for missing value", () => {
518
- const obj = { name: "test" };
519
- expect(hasValue(obj, "goal")).toBe(false);
520
- });
521
-
522
- test("returns false for empty string", () => {
523
- const obj = { name: "" };
524
- expect(hasValue(obj, "name")).toBe(false);
525
- });
526
-
527
- test("returns false for null", () => {
528
- const obj = { name: null };
529
- expect(hasValue(obj, "name")).toBe(false);
530
- });
531
-
532
- test("returns false for undefined", () => {
533
- const obj = { name: undefined };
534
- expect(hasValue(obj, "name")).toBe(false);
535
- });
536
- });
537
- });
538
-
539
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
540
- // WJTTC RACE 6: EDGE CASES & STRESS TESTS
541
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
542
-
543
- describe("🏁 WJTTC Race 6: Edge Cases", () => {
544
- describe("unicode handling", () => {
545
- test("handles Japanese characters", () => {
546
- const faf = parseYaml(`
547
- project:
548
- name: 日本語プロジェクト
549
- type: cli
550
- `);
551
- const result = calculateScore(faf);
552
- expect(result.filled).toBeGreaterThan(0);
553
- });
554
-
555
- test("handles emoji in values", () => {
556
- const faf = parseYaml(`
557
- project:
558
- name: 🚀 Rocket Project
559
- type: cli
560
- `);
561
- const result = calculateScore(faf);
562
- expect(result.filled).toBeGreaterThan(0);
563
- });
564
- });
565
-
566
- describe("special characters", () => {
567
- test("handles colons in values", () => {
568
- const faf = parseYaml(`
569
- project:
570
- goal: "Build a CLI: fast and simple"
571
- type: cli
572
- `);
573
- expect(faf.project.goal).toContain(":");
574
- });
575
-
576
- test("handles quotes in values", () => {
577
- const faf = parseYaml(`
578
- project:
579
- name: "Project 'Alpha'"
580
- type: cli
581
- `);
582
- const result = calculateScore(faf);
583
- expect(result.filled).toBeGreaterThan(0);
584
- });
585
- });
586
-
587
- describe("whitespace handling", () => {
588
- test("handles tabs instead of spaces", () => {
589
- const faf = parseYaml("project:\n\tname: test\n\ttype: cli");
590
- expect(faf.project).toBeDefined();
591
- });
592
-
593
- test("handles trailing whitespace", () => {
594
- const faf = parseYaml("project: \n name: test \n type: cli ");
595
- expect(faf.project.name).toBe("test");
596
- });
597
-
598
- test("handles CRLF line endings", () => {
599
- const faf = parseYaml("project:\r\n name: test\r\n type: cli");
600
- expect(faf.project).toBeDefined();
601
- });
602
- });
603
-
604
- describe("large content", () => {
605
- test("handles 100+ line FAF file", () => {
606
- let content = "project:\n name: Large\n type: fullstack\n";
607
- for (let i = 0; i < 100; i++) {
608
- content += ` field${i}: value${i}\n`;
609
- }
610
- expect(() => parseYaml(content)).not.toThrow();
611
- });
612
- });
613
- });
614
-
615
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
616
- // WJTTC RACE 7: CONCURRENT TESTS (Bun Feature Showcase)
617
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
618
-
619
- describe("🏁 WJTTC Race 7: Concurrent Tests", () => {
620
- test.concurrent("concurrent test 1: CLI scoring", async () => {
621
- const faf = parseYaml("project:\n name: CLI1\n type: cli");
622
- const result = calculateScore(faf);
623
- expect(result.projectType).toBe("cli");
624
- });
625
-
626
- test.concurrent("concurrent test 2: webapp scoring", async () => {
627
- const faf = parseYaml("project:\n name: Web1\n type: webapp");
628
- const result = calculateScore(faf);
629
- expect(result.projectType).toBe("webapp");
630
- });
631
-
632
- test.concurrent("concurrent test 3: api scoring", async () => {
633
- const faf = parseYaml("project:\n name: API1\n type: api");
634
- const result = calculateScore(faf);
635
- expect(result.projectType).toBe("api");
636
- });
637
-
638
- test.concurrent("concurrent test 4: fullstack scoring", async () => {
639
- const faf = parseYaml("project:\n name: Full1\n type: fullstack");
640
- const result = calculateScore(faf);
641
- expect(result.projectType).toBe("fullstack");
642
- });
643
-
644
- test.concurrent("concurrent test 5: tier calculation", async () => {
645
- const tier = getTier(85);
646
- expect(tier.name).toBe("Bronze");
647
- });
648
- });
649
-
650
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
651
- // WJTTC RACE 8: MOCKING & SPYING (Bun Feature Showcase)
652
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
653
-
654
- describe("🏁 WJTTC Race 8: Mocking & Spying", () => {
655
- describe("mock function basics", () => {
656
- test("mock tracks calls", () => {
657
- const fn = mock(() => "result");
658
- fn("arg1");
659
- fn("arg2");
660
-
661
- expect(fn).toHaveBeenCalledTimes(2);
662
- expect(fn.mock.calls[0][0]).toBe("arg1");
663
- expect(fn.mock.calls[1][0]).toBe("arg2");
664
- });
665
-
666
- test("mock can return custom values", () => {
667
- const fn = mock(() => 42);
668
- expect(fn()).toBe(42);
669
- });
670
-
671
- test("mockReturnValue works", () => {
672
- const fn = mock().mockReturnValue("custom");
673
- expect(fn()).toBe("custom");
674
- });
675
-
676
- test("mockImplementation works", () => {
677
- const fn = mock().mockImplementation((x: number) => x * 2);
678
- expect(fn(5)).toBe(10);
679
- });
680
- });
681
-
682
- describe("spyOn functionality", () => {
683
- test("spyOn tracks method calls", () => {
684
- const obj = {
685
- method: (x: number) => x + 1,
686
- };
687
-
688
- const spy = spyOn(obj, "method");
689
- obj.method(5);
690
-
691
- expect(spy).toHaveBeenCalledWith(5);
692
- });
693
- });
694
-
695
- describe("mock assertions", () => {
696
- test("toHaveBeenCalled works", () => {
697
- const fn = mock();
698
- fn();
699
- expect(fn).toHaveBeenCalled();
700
- });
701
-
702
- test("toHaveBeenCalledWith works", () => {
703
- const fn = mock();
704
- fn("hello", 123);
705
- expect(fn).toHaveBeenCalledWith("hello", 123);
706
- });
707
-
708
- test("toHaveReturned works", () => {
709
- const fn = mock(() => "value");
710
- fn();
711
- expect(fn).toHaveReturned();
712
- });
713
- });
714
- });
715
-
716
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
717
- // WJTTC RACE 9: LIFECYCLE HOOKS DEMONSTRATION
718
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
719
-
720
- describe("🏁 WJTTC Race 9: Lifecycle Hooks", () => {
721
- let setupValue: string;
722
- let testCount: number;
723
-
724
- beforeAll(() => {
725
- setupValue = "initialized";
726
- testCount = 0;
727
- });
728
-
729
- beforeEach(() => {
730
- testCount++;
731
- });
732
-
733
- afterEach(() => {
734
- // Cleanup after each test
735
- });
736
-
737
- afterAll(() => {
738
- // Final cleanup
739
- });
740
-
741
- test("beforeAll sets up value", () => {
742
- expect(setupValue).toBe("initialized");
743
- });
744
-
745
- test("beforeEach increments counter (first)", () => {
746
- expect(testCount).toBeGreaterThan(0);
747
- });
748
-
749
- test("beforeEach increments counter (second)", () => {
750
- expect(testCount).toBeGreaterThan(1);
751
- });
752
- });
753
-
754
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
755
- // WJTTC RACE 10: MATCHER SHOWCASE
756
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
757
-
758
- describe("🏁 WJTTC Race 10: Matcher Showcase", () => {
759
- describe("equality matchers", () => {
760
- test("toBe for strict equality", () => {
761
- expect(1).toBe(1);
762
- expect("hello").toBe("hello");
763
- });
764
-
765
- test("toEqual for deep equality", () => {
766
- expect({ a: 1 }).toEqual({ a: 1 });
767
- expect([1, 2, 3]).toEqual([1, 2, 3]);
768
- });
769
-
770
- test("toStrictEqual for strict deep equality", () => {
771
- expect({ a: 1 }).toStrictEqual({ a: 1 });
772
- });
773
- });
774
-
775
- describe("truthiness matchers", () => {
776
- test("toBeTruthy", () => {
777
- expect(1).toBeTruthy();
778
- expect("hello").toBeTruthy();
779
- expect([]).toBeTruthy();
780
- });
781
-
782
- test("toBeFalsy", () => {
783
- expect(0).toBeFalsy();
784
- expect("").toBeFalsy();
785
- expect(null).toBeFalsy();
786
- });
787
-
788
- test("toBeNull", () => {
789
- expect(null).toBeNull();
790
- });
791
-
792
- test("toBeUndefined", () => {
793
- expect(undefined).toBeUndefined();
794
- });
795
-
796
- test("toBeDefined", () => {
797
- expect("hello").toBeDefined();
798
- });
799
- });
800
-
801
- describe("number matchers", () => {
802
- test("toBeGreaterThan", () => {
803
- expect(10).toBeGreaterThan(5);
804
- });
805
-
806
- test("toBeGreaterThanOrEqual", () => {
807
- expect(10).toBeGreaterThanOrEqual(10);
808
- });
809
-
810
- test("toBeLessThan", () => {
811
- expect(5).toBeLessThan(10);
812
- });
813
-
814
- test("toBeLessThanOrEqual", () => {
815
- expect(10).toBeLessThanOrEqual(10);
816
- });
817
-
818
- test("toBeCloseTo for floating point", () => {
819
- expect(0.1 + 0.2).toBeCloseTo(0.3, 5);
820
- });
821
- });
822
-
823
- describe("string matchers", () => {
824
- test("toMatch with regex", () => {
825
- expect("hello world").toMatch(/world/);
826
- });
827
-
828
- test("toContain for substring", () => {
829
- expect("hello world").toContain("world");
830
- });
831
- });
832
-
833
- describe("collection matchers", () => {
834
- test("toContain for arrays", () => {
835
- expect([1, 2, 3]).toContain(2);
836
- });
837
-
838
- test("toHaveLength", () => {
839
- expect([1, 2, 3]).toHaveLength(3);
840
- expect("hello").toHaveLength(5);
841
- });
842
-
843
- test("toHaveProperty", () => {
844
- expect({ a: 1, b: 2 }).toHaveProperty("a");
845
- expect({ a: 1, b: 2 }).toHaveProperty("a", 1);
846
- });
847
- });
848
-
849
- describe("exception matchers", () => {
850
- test("toThrow", () => {
851
- expect(() => {
852
- throw new Error("fail");
853
- }).toThrow();
854
- });
855
-
856
- test("toThrow with message", () => {
857
- expect(() => {
858
- throw new Error("specific error");
859
- }).toThrow("specific error");
860
- });
861
-
862
- test("toThrow with Error class", () => {
863
- expect(() => {
864
- throw new TypeError("type error");
865
- }).toThrow(TypeError);
866
- });
867
- });
868
-
869
- describe("type matchers", () => {
870
- test("toBeInstanceOf", () => {
871
- expect(new Date()).toBeInstanceOf(Date);
872
- expect([]).toBeInstanceOf(Array);
873
- });
874
- });
875
- });
876
-
877
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
878
- // WJTTC FINAL LAP: INTEGRATION TESTS
879
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
880
-
881
- describe("🏁 WJTTC Final Lap: Integration Tests", () => {
882
- test("full workflow: parse → score → tier", () => {
883
- const yaml = `
884
- project:
885
- name: Integration Test
886
- goal: Test the full workflow
887
- main_language: TypeScript
888
- type: cli
889
- human_context:
890
- who: Developers
891
- what: A CLI tool
892
- why: Testing
893
- where: Terminal
894
- when: 2025
895
- how: bun run
896
- `;
897
- const faf = parseYaml(yaml);
898
- const result = calculateScore(faf);
899
- const tierResult = getTier(result.score);
900
-
901
- expect(faf.project.name).toBe("Integration Test");
902
- expect(result.projectType).toBe("cli");
903
- expect(result.filled).toBe(9);
904
- expect(result.total).toBe(9);
905
- expect(result.score).toBe(100);
906
- expect(tierResult.name).toBe("Trophy");
907
- expect(tierResult.emoji).toBe("🏆");
908
- });
909
-
910
- test("missing slots are correctly identified", () => {
911
- const faf = parseYaml(`
912
- project:
913
- name: Partial
914
- type: cli
915
- human_context:
916
- who: Someone
917
- `);
918
- const result = calculateScore(faf);
919
-
920
- expect(result.missing).toContain("project.goal");
921
- expect(result.missing).toContain("project.main_language");
922
- expect(result.missing).toContain("human_context.what");
923
- expect(result.missing).toContain("human_context.why");
924
- expect(result.missing).toContain("human_context.where");
925
- expect(result.missing).toContain("human_context.when");
926
- expect(result.missing).toContain("human_context.how");
927
- });
928
-
929
- test("section breakdown is accurate", () => {
930
- const faf = parseYaml(`
931
- project:
932
- name: Sectioned
933
- goal: Test sections
934
- type: cli
935
- human_context:
936
- who: Testers
937
- what: Testing
938
- why: Quality
939
- `);
940
- const result = calculateScore(faf);
941
-
942
- expect(result.sections.project.filled).toBe(2);
943
- expect(result.sections.project.total).toBe(3);
944
- expect(result.sections.human.filled).toBe(3);
945
- expect(result.sections.human.total).toBe(6);
946
- });
947
- });
948
-
949
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
950
- // CHAMPIONSHIP SUMMARY
951
- // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
952
-
953
- describe("🏆 Championship Summary", () => {
954
- test("WJTTC Championship Grade: All systems operational", () => {
955
- // This test confirms all modules are working together
956
- const faf = parseYaml("project:\n name: Champion\n type: cli");
957
- const result = calculateScore(faf);
958
- const tier = getTier(result.score);
959
-
960
- expect(faf).toBeDefined();
961
- expect(result).toBeDefined();
962
- expect(tier).toBeDefined();
963
- expect(SLOTS).toBeDefined();
964
- expect(TIERS).toBeDefined();
965
- });
966
- });