@feasibleone/blong-chain 1.0.0 โ 1.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 +23 -0
- package/README.md +559 -0
- package/dist/examples/demo.test.d.ts +6 -0
- package/dist/examples/demo.test.d.ts.map +1 -0
- package/dist/examples/demo.test.js.map +1 -0
- package/dist/examples/error-demo.test.d.ts +14 -0
- package/dist/examples/error-demo.test.d.ts.map +1 -0
- package/dist/examples/error-demo.test.js.map +1 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +663 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +14 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js.map +1 -0
- package/dist/package.json +39 -0
- package/dist/showcase.test.d.ts +19 -0
- package/dist/showcase.test.d.ts.map +1 -0
- package/dist/showcase.test.js.map +1 -0
- package/dist/test-types.d.ts +293 -0
- package/dist/test-types.d.ts.map +1 -0
- package/dist/test-types.js +5 -0
- package/dist/test-types.js.map +1 -0
- package/dist/timing-analysis.test.d.ts +2 -0
- package/dist/timing-analysis.test.d.ts.map +1 -0
- package/dist/timing-analysis.test.js.map +1 -0
- package/package.json +37 -10
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [1.1.0](https://github.com/feasibleone/blong/compare/blong-chain-v1.0.1...blong-chain-v1.1.0) (2026-02-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add checkpoint support ([#19](https://github.com/feasibleone/blong/issues/19)) ([097a7b8](https://github.com/feasibleone/blong/commit/097a7b80544b28f03f47f0ad6de186baf21004a1))
|
|
9
|
+
|
|
10
|
+
## [1.0.1](https://github.com/feasibleone/blong/compare/blong-chain-v1.0.0...blong-chain-v1.0.1) (2026-02-03)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* publishing ([dac7a64](https://github.com/feasibleone/blong/commit/dac7a649340467c026764abe102caa4f03599fe1))
|
|
16
|
+
|
|
17
|
+
## 1.0.0 (2026-02-03)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* implement blong-chain parallel testing framework ([589bd58](https://github.com/feasibleone/blong/commit/589bd587be36d9afea3e7eea35dea63c30255ee6))
|
|
23
|
+
* nested test context integration and error reporting capabilities ([9470aa5](https://github.com/feasibleone/blong/commit/9470aa53c9d1d676cd50ff004b3bb0eea491d782))
|
package/README.md
ADDED
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
# @feasibleone/blong-chain
|
|
2
|
+
|
|
3
|
+
**Parallel test execution with automatic dependency detection through thenable proxies.**
|
|
4
|
+
|
|
5
|
+
`blong-chain` is a TypeScript test framework that automatically detects
|
|
6
|
+
dependencies between test steps and executes them in parallel when possible,
|
|
7
|
+
maximizing performance while maintaining correctness.
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
- ๐ **Automatic Parallelization** - Independent steps run concurrently
|
|
12
|
+
- ๐ **Dependency Detection** - Access patterns automatically create dependencies
|
|
13
|
+
- ๐ **Progress Tracking** - Real-time execution monitoring with events
|
|
14
|
+
- ๐ฏ **Thenable Proxies** - Natural async/await syntax for step dependencies
|
|
15
|
+
- ๐ **Performance Metrics** - Queue time, execution time, and critical path analysis
|
|
16
|
+
- ๐ณ **Nested Groups** - Hierarchical test organization with proper indentation
|
|
17
|
+
- ๐ง **Error Handling** - Graceful failure with continued execution of
|
|
18
|
+
independent steps
|
|
19
|
+
- ๐งช **Test Framework Integration** - Works seamlessly with node:test, tap,
|
|
20
|
+
and others
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @feasibleone/blong-chain
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import {TestExecutor} from '@feasibleone/blong-chain';
|
|
32
|
+
import assert from 'node:assert/strict';
|
|
33
|
+
import {test} from 'node:test';
|
|
34
|
+
|
|
35
|
+
test('parallel execution example', async (t) => {
|
|
36
|
+
const executor = new TestExecutor({concurrency: 10});
|
|
37
|
+
|
|
38
|
+
const steps = [
|
|
39
|
+
async function fetchUser(assert, context) {
|
|
40
|
+
// Independent - runs immediately
|
|
41
|
+
return {id: 1, name: 'Alice'};
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
async function fetchAccount(assert, context) {
|
|
45
|
+
// Independent - runs in parallel with fetchUser
|
|
46
|
+
return {balance: 1000};
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
async function validateUser(assert, {fetchUser}) {
|
|
50
|
+
// Dependent - waits for fetchUser to complete
|
|
51
|
+
const user = await fetchUser;
|
|
52
|
+
assert.equal(user.name, 'Alice');
|
|
53
|
+
return {validated: true};
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
async function generateReport(assert, {fetchUser, fetchAccount}) {
|
|
57
|
+
// Multiple dependencies - waits for both
|
|
58
|
+
const user = await fetchUser;
|
|
59
|
+
const account = await fetchAccount;
|
|
60
|
+
return `User ${user.name} has balance ${account.balance}`;
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
await executor.execute(steps, {testId: 'example'}, t);
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Core Concepts
|
|
69
|
+
|
|
70
|
+
### Thenable Proxies
|
|
71
|
+
|
|
72
|
+
Steps access previous results through thenable proxies that automatically track
|
|
73
|
+
dependencies:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Pattern 1: Direct await
|
|
77
|
+
async function step1(assert, {previousStep}) {
|
|
78
|
+
const result = await previousStep;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Pattern 2: Destructure then await
|
|
82
|
+
async function step2(assert, {previousStep}) {
|
|
83
|
+
const result = await previousStep;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Pattern 3: Nested property access
|
|
87
|
+
async function step3(assert, {previousStep}) {
|
|
88
|
+
const name = await previousStep.user.name;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Pattern 4: Deep destructuring
|
|
92
|
+
async function step4(assert, {previousStep: {user: {name}}}) {
|
|
93
|
+
const userName = await name;
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Automatic Parallelization
|
|
98
|
+
|
|
99
|
+
The executor analyzes your access patterns and runs independent steps concurrently:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const steps = [
|
|
103
|
+
async function stepA() {
|
|
104
|
+
// Runs immediately
|
|
105
|
+
await someAsyncWork();
|
|
106
|
+
return {dataA: 'A'};
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
async function stepB() {
|
|
110
|
+
// Runs immediately in parallel with stepA
|
|
111
|
+
await someAsyncWork();
|
|
112
|
+
return {dataB: 'B'};
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
async function stepC(assert, {stepA}) {
|
|
116
|
+
// Waits for stepA (automatic dependency)
|
|
117
|
+
const a = await stepA;
|
|
118
|
+
return {dataC: a.dataA + 'C'};
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
async function stepD(assert, {stepA, stepB}) {
|
|
122
|
+
// Waits for both stepA and stepB (parallel wait)
|
|
123
|
+
const a = await stepA;
|
|
124
|
+
const b = await stepB;
|
|
125
|
+
assert.ok(a.dataA);
|
|
126
|
+
assert.ok(b.dataB);
|
|
127
|
+
return {dataD: 'D'};
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Meta Information
|
|
133
|
+
|
|
134
|
+
The special `$meta` property is always available directly without await:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
async function myStep(assert, {$meta}) {
|
|
138
|
+
// Access meta synchronously
|
|
139
|
+
console.log($meta.testId);
|
|
140
|
+
console.log($meta.environment);
|
|
141
|
+
|
|
142
|
+
// Meta is passed when executing
|
|
143
|
+
await executor.execute(steps, {
|
|
144
|
+
testId: 'test-123',
|
|
145
|
+
environment: 'production',
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Advanced Features
|
|
151
|
+
|
|
152
|
+
### Nested Test Groups
|
|
153
|
+
|
|
154
|
+
Organize steps into hierarchical groups for better structure and output:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
const databaseSetup = [
|
|
158
|
+
async function connect() { return {connected: true}; },
|
|
159
|
+
async function createSchema() { return {created: true}; },
|
|
160
|
+
async function seedData() { return {users: []}; },
|
|
161
|
+
] as any;
|
|
162
|
+
databaseSetup.name = 'Database Setup';
|
|
163
|
+
|
|
164
|
+
const apiTests = [
|
|
165
|
+
async function testEndpoint1() { return {status: 200}; },
|
|
166
|
+
async function testEndpoint2() { return {status: 200}; },
|
|
167
|
+
] as any;
|
|
168
|
+
apiTests.name = 'API Tests';
|
|
169
|
+
|
|
170
|
+
const steps = [
|
|
171
|
+
async function initialize() { return {ready: true}; },
|
|
172
|
+
databaseSetup, // Nested group
|
|
173
|
+
apiTests, // Nested group
|
|
174
|
+
async function cleanup() { return {done: true}; },
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
await executor.execute(steps, {}, t);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Output:**
|
|
181
|
+
|
|
182
|
+
```text
|
|
183
|
+
โถ Test Name
|
|
184
|
+
โ initialize
|
|
185
|
+
โถ Database Setup
|
|
186
|
+
โ connect
|
|
187
|
+
โ createSchema
|
|
188
|
+
โ seedData
|
|
189
|
+
โ Database Setup
|
|
190
|
+
โถ API Tests
|
|
191
|
+
โ testEndpoint1
|
|
192
|
+
โ testEndpoint2
|
|
193
|
+
โ API Tests
|
|
194
|
+
โ cleanup
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Checkpoints (Synchronization Barriers)
|
|
198
|
+
|
|
199
|
+
Use empty arrays `[]` as checkpoints to synchronize parallel execution. All steps before a checkpoint must complete before any steps after it begin:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
const steps = [
|
|
203
|
+
// Phase 1: These run in parallel
|
|
204
|
+
async function loadConfig() {
|
|
205
|
+
await fetchConfig();
|
|
206
|
+
return {apiUrl: 'https://api.example.com'};
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
async function initializeCache() {
|
|
210
|
+
await setupCache();
|
|
211
|
+
return {cacheReady: true};
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
async function setupLogging() {
|
|
215
|
+
await configureLogger();
|
|
216
|
+
return {loggerReady: true};
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
// Checkpoint: Wait for all Phase 1 steps to complete
|
|
220
|
+
[],
|
|
221
|
+
|
|
222
|
+
// Phase 2: These run in parallel, but only after Phase 1 completes
|
|
223
|
+
async function loadUsers({loadConfig}) {
|
|
224
|
+
const config = await loadConfig;
|
|
225
|
+
return await fetchUsers(config.apiUrl);
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
async function loadProducts({loadConfig}) {
|
|
229
|
+
const config = await loadConfig;
|
|
230
|
+
return await fetchProducts(config.apiUrl);
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
// Another checkpoint
|
|
234
|
+
[],
|
|
235
|
+
|
|
236
|
+
// Phase 3: Runs only after Phase 2 completes
|
|
237
|
+
async function generateReport({loadUsers, loadProducts}) {
|
|
238
|
+
const users = await loadUsers;
|
|
239
|
+
const products = await loadProducts;
|
|
240
|
+
return {report: combineData(users, products)};
|
|
241
|
+
},
|
|
242
|
+
];
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Use Cases:**
|
|
246
|
+
- **Phased execution**: Separate initialization, data loading, processing, and cleanup phases
|
|
247
|
+
- **Resource management**: Ensure all resources are ready before proceeding
|
|
248
|
+
- **Testing stages**: Complete all setup before running tests, then cleanup
|
|
249
|
+
- **Performance control**: Balance parallelism with resource constraints
|
|
250
|
+
|
|
251
|
+
### Progress Tracking and Events
|
|
252
|
+
|
|
253
|
+
Monitor test execution in real-time:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
const executor = new TestExecutor({concurrency: 10});
|
|
257
|
+
|
|
258
|
+
executor.on('test:start', (progress) => {
|
|
259
|
+
console.log('Test started:', progress.testName);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
executor.on('step:start', (stepName, progress) => {
|
|
263
|
+
console.log('Step started:', stepName);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
executor.on('step:end', (stepName, progress) => {
|
|
267
|
+
console.log('Step completed:', stepName, `in ${progress.duration}ms`);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
executor.on('step:error', (stepName, error, progress) => {
|
|
271
|
+
console.error('Step failed:', stepName, error.message);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
await executor.execute(steps, {});
|
|
275
|
+
|
|
276
|
+
// Get final progress
|
|
277
|
+
const progress = executor.getProgress();
|
|
278
|
+
console.log(`Completed ${progress.completedSteps}/${progress.totalSteps} steps`);
|
|
279
|
+
console.log(`Failed: ${progress.failedSteps}`);
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Dependency Graph Analysis
|
|
283
|
+
|
|
284
|
+
Inspect the dependency relationships:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
await executor.execute(steps, {});
|
|
288
|
+
|
|
289
|
+
const graph = executor.getDependencyGraph();
|
|
290
|
+
|
|
291
|
+
// View all steps
|
|
292
|
+
for (const [name, node] of graph.nodes) {
|
|
293
|
+
console.log(`${name}: ${node.status}`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// View dependencies
|
|
297
|
+
for (const edge of graph.edges) {
|
|
298
|
+
console.log(`${edge.from} depends on ${edge.to} via ${edge.property}`);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Performance Metrics
|
|
303
|
+
|
|
304
|
+
Analyze execution performance:
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
await executor.execute(steps, {});
|
|
308
|
+
|
|
309
|
+
const latency = executor.getLatencyReport();
|
|
310
|
+
|
|
311
|
+
console.log(`Total duration: ${latency.totalDuration}ms`);
|
|
312
|
+
console.log(`Parallel efficiency: ${latency.parallelEfficiency.toFixed(2)}x`);
|
|
313
|
+
console.log(`Critical path: ${latency.criticalPath.join(' โ ')}`);
|
|
314
|
+
|
|
315
|
+
// View bottlenecks
|
|
316
|
+
for (const bottleneck of latency.bottlenecks) {
|
|
317
|
+
console.log(
|
|
318
|
+
`${bottleneck.stepName} blocked ${bottleneck.blockedSteps.length} steps`
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// View individual step metrics
|
|
323
|
+
for (const [name, metrics] of latency.steps) {
|
|
324
|
+
console.log(`${name}:`, {
|
|
325
|
+
queue: metrics.queueTime,
|
|
326
|
+
wait: metrics.waitTime,
|
|
327
|
+
exec: metrics.executionTime,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Error Handling
|
|
333
|
+
|
|
334
|
+
Steps fail gracefully while independent steps continue:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
const steps = [
|
|
338
|
+
async function stepA() {
|
|
339
|
+
return {data: 'A'};
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
async function stepB() {
|
|
343
|
+
throw new Error('Step B failed');
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
async function stepC(assert, {stepA}) {
|
|
347
|
+
// This still runs - it's independent of stepB
|
|
348
|
+
const a = await stepA;
|
|
349
|
+
return {data: 'C'};
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
async function stepD(assert, {stepB}) {
|
|
353
|
+
// This can handle the error if needed
|
|
354
|
+
try {
|
|
355
|
+
await stepB;
|
|
356
|
+
} catch (error) {
|
|
357
|
+
assert.ok(error.message.includes('Step B failed'));
|
|
358
|
+
return {handled: true};
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
];
|
|
362
|
+
|
|
363
|
+
await executor.execute(steps, {});
|
|
364
|
+
|
|
365
|
+
// Check which steps failed
|
|
366
|
+
const progress = executor.getProgress();
|
|
367
|
+
for (const [name, step] of progress.steps) {
|
|
368
|
+
if (step.status === 'failed') {
|
|
369
|
+
console.log(`${name} failed:`, step.error?.message);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Configuration Options
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
const executor = new TestExecutor({
|
|
378
|
+
// Maximum concurrent steps (default: 10)
|
|
379
|
+
concurrency: 5,
|
|
380
|
+
|
|
381
|
+
// Capture stack traces for better error reporting (default: false)
|
|
382
|
+
// Note: Has performance impact
|
|
383
|
+
captureStackTraces: true,
|
|
384
|
+
|
|
385
|
+
// Test framework context (optional)
|
|
386
|
+
// Passed automatically when using test framework integration
|
|
387
|
+
framework: undefined,
|
|
388
|
+
});
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## Real-World Example
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
test('e-commerce checkout flow', async (t) => {
|
|
395
|
+
const executor = new TestExecutor({concurrency: 5});
|
|
396
|
+
|
|
397
|
+
const steps = [
|
|
398
|
+
async function loadProduct(assert, context) {
|
|
399
|
+
await new Promise(resolve => setTimeout(resolve, 30));
|
|
400
|
+
return {productId: 'PROD-123', price: 99.99, inStock: true};
|
|
401
|
+
},
|
|
402
|
+
|
|
403
|
+
async function loadCart(assert, context) {
|
|
404
|
+
await new Promise(resolve => setTimeout(resolve, 30));
|
|
405
|
+
return {cartId: 'CART-456', items: 2};
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
async function validateInventory(assert, {loadProduct}) {
|
|
409
|
+
const product = await loadProduct;
|
|
410
|
+
assert.ok(product.inStock);
|
|
411
|
+
return {valid: true, reservationId: 'RES-789'};
|
|
412
|
+
},
|
|
413
|
+
|
|
414
|
+
async function calculateShipping(assert, {loadCart}) {
|
|
415
|
+
const cart = await loadCart;
|
|
416
|
+
return {cost: 9.99, days: 3};
|
|
417
|
+
},
|
|
418
|
+
|
|
419
|
+
async function calculateTax(assert, {loadProduct}) {
|
|
420
|
+
const product = await loadProduct;
|
|
421
|
+
return {amount: product.price * 0.08};
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
async function calculateTotal(assert, {
|
|
425
|
+
loadProduct, calculateShipping, calculateTax
|
|
426
|
+
}) {
|
|
427
|
+
const product = await loadProduct;
|
|
428
|
+
const shipping = await calculateShipping;
|
|
429
|
+
const tax = await calculateTax;
|
|
430
|
+
|
|
431
|
+
return {
|
|
432
|
+
total: product.price + shipping.cost + tax.amount,
|
|
433
|
+
breakdown: {
|
|
434
|
+
product: product.price,
|
|
435
|
+
shipping: shipping.cost,
|
|
436
|
+
tax: tax.amount,
|
|
437
|
+
},
|
|
438
|
+
};
|
|
439
|
+
},
|
|
440
|
+
|
|
441
|
+
async function processPayment(assert, {
|
|
442
|
+
calculateTotal, validateInventory
|
|
443
|
+
}) {
|
|
444
|
+
const total = await calculateTotal;
|
|
445
|
+
const inventory = await validateInventory;
|
|
446
|
+
|
|
447
|
+
assert.ok(inventory.valid);
|
|
448
|
+
await new Promise(resolve => setTimeout(resolve, 40));
|
|
449
|
+
|
|
450
|
+
return {
|
|
451
|
+
paymentId: 'PAY-999',
|
|
452
|
+
amount: total.total,
|
|
453
|
+
status: 'completed',
|
|
454
|
+
};
|
|
455
|
+
},
|
|
456
|
+
|
|
457
|
+
async function createOrder(assert, {processPayment}) {
|
|
458
|
+
const payment = await processPayment;
|
|
459
|
+
assert.equal(payment.status, 'completed');
|
|
460
|
+
|
|
461
|
+
return {
|
|
462
|
+
orderId: 'ORD-111',
|
|
463
|
+
paymentId: payment.paymentId,
|
|
464
|
+
};
|
|
465
|
+
},
|
|
466
|
+
];
|
|
467
|
+
|
|
468
|
+
await executor.execute(steps, {
|
|
469
|
+
testId: 'checkout-001',
|
|
470
|
+
environment: 'test',
|
|
471
|
+
}, t);
|
|
472
|
+
|
|
473
|
+
// Verify results
|
|
474
|
+
const progress = executor.getProgress();
|
|
475
|
+
assert.equal(progress.status, 'completed');
|
|
476
|
+
assert.equal(progress.failedSteps, 0);
|
|
477
|
+
|
|
478
|
+
const latency = executor.getLatencyReport();
|
|
479
|
+
console.log(`Completed in ${latency.totalDuration}ms`);
|
|
480
|
+
console.log(`Parallel efficiency: ${latency.parallelEfficiency.toFixed(2)}x`);
|
|
481
|
+
});
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
In this example:
|
|
485
|
+
|
|
486
|
+
- `loadProduct` and `loadCart` run in parallel immediately
|
|
487
|
+
- `validateInventory` and `calculateShipping` wait only for their specific dependencies
|
|
488
|
+
- `calculateTax` runs as soon as `loadProduct` completes
|
|
489
|
+
- `calculateTotal` waits for all pricing components
|
|
490
|
+
- `processPayment` and `createOrder` form the critical path
|
|
491
|
+
- Total execution time is significantly less than sequential execution
|
|
492
|
+
|
|
493
|
+
## Documentation
|
|
494
|
+
|
|
495
|
+
- **[SHOWCASE.md](./SHOWCASE.md)** - Comprehensive feature showcase with all patterns
|
|
496
|
+
- **[TESTING.md](./TESTING.md)** - Testing guide and CI integration
|
|
497
|
+
- **[NESTED_TEST_CONTEXT.md](./NESTED_TEST_CONTEXT.md)** - Test framework
|
|
498
|
+
integration details
|
|
499
|
+
- **[test-types.ts](./test-types.ts)** - Complete TypeScript API documentation
|
|
500
|
+
|
|
501
|
+
## Running Tests
|
|
502
|
+
|
|
503
|
+
```bash
|
|
504
|
+
# Run unit tests
|
|
505
|
+
npm test
|
|
506
|
+
|
|
507
|
+
# Run showcase examples
|
|
508
|
+
npm run build
|
|
509
|
+
node --test dist/showcase.test.js
|
|
510
|
+
|
|
511
|
+
# Run all tests
|
|
512
|
+
npm run test:all
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
## How It Works
|
|
516
|
+
|
|
517
|
+
1. **Detection Phase**: When you destructure or access `context.stepName`, a
|
|
518
|
+
thenable proxy is returned
|
|
519
|
+
2. **Dependency Tracking**: The access is recorded as a dependency
|
|
520
|
+
3. **Scheduling Phase**: Steps are added to a priority queue based on dependencies
|
|
521
|
+
4. **Execution Phase**: Steps run as soon as all their dependencies complete
|
|
522
|
+
5. **Resolution Phase**: Step results are stored and proxies are resolved
|
|
523
|
+
6. **Checkpoints**: Empty arrays `[]` create synchronization barriers, waiting for
|
|
524
|
+
all previous steps to complete before continuing
|
|
525
|
+
|
|
526
|
+
This creates a dynamic dependency graph that enables maximum parallelization
|
|
527
|
+
while ensuring correctness, with optional synchronization points for phased execution.
|
|
528
|
+
|
|
529
|
+
## Use Cases
|
|
530
|
+
|
|
531
|
+
- **Integration Tests** - Test complex workflows with many async operations
|
|
532
|
+
- **E2E Tests** - Reduce test suite execution time through parallelization
|
|
533
|
+
- **Data Pipelines** - Orchestrate parallel data processing steps
|
|
534
|
+
- **API Testing** - Test multiple endpoints with shared setup steps
|
|
535
|
+
- **Performance Testing** - Identify bottlenecks with built-in metrics
|
|
536
|
+
|
|
537
|
+
## TypeScript Support
|
|
538
|
+
|
|
539
|
+
Full TypeScript support with comprehensive type definitions:
|
|
540
|
+
|
|
541
|
+
```typescript
|
|
542
|
+
import type {
|
|
543
|
+
ITestExecutor,
|
|
544
|
+
ITestContext,
|
|
545
|
+
ITestProgress,
|
|
546
|
+
IDependencyGraph,
|
|
547
|
+
ITestLatency,
|
|
548
|
+
StepFunction,
|
|
549
|
+
StepArray,
|
|
550
|
+
} from '@feasibleone/blong-chain';
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
## License
|
|
554
|
+
|
|
555
|
+
Part of the [Blong Framework](https://github.com/feasibleone/blong)
|
|
556
|
+
|
|
557
|
+
## Contributing
|
|
558
|
+
|
|
559
|
+
Issues and pull requests welcome at <https://github.com/feasibleone/blong>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.test.d.ts","sourceRoot":"","sources":["../../examples/demo.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.test.js","sourceRoot":"","sources":["../../examples/demo.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Demonstration of error reporting in nested test contexts
|
|
3
|
+
*
|
|
4
|
+
* This file shows how errors are properly reported with indentation and tracking.
|
|
5
|
+
* Run with: node --test error-demo.test.js
|
|
6
|
+
*
|
|
7
|
+
* You'll see that:
|
|
8
|
+
* 1. Errors appear in the nested test output with proper indentation
|
|
9
|
+
* 2. Error details (message, stack trace) are captured
|
|
10
|
+
* 3. Progress tracking records all error information
|
|
11
|
+
* 4. Other independent steps continue executing
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=error-demo.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-demo.test.d.ts","sourceRoot":"","sources":["../../examples/error-demo.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-demo.test.js","sourceRoot":"","sources":["../../examples/error-demo.test.ts"],"names":[],"mappings":"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"}
|