@forgehive/record-tape 0.2.0 → 0.2.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/README.md +385 -0
- package/dist/index.d.ts +10 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -63
- package/dist/index.js.map +1 -1
- package/dist/tests/data-methods.test.d.ts +2 -0
- package/dist/tests/data-methods.test.d.ts.map +1 -0
- package/dist/tests/data-methods.test.js +129 -0
- package/dist/tests/data-methods.test.js.map +1 -0
- package/dist/tests/index.test.js +2 -2
- package/dist/tests/index.test.js.map +1 -1
- package/dist/tests/log-format.test.js +8 -8
- package/dist/tests/log-format.test.js.map +1 -1
- package/dist/tests/safe-run.test.js +104 -265
- package/dist/tests/safe-run.test.js.map +1 -1
- package/dist/tests/save.test.js +13 -13
- package/dist/tests/save.test.js.map +1 -1
- package/dist/tests/task-listener.test.js +21 -31
- package/dist/tests/task-listener.test.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +20 -88
- package/src/tests/data-methods.test.ts +150 -0
- package/src/tests/index.test.ts +3 -8
- package/src/tests/log-format.test.ts +8 -8
- package/src/tests/safe-run.test.ts +108 -296
- package/src/tests/save.test.ts +13 -13
- package/src/tests/task-listener.test.ts +22 -41
- package/src/tests/mode.test.ts +0 -106
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { RecordTape } from '../index'
|
|
2
|
+
|
|
3
|
+
describe('RecordTape Data Methods', () => {
|
|
4
|
+
let tape: RecordTape
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
tape = new RecordTape()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
describe('getLength', () => {
|
|
11
|
+
test('should return 0 for empty tape', () => {
|
|
12
|
+
expect(tape.getLength()).toBe(0)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('should return correct length after adding records', () => {
|
|
16
|
+
const record1 = {
|
|
17
|
+
input: { userId: 1 },
|
|
18
|
+
output: { name: 'John' },
|
|
19
|
+
taskName: 'getUser',
|
|
20
|
+
boundaries: {},
|
|
21
|
+
type: 'success' as const
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const record2 = {
|
|
25
|
+
input: { userId: 2 },
|
|
26
|
+
output: { name: 'Jane' },
|
|
27
|
+
taskName: 'getUser',
|
|
28
|
+
boundaries: {},
|
|
29
|
+
type: 'success' as const
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
tape.push(record1)
|
|
33
|
+
expect(tape.getLength()).toBe(1)
|
|
34
|
+
|
|
35
|
+
tape.push(record2)
|
|
36
|
+
expect(tape.getLength()).toBe(2)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('should return correct length after removing records', () => {
|
|
40
|
+
const record = {
|
|
41
|
+
input: { userId: 1 },
|
|
42
|
+
output: { name: 'John' },
|
|
43
|
+
taskName: 'getUser',
|
|
44
|
+
boundaries: {},
|
|
45
|
+
type: 'success' as const
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
tape.push(record)
|
|
49
|
+
tape.push(record)
|
|
50
|
+
expect(tape.getLength()).toBe(2)
|
|
51
|
+
|
|
52
|
+
tape.shift()
|
|
53
|
+
expect(tape.getLength()).toBe(1)
|
|
54
|
+
|
|
55
|
+
tape.shift()
|
|
56
|
+
expect(tape.getLength()).toBe(0)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe('shift', () => {
|
|
61
|
+
test('should return undefined for empty tape', () => {
|
|
62
|
+
expect(tape.shift()).toBeUndefined()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('should return and remove first record', () => {
|
|
66
|
+
const record1 = {
|
|
67
|
+
input: { userId: 1 },
|
|
68
|
+
output: { name: 'John' },
|
|
69
|
+
taskName: 'getUser',
|
|
70
|
+
boundaries: {},
|
|
71
|
+
type: 'success' as const
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const record2 = {
|
|
75
|
+
input: { userId: 2 },
|
|
76
|
+
output: { name: 'Jane' },
|
|
77
|
+
taskName: 'getUser',
|
|
78
|
+
boundaries: {},
|
|
79
|
+
type: 'success' as const
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
tape.push(record1)
|
|
83
|
+
tape.push(record2)
|
|
84
|
+
|
|
85
|
+
const shiftedRecord = tape.shift()
|
|
86
|
+
|
|
87
|
+
// Should return the first record
|
|
88
|
+
expect(shiftedRecord).toEqual(expect.objectContaining({
|
|
89
|
+
taskName: 'getUser',
|
|
90
|
+
input: { userId: 1 },
|
|
91
|
+
output: { name: 'John' },
|
|
92
|
+
type: 'success'
|
|
93
|
+
}))
|
|
94
|
+
|
|
95
|
+
// Should have removed the first record
|
|
96
|
+
expect(tape.getLength()).toBe(1)
|
|
97
|
+
expect(tape.getLog()[0]).toEqual(expect.objectContaining({
|
|
98
|
+
taskName: 'getUser',
|
|
99
|
+
input: { userId: 2 },
|
|
100
|
+
output: { name: 'Jane' },
|
|
101
|
+
type: 'success'
|
|
102
|
+
}))
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('should work correctly with multiple shifts', () => {
|
|
106
|
+
const records = [
|
|
107
|
+
{
|
|
108
|
+
input: { userId: 1 },
|
|
109
|
+
output: { name: 'John' },
|
|
110
|
+
taskName: 'getUser',
|
|
111
|
+
boundaries: {},
|
|
112
|
+
type: 'success' as const
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
input: { userId: 2 },
|
|
116
|
+
output: { name: 'Jane' },
|
|
117
|
+
taskName: 'getUser',
|
|
118
|
+
boundaries: {},
|
|
119
|
+
type: 'success' as const
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
input: { userId: 3 },
|
|
123
|
+
output: { name: 'Bob' },
|
|
124
|
+
taskName: 'getUser',
|
|
125
|
+
boundaries: {},
|
|
126
|
+
type: 'success' as const
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
records.forEach(record => tape.push(record))
|
|
131
|
+
expect(tape.getLength()).toBe(3)
|
|
132
|
+
|
|
133
|
+
const first = tape.shift()
|
|
134
|
+
expect(first?.input).toEqual({ userId: 1 })
|
|
135
|
+
expect(tape.getLength()).toBe(2)
|
|
136
|
+
|
|
137
|
+
const second = tape.shift()
|
|
138
|
+
expect(second?.input).toEqual({ userId: 2 })
|
|
139
|
+
expect(tape.getLength()).toBe(1)
|
|
140
|
+
|
|
141
|
+
const third = tape.shift()
|
|
142
|
+
expect(third?.input).toEqual({ userId: 3 })
|
|
143
|
+
expect(tape.getLength()).toBe(0)
|
|
144
|
+
|
|
145
|
+
const fourth = tape.shift()
|
|
146
|
+
expect(fourth).toBeUndefined()
|
|
147
|
+
expect(tape.getLength()).toBe(0)
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
})
|
package/src/tests/index.test.ts
CHANGED
|
@@ -53,14 +53,9 @@ describe('Base tests', () => {
|
|
|
53
53
|
})
|
|
54
54
|
|
|
55
55
|
it('Should create a new tape with generic types', () => {
|
|
56
|
-
|
|
57
|
-
type
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const tape = new RecordTape<InputType, OutputType>({ path: emptyPath })
|
|
62
|
-
tape.addLogRecord({ name: 'test', input: [{name: 'test'}], output: { age: 1 }, type: 'success', boundaries: {} })
|
|
63
|
-
tape.addLogRecord({ name: 'test', input: [{name: 'test'}], error: 'test', type: 'error', boundaries: {} })
|
|
56
|
+
const tape = new RecordTape({ path: emptyPath })
|
|
57
|
+
tape.push({ input: [{name: 'test'}], output: { age: 1 }, type: 'success', boundaries: {}, taskName: 'test' })
|
|
58
|
+
tape.push({ input: [{name: 'test'}], error: 'test', type: 'error', boundaries: {}, taskName: 'test' })
|
|
64
59
|
|
|
65
60
|
const data = tape.getLog()
|
|
66
61
|
expect(data.length).toBe(2)
|
|
@@ -6,13 +6,13 @@ describe('Test log item formating', () => {
|
|
|
6
6
|
type OutputType = boolean
|
|
7
7
|
|
|
8
8
|
const tape = new RecordTape<InputType, OutputType>({})
|
|
9
|
-
tape.
|
|
10
|
-
tape.
|
|
9
|
+
tape.push({ input: true, output: true, boundaries: {}, type: 'success', taskName: 'name' })
|
|
10
|
+
tape.push({ input: true, error: 'invalid data', boundaries: {}, type: 'error', taskName: 'name' })
|
|
11
11
|
|
|
12
12
|
const str = tape.stringify()
|
|
13
13
|
|
|
14
|
-
expect(str).toEqual(`{"
|
|
15
|
-
{"
|
|
14
|
+
expect(str).toEqual(`{"input":true,"output":true,"boundaries":{},"type":"success","taskName":"name","metadata":{}}
|
|
15
|
+
{"input":true,"error":"invalid data","boundaries":{},"type":"error","taskName":"name","metadata":{}}
|
|
16
16
|
`)
|
|
17
17
|
})
|
|
18
18
|
|
|
@@ -21,16 +21,16 @@ describe('Test log item formating', () => {
|
|
|
21
21
|
type OutputType = boolean
|
|
22
22
|
|
|
23
23
|
const tape = new RecordTape<InputType, OutputType>({})
|
|
24
|
-
tape.
|
|
25
|
-
tape.
|
|
24
|
+
tape.push({ input: true, output: true, boundaries: {}, type: 'success', taskName: 'name' })
|
|
25
|
+
tape.push({ input: true, error: 'invalid data', boundaries: {}, type: 'error', taskName: 'name' })
|
|
26
26
|
|
|
27
27
|
const str = tape.stringify()
|
|
28
28
|
const tape2 = new RecordTape<InputType, OutputType>({})
|
|
29
29
|
const records = tape2.parse(str)
|
|
30
30
|
|
|
31
31
|
expect(records).toEqual([
|
|
32
|
-
{
|
|
33
|
-
{
|
|
32
|
+
{ input: true, output: true, boundaries: {}, type: 'success', taskName: 'name', metadata: {} },
|
|
33
|
+
{ input: true, error: 'invalid data', boundaries: {}, type: 'error', taskName: 'name', metadata: {} }
|
|
34
34
|
])
|
|
35
35
|
})
|
|
36
36
|
})
|
|
@@ -1,358 +1,170 @@
|
|
|
1
|
+
import { createTask, Schema } from '@forgehive/task'
|
|
1
2
|
import { RecordTape } from '../index'
|
|
2
|
-
import { createTask, Schema, type ExecutionRecord, type TaskRecord } from '@forgehive/task'
|
|
3
3
|
|
|
4
|
-
describe('
|
|
5
|
-
it('
|
|
6
|
-
|
|
7
|
-
const schema = new Schema({
|
|
8
|
-
value: Schema.number()
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
// Define the boundaries
|
|
12
|
-
const boundaries = {
|
|
13
|
-
fetchData: async (value: number): Promise<number> => {
|
|
14
|
-
return value * 2
|
|
15
|
-
}
|
|
16
|
-
}
|
|
4
|
+
describe('Safe run', () => {
|
|
5
|
+
it('Should run a simple task with no boundaries and register to a tape', async () => {
|
|
6
|
+
const tape = new RecordTape<{ value: number }, { doubled: number }>({})
|
|
17
7
|
|
|
18
|
-
// Create the task
|
|
19
8
|
const task = createTask({
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
9
|
+
name: 'simple-task',
|
|
10
|
+
schema: new Schema({
|
|
11
|
+
value: Schema.number()
|
|
12
|
+
}),
|
|
13
|
+
boundaries: {},
|
|
14
|
+
fn: async ({ value }) => {
|
|
15
|
+
return { doubled: value * 2 }
|
|
25
16
|
}
|
|
26
17
|
})
|
|
27
18
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// Run the task with safeRun and directly use the logItem
|
|
32
|
-
const [result, error, record] = await task.safeRun({ value: 5 })
|
|
33
|
-
tape.push('test-task', record)
|
|
34
|
-
|
|
35
|
-
// Verify the execution was successful
|
|
36
|
-
expect(error).toBeNull()
|
|
37
|
-
expect(result).toEqual({ result: 10, success: true })
|
|
38
|
-
|
|
39
|
-
// Get the recorded log from the tape
|
|
40
|
-
const recordedLog = tape.getLog()
|
|
41
|
-
|
|
42
|
-
// Verify the log was recorded correctly
|
|
43
|
-
expect(recordedLog).toHaveLength(1)
|
|
44
|
-
|
|
45
|
-
const logItem = recordedLog[0]
|
|
46
|
-
expect(logItem.name).toEqual('test-task')
|
|
47
|
-
expect(logItem.type).toEqual('success')
|
|
48
|
-
expect(logItem.input).toEqual({ value: 5 })
|
|
49
|
-
expect(logItem.output).toEqual({ result: 10, success: true })
|
|
50
|
-
expect(logItem.boundaries).toEqual({
|
|
51
|
-
fetchData: [{
|
|
52
|
-
input: [5],
|
|
53
|
-
output: 10,
|
|
54
|
-
error: null
|
|
55
|
-
}]
|
|
56
|
-
})
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
it('should record log items from safeRun successfully', async () => {
|
|
60
|
-
// Create a schema
|
|
61
|
-
const schema = new Schema({
|
|
62
|
-
value: Schema.number()
|
|
19
|
+
task.addListener((record) => {
|
|
20
|
+
tape.push(record)
|
|
63
21
|
})
|
|
64
22
|
|
|
65
|
-
//
|
|
66
|
-
const boundaries = {
|
|
67
|
-
fetchData: async (value: number): Promise<number> => {
|
|
68
|
-
return value * 2
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Create the task
|
|
73
|
-
const task = createTask({
|
|
74
|
-
schema,
|
|
75
|
-
boundaries,
|
|
76
|
-
fn: async function ({ value }, { fetchData }) {
|
|
77
|
-
const result = await fetchData(value)
|
|
78
|
-
return { result, success: true }
|
|
79
|
-
}
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
// Create a record tape
|
|
83
|
-
const tape = new RecordTape<{ value: number }, { result: number; success: boolean }, typeof boundaries>()
|
|
84
|
-
|
|
85
|
-
// Add listener to record the log items
|
|
86
|
-
task.addListener((record: TaskRecord<{ value: number }, { result: number; success: boolean }>) => {
|
|
87
|
-
// Manually ensure boundary records have error field for consistency with safeRun
|
|
88
|
-
if (record.boundaries && record.boundaries.fetchData && Array.isArray(record.boundaries.fetchData)) {
|
|
89
|
-
record.boundaries.fetchData = record.boundaries.fetchData.map((entry: Record<string, unknown>) => ({
|
|
90
|
-
...entry,
|
|
91
|
-
error: entry.error ?? null,
|
|
92
|
-
output: entry.output ?? null
|
|
93
|
-
}))
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Add the record using push method
|
|
97
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
98
|
-
tape.push('test-task', record as any)
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
// Run the task with safeRun
|
|
23
|
+
// Test simple execution
|
|
102
24
|
const [result, error] = await task.safeRun({ value: 5 })
|
|
103
25
|
|
|
104
|
-
// Verify the execution was successful
|
|
105
26
|
expect(error).toBeNull()
|
|
106
|
-
expect(result).toEqual({
|
|
107
|
-
|
|
108
|
-
// Get the recorded log from the tape
|
|
109
|
-
const recordedLog = tape.getLog()
|
|
27
|
+
expect(result).toEqual({ doubled: 10 })
|
|
110
28
|
|
|
111
|
-
|
|
112
|
-
expect(
|
|
113
|
-
expect(
|
|
114
|
-
name: 'test-task',
|
|
29
|
+
const log = tape.getLog()
|
|
30
|
+
expect(log).toHaveLength(1)
|
|
31
|
+
expect(log[0]).toEqual({
|
|
115
32
|
type: 'success',
|
|
116
33
|
input: { value: 5 },
|
|
117
|
-
output: {
|
|
118
|
-
boundaries: {
|
|
119
|
-
fetchData: [{
|
|
120
|
-
input: [5],
|
|
121
|
-
output: 10,
|
|
122
|
-
error: null
|
|
123
|
-
}]
|
|
124
|
-
},
|
|
34
|
+
output: { doubled: 10 },
|
|
35
|
+
boundaries: {},
|
|
125
36
|
metadata: {},
|
|
126
|
-
taskName:
|
|
37
|
+
taskName: 'simple-task'
|
|
127
38
|
})
|
|
128
39
|
})
|
|
129
40
|
|
|
130
|
-
it('
|
|
131
|
-
|
|
132
|
-
const schema = new Schema({
|
|
133
|
-
value: Schema.number()
|
|
134
|
-
})
|
|
41
|
+
it('Should run a task with boundaries and register to a tape', async () => {
|
|
42
|
+
const tape = new RecordTape<{ value: number }, { result: number; success: boolean }>({})
|
|
135
43
|
|
|
136
|
-
// Define the boundaries with a function that will throw an error
|
|
137
|
-
const boundaries = {
|
|
138
|
-
fetchData: async (value: number): Promise<number> => {
|
|
139
|
-
if (value < 0) {
|
|
140
|
-
throw new Error('Value cannot be negative')
|
|
141
|
-
}
|
|
142
|
-
return value * 2
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Create the task
|
|
147
44
|
const task = createTask({
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
45
|
+
name: 'test',
|
|
46
|
+
schema: new Schema({
|
|
47
|
+
value: Schema.number().min(10).max(20)
|
|
48
|
+
}),
|
|
49
|
+
boundaries: {
|
|
50
|
+
multiply: async (value: number): Promise<number> => {
|
|
51
|
+
return value * 2
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
fn: async ({ value }, { multiply }) => {
|
|
55
|
+
const result = await multiply(value)
|
|
56
|
+
return { result, success: result > 10 }
|
|
153
57
|
}
|
|
154
58
|
})
|
|
155
59
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
// Add listener to record the log items
|
|
160
|
-
task.addListener((record: TaskRecord<{ value: number }, { result: number; success: boolean }>) => {
|
|
161
|
-
// Manually ensure boundary records have error field for consistency with safeRun
|
|
162
|
-
if (record.boundaries && record.boundaries.fetchData && Array.isArray(record.boundaries.fetchData)) {
|
|
163
|
-
record.boundaries.fetchData = record.boundaries.fetchData.map((entry: Record<string, unknown>) => ({
|
|
164
|
-
...entry,
|
|
165
|
-
error: entry.error ?? null,
|
|
166
|
-
output: entry.output ?? null
|
|
167
|
-
}))
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Add the record using push method
|
|
171
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
172
|
-
tape.push('test-task', record as any)
|
|
60
|
+
task.addListener((record) => {
|
|
61
|
+
tape.push(record)
|
|
173
62
|
})
|
|
174
63
|
|
|
175
|
-
//
|
|
176
|
-
|
|
64
|
+
// Test invalid input
|
|
65
|
+
let [result, error] = await task.safeRun({ value: 5 })
|
|
177
66
|
|
|
178
|
-
|
|
179
|
-
expect(
|
|
180
|
-
expect(error).not.toBeNull()
|
|
181
|
-
expect(error?.message).toContain('Value cannot be negative')
|
|
67
|
+
expect(error).toBeDefined()
|
|
68
|
+
expect(error?.message).toContain('Invalid input')
|
|
182
69
|
|
|
183
|
-
//
|
|
184
|
-
|
|
70
|
+
// Test valid input
|
|
71
|
+
;[result, error] = await task.safeRun({ value: 15 })
|
|
72
|
+
expect(error).toBeNull()
|
|
73
|
+
expect(result).toEqual({ result: 30, success: true })
|
|
185
74
|
|
|
186
|
-
|
|
187
|
-
expect(
|
|
188
|
-
expect(
|
|
189
|
-
name: 'test-task',
|
|
75
|
+
const log = tape.getLog()
|
|
76
|
+
expect(log).toHaveLength(2)
|
|
77
|
+
expect(log[0]).toEqual({
|
|
190
78
|
type: 'error',
|
|
191
|
-
input: { value:
|
|
192
|
-
error: '
|
|
79
|
+
input: { value: 5 },
|
|
80
|
+
error: 'Invalid input on: value: Number must be greater than or equal to 10',
|
|
193
81
|
boundaries: {
|
|
194
|
-
|
|
195
|
-
input: [-5],
|
|
196
|
-
error: 'Value cannot be negative',
|
|
197
|
-
output: null
|
|
198
|
-
}]
|
|
82
|
+
multiply: []
|
|
199
83
|
},
|
|
200
84
|
metadata: {},
|
|
201
|
-
|
|
202
|
-
taskName: undefined
|
|
85
|
+
taskName: 'test'
|
|
203
86
|
})
|
|
204
|
-
})
|
|
205
87
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
88
|
+
expect(log[1]).toEqual({
|
|
89
|
+
type: 'success',
|
|
90
|
+
input: { value: 15 },
|
|
91
|
+
output: { result: 30, success: true },
|
|
92
|
+
boundaries: {
|
|
93
|
+
multiply: [{
|
|
94
|
+
input: [15],
|
|
95
|
+
output: 30
|
|
96
|
+
}]
|
|
97
|
+
},
|
|
98
|
+
metadata: {},
|
|
99
|
+
taskName: 'test'
|
|
210
100
|
})
|
|
101
|
+
})
|
|
211
102
|
|
|
212
|
-
|
|
213
|
-
const
|
|
214
|
-
fetchData: async (value: number): Promise<number> => {
|
|
215
|
-
if (value < 0) {
|
|
216
|
-
throw new Error('Value cannot be negative')
|
|
217
|
-
}
|
|
218
|
-
return value * 2
|
|
219
|
-
}
|
|
220
|
-
}
|
|
103
|
+
it('Should run a task with boundaries and register errors to a tape', async () => {
|
|
104
|
+
const tape = new RecordTape<{ value: number }, { result: number }>({})
|
|
221
105
|
|
|
222
|
-
// Create the task
|
|
223
106
|
const task = createTask({
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
107
|
+
name: 'test',
|
|
108
|
+
schema: new Schema({
|
|
109
|
+
value: Schema.number()
|
|
110
|
+
}),
|
|
111
|
+
boundaries: {
|
|
112
|
+
divide: async (value: number): Promise<number> => {
|
|
113
|
+
if (value === 0) {
|
|
114
|
+
throw new Error('Division by zero')
|
|
115
|
+
}
|
|
116
|
+
return 100 / value
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
fn: async ({ value }, { divide }) => {
|
|
120
|
+
const result = await divide(value)
|
|
121
|
+
return { result }
|
|
229
122
|
}
|
|
230
123
|
})
|
|
231
124
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
// Run the task with safeRun with a value that will cause an error
|
|
236
|
-
const [result, error, record] = await task.safeRun({ value: -5 })
|
|
125
|
+
task.addListener((record) => {
|
|
126
|
+
tape.push(record)
|
|
127
|
+
})
|
|
237
128
|
|
|
238
|
-
//
|
|
239
|
-
|
|
129
|
+
// Test division by zero
|
|
130
|
+
const [, error] = await task.safeRun({ value: 0 })
|
|
240
131
|
|
|
241
|
-
|
|
242
|
-
expect(
|
|
243
|
-
expect(error).not.toBeNull()
|
|
244
|
-
expect(error instanceof Error).toBe(true)
|
|
245
|
-
if (error instanceof Error) {
|
|
246
|
-
expect(error.message).toContain('Value cannot be negative')
|
|
247
|
-
}
|
|
132
|
+
expect(error).toBeDefined()
|
|
133
|
+
expect(error?.message).toBe('Division by zero')
|
|
248
134
|
|
|
249
|
-
//
|
|
250
|
-
const
|
|
135
|
+
// Test valid input
|
|
136
|
+
const [secondResult, secondError] = await task.safeRun({ value: 10 })
|
|
137
|
+
expect(secondError).toBeNull()
|
|
138
|
+
expect(secondResult).toEqual({ result: 10 })
|
|
251
139
|
|
|
252
|
-
|
|
253
|
-
expect(
|
|
254
|
-
expect(
|
|
255
|
-
name: 'test-error',
|
|
140
|
+
const log = tape.getLog()
|
|
141
|
+
expect(log).toHaveLength(2)
|
|
142
|
+
expect(log[0]).toEqual({
|
|
256
143
|
type: 'error',
|
|
257
|
-
input: { value:
|
|
258
|
-
error: '
|
|
144
|
+
input: { value: 0 },
|
|
145
|
+
error: 'Division by zero',
|
|
259
146
|
boundaries: {
|
|
260
|
-
|
|
261
|
-
input: [
|
|
262
|
-
|
|
263
|
-
error: 'Value cannot be negative'
|
|
147
|
+
divide: [{
|
|
148
|
+
input: [0],
|
|
149
|
+
error: 'Division by zero'
|
|
264
150
|
}]
|
|
265
151
|
},
|
|
266
152
|
metadata: {},
|
|
267
|
-
|
|
268
|
-
taskName: undefined
|
|
153
|
+
taskName: 'test'
|
|
269
154
|
})
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
it('should handle custom execution records with push', async () => {
|
|
273
|
-
// Create a record tape
|
|
274
|
-
const tape = new RecordTape<{ value: number }, { result: number }, { fetchData: (n: number) => Promise<number> }>()
|
|
275
155
|
|
|
276
|
-
|
|
277
|
-
const customRecord: ExecutionRecord<{ value: number }, { result: number }, { fetchData: (n: number) => Promise<number> }> = {
|
|
278
|
-
input: { value: 10 },
|
|
279
|
-
output: { result: 20 },
|
|
280
|
-
type: 'success',
|
|
281
|
-
boundaries: {
|
|
282
|
-
fetchData: [
|
|
283
|
-
{
|
|
284
|
-
input: [10],
|
|
285
|
-
output: 20
|
|
286
|
-
}
|
|
287
|
-
]
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Push the custom record
|
|
292
|
-
tape.push('custom-record', customRecord)
|
|
293
|
-
|
|
294
|
-
// Get the recorded log from the tape
|
|
295
|
-
const recordedLog = tape.getLog()
|
|
296
|
-
|
|
297
|
-
// Verify the log was recorded correctly
|
|
298
|
-
expect(recordedLog).toHaveLength(1)
|
|
299
|
-
expect(recordedLog[0]).toEqual({
|
|
300
|
-
name: 'custom-record',
|
|
156
|
+
expect(log[1]).toEqual({
|
|
301
157
|
type: 'success',
|
|
302
158
|
input: { value: 10 },
|
|
303
|
-
output: { result:
|
|
159
|
+
output: { result: 10 },
|
|
304
160
|
boundaries: {
|
|
305
|
-
|
|
161
|
+
divide: [{
|
|
306
162
|
input: [10],
|
|
307
|
-
output:
|
|
308
|
-
error: null
|
|
163
|
+
output: 10
|
|
309
164
|
}]
|
|
310
165
|
},
|
|
311
|
-
metadata: {}
|
|
312
|
-
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
it('should handle execution records with Promise outputs correctly', async () => {
|
|
316
|
-
// Create a record tape
|
|
317
|
-
const tape = new RecordTape<{ value: number }, { result: number }, { fetchData: (n: number) => Promise<number> }>()
|
|
318
|
-
|
|
319
|
-
// Create a custom execution record with a Promise output
|
|
320
|
-
const promiseResult = Promise.resolve({ result: 30 })
|
|
321
|
-
const promiseRecord: ExecutionRecord<{ value: number }, Promise<{ result: number }>, { fetchData: (n: number) => Promise<number> }> = {
|
|
322
|
-
input: { value: 15 },
|
|
323
|
-
output: promiseResult,
|
|
324
|
-
type: 'success',
|
|
325
|
-
boundaries: {
|
|
326
|
-
fetchData: [
|
|
327
|
-
{
|
|
328
|
-
input: [15],
|
|
329
|
-
output: 30
|
|
330
|
-
}
|
|
331
|
-
]
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Push the record with Promise output using type parameter
|
|
336
|
-
tape.push('promise-record', promiseRecord)
|
|
337
|
-
|
|
338
|
-
// Get the recorded log from the tape
|
|
339
|
-
const recordedLog = tape.getLog()
|
|
340
|
-
|
|
341
|
-
// Verify the log was recorded correctly, with Promise output set to null
|
|
342
|
-
expect(recordedLog).toHaveLength(1)
|
|
343
|
-
expect(recordedLog[0]).toEqual({
|
|
344
|
-
name: 'promise-record',
|
|
345
|
-
type: 'success',
|
|
346
|
-
input: { value: 15 },
|
|
347
|
-
output: null, // Promise output should be set to null
|
|
348
|
-
boundaries: {
|
|
349
|
-
fetchData: [{
|
|
350
|
-
input: [15],
|
|
351
|
-
output: 30,
|
|
352
|
-
error: null
|
|
353
|
-
}]
|
|
354
|
-
},
|
|
355
|
-
metadata: {}
|
|
166
|
+
metadata: {},
|
|
167
|
+
taskName: 'test'
|
|
356
168
|
})
|
|
357
169
|
})
|
|
358
170
|
})
|