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 +55 -576
- package/docs/api-reference.md +72 -0
- package/docs/audit-log.md +47 -0
- package/docs/best-practices.md +23 -0
- package/docs/getting-started.md +82 -0
- package/docs/http-kit.md +71 -0
- package/docs/storage.md +90 -0
- package/index.d.ts +5 -0
- package/index.d.ts.map +1 -0
- package/index.js +2 -2
- package/libs/fenneckit.d.ts +2 -0
- package/libs/fenneckit.d.ts.map +1 -0
- package/libs/labs.d.ts +70 -0
- package/libs/labs.d.ts.map +1 -0
- package/libs/labs.js +397 -46
- package/libs/testing.d.ts +9 -0
- package/libs/testing.d.ts.map +1 -0
- package/package.json +14 -3
- package/types.d.ts +39 -0
- package/types.d.ts.map +1 -0
- package/types.js +1 -0
- package/utility/report.d.ts +2 -0
- package/utility/report.d.ts.map +1 -0
- package/utility/report.js +26 -0
package/README.md
CHANGED
|
@@ -1,609 +1,88 @@
|
|
|
1
|
-
# π¦ FennecKit
|
|
1
|
+
# π¦ FennecKit
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
+
[](https://www.npmjs.com/package/fenneckit)
|
|
8
|
+
[](https://www.npmjs.com/package/fenneckit)
|
|
245
9
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
10
|
+
[](https://nodejs.org/)
|
|
11
|
+
[](https://www.typescriptlang.org/)
|
|
12
|
+
[](LICENSE)
|
|
249
13
|
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
408
|
-
kit.log("Starting user registration...");
|
|
409
|
-
|
|
24
|
+
await newLabs("User API", async (kit) => {
|
|
410
25
|
await kit.test("Create User", async () => {
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
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("
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
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
|
-
|
|
42
|
+
## Install
|
|
525
43
|
|
|
526
44
|
```bash
|
|
527
|
-
|
|
45
|
+
npm install fenneckit@latest --save-dev
|
|
528
46
|
```
|
|
529
47
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
## π Troubleshooting
|
|
48
|
+
Requires Node.js >= 20.
|
|
533
49
|
|
|
534
|
-
|
|
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
|
|
551
|
-
npx fenneckit
|
|
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
|
-
|
|
587
|
-
-
|
|
588
|
-
-
|
|
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
|
-
|
|
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
|
-
##
|
|
76
|
+
## Documentation
|
|
600
77
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
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
|
-
|
|
88
|
+
MIT. Copyright Β© 2026 Lasith Ruwantha Amrwansha.
|