@toa.io/core 1.0.0-alpha.292 → 1.0.0-alpha.299

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 (138) hide show
  1. package/package.json +10 -4
  2. package/transpiled/call.js +12 -0
  3. package/transpiled/call.js.map +1 -1
  4. package/transpiled/component.js +31 -4
  5. package/transpiled/component.js.map +1 -1
  6. package/transpiled/context.d.ts +5 -0
  7. package/transpiled/context.js +6 -0
  8. package/transpiled/context.js.map +1 -1
  9. package/transpiled/emission.d.ts +4 -2
  10. package/transpiled/emission.js +4 -2
  11. package/transpiled/emission.js.map +1 -1
  12. package/transpiled/entities/entity.js +34 -6
  13. package/transpiled/entities/entity.js.map +1 -1
  14. package/transpiled/entities/factory.d.ts +5 -0
  15. package/transpiled/entities/factory.js +6 -2
  16. package/transpiled/entities/factory.js.map +1 -1
  17. package/transpiled/event.d.ts +2 -2
  18. package/transpiled/event.js +6 -1
  19. package/transpiled/event.js.map +1 -1
  20. package/transpiled/exceptions.d.ts +19 -0
  21. package/transpiled/exceptions.js +74 -2
  22. package/transpiled/exceptions.js.map +1 -1
  23. package/transpiled/index.d.ts +2 -1
  24. package/transpiled/index.js +2 -1
  25. package/transpiled/index.js.map +1 -1
  26. package/transpiled/{outbox/outbox.d.ts → outbox.d.ts} +6 -7
  27. package/transpiled/outbox.js +424 -0
  28. package/transpiled/outbox.js.map +1 -0
  29. package/transpiled/query/options.js +1 -1
  30. package/transpiled/query/options.js.map +1 -1
  31. package/transpiled/receiver.js +14 -1
  32. package/transpiled/receiver.js.map +1 -1
  33. package/transpiled/remote.js +2 -3
  34. package/transpiled/remote.js.map +1 -1
  35. package/transpiled/state.d.ts +1 -1
  36. package/transpiled/trail.d.ts +49 -0
  37. package/transpiled/trail.js +98 -0
  38. package/transpiled/trail.js.map +1 -0
  39. package/transpiled/types/bindings.d.ts +22 -0
  40. package/transpiled/types/extensions.d.ts +13 -2
  41. package/transpiled/types/message.d.ts +5 -0
  42. package/transpiled/types/outbox.d.ts +29 -3
  43. package/transpiled/types/request.d.ts +5 -0
  44. package/transpiled/types/storages.d.ts +20 -0
  45. package/CHANGELOG.md +0 -43
  46. package/source/assignment.ts +0 -27
  47. package/source/call.ts +0 -63
  48. package/source/cascade.ts +0 -32
  49. package/source/component.ts +0 -83
  50. package/source/composition.ts +0 -27
  51. package/source/connector.ts +0 -217
  52. package/source/context.ts +0 -68
  53. package/source/contract/contract.ts +0 -23
  54. package/source/contract/index.ts +0 -2
  55. package/source/contract/reply.ts +0 -56
  56. package/source/contract/request.ts +0 -140
  57. package/source/contract/schemas.ts +0 -39
  58. package/source/discovery.ts +0 -53
  59. package/source/effect.ts +0 -14
  60. package/source/emission.ts +0 -21
  61. package/source/entities/changeset.ts +0 -37
  62. package/source/entities/entity.ts +0 -137
  63. package/source/entities/factory.ts +0 -52
  64. package/source/entities/index.ts +0 -4
  65. package/source/entities/newid.ts +0 -9
  66. package/source/entities/set.ts +0 -27
  67. package/source/event.ts +0 -57
  68. package/source/exceptions.ts +0 -133
  69. package/source/exposition.ts +0 -33
  70. package/source/guard.ts +0 -16
  71. package/source/index.ts +0 -36
  72. package/source/locator.ts +0 -37
  73. package/source/observation.ts +0 -16
  74. package/source/operation.ts +0 -139
  75. package/source/outbox/index.ts +0 -1
  76. package/source/outbox/outbox.ts +0 -341
  77. package/source/query/criteria.ts +0 -90
  78. package/source/query/options.ts +0 -35
  79. package/source/query.ts +0 -67
  80. package/source/receiver.ts +0 -120
  81. package/source/reflection.ts +0 -20
  82. package/source/remote.ts +0 -20
  83. package/source/state.ts +0 -179
  84. package/source/transition.ts +0 -79
  85. package/source/transmission.ts +0 -38
  86. package/source/types/atomicity.ts +0 -63
  87. package/source/types/bindings.ts +0 -59
  88. package/source/types/bridges.ts +0 -54
  89. package/source/types/extensions.ts +0 -89
  90. package/source/types/index.ts +0 -14
  91. package/source/types/message.ts +0 -5
  92. package/source/types/operations.ts +0 -31
  93. package/source/types/outbox.ts +0 -35
  94. package/source/types/receiver.ts +0 -10
  95. package/source/types/request.ts +0 -54
  96. package/source/types/state.ts +0 -9
  97. package/source/types/storages.ts +0 -134
  98. package/source/unmanaged.ts +0 -8
  99. package/test/call.fixtures.js +0 -25
  100. package/test/call.test.js +0 -79
  101. package/test/component.fixtures.js +0 -18
  102. package/test/component.test.js +0 -57
  103. package/test/connector.fixtures.js +0 -56
  104. package/test/connector.test.js +0 -266
  105. package/test/context.fixtures.js +0 -14
  106. package/test/context.test.js +0 -40
  107. package/test/contract/conditions.test.js +0 -32
  108. package/test/contract/contract.fixtures.js +0 -28
  109. package/test/contract/request.test.js +0 -196
  110. package/test/discovery.test.js +0 -71
  111. package/test/emission.fixtures.js +0 -13
  112. package/test/emission.test.js +0 -60
  113. package/test/entities/entity.fixtures.js +0 -24
  114. package/test/entities/entity.test.js +0 -137
  115. package/test/entities/factory.fixtures.js +0 -31
  116. package/test/entities/factory.test.js +0 -99
  117. package/test/entities/set.fixtures.js +0 -9
  118. package/test/entities/set.test.js +0 -13
  119. package/test/event.fixtures.js +0 -24
  120. package/test/event.test.js +0 -162
  121. package/test/locator.test.js +0 -120
  122. package/test/outbox.test.js +0 -202
  123. package/test/query.fixtures.js +0 -96
  124. package/test/query.test.js +0 -183
  125. package/test/receiver.fixtures.js +0 -20
  126. package/test/receiver.test.js +0 -144
  127. package/test/reflection.test.js +0 -31
  128. package/test/state.fixtures.js +0 -49
  129. package/test/state.test.js +0 -162
  130. package/test/transmission.fixtures.js +0 -13
  131. package/test/transmission.test.js +0 -77
  132. package/transpiled/outbox/index.d.ts +0 -1
  133. package/transpiled/outbox/index.js +0 -2
  134. package/transpiled/outbox/index.js.map +0 -1
  135. package/transpiled/outbox/outbox.js +0 -268
  136. package/transpiled/outbox/outbox.js.map +0 -1
  137. package/tsconfig.json +0 -10
  138. package/tsconfig.tsbuildinfo +0 -1
@@ -1,202 +0,0 @@
1
- import { it, beforeEach, afterEach, mock } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import { Outbox } from '../source/outbox/index.js'
5
-
6
- let emission, storage, atom, outbox, listeners
7
-
8
- const BATCH = 4
9
-
10
- /** rows as the storage hands them back, ids ascending like the uuid v7 they are */
11
- const page = (from, count) =>
12
- Array.from({ length: count }, (_, i) => ({
13
- id: String(from + i).padStart(4, '0'),
14
- event: { state: {} }
15
- }))
16
-
17
- beforeEach(() => {
18
- resetCalls()
19
- mock.timers.enable()
20
-
21
- emission = { emit: mock.fn(async () => undefined), link: mock.fn() }
22
-
23
- storage = {
24
- link: mock.fn(),
25
- outbox: {
26
- pending: mock.fn(async () => []),
27
- settle: mock.fn(async () => undefined)
28
- }
29
- }
30
-
31
- listeners = []
32
-
33
- atom = {
34
- slots: mock.fn(() => [0]),
35
- onassigned: (listener) => {
36
- listeners.push(listener)
37
- listener({ i: 0, n: 1 })
38
-
39
- return () => {
40
- listeners = listeners.filter((one) => one !== listener)
41
- }
42
- },
43
- link: mock.fn()
44
- }
45
- outbox = new Outbox(emission, storage, atom, { interval: 1000, batch: BATCH })
46
- })
47
-
48
- afterEach(() => {
49
- mock.timers.reset()
50
- })
51
-
52
- /** everything the current turn awaited, without moving the clock */
53
- const settled = async () => {
54
- for (let i = 0; i < 20; i++) await Promise.resolve()
55
- }
56
-
57
- /** one cycle, and everything it awaited */
58
- const cycle = async () => {
59
- mock.timers.tick(1000)
60
-
61
- for (let i = 0; i < 20; i++) await Promise.resolve()
62
- }
63
-
64
- it('should read nothing more when the first page is short', async () => {
65
- storage.outbox.pending.mock.mockImplementationOnce(async () => page(0, 3))
66
-
67
- await outbox.open()
68
- await cycle()
69
-
70
- assert.strictEqual(storage.outbox.pending.mock.callCount(), 1)
71
- assert.strictEqual(emission.emit.mock.callCount(), 3)
72
- })
73
-
74
- it('should keep reading while a page comes back full', async () => {
75
- storage.outbox.pending.mock.mockImplementationOnce(
76
- async () => page(0, BATCH),
77
- storage.outbox.pending.mock.callCount()
78
- )
79
- storage.outbox.pending.mock.mockImplementationOnce(
80
- async () => page(BATCH, BATCH),
81
- storage.outbox.pending.mock.callCount() + 1
82
- )
83
- storage.outbox.pending.mock.mockImplementationOnce(
84
- async () => page(2 * BATCH, 5),
85
- storage.outbox.pending.mock.callCount() + 2
86
- )
87
-
88
- await outbox.open()
89
- await cycle()
90
-
91
- assert.strictEqual(storage.outbox.pending.mock.callCount(), 3)
92
- assert.strictEqual(emission.emit.mock.callCount(), 2 * BATCH + 5)
93
- })
94
-
95
- it('should continue each page from the id the one before ended on', async () => {
96
- storage.outbox.pending.mock.mockImplementationOnce(
97
- async () => page(0, BATCH),
98
- storage.outbox.pending.mock.callCount()
99
- )
100
- storage.outbox.pending.mock.mockImplementationOnce(
101
- async () => page(BATCH, 1),
102
- storage.outbox.pending.mock.callCount() + 1
103
- )
104
-
105
- await outbox.open()
106
- await cycle()
107
-
108
- const [, second] = storage.outbox.pending.mock.calls
109
-
110
- assert.strictEqual(storage.outbox.pending.mock.calls[0].arguments[3], undefined)
111
- assert.deepStrictEqual(second.arguments[3], String(BATCH - 1).padStart(4, '0'))
112
- })
113
-
114
- it('should mark what it published, once, after the last page', async () => {
115
- storage.outbox.pending.mock.mockImplementationOnce(
116
- async () => page(0, BATCH),
117
- storage.outbox.pending.mock.callCount()
118
- )
119
- storage.outbox.pending.mock.mockImplementationOnce(
120
- async () => page(BATCH, 2),
121
- storage.outbox.pending.mock.callCount() + 1
122
- )
123
-
124
- await outbox.open()
125
- await cycle()
126
-
127
- assert.strictEqual(storage.outbox.settle.mock.callCount(), 1)
128
- assert.strictEqual(storage.outbox.settle.mock.calls[0].arguments[0].length, BATCH + 2)
129
- })
130
-
131
- it('should not publish a row it has published and not yet marked', async () => {
132
- storage.outbox.settle.mock.mockImplementationOnce(async () => {
133
- throw new Error('mongo is out')
134
- })
135
- storage.outbox.pending.mock.mockImplementationOnce(
136
- async () => page(0, 2),
137
- storage.outbox.pending.mock.callCount()
138
- )
139
- storage.outbox.pending.mock.mockImplementationOnce(
140
- async () => page(0, 2),
141
- storage.outbox.pending.mock.callCount() + 1
142
- )
143
-
144
- await outbox.open()
145
- await cycle()
146
- await cycle()
147
-
148
- assert.strictEqual(emission.emit.mock.callCount(), 2)
149
- })
150
-
151
- it('should read nothing while it owns no slots', async () => {
152
- atom.slots.mock.mockImplementation(() => null)
153
-
154
- await outbox.open()
155
- await cycle()
156
-
157
- assert.strictEqual(storage.outbox.pending.mock.callCount(), 0)
158
- })
159
-
160
- function resetCalls(target = [assert, BATCH, page, cycle], seen = new Set()) {
161
- if (target === null || typeof target !== 'object' || seen.has(target)) return
162
-
163
- seen.add(target)
164
-
165
- for (const value of Object.values(target))
166
- if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
167
- else resetCalls(value, seen)
168
- }
169
-
170
- it('should read as soon as a claim arrives, rather than on its next cycle', async () => {
171
- atom.slots.mock.mockImplementation(() => null)
172
-
173
- await outbox.open()
174
- await settled()
175
-
176
- assert.strictEqual(storage.outbox.pending.mock.callCount(), 0, 'nothing is owned yet')
177
-
178
- atom.slots.mock.mockImplementation(() => [0])
179
-
180
- for (const listener of listeners) listener({ i: 0, n: 1 })
181
-
182
- await settled()
183
-
184
- assert.strictEqual(
185
- storage.outbox.pending.mock.callCount(),
186
- 1,
187
- 'the lane is its own now, and the cycle is up to five seconds away'
188
- )
189
- })
190
-
191
- it('should read the lanes it inherits when the group resizes', async () => {
192
- await outbox.open()
193
- await settled()
194
-
195
- const before = storage.outbox.pending.mock.callCount()
196
-
197
- for (const listener of listeners) listener({ i: 0, n: 2 })
198
-
199
- await settled()
200
-
201
- assert.strictEqual(storage.outbox.pending.mock.callCount(), before + 1)
202
- })
@@ -1,96 +0,0 @@
1
- export const samples = {
2
- simple: {
3
- query: {
4
- criteria: 'name==Eddie'
5
- },
6
- parsed: {
7
- criteria: {
8
- type: 'COMPARISON',
9
- left: { type: 'SELECTOR', selector: 'name' },
10
- operator: '==',
11
- right: { type: 'VALUE', value: 'Eddie' }
12
- }
13
- },
14
- properties: {
15
- name: {
16
- type: 'string'
17
- }
18
- }
19
- },
20
-
21
- extended: {
22
- query: {
23
- criteria: 'flag==true;volume>2.1'
24
- },
25
- parsed: {
26
- criteria: {
27
- type: 'LOGIC',
28
- left: {
29
- type: 'COMPARISON',
30
- left: { type: 'SELECTOR', selector: 'flag' },
31
- operator: '==',
32
- right: { type: 'VALUE', value: true }
33
- },
34
- operator: ';',
35
- right: {
36
- type: 'COMPARISON',
37
- left: { type: 'SELECTOR', selector: 'volume' },
38
- operator: '>',
39
- right: { type: 'VALUE', value: 2.1 }
40
- }
41
- }
42
- },
43
- properties: {
44
- flag: {
45
- type: 'boolean'
46
- },
47
- volume: {
48
- type: 'number'
49
- }
50
- }
51
- },
52
-
53
- abc: {
54
- properties: {
55
- a: {
56
- type: 'string'
57
- },
58
- b: {
59
- type: 'string'
60
- },
61
- c: {
62
- type: 'string'
63
- }
64
- }
65
- },
66
-
67
- id: {
68
- properties: {
69
- id: {
70
- type: 'string'
71
- },
72
- name: {
73
- type: 'string'
74
- }
75
- },
76
- query: {
77
- id: '123',
78
- criteria: 'name==Eddie'
79
- },
80
- parsed: {
81
- id: '123',
82
- criteria: {
83
- type: 'COMPARISON',
84
- left: {
85
- type: 'SELECTOR',
86
- selector: 'name'
87
- },
88
- operator: '==',
89
- right: {
90
- type: 'VALUE',
91
- value: 'Eddie'
92
- }
93
- }
94
- }
95
- }
96
- }
@@ -1,183 +0,0 @@
1
- import { describe, it, beforeEach } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import { Query } from '../source/query.js'
5
- import * as fixtures from './query.fixtures.js'
6
-
7
- beforeEach(() => {
8
- resetCalls()
9
- })
10
-
11
- describe('criteria', () => {
12
- it('should not throw if no criteria', () => {
13
- const instance = new Query(fixtures.samples.simple.properties)
14
- const query = instance.parse({})
15
-
16
- assert.strictEqual(query.criteria, undefined)
17
- })
18
-
19
- it('should parse criteria', () => {
20
- const instance = new Query(fixtures.samples.simple.properties)
21
- const query = instance.parse(fixtures.samples.simple.query)
22
-
23
- assert.deepStrictEqual(query.criteria, fixtures.samples.simple.parsed.criteria)
24
- })
25
-
26
- it('should coerce every value of a list', () => {
27
- const instance = new Query({ n: { type: 'integer' } })
28
- const query = instance.parse({ criteria: 'n=in=(1,2,3)' })
29
-
30
- assert.deepStrictEqual(query.criteria.right.value, [1, 2, 3])
31
- })
32
-
33
- it('should keep a parsed criteria', () => {
34
- const instance = new Query(fixtures.samples.simple.properties)
35
-
36
- const first = instance.parse(fixtures.samples.simple.query).criteria
37
- const second = instance.parse(fixtures.samples.simple.query).criteria
38
-
39
- assert.strictEqual(second, first)
40
- })
41
-
42
- it('should not keep an invalid criteria', () => {
43
- const instance = new Query(fixtures.samples.simple.properties)
44
- const query = { criteria: 'nonexistent==1' }
45
-
46
- assert.throws(() => instance.parse(query))
47
- assert.throws(() => instance.parse(query))
48
- })
49
-
50
- it('should parse criteria with type coercion', () => {
51
- const instance = new Query(fixtures.samples.extended.properties)
52
- const query = instance.parse(fixtures.samples.extended.query)
53
-
54
- assert.deepStrictEqual(query.criteria, fixtures.samples.extended.parsed.criteria)
55
- })
56
-
57
- it('should refuse a value the property cannot hold', () => {
58
- const strict = new Query({
59
- volume: { type: 'number' },
60
- count: { type: 'integer' },
61
- booked: { type: 'boolean' }
62
- })
63
-
64
- const refused = [
65
- ['volume>abc', /takes a number/],
66
- ['volume==1.5kg', /takes a number/],
67
- ['count==1.5', /takes an integer/],
68
- ['count==12kg', /takes an integer/],
69
- ['booked==yes', /takes a boolean/],
70
- ['booked==TRUE', /takes a boolean/],
71
- ['volume=in=(1,two)', /'two' is not one/]
72
- ]
73
-
74
- for (const [criteria, message] of refused)
75
- assert.throws(
76
- () => strict.parse({ criteria }),
77
- (error) => message.test(error.message),
78
- criteria
79
- )
80
- })
81
-
82
- it('should read a value the property can hold', () => {
83
- const strict = new Query({
84
- volume: { type: 'number' },
85
- count: { type: 'integer' },
86
- booked: { type: 'boolean' },
87
- title: { type: 'string' }
88
- })
89
-
90
- const read = [
91
- ['volume>1.5', 1.5],
92
- ['volume>-1.5', -1.5],
93
- ['count==12', 12],
94
- ['booked==false', false],
95
- ['title==12kg', '12kg']
96
- ]
97
-
98
- for (const [criteria, value] of read)
99
- assert.deepStrictEqual(
100
- strict.parse({ criteria }).criteria.right.value,
101
- value,
102
- criteria
103
- )
104
- })
105
-
106
- it('should throw on unknown properties', () => {
107
- const instance = new Query(fixtures.samples.simple.properties)
108
-
109
- assert.throws(
110
- () => instance.parse({ criteria: 'lastname==Johnson' }),
111
- (error) => /not defined/.test(error.message)
112
- )
113
- })
114
-
115
- it('should parse id', () => {
116
- const instance = new Query(fixtures.samples.id.properties)
117
- const query = instance.parse({ ...fixtures.samples.id.query })
118
-
119
- assert.deepStrictEqual(query, fixtures.samples.id.parsed)
120
- })
121
- })
122
-
123
- describe('options', () => {
124
- const instance = new Query(fixtures.samples.abc.properties)
125
-
126
- it('should not throw if no options', () => {
127
- const query = instance.parse({})
128
-
129
- assert.strictEqual(query.options, undefined)
130
- })
131
-
132
- describe('omit, limit', () => {
133
- it('should pass', () => {
134
- const input = { omit: 1, limit: 1 }
135
- const query = instance.parse(input)
136
-
137
- assert.deepStrictEqual(query.options, input)
138
- })
139
- })
140
-
141
- describe('sort', () => {
142
- it('should set default values', () => {
143
- const sort = ['a', 'b:desc', 'c']
144
- const query = instance.parse({ sort })
145
-
146
- assert.deepStrictEqual(query.options.sort, [
147
- ['a', 'asc'],
148
- ['b', 'desc'],
149
- ['c', 'asc']
150
- ])
151
- })
152
-
153
- it('should throw on unknown properties', () => {
154
- const sort = ['d:asc']
155
-
156
- assert.throws(
157
- () => instance.parse({ sort }),
158
- (error) => /not defined/.test(error.message)
159
- )
160
- })
161
- })
162
-
163
- describe('projection', () => {
164
- it('should throw on unknown properties', () => {
165
- const projection = ['a', 'b', 'c', 'd']
166
-
167
- assert.throws(
168
- () => instance.parse({ projection }),
169
- (error) => /not defined/.test(error.message)
170
- )
171
- })
172
- })
173
- })
174
-
175
- function resetCalls(target = [assert, fixtures], seen = new Set()) {
176
- if (target === null || typeof target !== 'object' || seen.has(target)) return
177
-
178
- seen.add(target)
179
-
180
- for (const value of Object.values(target))
181
- if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
182
- else resetCalls(value, seen)
183
- }
@@ -1,20 +0,0 @@
1
- import { mock } from 'node:test'
2
-
3
- import { generate } from 'randomstring'
4
-
5
- export const definition = /** @type {toa.norm.component.Receiver} */ {
6
- operation: generate(),
7
- conditioned: false,
8
- adaptive: false
9
- }
10
-
11
- export const local = /** @type {import('@toa.io/core').Component} */ {
12
- locator: { id: 'default.dummy' },
13
- invoke: mock.fn()
14
- }
15
-
16
- // noinspection JSCheckFunctionSignatures
17
- export const bridge = /** @type {import('@toa.io/core/types').bridges.Event} */ {
18
- condition: mock.fn(async (payload) => !(payload.reject === true)),
19
- request: mock.fn(async () => ({ input: generate() }))
20
- }
@@ -1,144 +0,0 @@
1
- import { describe, it, beforeEach, mock } from 'node:test'
2
- import assert from 'node:assert/strict'
3
- import { isDeepStrictEqual } from 'node:util'
4
-
5
- import clone from 'clone-deep'
6
- import { generate } from 'randomstring'
7
- import { merge } from '@toa.io/generic'
8
-
9
- import { Connector } from '../source/connector.js'
10
-
11
- // the fixtures are not connectors, so a dependency is recorded rather than linked
12
- const depends = mock.method(Connector.prototype, 'depends', () => undefined)
13
-
14
- const dependencies = (instance) =>
15
- depends.mock.calls
16
- .filter((call) => call.this === instance)
17
- .map((call) => call.arguments[0])
18
-
19
- import { Receiver } from '../source/receiver.js'
20
- import * as fixtures from './receiver.fixtures.js'
21
-
22
- /** @type {import('@toa.io/core/types').Receiver} */
23
- let receiver
24
-
25
- /** @type {toa.norm.component.Receiver} */
26
- let definition
27
-
28
- beforeEach(() => {
29
- resetCalls()
30
- depends.mock.resetCalls()
31
-
32
- definition = clone(fixtures.definition)
33
- receiver = new Receiver(fixtures.definition, fixtures.local, fixtures.bridge)
34
- })
35
-
36
- it('should depend on local, bridge', () => {
37
- assert.ok(dependencies(receiver).some((one) => isDeepStrictEqual(one, fixtures.local)))
38
- assert.ok(dependencies(receiver).some((one) => isDeepStrictEqual(one, fixtures.bridge)))
39
- })
40
-
41
- it('should apply', async () => {
42
- const payload = { foo: 'bar' }
43
-
44
- await receiver.receive({ payload })
45
-
46
- assert.ok(
47
- fixtures.local.invoke.mock.calls.some(
48
- (call) =>
49
- call.arguments.length === 2 &&
50
- isDeepStrictEqual(call.arguments[0], definition.operation) &&
51
- isDeepStrictEqual(call.arguments[1], { input: payload })
52
- )
53
- )
54
- })
55
-
56
- for (const [adaptive] of [[false], [true]])
57
- it(`should pass UI extensions (adaptive: ${adaptive})`, async () => {
58
- resetCalls()
59
-
60
- definition.adaptive = adaptive
61
- receiver = new Receiver(definition, fixtures.local, fixtures.bridge)
62
-
63
- const payload = { foo: generate() }
64
- const extension = { [generate()]: generate() }
65
- const message = { payload, ...extension }
66
-
67
- await receiver.receive(message)
68
-
69
- const request = adaptive
70
- ? await fixtures.bridge.request.mock.calls[0].result
71
- : { input: payload }
72
- const expected = merge(clone(request), extension)
73
-
74
- const argument = fixtures.local.invoke.mock.calls[0].arguments[1]
75
-
76
- assert.deepStrictEqual(argument, expected)
77
- })
78
-
79
- describe('conditioned', () => {
80
- beforeEach(() => {
81
- definition.conditioned = true
82
- receiver = new Receiver(definition, fixtures.local, fixtures.bridge)
83
- })
84
-
85
- it('should test condition', async () => {
86
- const payload = { foo: 'bar' }
87
- await receiver.receive({ payload })
88
-
89
- assert.ok(
90
- fixtures.bridge.condition.mock.calls.some(
91
- (call) =>
92
- call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], payload)
93
- )
94
- )
95
- assert.ok(
96
- fixtures.local.invoke.mock.calls.some(
97
- (call) =>
98
- call.arguments.length === 2 &&
99
- isDeepStrictEqual(call.arguments[0], definition.operation) &&
100
- isDeepStrictEqual(call.arguments[1], { input: payload })
101
- )
102
- )
103
- })
104
-
105
- it('should not apply if condition is false', async () => {
106
- const payload = { reject: true }
107
- await receiver.receive({ payload })
108
-
109
- assert.strictEqual(fixtures.local.invoke.mock.callCount(), 0)
110
- })
111
- })
112
-
113
- describe('adaptive', () => {
114
- beforeEach(() => {
115
- definition.adaptive = true
116
- receiver = new Receiver(definition, fixtures.local, fixtures.bridge)
117
- })
118
-
119
- it('should apply', async () => {
120
- const payload = { reject: true }
121
- await receiver.receive({ payload })
122
-
123
- const request = await fixtures.bridge.request.mock.calls[0].result
124
-
125
- assert.ok(
126
- fixtures.local.invoke.mock.calls.some(
127
- (call) =>
128
- call.arguments.length === 2 &&
129
- isDeepStrictEqual(call.arguments[0], definition.operation) &&
130
- isDeepStrictEqual(call.arguments[1], request)
131
- )
132
- )
133
- })
134
- })
135
-
136
- function resetCalls(target = [assert, clone, fixtures], seen = new Set()) {
137
- if (target === null || typeof target !== 'object' || seen.has(target)) return
138
-
139
- seen.add(target)
140
-
141
- for (const value of Object.values(target))
142
- if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
143
- else resetCalls(value, seen)
144
- }
@@ -1,31 +0,0 @@
1
- import { it, beforeEach } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import { generate } from 'randomstring'
5
- import { Reflection, Connector } from '../source/index.js'
6
-
7
- it('should export', () => {
8
- assert.notStrictEqual(Reflection, undefined)
9
- })
10
-
11
- /** @type {import('@toa.io/core').Reflection<string>} */
12
- let reflection
13
-
14
- const value = generate()
15
-
16
- /** @type {import('@toa.io/core').ReflectionSource<string>} */
17
- const source = async () => value
18
-
19
- beforeEach(() => {
20
- reflection = new Reflection(source)
21
- })
22
-
23
- it('should be a Connector', () => {
24
- assert.ok(reflection instanceof Connector)
25
- })
26
-
27
- it('should reflect', async () => {
28
- await reflection.connect()
29
-
30
- assert.deepStrictEqual(reflection.value, value)
31
- })