@unlaxer/tramli-plugins 3.5.1 → 3.6.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/dist/cjs/api/plugin-registry.d.ts +5 -1
- package/dist/cjs/api/plugin-registry.js +18 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/observability/noop-telemetry-sink.d.ts +6 -0
- package/dist/cjs/observability/noop-telemetry-sink.js +9 -0
- package/dist/cjs/testing/scenario-test-plugin.d.ts +7 -0
- package/dist/cjs/testing/scenario-test-plugin.js +62 -0
- package/dist/esm/api/plugin-registry.d.ts +5 -1
- package/dist/esm/api/plugin-registry.js +18 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/observability/noop-telemetry-sink.d.ts +6 -0
- package/dist/esm/observability/noop-telemetry-sink.js +5 -0
- package/dist/esm/testing/scenario-test-plugin.d.ts +7 -0
- package/dist/esm/testing/scenario-test-plugin.js +62 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FlowDefinition, FlowEngine } from '@unlaxer/tramli';
|
|
1
|
+
import type { FlowDefinition, FlowEngine, Builder } from '@unlaxer/tramli';
|
|
2
2
|
import type { FlowPlugin } from './types.js';
|
|
3
3
|
import { PluginReport } from './types.js';
|
|
4
4
|
/**
|
|
@@ -10,6 +10,10 @@ export declare class PluginRegistry<S extends string> {
|
|
|
10
10
|
register(plugin: FlowPlugin): this;
|
|
11
11
|
/** Run all analysis plugins against a FlowDefinition. */
|
|
12
12
|
analyzeAll(definition: FlowDefinition<S>): PluginReport;
|
|
13
|
+
/** Build a FlowDefinition and run all analysis plugins. Throws if any ERROR findings. */
|
|
14
|
+
buildAndAnalyze(builder: Builder<S>): FlowDefinition<S>;
|
|
15
|
+
/** Run all analysis plugins and throw if any ERROR findings. For already-built definitions. */
|
|
16
|
+
analyzeAndValidate(definition: FlowDefinition<S>): void;
|
|
13
17
|
/** Apply all store plugins (wrapping in registration order). */
|
|
14
18
|
applyStorePlugins(store: any): any;
|
|
15
19
|
/** Install all engine plugins. */
|
|
@@ -22,6 +22,24 @@ class PluginRegistry {
|
|
|
22
22
|
}
|
|
23
23
|
return report;
|
|
24
24
|
}
|
|
25
|
+
/** Build a FlowDefinition and run all analysis plugins. Throws if any ERROR findings. */
|
|
26
|
+
buildAndAnalyze(builder) {
|
|
27
|
+
const def = builder.build();
|
|
28
|
+
const report = this.analyzeAll(def);
|
|
29
|
+
const errors = report.findings().filter(f => f.severity === 'ERROR');
|
|
30
|
+
if (errors.length > 0) {
|
|
31
|
+
throw new Error(`Analysis errors:\n${errors.map(e => ` [${e.pluginId}] ${e.message}`).join('\n')}`);
|
|
32
|
+
}
|
|
33
|
+
return def;
|
|
34
|
+
}
|
|
35
|
+
/** Run all analysis plugins and throw if any ERROR findings. For already-built definitions. */
|
|
36
|
+
analyzeAndValidate(definition) {
|
|
37
|
+
const report = this.analyzeAll(definition);
|
|
38
|
+
const errors = report.findings().filter(f => f.severity === 'ERROR');
|
|
39
|
+
if (errors.length > 0) {
|
|
40
|
+
throw new Error(`Analysis errors:\n${errors.map(e => ` [${e.pluginId}] ${e.message}`).join('\n')}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
25
43
|
/** Apply all store plugins (wrapping in registration order). */
|
|
26
44
|
applyStorePlugins(store) {
|
|
27
45
|
let wrapped = store;
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { ReplayService, ProjectionReplayService } from './eventstore/replay-serv
|
|
|
10
10
|
export { CompensationService } from './eventstore/compensation-service.js';
|
|
11
11
|
export type { VersionedTransitionEvent, CompensationPlan, CompensationResolver, ProjectionReducer, } from './eventstore/types.js';
|
|
12
12
|
export { ObservabilityEnginePlugin, InMemoryTelemetrySink } from './observability/observability-plugin.js';
|
|
13
|
+
export { NoopTelemetrySink } from './observability/noop-telemetry-sink.js';
|
|
13
14
|
export type { TelemetryEvent, TelemetrySink } from './observability/observability-plugin.js';
|
|
14
15
|
export { RichResumeExecutor, RichResumeRuntimePlugin } from './resume/rich-resume.js';
|
|
15
16
|
export type { RichResumeStatus, RichResumeResult } from './resume/rich-resume.js';
|
|
@@ -31,6 +32,7 @@ export { PolicyLintPlugin } from './lint/policy-lint-plugin.js';
|
|
|
31
32
|
export { allDefaultPolicies } from './lint/default-flow-policies.js';
|
|
32
33
|
export type { FlowPolicy } from './lint/types.js';
|
|
33
34
|
export { ScenarioTestPlugin } from './testing/scenario-test-plugin.js';
|
|
35
|
+
export type { TestFramework } from './testing/scenario-test-plugin.js';
|
|
34
36
|
export { ScenarioGenerationPlugin } from './testing/scenario-generation-plugin.js';
|
|
35
37
|
export type { FlowScenario, FlowTestPlan, ScenarioKind } from './testing/types.js';
|
|
36
38
|
export { GuaranteedSubflowValidator } from './subflow/guaranteed-subflow-validator.js';
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GuaranteedSubflowValidator = exports.ScenarioGenerationPlugin = exports.ScenarioTestPlugin = exports.allDefaultPolicies = exports.PolicyLintPlugin = exports.FlowDocumentationPlugin = exports.DocumentationPlugin = exports.DiagramGenerationPlugin = exports.DiagramPlugin = exports.flowSpec = exports.transitionSpec = exports.stateSpec = exports.HierarchyGenerationPlugin = exports.HierarchyCodeGenerator = exports.EntryExitCompiler = exports.IdempotencyRuntimePlugin = exports.IdempotentRichResumeExecutor = exports.InMemoryIdempotencyRegistry = exports.RichResumeRuntimePlugin = exports.RichResumeExecutor = exports.InMemoryTelemetrySink = exports.ObservabilityEnginePlugin = exports.CompensationService = exports.ProjectionReplayService = exports.ReplayService = exports.EventLogStoreDecorator = exports.EventLogStorePlugin = exports.AuditingFlowStore = exports.AuditStorePlugin = exports.PluginRegistry = exports.PluginReport = void 0;
|
|
3
|
+
exports.GuaranteedSubflowValidator = exports.ScenarioGenerationPlugin = exports.ScenarioTestPlugin = exports.allDefaultPolicies = exports.PolicyLintPlugin = exports.FlowDocumentationPlugin = exports.DocumentationPlugin = exports.DiagramGenerationPlugin = exports.DiagramPlugin = exports.flowSpec = exports.transitionSpec = exports.stateSpec = exports.HierarchyGenerationPlugin = exports.HierarchyCodeGenerator = exports.EntryExitCompiler = exports.IdempotencyRuntimePlugin = exports.IdempotentRichResumeExecutor = exports.InMemoryIdempotencyRegistry = exports.RichResumeRuntimePlugin = exports.RichResumeExecutor = exports.NoopTelemetrySink = exports.InMemoryTelemetrySink = exports.ObservabilityEnginePlugin = exports.CompensationService = exports.ProjectionReplayService = exports.ReplayService = exports.EventLogStoreDecorator = exports.EventLogStorePlugin = exports.AuditingFlowStore = exports.AuditStorePlugin = exports.PluginRegistry = exports.PluginReport = void 0;
|
|
4
4
|
// ── API framework ──
|
|
5
5
|
var types_js_1 = require("./api/types.js");
|
|
6
6
|
Object.defineProperty(exports, "PluginReport", { enumerable: true, get: function () { return types_js_1.PluginReport; } });
|
|
@@ -25,6 +25,8 @@ Object.defineProperty(exports, "CompensationService", { enumerable: true, get: f
|
|
|
25
25
|
var observability_plugin_js_1 = require("./observability/observability-plugin.js");
|
|
26
26
|
Object.defineProperty(exports, "ObservabilityEnginePlugin", { enumerable: true, get: function () { return observability_plugin_js_1.ObservabilityEnginePlugin; } });
|
|
27
27
|
Object.defineProperty(exports, "InMemoryTelemetrySink", { enumerable: true, get: function () { return observability_plugin_js_1.InMemoryTelemetrySink; } });
|
|
28
|
+
var noop_telemetry_sink_js_1 = require("./observability/noop-telemetry-sink.js");
|
|
29
|
+
Object.defineProperty(exports, "NoopTelemetrySink", { enumerable: true, get: function () { return noop_telemetry_sink_js_1.NoopTelemetrySink; } });
|
|
28
30
|
// ── Rich Resume ──
|
|
29
31
|
var rich_resume_js_1 = require("./resume/rich-resume.js");
|
|
30
32
|
Object.defineProperty(exports, "RichResumeExecutor", { enumerable: true, get: function () { return rich_resume_js_1.RichResumeExecutor; } });
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TelemetrySink, TelemetryEvent } from './observability-plugin.js';
|
|
2
|
+
/** No-op telemetry sink for benchmarking baseline. */
|
|
3
|
+
export declare class NoopTelemetrySink implements TelemetrySink {
|
|
4
|
+
emit(_event: TelemetryEvent): void;
|
|
5
|
+
events(): readonly TelemetryEvent[];
|
|
6
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NoopTelemetrySink = void 0;
|
|
4
|
+
/** No-op telemetry sink for benchmarking baseline. */
|
|
5
|
+
class NoopTelemetrySink {
|
|
6
|
+
emit(_event) { }
|
|
7
|
+
events() { return []; }
|
|
8
|
+
}
|
|
9
|
+
exports.NoopTelemetrySink = NoopTelemetrySink;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { FlowDefinition } from '@unlaxer/tramli';
|
|
2
2
|
import type { FlowTestPlan } from './types.js';
|
|
3
|
+
export type TestFramework = 'vitest' | 'jest';
|
|
3
4
|
/**
|
|
4
5
|
* Generates BDD-style test scenarios from a flow definition.
|
|
5
6
|
* Covers happy paths, error transitions, guard rejections, and timeout expiry.
|
|
6
7
|
*/
|
|
7
8
|
export declare class ScenarioTestPlugin {
|
|
9
|
+
/**
|
|
10
|
+
* Generate executable test code from a flow definition.
|
|
11
|
+
* Produces a string of vitest/jest test code that validates transitions
|
|
12
|
+
* against the definition's structure (no FlowEngine required).
|
|
13
|
+
*/
|
|
14
|
+
generateCode<S extends string>(definition: FlowDefinition<S>, framework?: TestFramework): string;
|
|
8
15
|
generate<S extends string>(definition: FlowDefinition<S>): FlowTestPlan;
|
|
9
16
|
}
|
|
@@ -6,6 +6,68 @@ exports.ScenarioTestPlugin = void 0;
|
|
|
6
6
|
* Covers happy paths, error transitions, guard rejections, and timeout expiry.
|
|
7
7
|
*/
|
|
8
8
|
class ScenarioTestPlugin {
|
|
9
|
+
/**
|
|
10
|
+
* Generate executable test code from a flow definition.
|
|
11
|
+
* Produces a string of vitest/jest test code that validates transitions
|
|
12
|
+
* against the definition's structure (no FlowEngine required).
|
|
13
|
+
*/
|
|
14
|
+
generateCode(definition, framework = 'vitest') {
|
|
15
|
+
const plan = this.generate(definition);
|
|
16
|
+
const lines = [];
|
|
17
|
+
const imp = framework === 'vitest' ? "import { describe, it, expect } from 'vitest';" : '';
|
|
18
|
+
if (imp)
|
|
19
|
+
lines.push(imp);
|
|
20
|
+
lines.push('');
|
|
21
|
+
lines.push(`describe('${definition.name} scenarios', () => {`);
|
|
22
|
+
for (const scenario of plan.scenarios) {
|
|
23
|
+
lines.push(` it('${scenario.name}', () => {`);
|
|
24
|
+
for (const step of scenario.steps) {
|
|
25
|
+
lines.push(` // ${step}`);
|
|
26
|
+
}
|
|
27
|
+
// Add assertion based on scenario kind
|
|
28
|
+
switch (scenario.kind) {
|
|
29
|
+
case 'happy': {
|
|
30
|
+
const fromMatch = scenario.steps[0]?.match(/given flow in (\S+)/);
|
|
31
|
+
const toMatch = scenario.steps[scenario.steps.length - 1]?.match(/then flow reaches (\S+)/);
|
|
32
|
+
if (fromMatch && toMatch) {
|
|
33
|
+
const from = fromMatch[1];
|
|
34
|
+
const to = toMatch[1];
|
|
35
|
+
lines.push(` const transitions = definition.transitionsFrom('${from}');`);
|
|
36
|
+
lines.push(` expect(transitions.some(t => t.to === '${to}')).toBe(true);`);
|
|
37
|
+
}
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
case 'error': {
|
|
41
|
+
const fromMatch = scenario.steps[0]?.match(/given flow in (\S+)/);
|
|
42
|
+
const toMatch = scenario.steps[scenario.steps.length - 1]?.match(/then flow transitions to (\S+)/);
|
|
43
|
+
if (fromMatch && toMatch) {
|
|
44
|
+
lines.push(` expect(definition.errorTransitions.get('${fromMatch[1]}')).toBe('${toMatch[1]}');`);
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
case 'guard_rejection': {
|
|
49
|
+
const guardMatch = scenario.steps[1]?.match(/when guard (\S+) rejects/);
|
|
50
|
+
if (guardMatch) {
|
|
51
|
+
lines.push(` expect(definition.maxGuardRetries).toBeGreaterThan(0);`);
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
case 'timeout': {
|
|
56
|
+
const fromMatch = scenario.steps[0]?.match(/given flow in (\S+)/);
|
|
57
|
+
if (fromMatch) {
|
|
58
|
+
lines.push(` const t = definition.transitionsFrom('${fromMatch[1]}').find(t => t.timeout != null);`);
|
|
59
|
+
lines.push(` expect(t).toBeDefined();`);
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
lines.push(' });');
|
|
65
|
+
lines.push('');
|
|
66
|
+
}
|
|
67
|
+
lines.push('});');
|
|
68
|
+
lines.push('');
|
|
69
|
+
return lines.join('\n');
|
|
70
|
+
}
|
|
9
71
|
generate(definition) {
|
|
10
72
|
const scenarios = [];
|
|
11
73
|
// Happy path scenarios from transitions
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FlowDefinition, FlowEngine } from '@unlaxer/tramli';
|
|
1
|
+
import type { FlowDefinition, FlowEngine, Builder } from '@unlaxer/tramli';
|
|
2
2
|
import type { FlowPlugin } from './types.js';
|
|
3
3
|
import { PluginReport } from './types.js';
|
|
4
4
|
/**
|
|
@@ -10,6 +10,10 @@ export declare class PluginRegistry<S extends string> {
|
|
|
10
10
|
register(plugin: FlowPlugin): this;
|
|
11
11
|
/** Run all analysis plugins against a FlowDefinition. */
|
|
12
12
|
analyzeAll(definition: FlowDefinition<S>): PluginReport;
|
|
13
|
+
/** Build a FlowDefinition and run all analysis plugins. Throws if any ERROR findings. */
|
|
14
|
+
buildAndAnalyze(builder: Builder<S>): FlowDefinition<S>;
|
|
15
|
+
/** Run all analysis plugins and throw if any ERROR findings. For already-built definitions. */
|
|
16
|
+
analyzeAndValidate(definition: FlowDefinition<S>): void;
|
|
13
17
|
/** Apply all store plugins (wrapping in registration order). */
|
|
14
18
|
applyStorePlugins(store: any): any;
|
|
15
19
|
/** Install all engine plugins. */
|
|
@@ -19,6 +19,24 @@ export class PluginRegistry {
|
|
|
19
19
|
}
|
|
20
20
|
return report;
|
|
21
21
|
}
|
|
22
|
+
/** Build a FlowDefinition and run all analysis plugins. Throws if any ERROR findings. */
|
|
23
|
+
buildAndAnalyze(builder) {
|
|
24
|
+
const def = builder.build();
|
|
25
|
+
const report = this.analyzeAll(def);
|
|
26
|
+
const errors = report.findings().filter(f => f.severity === 'ERROR');
|
|
27
|
+
if (errors.length > 0) {
|
|
28
|
+
throw new Error(`Analysis errors:\n${errors.map(e => ` [${e.pluginId}] ${e.message}`).join('\n')}`);
|
|
29
|
+
}
|
|
30
|
+
return def;
|
|
31
|
+
}
|
|
32
|
+
/** Run all analysis plugins and throw if any ERROR findings. For already-built definitions. */
|
|
33
|
+
analyzeAndValidate(definition) {
|
|
34
|
+
const report = this.analyzeAll(definition);
|
|
35
|
+
const errors = report.findings().filter(f => f.severity === 'ERROR');
|
|
36
|
+
if (errors.length > 0) {
|
|
37
|
+
throw new Error(`Analysis errors:\n${errors.map(e => ` [${e.pluginId}] ${e.message}`).join('\n')}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
22
40
|
/** Apply all store plugins (wrapping in registration order). */
|
|
23
41
|
applyStorePlugins(store) {
|
|
24
42
|
let wrapped = store;
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { ReplayService, ProjectionReplayService } from './eventstore/replay-serv
|
|
|
10
10
|
export { CompensationService } from './eventstore/compensation-service.js';
|
|
11
11
|
export type { VersionedTransitionEvent, CompensationPlan, CompensationResolver, ProjectionReducer, } from './eventstore/types.js';
|
|
12
12
|
export { ObservabilityEnginePlugin, InMemoryTelemetrySink } from './observability/observability-plugin.js';
|
|
13
|
+
export { NoopTelemetrySink } from './observability/noop-telemetry-sink.js';
|
|
13
14
|
export type { TelemetryEvent, TelemetrySink } from './observability/observability-plugin.js';
|
|
14
15
|
export { RichResumeExecutor, RichResumeRuntimePlugin } from './resume/rich-resume.js';
|
|
15
16
|
export type { RichResumeStatus, RichResumeResult } from './resume/rich-resume.js';
|
|
@@ -31,6 +32,7 @@ export { PolicyLintPlugin } from './lint/policy-lint-plugin.js';
|
|
|
31
32
|
export { allDefaultPolicies } from './lint/default-flow-policies.js';
|
|
32
33
|
export type { FlowPolicy } from './lint/types.js';
|
|
33
34
|
export { ScenarioTestPlugin } from './testing/scenario-test-plugin.js';
|
|
35
|
+
export type { TestFramework } from './testing/scenario-test-plugin.js';
|
|
34
36
|
export { ScenarioGenerationPlugin } from './testing/scenario-generation-plugin.js';
|
|
35
37
|
export type { FlowScenario, FlowTestPlan, ScenarioKind } from './testing/types.js';
|
|
36
38
|
export { GuaranteedSubflowValidator } from './subflow/guaranteed-subflow-validator.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export { ReplayService, ProjectionReplayService } from './eventstore/replay-serv
|
|
|
11
11
|
export { CompensationService } from './eventstore/compensation-service.js';
|
|
12
12
|
// ── Observability ──
|
|
13
13
|
export { ObservabilityEnginePlugin, InMemoryTelemetrySink } from './observability/observability-plugin.js';
|
|
14
|
+
export { NoopTelemetrySink } from './observability/noop-telemetry-sink.js';
|
|
14
15
|
// ── Rich Resume ──
|
|
15
16
|
export { RichResumeExecutor, RichResumeRuntimePlugin } from './resume/rich-resume.js';
|
|
16
17
|
// ── Idempotency ──
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TelemetrySink, TelemetryEvent } from './observability-plugin.js';
|
|
2
|
+
/** No-op telemetry sink for benchmarking baseline. */
|
|
3
|
+
export declare class NoopTelemetrySink implements TelemetrySink {
|
|
4
|
+
emit(_event: TelemetryEvent): void;
|
|
5
|
+
events(): readonly TelemetryEvent[];
|
|
6
|
+
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { FlowDefinition } from '@unlaxer/tramli';
|
|
2
2
|
import type { FlowTestPlan } from './types.js';
|
|
3
|
+
export type TestFramework = 'vitest' | 'jest';
|
|
3
4
|
/**
|
|
4
5
|
* Generates BDD-style test scenarios from a flow definition.
|
|
5
6
|
* Covers happy paths, error transitions, guard rejections, and timeout expiry.
|
|
6
7
|
*/
|
|
7
8
|
export declare class ScenarioTestPlugin {
|
|
9
|
+
/**
|
|
10
|
+
* Generate executable test code from a flow definition.
|
|
11
|
+
* Produces a string of vitest/jest test code that validates transitions
|
|
12
|
+
* against the definition's structure (no FlowEngine required).
|
|
13
|
+
*/
|
|
14
|
+
generateCode<S extends string>(definition: FlowDefinition<S>, framework?: TestFramework): string;
|
|
8
15
|
generate<S extends string>(definition: FlowDefinition<S>): FlowTestPlan;
|
|
9
16
|
}
|
|
@@ -3,6 +3,68 @@
|
|
|
3
3
|
* Covers happy paths, error transitions, guard rejections, and timeout expiry.
|
|
4
4
|
*/
|
|
5
5
|
export class ScenarioTestPlugin {
|
|
6
|
+
/**
|
|
7
|
+
* Generate executable test code from a flow definition.
|
|
8
|
+
* Produces a string of vitest/jest test code that validates transitions
|
|
9
|
+
* against the definition's structure (no FlowEngine required).
|
|
10
|
+
*/
|
|
11
|
+
generateCode(definition, framework = 'vitest') {
|
|
12
|
+
const plan = this.generate(definition);
|
|
13
|
+
const lines = [];
|
|
14
|
+
const imp = framework === 'vitest' ? "import { describe, it, expect } from 'vitest';" : '';
|
|
15
|
+
if (imp)
|
|
16
|
+
lines.push(imp);
|
|
17
|
+
lines.push('');
|
|
18
|
+
lines.push(`describe('${definition.name} scenarios', () => {`);
|
|
19
|
+
for (const scenario of plan.scenarios) {
|
|
20
|
+
lines.push(` it('${scenario.name}', () => {`);
|
|
21
|
+
for (const step of scenario.steps) {
|
|
22
|
+
lines.push(` // ${step}`);
|
|
23
|
+
}
|
|
24
|
+
// Add assertion based on scenario kind
|
|
25
|
+
switch (scenario.kind) {
|
|
26
|
+
case 'happy': {
|
|
27
|
+
const fromMatch = scenario.steps[0]?.match(/given flow in (\S+)/);
|
|
28
|
+
const toMatch = scenario.steps[scenario.steps.length - 1]?.match(/then flow reaches (\S+)/);
|
|
29
|
+
if (fromMatch && toMatch) {
|
|
30
|
+
const from = fromMatch[1];
|
|
31
|
+
const to = toMatch[1];
|
|
32
|
+
lines.push(` const transitions = definition.transitionsFrom('${from}');`);
|
|
33
|
+
lines.push(` expect(transitions.some(t => t.to === '${to}')).toBe(true);`);
|
|
34
|
+
}
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
case 'error': {
|
|
38
|
+
const fromMatch = scenario.steps[0]?.match(/given flow in (\S+)/);
|
|
39
|
+
const toMatch = scenario.steps[scenario.steps.length - 1]?.match(/then flow transitions to (\S+)/);
|
|
40
|
+
if (fromMatch && toMatch) {
|
|
41
|
+
lines.push(` expect(definition.errorTransitions.get('${fromMatch[1]}')).toBe('${toMatch[1]}');`);
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
case 'guard_rejection': {
|
|
46
|
+
const guardMatch = scenario.steps[1]?.match(/when guard (\S+) rejects/);
|
|
47
|
+
if (guardMatch) {
|
|
48
|
+
lines.push(` expect(definition.maxGuardRetries).toBeGreaterThan(0);`);
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
case 'timeout': {
|
|
53
|
+
const fromMatch = scenario.steps[0]?.match(/given flow in (\S+)/);
|
|
54
|
+
if (fromMatch) {
|
|
55
|
+
lines.push(` const t = definition.transitionsFrom('${fromMatch[1]}').find(t => t.timeout != null);`);
|
|
56
|
+
lines.push(` expect(t).toBeDefined();`);
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
lines.push(' });');
|
|
62
|
+
lines.push('');
|
|
63
|
+
}
|
|
64
|
+
lines.push('});');
|
|
65
|
+
lines.push('');
|
|
66
|
+
return lines.join('\n');
|
|
67
|
+
}
|
|
6
68
|
generate(definition) {
|
|
7
69
|
const scenarios = [];
|
|
8
70
|
// Happy path scenarios from transitions
|
package/package.json
CHANGED