@forgehive/task 0.1.6 → 0.1.8

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.
@@ -0,0 +1,314 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const schema_1 = require("@forgehive/schema");
4
+ const index_1 = require("../index");
5
+ describe('Complex boundary replay tests', () => {
6
+ // Test data
7
+ let priceData;
8
+ let portfolioData;
9
+ // Boundaries for the portfolio task
10
+ let boundaries;
11
+ // The task - using eslint-disable to allow any type for this test
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ let calculatePortfolioValue;
14
+ beforeEach(() => {
15
+ // Setup mock data
16
+ priceData = {
17
+ 'AAPL': 182.63,
18
+ 'MSFT': 421.90,
19
+ 'GOOGL': 171.04,
20
+ 'AMZN': 184.72
21
+ };
22
+ portfolioData = {
23
+ 'user1': {
24
+ id: 'portfolio1',
25
+ userId: 'user1',
26
+ stocks: [
27
+ { ticker: 'AAPL', quantity: 10 },
28
+ { ticker: 'MSFT', quantity: 5 },
29
+ { ticker: 'GOOGL', quantity: 8 }
30
+ ]
31
+ },
32
+ 'user2': {
33
+ id: 'portfolio2',
34
+ userId: 'user2',
35
+ stocks: [
36
+ { ticker: 'AMZN', quantity: 15 },
37
+ { ticker: 'MSFT', quantity: 3 }
38
+ ]
39
+ }
40
+ };
41
+ // Define boundaries with realistic functions
42
+ boundaries = {
43
+ fetchPrice: async (ticker) => {
44
+ // Check if we have a price for this ticker
45
+ if (!priceData[ticker]) {
46
+ throw new Error(`Price data not available for ticker: ${ticker}`);
47
+ }
48
+ return priceData[ticker];
49
+ },
50
+ fetchPortfolio: async (userId) => {
51
+ // Check if we have a portfolio for this user
52
+ if (!portfolioData[userId]) {
53
+ throw new Error(`Portfolio not found for user: ${userId}`);
54
+ }
55
+ return portfolioData[userId];
56
+ }
57
+ };
58
+ // Create a schema for the task
59
+ const schema = new schema_1.Schema({
60
+ userId: schema_1.Schema.string()
61
+ });
62
+ // Create the portfolio value calculation task
63
+ calculatePortfolioValue = (0, index_1.createTask)(schema, boundaries, async ({ userId }, { fetchPortfolio, fetchPrice }) => {
64
+ // First fetch the portfolio for the user
65
+ const portfolio = await fetchPortfolio(userId);
66
+ // Then calculate the value of each stock and the total portfolio value
67
+ const stocksWithValue = await Promise.all(portfolio.stocks.map(async (stock) => {
68
+ const price = await fetchPrice(stock.ticker);
69
+ const value = price * stock.quantity;
70
+ return {
71
+ ticker: stock.ticker,
72
+ quantity: stock.quantity,
73
+ price,
74
+ value
75
+ };
76
+ }));
77
+ // Calculate total value
78
+ const totalValue = stocksWithValue.reduce((sum, stock) => sum + stock.value, 0);
79
+ // Return portfolio value information
80
+ return {
81
+ id: portfolio.id,
82
+ userId: portfolio.userId,
83
+ totalValue,
84
+ stocks: stocksWithValue
85
+ };
86
+ });
87
+ });
88
+ it('Should calculate portfolio value using multiple boundaries', async () => {
89
+ // Run the task for user1
90
+ const result = await calculatePortfolioValue.run({ userId: 'user1' });
91
+ // Verify the structure of the result
92
+ expect(result).toHaveProperty('id', 'portfolio1');
93
+ expect(result).toHaveProperty('userId', 'user1');
94
+ expect(result).toHaveProperty('totalValue');
95
+ expect(result).toHaveProperty('stocks');
96
+ // Verify portfolio calculations
97
+ expect(result.stocks).toHaveLength(3);
98
+ // Calculate expected values
99
+ const expectedTotalValue = (priceData['AAPL'] * 10) +
100
+ (priceData['MSFT'] * 5) +
101
+ (priceData['GOOGL'] * 8);
102
+ // Verify total value matches expected
103
+ expect(result.totalValue).toBeCloseTo(expectedTotalValue);
104
+ // Verify each stock's value
105
+ const applStock = result.stocks.find((s) => s.ticker === 'AAPL');
106
+ expect(applStock).toBeDefined();
107
+ expect(applStock === null || applStock === void 0 ? void 0 : applStock.price).toBe(priceData['AAPL']);
108
+ expect(applStock === null || applStock === void 0 ? void 0 : applStock.value).toBeCloseTo(priceData['AAPL'] * 10);
109
+ const msftStock = result.stocks.find((s) => s.ticker === 'MSFT');
110
+ expect(msftStock).toBeDefined();
111
+ expect(msftStock === null || msftStock === void 0 ? void 0 : msftStock.price).toBe(priceData['MSFT']);
112
+ expect(msftStock === null || msftStock === void 0 ? void 0 : msftStock.value).toBeCloseTo(priceData['MSFT'] * 5);
113
+ const googlStock = result.stocks.find((s) => s.ticker === 'GOOGL');
114
+ expect(googlStock).toBeDefined();
115
+ expect(googlStock === null || googlStock === void 0 ? void 0 : googlStock.price).toBe(priceData['GOOGL']);
116
+ expect(googlStock === null || googlStock === void 0 ? void 0 : googlStock.value).toBeCloseTo(priceData['GOOGL'] * 8);
117
+ });
118
+ it('Should replay portfolio calculation from an execution log', async () => {
119
+ // First create a portfolio value calculation execution log
120
+ const executionLog = {
121
+ input: { userId: 'user1' },
122
+ output: {
123
+ id: 'portfolio1',
124
+ userId: 'user1',
125
+ totalValue: 4363.02,
126
+ stocks: [
127
+ { ticker: 'AAPL', quantity: 10, price: 190.50, value: 1905.00 },
128
+ { ticker: 'MSFT', quantity: 5, price: 405.75, value: 2028.75 },
129
+ { ticker: 'GOOGL', quantity: 8, price: 161.16, value: 429.27 }
130
+ ]
131
+ },
132
+ boundaries: {
133
+ fetchPortfolio: [
134
+ {
135
+ input: ['user1'],
136
+ output: {
137
+ id: 'portfolio1',
138
+ userId: 'user1',
139
+ stocks: [
140
+ { ticker: 'AAPL', quantity: 10 },
141
+ { ticker: 'MSFT', quantity: 5 },
142
+ { ticker: 'GOOGL', quantity: 8 }
143
+ ]
144
+ }
145
+ }
146
+ ],
147
+ fetchPrice: [
148
+ {
149
+ input: ['AAPL'],
150
+ output: 190.50
151
+ },
152
+ {
153
+ input: ['MSFT'],
154
+ output: 405.75
155
+ },
156
+ {
157
+ input: ['GOOGL'],
158
+ output: 161.16
159
+ }
160
+ ]
161
+ }
162
+ };
163
+ // Use replay mode for all boundaries
164
+ const [replayResult, replayError, replayLog] = await calculatePortfolioValue.safeReplay(executionLog, {
165
+ boundaries: {
166
+ fetchPortfolio: 'replay',
167
+ fetchPrice: 'replay'
168
+ }
169
+ });
170
+ // Verify there was no error
171
+ expect(replayError).toBeNull();
172
+ // Verify the replayed result
173
+ expect(replayResult).toHaveProperty('id', 'portfolio1');
174
+ expect(replayResult).toHaveProperty('userId', 'user1');
175
+ expect(replayResult).toHaveProperty('totalValue', 5223.03);
176
+ expect(replayResult).toHaveProperty('stocks');
177
+ expect(replayResult.stocks).toHaveLength(3);
178
+ // Check values match the execution log exactly
179
+ const applStock = replayResult.stocks.find((s) => s.ticker === 'AAPL');
180
+ expect(applStock === null || applStock === void 0 ? void 0 : applStock.price).toBe(190.50);
181
+ expect(applStock === null || applStock === void 0 ? void 0 : applStock.value).toBe(1905.00);
182
+ // Verify that boundary calls were properly replayed
183
+ expect(replayLog.boundaries.fetchPortfolio).toHaveLength(1);
184
+ expect(replayLog.boundaries.fetchPrice).toHaveLength(3);
185
+ });
186
+ it('Should handle errors during replay', async () => {
187
+ // Create an execution log with an error in one of the price fetches
188
+ const executionLog = {
189
+ input: { userId: 'user1' },
190
+ error: 'Price data not available for ticker: GOOGL',
191
+ boundaries: {
192
+ fetchPortfolio: [
193
+ {
194
+ input: ['user1'],
195
+ output: {
196
+ id: 'portfolio1',
197
+ userId: 'user1',
198
+ stocks: [
199
+ { ticker: 'AAPL', quantity: 10 },
200
+ { ticker: 'MSFT', quantity: 5 },
201
+ { ticker: 'GOOGL', quantity: 8 }
202
+ ]
203
+ }
204
+ }
205
+ ],
206
+ fetchPrice: [
207
+ {
208
+ input: ['AAPL'],
209
+ output: 190.50
210
+ },
211
+ {
212
+ input: ['MSFT'],
213
+ output: 405.75
214
+ },
215
+ {
216
+ input: ['GOOGL'],
217
+ error: 'Price data not available for ticker: GOOGL'
218
+ }
219
+ ]
220
+ }
221
+ };
222
+ // Use replay mode for all boundaries
223
+ const [replayResult, replayError, replayLog] = await calculatePortfolioValue.safeReplay(executionLog, {
224
+ boundaries: {
225
+ fetchPortfolio: 'replay',
226
+ fetchPrice: 'replay'
227
+ }
228
+ });
229
+ // Verify error was properly replayed
230
+ expect(replayResult).toBeNull();
231
+ expect(replayError).not.toBeNull();
232
+ expect(replayError === null || replayError === void 0 ? void 0 : replayError.message).toBe('Price data not available for ticker: GOOGL');
233
+ // Verify that boundary calls were properly replayed up to the error
234
+ expect(replayLog.boundaries.fetchPortfolio).toHaveLength(1);
235
+ expect(replayLog.boundaries.fetchPrice).toHaveLength(3);
236
+ // Check the error in the boundary
237
+ const googPriceCall = replayLog.boundaries.fetchPrice.find((call) => call.input && call.input[0] === 'GOOGL');
238
+ expect(googPriceCall).toBeDefined();
239
+ expect(googPriceCall === null || googPriceCall === void 0 ? void 0 : googPriceCall.error).toBe('Price data not available for ticker: GOOGL');
240
+ });
241
+ it('Should support mixed replay with some boundaries in replay mode and others in proxy mode', async () => {
242
+ // Update prices for the test
243
+ priceData['AAPL'] = 195.00; // Different from replay data
244
+ // Create an execution log with historical data
245
+ const executionLog = {
246
+ input: { userId: 'user1' },
247
+ output: {
248
+ id: 'portfolio1',
249
+ userId: 'user1',
250
+ totalValue: 4363.02,
251
+ stocks: [
252
+ { ticker: 'AAPL', quantity: 10, price: 190.50, value: 1905.00 },
253
+ { ticker: 'MSFT', quantity: 5, price: 405.75, value: 2028.75 },
254
+ { ticker: 'GOOGL', quantity: 8, price: 161.16, value: 429.27 }
255
+ ]
256
+ },
257
+ boundaries: {
258
+ fetchPortfolio: [
259
+ {
260
+ input: ['user1'],
261
+ output: {
262
+ id: 'portfolio1',
263
+ userId: 'user1',
264
+ stocks: [
265
+ { ticker: 'AAPL', quantity: 10 },
266
+ { ticker: 'MSFT', quantity: 5 },
267
+ { ticker: 'GOOGL', quantity: 8 }
268
+ ]
269
+ }
270
+ }
271
+ ],
272
+ fetchPrice: [
273
+ {
274
+ input: ['AAPL'],
275
+ output: 190.50
276
+ },
277
+ {
278
+ input: ['MSFT'],
279
+ output: 405.75
280
+ },
281
+ {
282
+ input: ['GOOGL'],
283
+ output: 161.16
284
+ }
285
+ ]
286
+ }
287
+ };
288
+ // Use replay mode for portfolio but proxy mode for prices
289
+ const [replayResult, replayError, replayLog] = await calculatePortfolioValue.safeReplay(executionLog, {
290
+ boundaries: {
291
+ fetchPortfolio: 'replay', // Use replay for portfolio
292
+ fetchPrice: 'proxy' // Use proxy (real execution) for prices
293
+ }
294
+ });
295
+ // Verify there was no error
296
+ expect(replayError).toBeNull();
297
+ // The result should reflect the updated AAPL price of 195.00
298
+ expect(replayResult).toHaveProperty('id', 'portfolio1');
299
+ expect(replayResult).toHaveProperty('userId', 'user1');
300
+ // Calculate expected value with current prices
301
+ const expectedValue = (priceData['AAPL'] * 10) + // AAPL: 195.00 * 10
302
+ (priceData['MSFT'] * 5) + // MSFT: 421.90 * 5
303
+ (priceData['GOOGL'] * 8); // GOOGL: 171.04 * 8
304
+ expect(replayResult.totalValue).toBeCloseTo(expectedValue);
305
+ // Check AAPL price reflects the current price, not the replay data
306
+ const applStock = replayResult.stocks.find((s) => s.ticker === 'AAPL');
307
+ expect(applStock === null || applStock === void 0 ? void 0 : applStock.price).toBe(195.00);
308
+ expect(applStock === null || applStock === void 0 ? void 0 : applStock.value).toBeCloseTo(195.00 * 10);
309
+ // Verify the log shows the mixed sources correctly
310
+ expect(replayLog.boundaries.fetchPortfolio).toHaveLength(1);
311
+ expect(replayLog.boundaries.fetchPrice).toHaveLength(3);
312
+ });
313
+ });
314
+ //# sourceMappingURL=safe-replay-complex-boundary.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-replay-complex-boundary.test.js","sourceRoot":"","sources":["../../src/test/safe-replay-complex-boundary.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=safe-replay.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-replay.test.d.ts","sourceRoot":"","sources":["../../src/test/safe-replay.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const schema_1 = require("@forgehive/schema");
4
+ const index_1 = require("../index");
5
+ describe('safeReplay functionality tests', () => {
6
+ // Common variables
7
+ let prices;
8
+ let boundaries;
9
+ // ToDo: Add correct type for schema and getTickerPrice
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+ let schema;
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ let getTickerPrice; // Using any temporarily until we implement safeReplay
14
+ beforeEach(() => {
15
+ // Create a schema for the task
16
+ schema = new schema_1.Schema({
17
+ ticker: schema_1.Schema.string()
18
+ });
19
+ // Mock price data
20
+ prices = {
21
+ 'AAPL': 150.23
22
+ };
23
+ // Define the boundaries
24
+ boundaries = {
25
+ fetchData: async (ticker) => {
26
+ // check if the ticker is in the prices object
27
+ if (!prices[ticker]) {
28
+ throw new Error(`Ticker ${ticker} not found in prices`);
29
+ }
30
+ return prices[ticker];
31
+ }
32
+ };
33
+ // Create the task using createTask
34
+ getTickerPrice = (0, index_1.createTask)(schema, boundaries, async ({ ticker }, { fetchData }) => {
35
+ const price = await fetchData(ticker);
36
+ return {
37
+ ticker,
38
+ price
39
+ };
40
+ });
41
+ });
42
+ it('Should replay a previous execution using the execution log and replay the fetchData boundary', async () => {
43
+ // Create a manual execution log
44
+ const executionLog = {
45
+ input: { ticker: 'AAPL' },
46
+ output: {
47
+ ticker: 'AAPL',
48
+ price: 160.23
49
+ },
50
+ boundaries: {
51
+ fetchData: [
52
+ {
53
+ input: ['AAPL'],
54
+ output: 160.23
55
+ }
56
+ ]
57
+ }
58
+ };
59
+ // No safeReplay method yet, this will be implemented later
60
+ // This will be our test for that functionality
61
+ const [replayResult, replayError, replayLog] = await getTickerPrice.safeReplay(executionLog);
62
+ // Verify the replay execution
63
+ expect(replayError).toBeNull();
64
+ expect(replayResult).toMatchObject({
65
+ ticker: 'AAPL',
66
+ price: 150.23
67
+ });
68
+ expect(replayLog).toMatchObject({
69
+ input: { ticker: 'AAPL' },
70
+ output: {
71
+ ticker: 'AAPL',
72
+ price: 150.23
73
+ },
74
+ boundaries: {
75
+ fetchData: [
76
+ {
77
+ input: ['AAPL'],
78
+ output: 150.23,
79
+ }
80
+ ]
81
+ }
82
+ });
83
+ });
84
+ it('Should execute with mixed boundaries modes', async () => {
85
+ // Create a manual execution log for testing
86
+ const executionLog = {
87
+ input: { ticker: 'AAPL' },
88
+ output: {
89
+ ticker: 'AAPL',
90
+ price: 160.23
91
+ },
92
+ boundaries: {
93
+ fetchData: [
94
+ {
95
+ input: ['AAPL'],
96
+ output: 160.23
97
+ }
98
+ ]
99
+ }
100
+ };
101
+ // Use mixed mode - replay for fetchData but execute logAccess
102
+ const [replayResult, replayError, replayLog] = await getTickerPrice.safeReplay(executionLog, {
103
+ boundaries: {
104
+ fetchData: 'replay',
105
+ }
106
+ });
107
+ // Verify the replay execution
108
+ expect(replayError).toBeNull();
109
+ expect(replayResult).toMatchObject({
110
+ ticker: 'AAPL',
111
+ price: 160.23
112
+ });
113
+ expect(replayLog).toMatchObject({
114
+ input: { ticker: 'AAPL' },
115
+ output: {
116
+ ticker: 'AAPL',
117
+ price: 160.23
118
+ },
119
+ boundaries: {
120
+ fetchData: [
121
+ {
122
+ input: ['AAPL'],
123
+ output: 160.23
124
+ }
125
+ ]
126
+ }
127
+ });
128
+ });
129
+ it('Should properly handle errors in boundary replay mode', async () => {
130
+ // Create a manual execution log with an error in the boundary
131
+ const executionLog = {
132
+ input: { ticker: 'AAPL' },
133
+ output: null,
134
+ error: 'API error: Rate limit exceeded',
135
+ boundaries: {
136
+ fetchData: [
137
+ {
138
+ input: ['AAPL'],
139
+ error: 'API error: Rate limit exceeded'
140
+ }
141
+ ]
142
+ }
143
+ };
144
+ // Use replay mode for fetchData
145
+ const [replayResult, replayError, replayLog] = await getTickerPrice.safeReplay(executionLog, {
146
+ boundaries: {
147
+ fetchData: 'replay',
148
+ }
149
+ });
150
+ // Verify the replay execution - should have an error
151
+ expect(replayResult).toBeNull();
152
+ expect(replayError).not.toBeNull();
153
+ expect(replayError === null || replayError === void 0 ? void 0 : replayError.message).toBe('API error: Rate limit exceeded');
154
+ // The log should contain the error from the boundary
155
+ expect(replayLog.error).toBeDefined();
156
+ expect(replayLog.boundaries.fetchData[0].error).toBe('API error: Rate limit exceeded');
157
+ });
158
+ });
159
+ //# sourceMappingURL=safe-replay.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-replay.test.js","sourceRoot":"","sources":["../../src/test/safe-replay.test.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const index_1 = require("../index");
4
4
  describe('Task safeRun tests', () => {
5
- it('returns [null, result, boundaryLogs] on successful execution', async () => {
5
+ it('returns [result, null, record] on successful execution', async () => {
6
6
  // Create a simple schema
7
7
  const schema = new index_1.Schema({
8
8
  value: index_1.Schema.number()
@@ -19,14 +19,20 @@ describe('Task safeRun tests', () => {
19
19
  return { result, success: true };
20
20
  });
21
21
  // Call safeRun with valid input
22
- const [error, result, boundaryLogs] = await successTask.safeRun({ value: 5 });
22
+ const [result, error, record] = await successTask.safeRun({ value: 5 });
23
23
  // Verify success case
24
24
  expect(error).toBeNull();
25
25
  expect(result).toEqual({ result: 10, success: true });
26
- expect(boundaryLogs).not.toBeNull();
27
- expect(boundaryLogs).toHaveProperty('fetchData');
26
+ expect(record).not.toBeNull();
27
+ expect(record).toHaveProperty('boundaries.fetchData');
28
+ expect(record.boundaries.fetchData).toHaveLength(1);
29
+ // useful to check types on record
30
+ const data = record.boundaries.fetchData[0];
31
+ expect(data.input).toEqual([5]);
32
+ expect(data.output).toEqual(10);
33
+ expect(data.error).toBeUndefined();
28
34
  });
29
- it('returns [error, null, boundaryLogs] on failed execution', async () => {
35
+ it('returns [null, error, record] on failed execution', async () => {
30
36
  // Create a simple schema
31
37
  const schema = new index_1.Schema({
32
38
  value: index_1.Schema.number()
@@ -46,15 +52,23 @@ describe('Task safeRun tests', () => {
46
52
  return { result, success: true };
47
53
  });
48
54
  // Call safeRun with problematic input that will cause an error
49
- const [error, result, boundaryLogs] = await errorTask.safeRun({ value: -5 });
55
+ const [result, error, record] = await errorTask.safeRun({ value: -5 });
50
56
  // Verify error case
51
- expect(error).toBeInstanceOf(Error);
52
- expect(error === null || error === void 0 ? void 0 : error.message).toContain('Value cannot be negative');
57
+ expect(error).not.toBeNull();
58
+ expect(error instanceof Error).toBe(true);
59
+ if (error instanceof Error) {
60
+ expect(error.message).toContain('Value cannot be negative');
61
+ }
53
62
  expect(result).toBeNull();
54
- expect(boundaryLogs).not.toBeNull();
55
- expect(boundaryLogs).toHaveProperty('fetchData');
63
+ expect(record).not.toBeNull();
64
+ expect(record).toHaveProperty('boundaries.fetchData');
65
+ expect(record.boundaries.fetchData).toHaveLength(1);
66
+ const data = record.boundaries.fetchData[0];
67
+ expect(data.input).toEqual([-5]);
68
+ expect(data.error).toContain('Value cannot be negative');
69
+ expect(data.output).toBeUndefined();
56
70
  });
57
- it('returns [error, null, null] on schema validation failure', async () => {
71
+ it('returns [null, error, record] on schema validation failure', async () => {
58
72
  // Create a schema that requires a positive number
59
73
  const schema = new index_1.Schema({
60
74
  value: index_1.Schema.number().min(1, 'Value must be positive')
@@ -71,12 +85,20 @@ describe('Task safeRun tests', () => {
71
85
  return { result, success: true };
72
86
  });
73
87
  // Call safeRun with invalid input that will fail schema validation
74
- const [error, result, boundaryLogs] = await validationTask.safeRun({ value: 0 });
88
+ const [result, error, record] = await validationTask.safeRun({ value: 0 });
75
89
  // Verify validation error case
76
90
  expect(error).toBeInstanceOf(Error);
77
- expect(error === null || error === void 0 ? void 0 : error.message).toContain('Value must be positive');
91
+ expect(error instanceof Error).toBe(true);
92
+ if (error instanceof Error) {
93
+ expect(error.message).toContain('Value must be positive');
94
+ }
78
95
  expect(result).toBeNull();
79
- expect(boundaryLogs).toBeNull(); // No boundary calls were made due to validation failure
96
+ expect(record).not.toBeNull();
97
+ expect(record.input).toEqual({ value: 0 });
98
+ expect(record.error).toContain('Value must be positive');
99
+ expect(record.boundaries).toEqual({
100
+ fetchData: []
101
+ });
80
102
  });
81
103
  it('properly calls the listener with safeRun and run', async () => {
82
104
  // Create a schema
@@ -106,12 +128,18 @@ describe('Task safeRun tests', () => {
106
128
  // First call should be for safeRun with value 10
107
129
  expect(originalListener).toHaveBeenNthCalledWith(1, expect.objectContaining({
108
130
  input: { value: 10 },
109
- output: 20
131
+ output: 20,
132
+ boundaries: {
133
+ fetchData: expect.any(Array)
134
+ }
110
135
  }));
111
136
  // Second call should be for run with value 20
112
137
  expect(originalListener).toHaveBeenNthCalledWith(2, expect.objectContaining({
113
138
  input: { value: 20 },
114
- output: 40
139
+ output: 40,
140
+ boundaries: {
141
+ fetchData: expect.any(Array)
142
+ }
115
143
  }));
116
144
  });
117
145
  it('handles multiple boundary calls correctly', async () => {
@@ -135,25 +163,23 @@ describe('Task safeRun tests', () => {
135
163
  return { doubled, total };
136
164
  });
137
165
  // Call safeRun
138
- const [error, result, boundaryLogs] = await multiBoundaryTask.safeRun({ values: [1, 2, 3] });
166
+ const [result, error, record] = await multiBoundaryTask.safeRun({ values: [1, 2, 3] });
139
167
  // Verify success
140
168
  expect(error).toBeNull();
141
169
  expect(result).toEqual({
142
170
  doubled: [2, 4, 6],
143
171
  total: 12
144
172
  });
145
- // Verify boundary logs for both boundaries
146
- expect(boundaryLogs).not.toBeNull();
147
- expect(boundaryLogs).toHaveProperty('doubleValue');
148
- expect(boundaryLogs).toHaveProperty('sumValues');
149
- // Check that doubleValue was called 3 times (once for each input value)
150
- // @ts-expect-error - we know the boundaryLogs is not null here
151
- expect(boundaryLogs.doubleValue).toHaveLength(3);
152
- // Check that sumValues was called once with the doubled values
153
- // @ts-expect-error - we know the boundaryLogs is not null here
154
- expect(boundaryLogs.sumValues).toHaveLength(1);
155
- // @ts-expect-error - we know the boundaryLogs is not null here
156
- expect(boundaryLogs.sumValues[0].input).toEqual([[2, 4, 6]]);
173
+ // Verify record structure
174
+ expect(record).not.toBeNull();
175
+ expect(record).toHaveProperty('boundaries.doubleValue');
176
+ expect(record).toHaveProperty('boundaries.sumValues');
177
+ expect(record.boundaries.doubleValue).toHaveLength(3);
178
+ expect(record.boundaries.sumValues).toHaveLength(1);
179
+ expect(record.boundaries.doubleValue[0]).toEqual({ input: [1], output: 2 });
180
+ expect(record.boundaries.doubleValue[1]).toEqual({ input: [2], output: 4 });
181
+ expect(record.boundaries.doubleValue[2]).toEqual({ input: [3], output: 6 });
182
+ expect(record.boundaries.sumValues[0]).toEqual({ input: [[2, 4, 6]], output: 12 });
157
183
  });
158
184
  });
159
185
  //# sourceMappingURL=safe-run.test.js.map