@sensigo/realm-testing 0.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.
Files changed (50) hide show
  1. package/README.md +132 -0
  2. package/dist/assertions/evidence.d.ts +26 -0
  3. package/dist/assertions/evidence.d.ts.map +1 -0
  4. package/dist/assertions/evidence.js +60 -0
  5. package/dist/assertions/evidence.js.map +1 -0
  6. package/dist/fixtures/fixture-loader.d.ts +74 -0
  7. package/dist/fixtures/fixture-loader.d.ts.map +1 -0
  8. package/dist/fixtures/fixture-loader.js +62 -0
  9. package/dist/fixtures/fixture-loader.js.map +1 -0
  10. package/dist/helpers/test-adapter.d.ts +7 -0
  11. package/dist/helpers/test-adapter.d.ts.map +1 -0
  12. package/dist/helpers/test-adapter.js +8 -0
  13. package/dist/helpers/test-adapter.js.map +1 -0
  14. package/dist/helpers/test-processor.d.ts +7 -0
  15. package/dist/helpers/test-processor.d.ts.map +1 -0
  16. package/dist/helpers/test-processor.js +8 -0
  17. package/dist/helpers/test-processor.js.map +1 -0
  18. package/dist/helpers/test-step-handler.d.ts +7 -0
  19. package/dist/helpers/test-step-handler.d.ts.map +1 -0
  20. package/dist/helpers/test-step-handler.js +14 -0
  21. package/dist/helpers/test-step-handler.js.map +1 -0
  22. package/dist/index.d.ts +16 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +20 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/mocks/mock-agent.d.ts +21 -0
  27. package/dist/mocks/mock-agent.d.ts.map +1 -0
  28. package/dist/mocks/mock-agent.js +85 -0
  29. package/dist/mocks/mock-agent.js.map +1 -0
  30. package/dist/mocks/mock-gate.d.ts +9 -0
  31. package/dist/mocks/mock-gate.d.ts.map +1 -0
  32. package/dist/mocks/mock-gate.js +21 -0
  33. package/dist/mocks/mock-gate.js.map +1 -0
  34. package/dist/mocks/mock-service.d.ts +23 -0
  35. package/dist/mocks/mock-service.d.ts.map +1 -0
  36. package/dist/mocks/mock-service.js +41 -0
  37. package/dist/mocks/mock-service.js.map +1 -0
  38. package/dist/runner/test-runner.d.ts +29 -0
  39. package/dist/runner/test-runner.d.ts.map +1 -0
  40. package/dist/runner/test-runner.js +161 -0
  41. package/dist/runner/test-runner.js.map +1 -0
  42. package/dist/servers/github-mock-server.d.ts +20 -0
  43. package/dist/servers/github-mock-server.d.ts.map +1 -0
  44. package/dist/servers/github-mock-server.js +107 -0
  45. package/dist/servers/github-mock-server.js.map +1 -0
  46. package/dist/store/in-memory-store.d.ts +11 -0
  47. package/dist/store/in-memory-store.d.ts.map +1 -0
  48. package/dist/store/in-memory-store.js +110 -0
  49. package/dist/store/in-memory-store.js.map +1 -0
  50. package/package.json +54 -0
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # @sensigo/realm-testing
2
+
3
+ `@sensigo/realm-testing` — testing utilities for Realm workflows. Use this package to write unit and integration tests against your workflow definitions without making real service calls or writing to disk.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ npm install --save-dev @sensigo/realm-testing
9
+ ```
10
+
11
+ Requires `@sensigo/realm` at the same version to be installed in your project.
12
+
13
+ ## Usage — YAML Fixture Tests
14
+
15
+ Fixture tests are the fastest way to test a complete workflow. Each fixture file declares the initial params, mock service responses, agent step outputs, and the expected final state. The `runFixtureTests` runner loads your workflow, drives it to completion using the fixture data, and returns a result for each fixture.
16
+
17
+ ```ts
18
+ // workflow-test.ts
19
+ import { describe, it, expect } from 'vitest';
20
+ import { runFixtureTests } from '@sensigo/realm-testing';
21
+ import path from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
+
24
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
25
+
26
+ describe('my-workflow fixtures', async () => {
27
+ const results = await runFixtureTests({
28
+ workflowPath: path.join(__dirname, '../my-workflow'), // accepts workflow.yaml path OR its containing directory
29
+ fixturesPath: path.join(__dirname, '../my-workflow/fixtures'),
30
+ });
31
+
32
+ for (const result of results) {
33
+ it(result.name, () => {
34
+ expect(result.passed, result.error).toBe(true);
35
+ });
36
+ }
37
+ });
38
+ ```
39
+
40
+ ## Usage — Programmatic Tests
41
+
42
+ Use programmatic tests when you need fine-grained control over a single step, a specific execution path, or assertions on individual evidence entries.
43
+
44
+ ```ts
45
+ import { describe, it, expect } from 'vitest';
46
+ import { InMemoryStore, assertFinalState } from '@sensigo/realm-testing';
47
+ import { loadWorkflowFromFile } from '@sensigo/realm'; // NOTE: from @sensigo/realm, not @sensigo/realm-testing
48
+ import path from 'node:path';
49
+ import { fileURLToPath } from 'node:url';
50
+
51
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
52
+
53
+ describe('my-workflow programmatic', () => {
54
+ it('run reaches expected final state', async () => {
55
+ const store = new InMemoryStore();
56
+ const definition = await loadWorkflowFromFile(
57
+ path.join(__dirname, '../my-workflow/workflow.yaml'),
58
+ );
59
+ const run = await store.create({
60
+ workflowId: definition.id,
61
+ workflowVersion: definition.version,
62
+ params: { input: 'hello' },
63
+ });
64
+
65
+ // drive the run to completion first — see examples/02-ticket-classifier/ for a full test
66
+ assertFinalState(run, 'completed');
67
+ });
68
+ });
69
+ ```
70
+
71
+ ## API Reference
72
+
73
+ ### Store
74
+
75
+ | Symbol | Description |
76
+ | --------------- | --------------------------------------------------------------------------------------- |
77
+ | `InMemoryStore` | In-memory `RunStore` implementation. No I/O, no locking. Safe to use in parallel tests. |
78
+
79
+ ### Fixtures
80
+
81
+ | Symbol | Description |
82
+ | ----------------------- | -------------------------------------------------- |
83
+ | `loadFixtureFromFile` | Load a single fixture from a `.yaml` file path. |
84
+ | `loadFixtureFromString` | Parse a fixture from a YAML string. |
85
+ | `loadFixturesFromDir` | Load all `*.yaml` fixtures from a directory. |
86
+ | `TestFixture` | Type — a parsed fixture object. |
87
+ | `MockOperations` | Type — the mock service call map within a fixture. |
88
+
89
+ ### Mocks
90
+
91
+ | Symbol | Description |
92
+ | ----------------------- | -------------------------------------------------------------------------------- |
93
+ | `MockServiceRecorder` | Records adapter calls for later assertion. |
94
+ | `createAgentDispatcher` | Creates a dispatcher that returns fixture-defined agent step outputs. |
95
+ | `createGateResponder` | Creates a gate responder that auto-resolves gates using fixture-defined choices. |
96
+
97
+ ### Assertions
98
+
99
+ | Symbol | Description |
100
+ | --------------------- | -------------------------------------------------------------- |
101
+ | `assertFinalState` | Assert the run reached a specific terminal state. |
102
+ | `assertStepSucceeded` | Assert a named step completed without error. |
103
+ | `assertStepFailed` | Assert a named step is in the failed steps list. |
104
+ | `assertStepOutput` | Assert the output of a completed step matches a value. |
105
+ | `assertEvidenceHash` | Assert the evidence hash for a step matches an expected value. |
106
+
107
+ ### Unit test helpers
108
+
109
+ | Symbol | Description |
110
+ | ----------------- | -------------------------------------------------------------------- |
111
+ | `testStepHandler` | Run a single step handler in isolation and return its output. |
112
+ | `testProcessor` | Run a processor function against a run record and return the result. |
113
+ | `testAdapter` | Invoke an adapter operation and return the `ServiceResponse`. |
114
+
115
+ ### Runner
116
+
117
+ | Symbol | Description |
118
+ | ------------------------ | --------------------------------------------------------------------------------------- |
119
+ | `runFixtureTests` | Drive a workflow to completion for all fixtures in a directory. Returns `TestResult[]`. |
120
+ | `RunFixtureTestsOptions` | Type — options for `runFixtureTests` (`workflowPath`, `fixturesPath`, `registry?`). |
121
+ | `TestResult` | Type — result of a single fixture run (`name`, `passed`, `error?`). |
122
+
123
+ ### Servers
124
+
125
+ | Symbol | Description |
126
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
127
+ | `startGitHubMockServer` | Integration testing helper for workflows that use the GitHub adapter. See the `examples/08-pr-review/` example for usage. |
128
+ | `GitHubMockServerHandle` | Type — handle returned by `startGitHubMockServer` (`url`, `close()`). |
129
+
130
+ ## Full documentation
131
+
132
+ Full documentation: https://github.com/sensigo-hq/realm
@@ -0,0 +1,26 @@
1
+ import type { RunRecord, EvidenceSnapshot, RunPhase } from '@sensigo/realm';
2
+ /**
3
+ * Throws if run.run_phase !== expectedPhase.
4
+ * Use to verify the workflow reached the expected terminal phase.
5
+ */
6
+ export declare function assertFinalState(run: RunRecord, expectedPhase: RunPhase | string): void;
7
+ /**
8
+ * Throws if no non-gate_response snapshot with step_id === stepId and status === 'success'
9
+ * exists in evidence.
10
+ */
11
+ export declare function assertStepSucceeded(evidence: EvidenceSnapshot[], stepId: string): void;
12
+ /**
13
+ * Throws if no non-gate_response snapshot with step_id === stepId and status === 'error'
14
+ * exists in evidence.
15
+ */
16
+ export declare function assertStepFailed(evidence: EvidenceSnapshot[], stepId: string): void;
17
+ /**
18
+ * Throws if the last non-gate_response snapshot for stepId does not contain all keys
19
+ * in expected (shallow check — only top-level keys are compared).
20
+ */
21
+ export declare function assertStepOutput(evidence: EvidenceSnapshot[], stepId: string, expected: Record<string, unknown>): void;
22
+ /**
23
+ * Throws if the last non-gate_response snapshot for stepId has evidence_hash !== expectedHash.
24
+ */
25
+ export declare function assertEvidenceHash(evidence: EvidenceSnapshot[], stepId: string, expectedHash: string): void;
26
+ //# sourceMappingURL=evidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../../src/assertions/evidence.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE5E;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAMvF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAOtF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAOnF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,gBAAgB,EAAE,EAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAcN;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,gBAAgB,EAAE,EAC5B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,IAAI,CAWN"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Throws if run.run_phase !== expectedPhase.
3
+ * Use to verify the workflow reached the expected terminal phase.
4
+ */
5
+ export function assertFinalState(run, expectedPhase) {
6
+ if (run.run_phase !== expectedPhase) {
7
+ throw new Error(`assertFinalState: expected phase '${expectedPhase}' but run is in phase '${run.run_phase}'`);
8
+ }
9
+ }
10
+ /**
11
+ * Throws if no non-gate_response snapshot with step_id === stepId and status === 'success'
12
+ * exists in evidence.
13
+ */
14
+ export function assertStepSucceeded(evidence, stepId) {
15
+ const found = evidence.some((e) => e.step_id === stepId && e.kind !== 'gate_response' && e.status === 'success');
16
+ if (!found) {
17
+ throw new Error(`assertStepSucceeded: no 'success' snapshot found for step '${stepId}'`);
18
+ }
19
+ }
20
+ /**
21
+ * Throws if no non-gate_response snapshot with step_id === stepId and status === 'error'
22
+ * exists in evidence.
23
+ */
24
+ export function assertStepFailed(evidence, stepId) {
25
+ const found = evidence.some((e) => e.step_id === stepId && e.kind !== 'gate_response' && e.status === 'error');
26
+ if (!found) {
27
+ throw new Error(`assertStepFailed: no 'error' snapshot found for step '${stepId}'`);
28
+ }
29
+ }
30
+ /**
31
+ * Throws if the last non-gate_response snapshot for stepId does not contain all keys
32
+ * in expected (shallow check — only top-level keys are compared).
33
+ */
34
+ export function assertStepOutput(evidence, stepId, expected) {
35
+ const snaps = evidence.filter((e) => e.step_id === stepId && e.kind !== 'gate_response');
36
+ const snap = snaps[snaps.length - 1];
37
+ if (snap === undefined) {
38
+ throw new Error(`assertStepOutput: no snapshot found for step '${stepId}'`);
39
+ }
40
+ for (const [key, value] of Object.entries(expected)) {
41
+ if (snap.output_summary[key] !== value) {
42
+ throw new Error(`assertStepOutput: step '${stepId}' output_summary.${key} expected ${JSON.stringify(value)} ` +
43
+ `but got ${JSON.stringify(snap.output_summary[key])}`);
44
+ }
45
+ }
46
+ }
47
+ /**
48
+ * Throws if the last non-gate_response snapshot for stepId has evidence_hash !== expectedHash.
49
+ */
50
+ export function assertEvidenceHash(evidence, stepId, expectedHash) {
51
+ const snaps = evidence.filter((e) => e.step_id === stepId && e.kind !== 'gate_response');
52
+ const snap = snaps[snaps.length - 1];
53
+ if (snap === undefined) {
54
+ throw new Error(`assertEvidenceHash: no snapshot found for step '${stepId}'`);
55
+ }
56
+ if (snap.evidence_hash !== expectedHash) {
57
+ throw new Error(`assertEvidenceHash: step '${stepId}' expected hash '${expectedHash}' but got '${snap.evidence_hash}'`);
58
+ }
59
+ }
60
+ //# sourceMappingURL=evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/assertions/evidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import type { ServiceResponse } from '@sensigo/realm';
2
+ /** Mock adapter responses keyed by operation name. */
3
+ export interface MockOperations {
4
+ [operation: string]: ServiceResponse;
5
+ }
6
+ /** A single test scenario loaded from a fixture YAML file. */
7
+ export interface TestFixture {
8
+ /** Human-readable fixture name, used in test output. */
9
+ name: string;
10
+ /** Params passed to start_run. */
11
+ params: Record<string, unknown>;
12
+ /**
13
+ * Mock adapter responses keyed by service name, then operation name.
14
+ * Example: { google_docs: { fetch_document: { status: 200, data: { text: '...' } } } }
15
+ */
16
+ mocks: Record<string, MockOperations>;
17
+ /**
18
+ * Pre-built agent responses keyed by step ID.
19
+ * Used by the dispatcher for steps with execution: agent.
20
+ */
21
+ agent_responses: Record<string, Record<string, unknown>>;
22
+ /**
23
+ * Ordered list of error messages to inject for an agent step before its real response is
24
+ * returned. The dispatcher returns each message as a WorkflowError in order, one per call.
25
+ * Once all errors are exhausted the step receives its normal `agent_responses` entry.
26
+ *
27
+ * The test runner automatically resets the run state after each injected error (simulating
28
+ * what `realm run resume --from <step>` does interactively), then retries the step.
29
+ *
30
+ * Example:
31
+ * agent_errors:
32
+ * tag_content:
33
+ * - "provider timed out after 30s"
34
+ */
35
+ agent_errors?: Record<string, string[]>;
36
+ /**
37
+ * Gate choices keyed by step name. Defaults to 'approve' for any step not listed.
38
+ */
39
+ gate_responses?: Record<string, string>;
40
+ expected: {
41
+ /** Expected state of the run after driving it to completion. */
42
+ final_state: string;
43
+ /**
44
+ * Optional exact set of step IDs expected in skipped_steps at run completion.
45
+ * Sorted before comparison — order does not matter. Set equality is enforced:
46
+ * any additional or missing step ID causes the fixture to fail.
47
+ */
48
+ skipped_steps?: string[];
49
+ /**
50
+ * Optional list of expected evidence entries. Each entry must match a snapshot
51
+ * in the run's evidence chain (by step_id and optionally status).
52
+ */
53
+ evidence?: Array<{
54
+ step_id: string;
55
+ status?: 'success' | 'error' | 'skipped';
56
+ }>;
57
+ };
58
+ }
59
+ /**
60
+ * Loads a TestFixture from a YAML file on disk.
61
+ * @throws Error on read failure or missing required fields.
62
+ */
63
+ export declare function loadFixtureFromFile(filePath: string): TestFixture;
64
+ /**
65
+ * Parses a YAML string into a TestFixture.
66
+ * @throws Error if required fields (name, expected.final_state) are missing.
67
+ */
68
+ export declare function loadFixtureFromString(content: string): TestFixture;
69
+ /**
70
+ * Loads all *.yaml files from dirPath and returns them as TestFixture[].
71
+ * @throws Error if dirPath does not exist.
72
+ */
73
+ export declare function loadFixturesFromDir(dirPath: string): TestFixture[];
74
+ //# sourceMappingURL=fixture-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture-loader.d.ts","sourceRoot":"","sources":["../../src/fixtures/fixture-loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC;CACtC;AAED,8DAA8D;AAC9D,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACtC;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzD;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACxC;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,QAAQ,EAAE;QACR,gEAAgE;QAChE,WAAW,EAAE,MAAM,CAAC;QACpB;;;;WAIG;QACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB;;;WAGG;QACH,QAAQ,CAAC,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;SAAE,CAAC,CAAC;KACjF,CAAC;CACH;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAGjE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CA2ClE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAMlE"}
@@ -0,0 +1,62 @@
1
+ // Fixture loader — reads and parses YAML test fixture files.
2
+ import { readFileSync, readdirSync, existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { load } from 'js-yaml';
5
+ /**
6
+ * Loads a TestFixture from a YAML file on disk.
7
+ * @throws Error on read failure or missing required fields.
8
+ */
9
+ export function loadFixtureFromFile(filePath) {
10
+ const content = readFileSync(filePath, 'utf8');
11
+ return loadFixtureFromString(content);
12
+ }
13
+ /**
14
+ * Parses a YAML string into a TestFixture.
15
+ * @throws Error if required fields (name, expected.final_state) are missing.
16
+ */
17
+ export function loadFixtureFromString(content) {
18
+ const parsed = load(content);
19
+ if (typeof parsed['name'] !== 'string' || parsed['name'].trim() === '') {
20
+ throw new Error('Fixture must have a non-empty string "name" field');
21
+ }
22
+ const expected = parsed['expected'];
23
+ if (expected === undefined || typeof expected['final_state'] !== 'string') {
24
+ throw new Error('Fixture must have an "expected.final_state" string field');
25
+ }
26
+ let expectedObj = { final_state: expected['final_state'] };
27
+ if (expected['skipped_steps'] !== undefined) {
28
+ expectedObj = { ...expectedObj, skipped_steps: expected['skipped_steps'] };
29
+ }
30
+ if (expected['evidence'] !== undefined) {
31
+ expectedObj = {
32
+ ...expectedObj,
33
+ evidence: expected['evidence'],
34
+ };
35
+ }
36
+ const base = {
37
+ name: parsed['name'],
38
+ params: parsed['params'] ?? {},
39
+ mocks: parsed['mocks'] ?? {},
40
+ agent_responses: parsed['agent_responses'] ?? {},
41
+ expected: expectedObj,
42
+ };
43
+ if (parsed['agent_errors'] !== undefined) {
44
+ base.agent_errors = parsed['agent_errors'];
45
+ }
46
+ if (parsed['gate_responses'] !== undefined) {
47
+ return { ...base, gate_responses: parsed['gate_responses'] };
48
+ }
49
+ return base;
50
+ }
51
+ /**
52
+ * Loads all *.yaml files from dirPath and returns them as TestFixture[].
53
+ * @throws Error if dirPath does not exist.
54
+ */
55
+ export function loadFixturesFromDir(dirPath) {
56
+ if (!existsSync(dirPath)) {
57
+ throw new Error(`Fixture directory does not exist: ${dirPath}`);
58
+ }
59
+ const files = readdirSync(dirPath).filter((f) => f.endsWith('.yaml') || f.endsWith('.yml'));
60
+ return files.map((f) => loadFixtureFromFile(join(dirPath, f)));
61
+ }
62
+ //# sourceMappingURL=fixture-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture-loader.js","sourceRoot":"","sources":["../../src/fixtures/fixture-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ServiceAdapter, ServiceResponse } from '@sensigo/realm';
2
+ /**
3
+ * Calls adapter.fetch(operation, params, {}) and returns the response.
4
+ * params defaults to {} if not provided.
5
+ */
6
+ export declare function testAdapter(adapter: ServiceAdapter, operation: string, params?: Record<string, unknown>): Promise<ServiceResponse>;
7
+ //# sourceMappingURL=test-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-adapter.d.ts","sourceRoot":"","sources":["../../src/helpers/test-adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtE;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,eAAe,CAAC,CAE1B"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Calls adapter.fetch(operation, params, {}) and returns the response.
3
+ * params defaults to {} if not provided.
4
+ */
5
+ export async function testAdapter(adapter, operation, params) {
6
+ return adapter.fetch(operation, params ?? {}, {});
7
+ }
8
+ //# sourceMappingURL=test-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-adapter.js","sourceRoot":"","sources":["../../src/helpers/test-adapter.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAuB,EACvB,SAAiB,EACjB,MAAgC;IAEhC,OAAO,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Processor, ProcessorInput, ProcessorOutput } from '@sensigo/realm';
2
+ /**
3
+ * Calls processor.process(content, config) and returns the result.
4
+ * config defaults to {} if not provided.
5
+ */
6
+ export declare function testProcessor(processor: Processor, content: ProcessorInput, config?: Record<string, unknown>): Promise<ProcessorOutput>;
7
+ //# sourceMappingURL=test-processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-processor.d.ts","sourceRoot":"","sources":["../../src/helpers/test-processor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjF;;;GAGG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,cAAc,EACvB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,eAAe,CAAC,CAE1B"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Calls processor.process(content, config) and returns the result.
3
+ * config defaults to {} if not provided.
4
+ */
5
+ export async function testProcessor(processor, content, config) {
6
+ return processor.process(content, config ?? {});
7
+ }
8
+ //# sourceMappingURL=test-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-processor.js","sourceRoot":"","sources":["../../src/helpers/test-processor.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,SAAoB,EACpB,OAAuB,EACvB,MAAgC;IAEhC,OAAO,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { StepHandler, StepHandlerInputs, StepContext, StepHandlerResult } from '@sensigo/realm';
2
+ /**
3
+ * Calls handler.execute(inputs, context) and returns the result.
4
+ * context defaults to { run_id: 'test-run', run_params: {}, config: {} } if not provided.
5
+ */
6
+ export declare function testStepHandler(handler: StepHandler, inputs: StepHandlerInputs, context?: Partial<StepContext>): Promise<StepHandlerResult>;
7
+ //# sourceMappingURL=test-step-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-step-handler.d.ts","sourceRoot":"","sources":["../../src/helpers/test-step-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,iBAAiB,EACzB,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC7B,OAAO,CAAC,iBAAiB,CAAC,CAQ5B"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Calls handler.execute(inputs, context) and returns the result.
3
+ * context defaults to { run_id: 'test-run', run_params: {}, config: {} } if not provided.
4
+ */
5
+ export async function testStepHandler(handler, inputs, context) {
6
+ const fullContext = {
7
+ run_id: 'test-run',
8
+ run_params: {},
9
+ config: {},
10
+ ...context,
11
+ };
12
+ return handler.execute(inputs, fullContext);
13
+ }
14
+ //# sourceMappingURL=test-step-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-step-handler.js","sourceRoot":"","sources":["../../src/helpers/test-step-handler.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAoB,EACpB,MAAyB,EACzB,OAA8B;IAE9B,MAAM,WAAW,GAAgB;QAC/B,MAAM,EAAE,UAAU;QAClB,UAAU,EAAE,EAAE;QACd,MAAM,EAAE,EAAE;QACV,GAAG,OAAO;KACX,CAAC;IACF,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,16 @@
1
+ export { InMemoryStore } from './store/in-memory-store.js';
2
+ export { loadFixtureFromFile, loadFixtureFromString, loadFixturesFromDir, } from './fixtures/fixture-loader.js';
3
+ export type { TestFixture, MockOperations } from './fixtures/fixture-loader.js';
4
+ export { MockServiceRecorder } from './mocks/mock-service.js';
5
+ export type { RecordedCall } from './mocks/mock-service.js';
6
+ export { createAgentDispatcher } from './mocks/mock-agent.js';
7
+ export { createGateResponder } from './mocks/mock-gate.js';
8
+ export { assertFinalState, assertStepSucceeded, assertStepFailed, assertStepOutput, assertEvidenceHash, } from './assertions/evidence.js';
9
+ export { testStepHandler } from './helpers/test-step-handler.js';
10
+ export { testAdapter } from './helpers/test-adapter.js';
11
+ export { runFixtureTests } from './runner/test-runner.js';
12
+ export type { TestResult, RunFixtureTestsOptions } from './runner/test-runner.js';
13
+ export { startGitHubMockServer } from './servers/github-mock-server.js';
14
+ export type { GitHubMockServerHandle } from './servers/github-mock-server.js';
15
+ export declare const VERSION = "0.1.0";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAGhF,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAGxD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAGlF,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,YAAY,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE9E,eAAO,MAAM,OAAO,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ // @sensigo/realm-testing — testing utilities for Realm workflows
2
+ // Store
3
+ export { InMemoryStore } from './store/in-memory-store.js';
4
+ // Fixtures
5
+ export { loadFixtureFromFile, loadFixtureFromString, loadFixturesFromDir, } from './fixtures/fixture-loader.js';
6
+ // Mocks
7
+ export { MockServiceRecorder } from './mocks/mock-service.js';
8
+ export { createAgentDispatcher } from './mocks/mock-agent.js';
9
+ export { createGateResponder } from './mocks/mock-gate.js';
10
+ // Assertions
11
+ export { assertFinalState, assertStepSucceeded, assertStepFailed, assertStepOutput, assertEvidenceHash, } from './assertions/evidence.js';
12
+ // Unit test helpers
13
+ export { testStepHandler } from './helpers/test-step-handler.js';
14
+ export { testAdapter } from './helpers/test-adapter.js';
15
+ // Runner
16
+ export { runFixtureTests } from './runner/test-runner.js';
17
+ // Servers
18
+ export { startGitHubMockServer } from './servers/github-mock-server.js';
19
+ export const VERSION = '0.1.0';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iEAAiE;AAEjE,QAAQ;AACR,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE3D,WAAW;AACX,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AAGtC,QAAQ;AACR,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,aAAa;AACb,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAElC,oBAAoB;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,SAAS;AACT,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,UAAU;AACV,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAGxE,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { type StepDispatcher, type WorkflowDefinition, type ExtensionRegistry } from '@sensigo/realm';
2
+ /**
3
+ * Creates a StepDispatcher for use in tests.
4
+ *
5
+ * Dispatch priority per step:
6
+ * 1. execution: 'agent' → injects errors from agentErrors[stepName] in call order before
7
+ * returning agentResponses[stepName]; throws ENGINE_HANDLER_FAILED if response is absent
8
+ * 2. handler → calls handler.execute() from registry (or fallbackRegistry); throws if not found
9
+ * 3. uses_service → calls adapter.fetch() from registry (or fallbackRegistry); throws if not found
10
+ * 4. none of the above → returns {}
11
+ *
12
+ * If stepDef is undefined (step name not in definition), returns {} without throwing.
13
+ *
14
+ * @param agentErrors Optional map of step name → ordered error messages. The dispatcher
15
+ * returns each error as a WorkflowError on successive calls to that step before falling
16
+ * through to the normal agentResponses entry.
17
+ * @param fallbackRegistry Optional secondary registry searched when the primary registry
18
+ * has no match. Useful for merging per-fixture mock adapters with caller-provided handlers.
19
+ */
20
+ export declare function createAgentDispatcher(definition: WorkflowDefinition, registry: ExtensionRegistry, agentResponses: Record<string, Record<string, unknown>>, fallbackRegistry?: ExtensionRegistry, agentErrors?: Record<string, string[]>): StepDispatcher;
21
+ //# sourceMappingURL=mock-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-agent.d.ts","sourceRoot":"","sources":["../../src/mocks/mock-agent.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,kBAAkB,EAC9B,QAAQ,EAAE,iBAAiB,EAC3B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACvD,gBAAgB,CAAC,EAAE,iBAAiB,EACpC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GACrC,cAAc,CAoFhB"}
@@ -0,0 +1,85 @@
1
+ // createAgentDispatcher — test dispatcher using pre-built responses and registry lookups.
2
+ import { WorkflowError, } from '@sensigo/realm';
3
+ /**
4
+ * Creates a StepDispatcher for use in tests.
5
+ *
6
+ * Dispatch priority per step:
7
+ * 1. execution: 'agent' → injects errors from agentErrors[stepName] in call order before
8
+ * returning agentResponses[stepName]; throws ENGINE_HANDLER_FAILED if response is absent
9
+ * 2. handler → calls handler.execute() from registry (or fallbackRegistry); throws if not found
10
+ * 3. uses_service → calls adapter.fetch() from registry (or fallbackRegistry); throws if not found
11
+ * 4. none of the above → returns {}
12
+ *
13
+ * If stepDef is undefined (step name not in definition), returns {} without throwing.
14
+ *
15
+ * @param agentErrors Optional map of step name → ordered error messages. The dispatcher
16
+ * returns each error as a WorkflowError on successive calls to that step before falling
17
+ * through to the normal agentResponses entry.
18
+ * @param fallbackRegistry Optional secondary registry searched when the primary registry
19
+ * has no match. Useful for merging per-fixture mock adapters with caller-provided handlers.
20
+ */
21
+ export function createAgentDispatcher(definition, registry, agentResponses, fallbackRegistry, agentErrors) {
22
+ // Tracks how many times each agent step has been called within this dispatcher instance.
23
+ const callCounts = {};
24
+ return async (stepName, input, run) => {
25
+ const stepDef = definition.steps[stepName];
26
+ if (stepDef === undefined) {
27
+ return {};
28
+ }
29
+ if (stepDef.execution === 'agent') {
30
+ const callIndex = callCounts[stepName] ?? 0;
31
+ callCounts[stepName] = callIndex + 1;
32
+ const errorQueue = agentErrors?.[stepName];
33
+ if (errorQueue !== undefined && callIndex < errorQueue.length) {
34
+ throw new WorkflowError(errorQueue[callIndex], {
35
+ code: 'ENGINE_HANDLER_FAILED',
36
+ category: 'ENGINE',
37
+ agentAction: 'stop',
38
+ retryable: false,
39
+ });
40
+ }
41
+ const response = agentResponses[stepName];
42
+ if (response === undefined) {
43
+ throw new WorkflowError(`createAgentDispatcher: no pre-built response for agent step '${stepName}'`, {
44
+ code: 'ENGINE_HANDLER_FAILED',
45
+ category: 'ENGINE',
46
+ agentAction: 'report_to_user',
47
+ retryable: false,
48
+ });
49
+ }
50
+ return response;
51
+ }
52
+ if (stepDef.handler !== undefined) {
53
+ const handler = registry.getHandler(stepDef.handler) ?? fallbackRegistry?.getHandler(stepDef.handler);
54
+ if (handler === undefined) {
55
+ throw new WorkflowError(`createAgentDispatcher: no handler registered for '${stepDef.handler}'`, {
56
+ code: 'ENGINE_HANDLER_FAILED',
57
+ category: 'ENGINE',
58
+ agentAction: 'report_to_user',
59
+ retryable: false,
60
+ });
61
+ }
62
+ const result = await handler.execute({ params: input }, { run_id: run.id, run_params: run.params, config: {} });
63
+ return result.data;
64
+ }
65
+ if (stepDef.uses_service !== undefined) {
66
+ const serviceDef = definition.services?.[stepDef.uses_service];
67
+ const adapterId = serviceDef?.adapter;
68
+ const adapter = adapterId !== undefined
69
+ ? (registry.getAdapter(adapterId) ?? fallbackRegistry?.getAdapter(adapterId))
70
+ : undefined;
71
+ if (adapter === undefined) {
72
+ throw new WorkflowError(`createAgentDispatcher: no adapter registered for service '${stepDef.uses_service}'`, {
73
+ code: 'ENGINE_ADAPTER_FAILED',
74
+ category: 'ENGINE',
75
+ agentAction: 'report_to_user',
76
+ retryable: false,
77
+ });
78
+ }
79
+ const resp = await adapter.fetch(stepName, input, {});
80
+ return resp.data;
81
+ }
82
+ return {};
83
+ };
84
+ }
85
+ //# sourceMappingURL=mock-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-agent.js","sourceRoot":"","sources":["../../src/mocks/mock-agent.ts"],"names":[],"mappings":"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"}