@jamesaphoenix/tx-test-utils 0.4.2

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 (101) hide show
  1. package/dist/database/index.d.ts +8 -0
  2. package/dist/database/index.d.ts.map +1 -0
  3. package/dist/database/index.js +7 -0
  4. package/dist/database/index.js.map +1 -0
  5. package/dist/database/test-database.d.ts +101 -0
  6. package/dist/database/test-database.d.ts.map +1 -0
  7. package/dist/database/test-database.js +130 -0
  8. package/dist/database/test-database.js.map +1 -0
  9. package/dist/factories/anchor.factory.d.ts +117 -0
  10. package/dist/factories/anchor.factory.d.ts.map +1 -0
  11. package/dist/factories/anchor.factory.js +201 -0
  12. package/dist/factories/anchor.factory.js.map +1 -0
  13. package/dist/factories/candidate.factory.d.ts +151 -0
  14. package/dist/factories/candidate.factory.d.ts.map +1 -0
  15. package/dist/factories/candidate.factory.js +194 -0
  16. package/dist/factories/candidate.factory.js.map +1 -0
  17. package/dist/factories/edge.factory.d.ts +119 -0
  18. package/dist/factories/edge.factory.d.ts.map +1 -0
  19. package/dist/factories/edge.factory.js +191 -0
  20. package/dist/factories/edge.factory.js.map +1 -0
  21. package/dist/factories/factories.test.d.ts +8 -0
  22. package/dist/factories/factories.test.d.ts.map +1 -0
  23. package/dist/factories/factories.test.js +419 -0
  24. package/dist/factories/factories.test.js.map +1 -0
  25. package/dist/factories/index.d.ts +15 -0
  26. package/dist/factories/index.d.ts.map +1 -0
  27. package/dist/factories/index.js +21 -0
  28. package/dist/factories/index.js.map +1 -0
  29. package/dist/factories/learning.factory.d.ts +107 -0
  30. package/dist/factories/learning.factory.d.ts.map +1 -0
  31. package/dist/factories/learning.factory.js +150 -0
  32. package/dist/factories/learning.factory.js.map +1 -0
  33. package/dist/factories/task.factory.d.ts +106 -0
  34. package/dist/factories/task.factory.d.ts.map +1 -0
  35. package/dist/factories/task.factory.js +151 -0
  36. package/dist/factories/task.factory.js.map +1 -0
  37. package/dist/fixtures/index.d.ts +36 -0
  38. package/dist/fixtures/index.d.ts.map +1 -0
  39. package/dist/fixtures/index.js +47 -0
  40. package/dist/fixtures/index.js.map +1 -0
  41. package/dist/helpers/effect.d.ts +186 -0
  42. package/dist/helpers/effect.d.ts.map +1 -0
  43. package/dist/helpers/effect.js +298 -0
  44. package/dist/helpers/effect.js.map +1 -0
  45. package/dist/helpers/effect.test.d.ts +7 -0
  46. package/dist/helpers/effect.test.d.ts.map +1 -0
  47. package/dist/helpers/effect.test.js +271 -0
  48. package/dist/helpers/effect.test.js.map +1 -0
  49. package/dist/helpers/index.d.ts +7 -0
  50. package/dist/helpers/index.d.ts.map +1 -0
  51. package/dist/helpers/index.js +11 -0
  52. package/dist/helpers/index.js.map +1 -0
  53. package/dist/index.d.ts +26 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +52 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/llm-cache/cache.d.ts +152 -0
  58. package/dist/llm-cache/cache.d.ts.map +1 -0
  59. package/dist/llm-cache/cache.js +199 -0
  60. package/dist/llm-cache/cache.js.map +1 -0
  61. package/dist/llm-cache/cache.test.d.ts +7 -0
  62. package/dist/llm-cache/cache.test.d.ts.map +1 -0
  63. package/dist/llm-cache/cache.test.js +310 -0
  64. package/dist/llm-cache/cache.test.js.map +1 -0
  65. package/dist/llm-cache/cli.d.ts +113 -0
  66. package/dist/llm-cache/cli.d.ts.map +1 -0
  67. package/dist/llm-cache/cli.js +248 -0
  68. package/dist/llm-cache/cli.js.map +1 -0
  69. package/dist/llm-cache/index.d.ts +31 -0
  70. package/dist/llm-cache/index.d.ts.map +1 -0
  71. package/dist/llm-cache/index.js +31 -0
  72. package/dist/llm-cache/index.js.map +1 -0
  73. package/dist/mocks/anthropic.mock.d.ts +173 -0
  74. package/dist/mocks/anthropic.mock.d.ts.map +1 -0
  75. package/dist/mocks/anthropic.mock.js +125 -0
  76. package/dist/mocks/anthropic.mock.js.map +1 -0
  77. package/dist/mocks/ast-grep.mock.d.ts +216 -0
  78. package/dist/mocks/ast-grep.mock.d.ts.map +1 -0
  79. package/dist/mocks/ast-grep.mock.js +164 -0
  80. package/dist/mocks/ast-grep.mock.js.map +1 -0
  81. package/dist/mocks/file-system.mock.d.ts +181 -0
  82. package/dist/mocks/file-system.mock.d.ts.map +1 -0
  83. package/dist/mocks/file-system.mock.js +280 -0
  84. package/dist/mocks/file-system.mock.js.map +1 -0
  85. package/dist/mocks/index.d.ts +10 -0
  86. package/dist/mocks/index.d.ts.map +1 -0
  87. package/dist/mocks/index.js +16 -0
  88. package/dist/mocks/index.js.map +1 -0
  89. package/dist/mocks/mocks.test.d.ts +10 -0
  90. package/dist/mocks/mocks.test.d.ts.map +1 -0
  91. package/dist/mocks/mocks.test.js +961 -0
  92. package/dist/mocks/mocks.test.js.map +1 -0
  93. package/dist/mocks/openai.mock.d.ts +205 -0
  94. package/dist/mocks/openai.mock.d.ts.map +1 -0
  95. package/dist/mocks/openai.mock.js +178 -0
  96. package/dist/mocks/openai.mock.js.map +1 -0
  97. package/dist/setup/index.d.ts +7 -0
  98. package/dist/setup/index.d.ts.map +1 -0
  99. package/dist/setup/index.js +9 -0
  100. package/dist/setup/index.js.map +1 -0
  101. package/package.json +80 -0
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Effect-TS test helpers for running and asserting on Effects.
3
+ *
4
+ * Provides convenient utilities for testing Effect-based code with
5
+ * proper Layer injection support.
6
+ *
7
+ * @module @tx/test-utils/helpers/effect
8
+ */
9
+ import { Effect, Cause, Layer, Either } from "effect";
10
+ /**
11
+ * Options for running Effects in tests.
12
+ */
13
+ export interface RunEffectOptions {
14
+ /** Timeout in milliseconds (default: 5000) */
15
+ timeout?: number;
16
+ }
17
+ /**
18
+ * Result of running an Effect with Either semantics.
19
+ */
20
+ export type EffectResult<A, E> = Either.Either<A, E>;
21
+ /**
22
+ * Run an Effect and return the result.
23
+ * Throws an error if the Effect fails.
24
+ *
25
+ * Supports Layer injection for dependency testing.
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * // Without layers
30
+ * const result = await runEffect(Effect.succeed(42))
31
+ * expect(result).toBe(42)
32
+ *
33
+ * // With single layer
34
+ * const result = await runEffect(myService.getData(), TestServiceLayer)
35
+ *
36
+ * // With multiple layers (merged)
37
+ * const result = await runEffect(
38
+ * myService.getData(),
39
+ * Layer.merge(TestDatabaseLayer, TestConfigLayer)
40
+ * )
41
+ * ```
42
+ */
43
+ export declare const runEffect: <A, E, R>(effect: Effect.Effect<A, E, R>, layer?: Layer.Layer<R, E, never>, options?: RunEffectOptions) => Promise<A>;
44
+ /**
45
+ * Run an Effect and expect it to fail.
46
+ * Throws if the Effect succeeds.
47
+ * Returns the failure cause for inspection.
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const cause = await runEffectFail(
52
+ * TaskService.get('nonexistent'),
53
+ * TestLayer
54
+ * )
55
+ *
56
+ * expect(Cause.isFailType(cause)).toBe(true)
57
+ * ```
58
+ */
59
+ export declare const runEffectFail: <A, E, R>(effect: Effect.Effect<A, E, R>, layer?: Layer.Layer<R, E, never>, options?: RunEffectOptions) => Promise<Cause.Cause<E>>;
60
+ /**
61
+ * Run an Effect and return an Either (success or failure).
62
+ * Never throws - always returns a result.
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * const result = await runEffectEither(myEffect, TestLayer)
67
+ *
68
+ * if (Either.isRight(result)) {
69
+ * console.log('Success:', result.right)
70
+ * } else {
71
+ * console.log('Failed:', result.left)
72
+ * }
73
+ * ```
74
+ */
75
+ export declare const runEffectEither: <A, E, R>(effect: Effect.Effect<A, E, R>, layer?: Layer.Layer<R, E, never>, options?: RunEffectOptions) => Promise<Either.Either<A, E>>;
76
+ /**
77
+ * Assert that an Effect succeeds and optionally validate the result.
78
+ * Returns the success value for further assertions.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * // Basic success assertion
83
+ * const result = await expectEffectSuccess(myEffect, TestLayer)
84
+ *
85
+ * // With value validation
86
+ * const result = await expectEffectSuccess(
87
+ * myEffect,
88
+ * TestLayer,
89
+ * (value) => {
90
+ * expect(value.id).toBeDefined()
91
+ * }
92
+ * )
93
+ * ```
94
+ */
95
+ export declare const expectEffectSuccess: <A, E, R>(effect: Effect.Effect<A, E, R>, layer?: Layer.Layer<R, E, never>, validate?: (value: A) => void | Promise<void>) => Promise<A>;
96
+ /**
97
+ * Assert that an Effect fails with a specific error type.
98
+ * Returns the error for further assertions.
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * // Basic failure assertion
103
+ * const error = await expectEffectFailure(
104
+ * TaskService.get('nonexistent'),
105
+ * TestLayer
106
+ * )
107
+ *
108
+ * // With error type checking (using _tag for TaggedError)
109
+ * const error = await expectEffectFailure(
110
+ * TaskService.get('nonexistent'),
111
+ * TestLayer,
112
+ * (err) => {
113
+ * expect(err._tag).toBe('TaskNotFoundError')
114
+ * }
115
+ * )
116
+ *
117
+ * // Type-safe error extraction
118
+ * const error = await expectEffectFailure<TaskNotFoundError>(
119
+ * TaskService.get('nonexistent'),
120
+ * TestLayer,
121
+ * (err) => {
122
+ * expect(err.id).toBe('nonexistent')
123
+ * }
124
+ * )
125
+ * ```
126
+ */
127
+ export declare const expectEffectFailure: <E, A = unknown, R = never>(effect: Effect.Effect<A, E, R>, layer?: Layer.Layer<R, E, never>, validate?: (error: E) => void | Promise<void>) => Promise<E>;
128
+ /**
129
+ * Merge multiple layers into a single layer.
130
+ * Convenience wrapper around Layer.mergeAll for test setup.
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * const testLayer = mergeLayers(
135
+ * TestDatabaseLayer,
136
+ * MockServiceLayer,
137
+ * TestConfigLayer
138
+ * )
139
+ *
140
+ * const result = await runEffect(myEffect, testLayer)
141
+ * ```
142
+ */
143
+ export declare const mergeLayers: <Layers extends readonly Layer.Layer<any, any, any>[]>(...layers: Layers) => Layer.Layer<Layer.Layer.Success<Layers[number]>, Layer.Layer.Error<Layers[number]>, Layer.Layer.Context<Layers[number]>>;
144
+ /**
145
+ * Create a test context that automatically cleans up after each test.
146
+ * Useful for setting up database and services that need cleanup.
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * import { createTestContext } from '@tx/test-utils'
151
+ *
152
+ * describe('MyService', () => {
153
+ * const ctx = createTestContext(() =>
154
+ * mergeLayers(TestDatabaseLayer, MockServiceLayer)
155
+ * )
156
+ *
157
+ * it('should do something', async () => {
158
+ * const result = await ctx.runEffect(myService.getData())
159
+ * expect(result).toBeDefined()
160
+ * })
161
+ * })
162
+ * ```
163
+ */
164
+ export declare const createTestContext: <R, E>(createLayer: () => Layer.Layer<R, E, never>) => {
165
+ /**
166
+ * Get the current layer, creating it if needed.
167
+ */
168
+ getLayer: () => Layer.Layer<R, E, never>;
169
+ /**
170
+ * Run an Effect with the test layer.
171
+ */
172
+ runEffect: <A, EE extends E>(effect: Effect.Effect<A, EE, R>, options?: RunEffectOptions) => Promise<A>;
173
+ /**
174
+ * Run an Effect and expect failure.
175
+ */
176
+ runEffectFail: <A, EE_1 extends E>(effect: Effect.Effect<A, EE_1, R>, options?: RunEffectOptions) => Promise<Cause.Cause<EE_1>>;
177
+ /**
178
+ * Run an Effect and return Either.
179
+ */
180
+ runEffectEither: <A, EE_2 extends E>(effect: Effect.Effect<A, EE_2, R>, options?: RunEffectOptions) => Promise<Either.Either<A, EE_2>>;
181
+ /**
182
+ * Reset the layer (forces recreation on next use).
183
+ */
184
+ reset: () => void;
185
+ };
186
+ //# sourceMappingURL=effect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../src/helpers/effect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Effect-TS test helpers for running and asserting on Effects.
3
+ *
4
+ * Provides convenient utilities for testing Effect-based code with
5
+ * proper Layer injection support.
6
+ *
7
+ * @module @tx/test-utils/helpers/effect
8
+ */
9
+ import { Effect, Exit, Cause, Layer, Either, pipe, Chunk, Option } from "effect";
10
+ // =============================================================================
11
+ // Effect Runners
12
+ // =============================================================================
13
+ /**
14
+ * Run an Effect and return the result.
15
+ * Throws an error if the Effect fails.
16
+ *
17
+ * Supports Layer injection for dependency testing.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * // Without layers
22
+ * const result = await runEffect(Effect.succeed(42))
23
+ * expect(result).toBe(42)
24
+ *
25
+ * // With single layer
26
+ * const result = await runEffect(myService.getData(), TestServiceLayer)
27
+ *
28
+ * // With multiple layers (merged)
29
+ * const result = await runEffect(
30
+ * myService.getData(),
31
+ * Layer.merge(TestDatabaseLayer, TestConfigLayer)
32
+ * )
33
+ * ```
34
+ */
35
+ export const runEffect = async (effect, layer, options = {}) => {
36
+ const { timeout = 5000 } = options;
37
+ const runnable = layer
38
+ ? pipe(effect, Effect.provide(layer))
39
+ : effect;
40
+ const withTimeout = pipe(runnable, Effect.timeoutFail({
41
+ duration: timeout,
42
+ onTimeout: () => new Error(`Effect timed out after ${timeout}ms`)
43
+ }));
44
+ const exit = await Effect.runPromiseExit(withTimeout);
45
+ if (Exit.isFailure(exit)) {
46
+ const cause = exit.cause;
47
+ const prettyError = Cause.pretty(cause);
48
+ throw new Error(`Effect failed:\n${prettyError}`);
49
+ }
50
+ return exit.value;
51
+ };
52
+ /**
53
+ * Run an Effect and expect it to fail.
54
+ * Throws if the Effect succeeds.
55
+ * Returns the failure cause for inspection.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const cause = await runEffectFail(
60
+ * TaskService.get('nonexistent'),
61
+ * TestLayer
62
+ * )
63
+ *
64
+ * expect(Cause.isFailType(cause)).toBe(true)
65
+ * ```
66
+ */
67
+ export const runEffectFail = async (effect, layer, options = {}) => {
68
+ const { timeout = 5000 } = options;
69
+ const runnable = layer
70
+ ? pipe(effect, Effect.provide(layer))
71
+ : effect;
72
+ const withTimeout = pipe(runnable, Effect.timeoutFail({
73
+ duration: timeout,
74
+ onTimeout: () => new Error(`Effect timed out after ${timeout}ms`)
75
+ }));
76
+ const exit = await Effect.runPromiseExit(withTimeout);
77
+ if (Exit.isSuccess(exit)) {
78
+ throw new Error(`Expected Effect to fail, but it succeeded with: ${JSON.stringify(exit.value)}`);
79
+ }
80
+ // Cast to remove the timeout error from the cause type since we handle it above
81
+ return exit.cause;
82
+ };
83
+ /**
84
+ * Run an Effect and return an Either (success or failure).
85
+ * Never throws - always returns a result.
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const result = await runEffectEither(myEffect, TestLayer)
90
+ *
91
+ * if (Either.isRight(result)) {
92
+ * console.log('Success:', result.right)
93
+ * } else {
94
+ * console.log('Failed:', result.left)
95
+ * }
96
+ * ```
97
+ */
98
+ export const runEffectEither = async (effect, layer, options = {}) => {
99
+ const { timeout = 5000 } = options;
100
+ const runnable = layer
101
+ ? pipe(effect, Effect.provide(layer))
102
+ : effect;
103
+ const withTimeout = pipe(runnable, Effect.timeoutFail({
104
+ duration: timeout,
105
+ onTimeout: () => new Error(`Effect timed out after ${timeout}ms`)
106
+ }));
107
+ const exit = await Effect.runPromiseExit(withTimeout);
108
+ if (Exit.isFailure(exit)) {
109
+ // Extract the first failure from the cause
110
+ const failures = Cause.failures(exit.cause);
111
+ const firstFailureOption = Chunk.head(failures);
112
+ if (Option.isSome(firstFailureOption)) {
113
+ return Either.left(firstFailureOption.value);
114
+ }
115
+ // If no typed failure, check for defects or interrupts
116
+ const defects = Cause.defects(exit.cause);
117
+ const defectsArray = Chunk.toArray(defects);
118
+ if (defectsArray.length > 0) {
119
+ throw defectsArray[0];
120
+ }
121
+ throw new Error(`Effect failed with unexpected cause: ${Cause.pretty(exit.cause)}`);
122
+ }
123
+ return Either.right(exit.value);
124
+ };
125
+ // =============================================================================
126
+ // Effect Assertions
127
+ // =============================================================================
128
+ /**
129
+ * Assert that an Effect succeeds and optionally validate the result.
130
+ * Returns the success value for further assertions.
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * // Basic success assertion
135
+ * const result = await expectEffectSuccess(myEffect, TestLayer)
136
+ *
137
+ * // With value validation
138
+ * const result = await expectEffectSuccess(
139
+ * myEffect,
140
+ * TestLayer,
141
+ * (value) => {
142
+ * expect(value.id).toBeDefined()
143
+ * }
144
+ * )
145
+ * ```
146
+ */
147
+ export const expectEffectSuccess = async (effect, layer, validate) => {
148
+ const result = await runEffect(effect, layer);
149
+ if (validate) {
150
+ await validate(result);
151
+ }
152
+ return result;
153
+ };
154
+ /**
155
+ * Assert that an Effect fails with a specific error type.
156
+ * Returns the error for further assertions.
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * // Basic failure assertion
161
+ * const error = await expectEffectFailure(
162
+ * TaskService.get('nonexistent'),
163
+ * TestLayer
164
+ * )
165
+ *
166
+ * // With error type checking (using _tag for TaggedError)
167
+ * const error = await expectEffectFailure(
168
+ * TaskService.get('nonexistent'),
169
+ * TestLayer,
170
+ * (err) => {
171
+ * expect(err._tag).toBe('TaskNotFoundError')
172
+ * }
173
+ * )
174
+ *
175
+ * // Type-safe error extraction
176
+ * const error = await expectEffectFailure<TaskNotFoundError>(
177
+ * TaskService.get('nonexistent'),
178
+ * TestLayer,
179
+ * (err) => {
180
+ * expect(err.id).toBe('nonexistent')
181
+ * }
182
+ * )
183
+ * ```
184
+ */
185
+ export const expectEffectFailure = async (effect, layer, validate) => {
186
+ const cause = await runEffectFail(effect, layer);
187
+ // Extract the first typed failure
188
+ const failures = Cause.failures(cause);
189
+ const firstFailureOption = Chunk.head(failures);
190
+ if (Option.isNone(firstFailureOption)) {
191
+ throw new Error(`Expected a typed failure but got: ${Cause.pretty(cause)}`);
192
+ }
193
+ const firstFailure = firstFailureOption.value;
194
+ if (validate) {
195
+ await validate(firstFailure);
196
+ }
197
+ return firstFailure;
198
+ };
199
+ // =============================================================================
200
+ // Layer Utilities
201
+ // =============================================================================
202
+ /**
203
+ * Merge multiple layers into a single layer.
204
+ * Convenience wrapper around Layer.mergeAll for test setup.
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * const testLayer = mergeLayers(
209
+ * TestDatabaseLayer,
210
+ * MockServiceLayer,
211
+ * TestConfigLayer
212
+ * )
213
+ *
214
+ * const result = await runEffect(myEffect, testLayer)
215
+ * ```
216
+ */
217
+ export const mergeLayers = (...layers) => {
218
+ if (layers.length === 0) {
219
+ return Layer.empty;
220
+ }
221
+ if (layers.length === 1) {
222
+ return layers[0];
223
+ }
224
+ // Use explicit type to handle the reduce properly
225
+ let result = layers[0];
226
+ for (let i = 1; i < layers.length; i++) {
227
+ result = Layer.merge(result, layers[i]);
228
+ }
229
+ return result;
230
+ };
231
+ /**
232
+ * Create a test context that automatically cleans up after each test.
233
+ * Useful for setting up database and services that need cleanup.
234
+ *
235
+ * @example
236
+ * ```typescript
237
+ * import { createTestContext } from '@tx/test-utils'
238
+ *
239
+ * describe('MyService', () => {
240
+ * const ctx = createTestContext(() =>
241
+ * mergeLayers(TestDatabaseLayer, MockServiceLayer)
242
+ * )
243
+ *
244
+ * it('should do something', async () => {
245
+ * const result = await ctx.runEffect(myService.getData())
246
+ * expect(result).toBeDefined()
247
+ * })
248
+ * })
249
+ * ```
250
+ */
251
+ export const createTestContext = (createLayer) => {
252
+ let currentLayer = null;
253
+ return {
254
+ /**
255
+ * Get the current layer, creating it if needed.
256
+ */
257
+ getLayer: () => {
258
+ if (!currentLayer) {
259
+ currentLayer = createLayer();
260
+ }
261
+ return currentLayer;
262
+ },
263
+ /**
264
+ * Run an Effect with the test layer.
265
+ */
266
+ runEffect: (effect, options) => {
267
+ if (!currentLayer) {
268
+ currentLayer = createLayer();
269
+ }
270
+ return runEffect(effect, currentLayer, options);
271
+ },
272
+ /**
273
+ * Run an Effect and expect failure.
274
+ */
275
+ runEffectFail: (effect, options) => {
276
+ if (!currentLayer) {
277
+ currentLayer = createLayer();
278
+ }
279
+ return runEffectFail(effect, currentLayer, options);
280
+ },
281
+ /**
282
+ * Run an Effect and return Either.
283
+ */
284
+ runEffectEither: (effect, options) => {
285
+ if (!currentLayer) {
286
+ currentLayer = createLayer();
287
+ }
288
+ return runEffectEither(effect, currentLayer, options);
289
+ },
290
+ /**
291
+ * Reset the layer (forces recreation on next use).
292
+ */
293
+ reset: () => {
294
+ currentLayer = null;
295
+ }
296
+ };
297
+ };
298
+ //# sourceMappingURL=effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect.js","sourceRoot":"","sources":["../../src/helpers/effect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Effect test helpers unit tests.
3
+ *
4
+ * Tests the Effect runners and assertions for correct behavior.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=effect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect.test.d.ts","sourceRoot":"","sources":["../../src/helpers/effect.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}