fenneckit 1.0.4 β†’ 1.2.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.
package/README.md CHANGED
@@ -1,609 +1,88 @@
1
- # 🦊 FennecKit: Lab-Based Testing & Development Utility
1
+ # 🦊 FennecKit
2
2
 
3
3
  ![logo](./fenneckit.png)
4
4
 
5
- ```bash
6
- npm install fenneckit@latest --save-dev
7
- npx fenneckit --help
8
- ```
9
- **English**: A Complete Storage System for Practical and Seamless Data Analysis
10
-
11
- **Zero Config** β€’ Sequential Labs β€’ Inter-Lab Data Sharing (within the same file) β€’ Store Management
12
-
13
- **🦊Example** : soon
14
-
15
- ---
16
-
17
- ## 🎯 What is FennecKit?
18
-
19
- FennecKit is a lightweight, **zero-config** testing & development utility built around the concept of **Labs**.
20
-
21
- ### What is a "Lab"?
22
-
23
- A **Lab** is a collection of sequential tasks (a workflow) that together accomplish one objective.
24
-
25
- **Examples**:
26
- - User Registration Lab β†’ create user β†’ validate β†’ save to DB β†’ send email
27
- - Payment Processing Lab β†’ validate β†’ charge β†’ generate invoice
28
- - API Testing Lab β†’ hit endpoints β†’ verify responses β†’ check side effects
29
-
30
- ```typescript
31
- // Lab = Collection of sequential tasks
32
- await newLabs("User Registration Lab", async (kit) => {
33
- await kit.test("Validate Email", async () => {
34
- kit.done("Email validated");
35
- });
36
-
37
- await kit.test("Save to Database", async () => {
38
- kit.done("User saved");
39
- });
40
-
41
- await kit.test("Send Verification Email", async () => {
42
- kit.done("Email sent");
43
- });
44
- });
45
- ```
46
-
47
- ---
48
-
49
- ## ⚑ Zero Config & Runner
50
-
51
- FennecKit requires **no configuration files**.
52
-
53
- ### How to run
54
-
55
- ```bash
56
- # Run a specific lab file
57
- npx fenneckit lab.js
58
-
59
- # Or just
60
- npx fenneckit
61
-
62
- # The runner automatically finds all *.labs.js / *.labs.ts files
63
- # and executes them one after another (sequentially)
64
- ```
65
-
66
- **What the runner does**:
67
- 1. Discovers lab files in the current directory (and subdirectories if configured)
68
- 2. Runs each file **one by one**
69
- 3. Inside each file, Labs run in the order they are written
70
- 4. Generates a report (`fenneckit.md`) after execution
71
-
72
- > **Important limitation**
73
- > Data sharing (`setStore` / `getStore`) only works **inside the same file**.
74
- > Different lab files **cannot** share STORE or TEMP data with each other.
75
-
76
- ---
77
-
78
- ## 🌳 Data Sharing Hierarchy (Tree Structure)
79
-
80
- ```
81
- πŸ“ FennecKit Execution
82
- β”‚
83
- β”œβ”€ πŸ“„ file1.labs.js (STORE Instance #1)
84
- β”‚ β”‚
85
- β”‚ β”œβ”€ πŸ”¬ Lab 1 (User Registration)
86
- β”‚ β”‚ β”œβ”€ πŸ“ Test 1: Create User
87
- β”‚ β”‚ β”‚ β”œβ”€ STORE: {"userId": "123"} βœ… Shared with Lab 2
88
- β”‚ β”‚ β”‚ └─ TEMP: {"token": "abc"} ❌ Only here
89
- β”‚ β”‚ β”‚
90
- β”‚ β”‚ └─ πŸ“ Test 2: Send Email
91
- β”‚ β”‚ └─ Can access STORE from Test 1
92
- β”‚ β”‚
93
- β”‚ β”œβ”€ πŸ”¬ Lab 2 (Authentication)
94
- β”‚ β”‚ β”œβ”€ πŸ“ Test 1: Generate Token
95
- β”‚ β”‚ β”‚ β”œβ”€ STORE: {"userId": "123"} βœ… From Lab 1
96
- β”‚ β”‚ β”‚ └─ TEMP: {"token": "new"} ❌ Only here
97
- β”‚ β”‚ β”‚
98
- β”‚ β”‚ └─ πŸ“ Test 2: Verify Token
99
- β”‚ β”‚ └─ Can access STORE from Labs 1 & 2
100
- β”‚ β”‚
101
- β”‚ └─ πŸ”¬ Lab 3 (Cleanup)
102
- β”‚ └─ File STORE cleared when execution ends
103
- β”‚
104
- β”œβ”€ πŸ“„ file2.labs.js (STORE Instance #2 - ISOLATED)
105
- β”‚ β”‚
106
- β”‚ β”œβ”€ πŸ”¬ Lab 1
107
- β”‚ β”‚ └─ ❌ CANNOT access file1.labs.js STORE
108
- β”‚ β”‚
109
- β”‚ └─ πŸ”¬ Lab 2
110
- β”‚ └─ ❌ CANNOT access file1.labs.js STORE
111
- β”‚
112
- └─ πŸ“„ file3.labs.js (STORE Instance #3 - ISOLATED)
113
- └─ ❌ Isolated from file1.labs.js and file2.labs.js
114
- ```
115
-
116
- ### Understanding the Hierarchy
117
-
118
- **πŸ”΄ Level 1: Different Files = NO Data Sharing**
119
- ```
120
- file1.labs.js ← STORE Instance #1 (isolated)
121
- file2.labs.js ← STORE Instance #2 (isolated)
122
- file3.labs.js ← STORE Instance #3 (isolated)
123
-
124
- ❌ file1's STORE β‰  file2's STORE β‰  file3's STORE
125
- ```
126
-
127
- **🟑 Level 2: Same File, Different Labs = STORE Sharing**
128
- ```
129
- file1.labs.js
130
- β”œβ”€ Lab 1: setStore("userId", "123")
131
- β”œβ”€ Lab 2: getStore("userId") βœ… Can access
132
- └─ Lab 3: getStore("userId") βœ… Can still access
133
- ```
134
-
135
- **🟒 Level 3: Same Lab, Different Tests = STORE + TEMP Sharing**
136
- ```
137
- Lab 1 (User Registration)
138
- β”œβ”€ Test 1:
139
- β”‚ β”œβ”€ setStore("userId", "123") βœ… Shared with other tests
140
- β”‚ └─ setTemp("token", "abc") βœ… Shared with other tests in Lab 1
141
- β”‚
142
- β”œβ”€ Test 2:
143
- β”‚ β”œβ”€ getStore("userId") βœ… Works (from Test 1)
144
- β”‚ └─ getTemp("token") βœ… Works (from Test 1)
145
- β”‚
146
- └─ Lab 1 ends β†’ TEMP cleared, STORE remains
147
- ```
148
-
149
- ---
150
-
151
- ## πŸ”— Data Communication Between Labs (Inter-Lab Communication)
152
-
153
- ### The Problem with Jest / Vitest
154
-
155
- In Jest and Vitest every test is isolated. You cannot pass data from one test to another.
156
-
157
- ### FennecKit Solution – Three Storage Levels
158
-
159
- ```
160
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
161
- β”‚ FennecKit Storage System (Per File) β”‚
162
- β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
163
- β”‚ β”‚
164
- β”‚ LEVEL 1: FILE SCOPE (Entire File) β”‚
165
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
166
- β”‚ β”‚ STORE (Global - Persistent within file) β”‚ β”‚
167
- β”‚ β”‚ β”œβ”€ Shared across ALL Labs in this file β”‚ β”‚
168
- β”‚ β”‚ β”œβ”€ Available until file execution ends β”‚ β”‚
169
- β”‚ β”‚ β”œβ”€ Can be manually cleared with clearStore() β”‚ β”‚
170
- β”‚ β”‚ └─ Example: userId, authToken, orderData β”‚ β”‚
171
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
172
- β”‚ β”‚
173
- β”‚ LEVEL 2: LAB SCOPE (Single Lab) β”‚
174
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
175
- β”‚ β”‚ STORE (Available to this and following Labs) β”‚ β”‚
176
- β”‚ β”‚ └─ Set in Lab 1, used in Lab 2, Lab 3, etc β”‚ β”‚
177
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
178
- β”‚ β”‚
179
- β”‚ LEVEL 3: LAB-LOCAL SCOPE (Single Lab Only) β”‚
180
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
181
- β”‚ β”‚ TEMP (Local - Auto-Cleaned) β”‚ β”‚
182
- β”‚ β”‚ β”œβ”€ Only available inside current Lab β”‚ β”‚
183
- β”‚ β”‚ β”œβ”€ Automatically cleared when Lab ends β”‚ β”‚
184
- β”‚ β”‚ β”œβ”€ Cannot be manually cleared β”‚ β”‚
185
- β”‚ β”‚ └─ Example: timestamps, temp calculations β”‚ β”‚
186
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
187
- β”‚ β”‚
188
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
189
- ```
190
-
191
- ### Storage Demo (same file)
192
-
193
- ```typescript
194
- // ========== LAB 1: User Registration ==========
195
- await newLabs("User Registration", async (kit) => {
196
- await kit.test("Create User", async () => {
197
- const userId = "user_123";
198
- const email = "john@example.com";
199
-
200
- // STORE β†’ available to all Labs in this file
201
- kit.setStore("userId", userId);
202
- kit.setStore("userEmail", email);
203
-
204
- // TEMP β†’ only for this Lab
205
- kit.setTemp("tempToken", "abc123");
206
-
207
- kit.done("User created");
208
- });
209
- });
210
-
211
- // ========== LAB 2: Authentication ==========
212
- await newLabs("Authentication", async (kit) => {
213
- await kit.test("Generate Token", async () => {
214
- const userId = kit.getStore("userId"); // βœ… works (from Lab 1)
215
- const email = kit.getStore("userEmail"); // βœ… works (from Lab 1)
216
- const token = kit.getTemp("tempToken"); // ❌ undefined (cleared after Lab 1)
217
-
218
- kit.done(`Token generated for: ${email}`);
219
- });
220
- });
221
- ```
222
-
223
- ---
224
-
225
- ## 🧹 NEW: clearStore() Feature (v1.1.0)
226
-
227
- Manually clear Store data between Labs for better state management and security.
228
-
229
- ### Two Ways to Clear
230
-
231
- #### 1. Clear specific key (inside Lab)
232
- ```typescript
233
- await newLabs("My Lab", async (kit) => {
234
- await kit.test("Store sensitive data", async () => {
235
- kit.setStore("authToken", "secret123");
236
- kit.done("Token stored");
237
- });
238
-
239
- await kit.test("Cleanup", async () => {
240
- kit.clearStore("authToken"); // Remove only this key
241
- kit.done("Token cleared");
242
- });
243
- });
244
- ```
5
+ <div align="center">
6
+
7
+ [![npm version](https://img.shields.io/npm/v/fenneckit?style=flat-square&color=3178c6&logo=npm)](https://www.npmjs.com/package/fenneckit)
8
+ [![npm downloads](https://img.shields.io/npm/dm/fenneckit?style=flat-square&logo=npm)](https://www.npmjs.com/package/fenneckit)
245
9
 
246
- #### 2. Clear all data (global)
247
- ```typescript
248
- import { newLabs, clearStore } from "fenneckit";
10
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20-green?style=flat-square&logo=node.js)](https://nodejs.org/)
11
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-3178c6?style=flat-square&logo=typescript)](https://www.typescriptlang.org/)
12
+ [![License](https://img.shields.io/badge/license-MIT-brightgreen?style=flat-square)](LICENSE)
249
13
 
250
- await newLabs("Lab 1", async (kit) => {
251
- await kit.test("Setup", async () => {
252
- kit.setStore("data1", "value1");
253
- kit.setStore("data2", "value2");
254
- kit.done("Stored");
255
- });
256
- });
257
-
258
- clearStore(); // Clear all STORE data globally
14
+ </div>
15
+ **Lab-based testing utility.** Sequential tests that share data, zero config, encrypted secrets, and a built-in HTTP client.
259
16
 
260
- await newLabs("Lab 2", async (kit) => {
261
- await kit.test("Fresh Start", async () => {
262
- const data = kit.getStore("data1"); // undefined
263
- kit.done("Fresh state");
264
- });
265
- });
266
- ```
17
+ ## Why FennecKit?
267
18
 
268
- ### When to Use clearStore()
19
+ In Jest/Vitest every test starts fresh, so multi-step workflows (create user β†’ read user β†’ delete user) need mocks or duplicated setup. In FennecKit, tests inside one **Lab** run in order and share data.
269
20
 
270
- | Scenario | Method | Why |
271
- |----------|--------|-----|
272
- | Remove sensitive data | `clearStore("token")` | Security |
273
- | Free memory | `clearStore("largeObject")` | Performance |
274
- | Test isolation | `clearStore()` | Prevent data leakage |
275
- | Between phases | `clearStore("tempData")` | Clean state |
276
-
277
- ---
278
-
279
- ## πŸ“Š Storage Lifecycle (per file)
280
-
281
- ```
282
- FILE EXECUTION START
283
- β”‚
284
- β”œβ”€ Lab 1
285
- β”‚ β”œβ”€ setStore(...) β†’ kept across all labs
286
- β”‚ β”œβ”€ setTemp(...) β†’ kept only for this Lab
287
- β”‚ β”œβ”€ clearStore(...) β†’ optionally remove keys
288
- β”‚ └─ Lab ends β†’ TEMP cleared, STORE remains (unless cleared)
289
- β”‚
290
- β”œβ”€ Lab 2
291
- β”‚ β”œβ”€ getStore(...) β†’ works (if not cleared)
292
- β”‚ β”œβ”€ getTemp(...) β†’ undefined (cleared after Lab 1)
293
- β”‚ β”œβ”€ clearStore(...) β†’ can clear for next labs
294
- β”‚ └─ Lab ends β†’ TEMP cleared, STORE remains (unless cleared)
295
- β”‚
296
- └─ FILE END β†’ STORE completely cleared
297
- ```
298
-
299
- **Remember**: This lifecycle is **per file**.
300
- Running `npx fenneckit fileA.labs.js` and then `npx fenneckit fileB.labs.js` gives two completely separate STORE instances.
301
-
302
- ---
303
-
304
- ## πŸ’‘ Real-World Example (Single File)
305
-
306
- ```typescript
307
- // order-pipeline.labs.js
308
-
309
- import { newLabs, clearStore } from "fenneckit";
310
-
311
- // LAB 1
312
- await newLabs("Order Validation", async (kit) => {
313
- await kit.test("Check Product Stock", async () => {
314
- kit.setStore("productId", "prod_456");
315
- kit.setStore("stockAvailable", 50);
316
- kit.setTemp("validationTime", Date.now());
317
- kit.done("Product stock verified");
318
- });
319
- });
320
-
321
- // LAB 2
322
- await newLabs("Payment Processing", async (kit) => {
323
- await kit.test("Charge Customer Card", async () => {
324
- const productId = kit.getStore("productId"); // βœ… From Lab 1
325
- const chargeId = `charge_${Date.now()}`;
326
-
327
- kit.setStore("chargeId", chargeId);
328
- kit.setStore("orderStatus", "paid");
329
- kit.setTemp("transactionId", chargeId);
330
-
331
- kit.done(`Payment charged: ${chargeId}`);
332
- });
333
- });
334
-
335
- // Clear sensitive payment data before shipping
336
- clearStore("chargeId");
337
-
338
- // LAB 3
339
- await newLabs("Shipping & Notification", async (kit) => {
340
- await kit.test("Create Shipping Label", async () => {
341
- const status = kit.getStore("orderStatus"); // βœ… Available
342
- const chargeId = kit.getStore("chargeId"); // ❌ Cleared
343
- const tempTx = kit.getTemp("transactionId"); // ❌ Undefined
344
-
345
- if (status === "paid") {
346
- const tracking = `TRACK_${Date.now()}`;
347
- kit.setStore("trackingNumber", tracking);
348
- kit.done(`Shipping label created: ${tracking}`);
349
- }
350
- });
351
-
352
- await kit.test("Send Notification Email", async () => {
353
- const tracking = kit.getStore("trackingNumber");
354
- kit.done(`Email sent with tracking: ${tracking}`);
355
- });
356
- });
357
- ```
358
-
359
- Run it:
360
-
361
- ```bash
362
- npx fenneckit order-pipeline.labs.js
363
- ```
364
-
365
- ---
366
-
367
- ## πŸ› οΈ LabContext Methods
368
-
369
- ```typescript
370
- interface LabContext {
371
- // Testing & Flow
372
- test(name: string, fn: () => Promise<any>): Promise<any>
373
- done(msg: string): void
374
- err(msg: string): void // stops the Lab
375
- flatErr(msg: string): void // continues
376
- log(msg: string): void
377
- warning(msg: string): void // warning
378
-
379
- // Flow control
380
- out(): void // exit Lab immediately
381
- ret(): void // restart Lab
382
-
383
- // Persistent (across Labs in same file)
384
- setStore(key: string, value: any): void
385
- getStore(key: string): any
386
- clearStore(key?: string): void // NEW: clear specific key or all
387
-
388
- // Temporary (Lab-local only)
389
- setTemp(key: string, value: any): void
390
- getTemp(key: string): any
391
- }
392
- ```
393
-
394
- ---
395
-
396
- ## πŸš€ Quick Start
397
-
398
- ### 1. Create a lab file
399
-
400
- ```bash
401
- # example.labs.js
402
- ```
403
-
404
- ```typescript
21
+ ```ts
405
22
  import { newLabs } from "fenneckit";
406
23
 
407
- await newLabs("User Registration Workflow", async (kit) => {
408
- kit.log("Starting user registration...");
409
-
24
+ await newLabs("User API", async (kit) => {
410
25
  await kit.test("Create User", async () => {
411
- const id = "user_" + Date.now();
412
- kit.setStore("userId", id);
413
- kit.done(`User created: ${id}`);
414
- });
415
-
416
- await kit.test("Send Welcome Email", async () => {
417
- const id = kit.getStore("userId");
418
- kit.done(`Email sent to user: ${id}`);
419
- });
420
- });
421
- ```
422
-
423
- ### 2. Run
424
-
425
- ```bash
426
- npx fenneckit example.labs.js
427
- ```
428
-
429
- ### 3. Check report
430
-
431
- ```bash
432
- cat fenneckit.md
433
- ```
434
-
435
- ---
436
-
437
- ## πŸ“‹ setStore vs setTemp vs clearStore
438
-
439
- | Scenario | Use | Why |
440
- |----------|-----|-----|
441
- | Pass data between Labs | `setStore` | Survives Lab end |
442
- | Performance timing | `setTemp` | Only needed inside one Lab |
443
- | Auth token / DB connection | `setStore` | Needed by multiple Labs |
444
- | Temporary calculation | `setTemp` | Auto-cleaned |
445
- | Remove sensitive data | `clearStore` | Security |
446
- | Reset before next phase | `clearStore` | Fresh state |
447
- | Cross-file sharing | ❌ Impossible | STORE is scoped to one file only |
448
-
449
- ---
450
-
451
- ## 🎯 Best Practices
452
-
453
- 1. **Clear names**
454
- ```typescript
455
- kit.setStore("userId", id);
456
- kit.setStore("authToken", token);
457
- ```
458
-
459
- 2. **Always check before use**
460
- ```typescript
461
- const userId = kit.getStore("userId");
462
- if (!userId) {
463
- kit.err("userId missing from previous Lab!");
464
- }
465
- ```
466
-
467
- 3. **Clear sensitive data**
468
- ```typescript
469
- kit.clearStore("password");
470
- kit.clearStore("creditCard");
471
- ```
472
-
473
- 4. **One concern per Lab**
474
- Keep each Lab focused. Use STORE to pass only the necessary data.
475
-
476
- 5. **Do not rely on cross-file data**
477
- If you need data from another file, write it to disk or a database yourself.
478
-
479
- ---
480
-
481
- ## πŸ”„ Complete Multi-Lab Example (Payment β†’ Invoice)
482
-
483
- ```typescript
484
- import { newLabs, clearStore } from "fenneckit";
485
-
486
- await newLabs("Payment Validation", async (kit) => {
487
- await kit.test("Validate Payment Details", async () => {
488
- kit.setStore("customerId", "cust_123");
489
- kit.setStore("amount", 299.99);
490
- kit.setStore("currency", "USD");
491
- kit.setTemp("validatedAt", Date.now());
492
- kit.done("Payment validated: 299.99 USD");
493
- });
494
- });
495
-
496
- await newLabs("Process Charge", async (kit) => {
497
- await kit.test("Charge Card", async () => {
498
- const amount = kit.getStore("amount");
499
- const chargeId = `charge_${Date.now()}`;
500
- kit.setStore("chargeId", chargeId);
501
- kit.setStore("chargedAt", new Date().toISOString());
502
- kit.done(`Charged: ${chargeId} for ${amount}`);
503
- });
504
- });
505
-
506
- // Clear payment details (security)
507
- clearStore("chargeId");
508
-
509
- await newLabs("Generate Invoice", async (kit) => {
510
- await kit.test("Create Invoice PDF", async () => {
511
- const invoiceId = `inv_${Date.now()}`;
512
- kit.setStore("invoiceId", invoiceId);
513
- kit.done(`Invoice created: ${invoiceId}`);
26
+ const res = await kit.http.post("https://api.example.com/users", {
27
+ name: "John",
28
+ });
29
+ kit.setStore("userId", res.data.id);
30
+ kit.done("User created");
514
31
  });
515
32
 
516
- await kit.test("Send Invoice Email", async () => {
517
- const invoiceId = kit.getStore("invoiceId");
518
- const customerId = kit.getStore("customerId");
519
- kit.done(`Invoice ${invoiceId} emailed to ${customerId}`);
33
+ await kit.test("Get User", async () => {
34
+ const res = await kit.http.get(
35
+ `https://api.example.com/users/${kit.getStore("userId")}`,
36
+ );
37
+ kit.done(`Status ${res.status}`);
520
38
  });
521
39
  });
522
40
  ```
523
41
 
524
- Run:
42
+ ## Install
525
43
 
526
44
  ```bash
527
- npx fenneckit payment-pipeline.labs.js
45
+ npm install fenneckit@latest --save-dev
528
46
  ```
529
47
 
530
- ---
531
-
532
- ## πŸ“ž Troubleshooting
48
+ Requires Node.js >= 20.
533
49
 
534
- **Q: Lab 2 cannot see Lab 1 data?**
535
- A: You used `setTemp`. Switch to `setStore`.
50
+ ## Run
536
51
 
537
- **Q: I cleared data but it's still there?**
538
- A: Make sure you're using `clearStore()` correctly. Check key name.
539
-
540
- **Q: Can STORE survive across different files?**
541
- A: No. Each file execution has its own isolated STORE.
542
- `npx fenneckit a.labs.js` and `npx fenneckit b.labs.js` do not share data.
543
-
544
- **Q: How is TEMP cleaned?**
545
- A: Automatically when the Lab finishes. No manual cleanup needed.
546
-
547
- **Q: How do I run multiple files?**
548
- A:
549
52
  ```bash
550
- npx fenneckit file1.labs.js
551
- npx fenneckit file2.labs.js
552
- # or let the runner discover all *.labs.* files
553
- npx fenneckit
53
+ npx fenneckit # auto-discover and run all *.labs.js files
54
+ npx fenneckit user.labs.js # run one file
554
55
  ```
555
56
 
556
- ---
557
-
558
- ## 🎨 Color / Status Legend
559
-
560
- - `βœ…` / `🟒` Success
561
- - `❌` / `πŸ”΄` Failed (Lab continues)
562
- - `πŸ›‘` Error (Lab stops)
563
- - `⚠️` / `🟑` Warning
564
- - `πŸ“` / `βšͺ` Info
565
- - `βš™οΈ` Store operation
566
- - `⏱️` Temp operation
567
- - `🧹` Clear operation
568
-
569
- ---
570
-
571
- ## πŸ’ͺ Perfect For
572
-
573
- - Backend API testing (Express, Fastify, etc.)
574
- - Database migration validation
575
- - CLI tool workflows
576
- - Microservice chaining
577
- - Pre-deployment smoke checks
578
- - Development-time sanity tests
579
- - State management testing
580
- - Data pipeline validation
581
-
582
- ---
583
-
584
- ## πŸ“ Version History
57
+ ## Concepts
585
58
 
586
- ### v1.0.0-beta (Current)
587
- - ✨ Added `clearStore()` for store management
588
- - 🌳 Improved data sharing hierarchy documentation
589
- - 🧹 Better state cleanup capabilities
59
+ - **Lab**: a group of sequential tests working toward one goal.
60
+ - **Test**: one step inside a lab, run with `kit.test(name, fn)`.
61
+ - **Storage**: data shared between tests of the same lab (see below).
590
62
 
591
- ### v1.0.0 (Initial Release)
592
- - Core Lab functionality
593
- - STORE & TEMP storage
594
- - Zero config runner
595
- - Report generation
63
+ ## Features
596
64
 
597
- ---
65
+ | Feature | What it does | Docs |
66
+ | ------------ | ------------------------------------------ | ------------------------------------------ |
67
+ | πŸ”¬ Labs | Group tests into workflows | [Getting started](docs/getting-started.md) |
68
+ | πŸ“¦ STORE | Plain shared data | [Storage](docs/storage.md) |
69
+ | πŸ” SECRET | AES-256-GCM encrypted data | [Storage](docs/storage.md#secret) |
70
+ | πŸ—‚οΈ NAMESPACE | Grouped data per entity | [Storage](docs/storage.md#namespace) |
71
+ | ⏱️ TEMP | Lab-local scratch data | [Storage](docs/storage.md#temp) |
72
+ | ⏰ TTL | Auto-expiring STORE/SECRET values | [Storage](docs/storage.md#ttl) |
73
+ | πŸ“‘ HTTP Kit | Client with auth, retry, history | [HTTP Kit](docs/http-kit.md) |
74
+ | πŸ“‹ Audit Log | Trace store/secret access, export JSON/CSV | [Audit log](docs/audit-log.md) |
598
75
 
599
- ## πŸ“ License
76
+ ## Documentation
600
77
 
601
- **Copyright Β© 2026 Lasith Ruwantha Amrwansha**
602
- Written: 2026/09/17
603
- Updated: 2026/09/20
604
- Author: Ruwantha Amrwansha
605
- Library: FennecKit 🦊
78
+ - [Getting started](docs/getting-started.md)
79
+ - [Storage (STORE, SECRET, NAMESPACE, TEMP, TTL)](docs/storage.md)
80
+ - [HTTP Kit](docs/http-kit.md)
81
+ - [Audit log](docs/audit-log.md)
82
+ - [API reference](docs/api-reference.md)
83
+ - [Best practices](docs/best-practices.md)
84
+ - [Changelog](docs/changelog.md)
606
85
 
607
- ---
86
+ ## License
608
87
 
609
- **Happy Testing! 🦊⚑**
88
+ MIT. Copyright Β© 2026 Lasith Ruwantha Amrwansha.