@toa.io/core 1.0.0-alpha.29 → 1.0.0-alpha.291

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 (304) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/package.json +22 -12
  3. package/source/assignment.ts +27 -0
  4. package/source/call.ts +63 -0
  5. package/source/cascade.ts +32 -0
  6. package/source/component.ts +83 -0
  7. package/source/composition.ts +27 -0
  8. package/source/connector.ts +217 -0
  9. package/source/context.ts +68 -0
  10. package/source/contract/contract.ts +23 -0
  11. package/source/contract/index.ts +2 -0
  12. package/source/contract/reply.ts +56 -0
  13. package/source/contract/request.ts +140 -0
  14. package/source/contract/schemas.ts +39 -0
  15. package/source/discovery.ts +53 -0
  16. package/source/effect.ts +14 -0
  17. package/source/emission.ts +21 -0
  18. package/source/entities/changeset.ts +37 -0
  19. package/source/entities/entity.ts +137 -0
  20. package/source/entities/factory.ts +52 -0
  21. package/source/entities/index.ts +4 -0
  22. package/source/entities/newid.ts +9 -0
  23. package/source/entities/set.ts +27 -0
  24. package/source/event.ts +57 -0
  25. package/source/exceptions.ts +133 -0
  26. package/source/exposition.ts +33 -0
  27. package/source/guard.ts +16 -0
  28. package/source/index.ts +36 -0
  29. package/source/locator.ts +37 -0
  30. package/source/observation.ts +16 -0
  31. package/source/operation.ts +139 -0
  32. package/source/outbox/index.ts +1 -0
  33. package/source/outbox/outbox.ts +341 -0
  34. package/source/query/criteria.ts +90 -0
  35. package/source/query/options.ts +35 -0
  36. package/source/query.ts +67 -0
  37. package/source/receiver.ts +120 -0
  38. package/source/reflection.ts +20 -0
  39. package/source/remote.ts +20 -0
  40. package/source/state.ts +179 -0
  41. package/source/transition.ts +79 -0
  42. package/source/transmission.ts +38 -0
  43. package/source/types/atomicity.ts +63 -0
  44. package/source/types/bindings.ts +59 -0
  45. package/source/types/bridges.ts +54 -0
  46. package/source/types/extensions.ts +89 -0
  47. package/source/types/index.ts +14 -0
  48. package/{types/message.d.ts → source/types/message.ts} +2 -0
  49. package/source/types/operations.ts +31 -0
  50. package/source/types/outbox.ts +35 -0
  51. package/source/types/receiver.ts +10 -0
  52. package/source/types/request.ts +54 -0
  53. package/source/types/state.ts +9 -0
  54. package/source/types/storages.ts +134 -0
  55. package/source/unmanaged.ts +8 -0
  56. package/test/call.fixtures.js +10 -12
  57. package/test/call.test.js +42 -9
  58. package/test/component.fixtures.js +5 -8
  59. package/test/component.test.js +27 -10
  60. package/test/connector.fixtures.js +29 -13
  61. package/test/connector.test.js +128 -38
  62. package/test/context.fixtures.js +8 -12
  63. package/test/context.test.js +19 -8
  64. package/test/contract/conditions.test.js +15 -9
  65. package/test/contract/contract.fixtures.js +11 -16
  66. package/test/contract/request.test.js +130 -46
  67. package/test/discovery.test.js +71 -0
  68. package/test/emission.fixtures.js +6 -10
  69. package/test/emission.test.js +37 -12
  70. package/test/entities/entity.fixtures.js +11 -16
  71. package/test/entities/entity.test.js +105 -50
  72. package/test/entities/factory.fixtures.js +26 -13
  73. package/test/entities/factory.test.js +68 -17
  74. package/test/entities/set.fixtures.js +6 -8
  75. package/test/entities/set.test.js +6 -5
  76. package/test/event.fixtures.js +9 -14
  77. package/test/event.test.js +78 -34
  78. package/test/locator.test.js +32 -25
  79. package/test/outbox.test.js +202 -0
  80. package/test/query.fixtures.js +1 -5
  81. package/test/query.test.js +111 -14
  82. package/test/receiver.fixtures.js +9 -12
  83. package/test/receiver.test.js +80 -31
  84. package/test/reflection.test.js +9 -8
  85. package/test/state.fixtures.js +33 -31
  86. package/test/state.test.js +135 -19
  87. package/test/transmission.fixtures.js +4 -6
  88. package/test/transmission.test.js +47 -16
  89. package/transpiled/assignment.d.ts +6 -0
  90. package/transpiled/assignment.js +20 -0
  91. package/transpiled/assignment.js.map +1 -0
  92. package/transpiled/call.d.ts +10 -0
  93. package/transpiled/call.js +52 -0
  94. package/transpiled/call.js.map +1 -0
  95. package/transpiled/cascade.d.ts +7 -0
  96. package/transpiled/cascade.js +28 -0
  97. package/transpiled/cascade.js.map +1 -0
  98. package/transpiled/component.d.ts +15 -0
  99. package/transpiled/component.js +61 -0
  100. package/transpiled/component.js.map +1 -0
  101. package/transpiled/composition.d.ts +6 -0
  102. package/transpiled/composition.js +23 -0
  103. package/transpiled/composition.js.map +1 -0
  104. package/transpiled/connector.d.ts +47 -0
  105. package/transpiled/connector.js +185 -0
  106. package/transpiled/connector.js.map +1 -0
  107. package/transpiled/context.d.ts +18 -0
  108. package/transpiled/context.js +42 -0
  109. package/transpiled/context.js.map +1 -0
  110. package/transpiled/contract/contract.d.ts +10 -0
  111. package/transpiled/contract/contract.js +14 -0
  112. package/transpiled/contract/contract.js.map +1 -0
  113. package/transpiled/contract/index.d.ts +2 -0
  114. package/transpiled/contract/index.js +3 -0
  115. package/transpiled/contract/index.js.map +1 -0
  116. package/transpiled/contract/reply.d.ts +7 -0
  117. package/transpiled/contract/reply.js +48 -0
  118. package/transpiled/contract/reply.js.map +1 -0
  119. package/transpiled/contract/request.d.ts +29 -0
  120. package/transpiled/contract/request.js +103 -0
  121. package/transpiled/contract/request.js.map +1 -0
  122. package/transpiled/contract/schemas.d.ts +4 -0
  123. package/transpiled/contract/schemas.js +36 -0
  124. package/transpiled/contract/schemas.js.map +1 -0
  125. package/transpiled/discovery.d.ts +12 -0
  126. package/transpiled/discovery.js +34 -0
  127. package/transpiled/discovery.js.map +1 -0
  128. package/transpiled/effect.d.ts +5 -0
  129. package/transpiled/effect.js +11 -0
  130. package/transpiled/effect.js.map +1 -0
  131. package/transpiled/emission.d.ts +8 -0
  132. package/transpiled/emission.js +14 -0
  133. package/transpiled/emission.js.map +1 -0
  134. package/transpiled/entities/changeset.d.ts +10 -0
  135. package/transpiled/entities/changeset.js +27 -0
  136. package/transpiled/entities/changeset.js.map +1 -0
  137. package/transpiled/entities/entity.d.ts +19 -0
  138. package/transpiled/entities/entity.js +109 -0
  139. package/transpiled/entities/entity.js.map +1 -0
  140. package/transpiled/entities/factory.d.ts +22 -0
  141. package/transpiled/entities/factory.js +34 -0
  142. package/transpiled/entities/factory.js.map +1 -0
  143. package/transpiled/entities/index.d.ts +4 -0
  144. package/transpiled/entities/index.js +5 -0
  145. package/transpiled/entities/index.js.map +1 -0
  146. package/transpiled/entities/newid.d.ts +1 -0
  147. package/transpiled/entities/newid.js +7 -0
  148. package/transpiled/entities/newid.js.map +1 -0
  149. package/transpiled/entities/set.d.ts +10 -0
  150. package/transpiled/entities/set.js +19 -0
  151. package/transpiled/entities/set.js.map +1 -0
  152. package/transpiled/event.d.ts +14 -0
  153. package/transpiled/event.js +38 -0
  154. package/transpiled/event.js.map +1 -0
  155. package/transpiled/exceptions.d.ts +61 -0
  156. package/transpiled/exceptions.js +93 -0
  157. package/transpiled/exceptions.js.map +1 -0
  158. package/transpiled/exposition.d.ts +18 -0
  159. package/transpiled/exposition.js +18 -0
  160. package/transpiled/exposition.js.map +1 -0
  161. package/transpiled/guard.d.ts +7 -0
  162. package/transpiled/guard.js +12 -0
  163. package/transpiled/guard.js.map +1 -0
  164. package/transpiled/index.d.ts +35 -0
  165. package/transpiled/index.js +29 -0
  166. package/transpiled/index.js.map +1 -0
  167. package/transpiled/locator.d.ts +12 -0
  168. package/transpiled/locator.js +32 -0
  169. package/transpiled/locator.js.map +1 -0
  170. package/transpiled/observation.d.ts +5 -0
  171. package/transpiled/observation.js +12 -0
  172. package/transpiled/observation.js.map +1 -0
  173. package/transpiled/operation.d.ts +49 -0
  174. package/transpiled/operation.js +78 -0
  175. package/transpiled/operation.js.map +1 -0
  176. package/transpiled/outbox/index.d.ts +1 -0
  177. package/transpiled/outbox/index.js +2 -0
  178. package/transpiled/outbox/index.js.map +1 -0
  179. package/transpiled/outbox/outbox.d.ts +46 -0
  180. package/transpiled/outbox/outbox.js +268 -0
  181. package/transpiled/outbox/outbox.js.map +1 -0
  182. package/transpiled/query/criteria.d.ts +6 -0
  183. package/transpiled/query/criteria.js +74 -0
  184. package/transpiled/query/criteria.js.map +1 -0
  185. package/transpiled/query/options.d.ts +3 -0
  186. package/transpiled/query/options.js +27 -0
  187. package/transpiled/query/options.js.map +1 -0
  188. package/transpiled/query.d.ts +9 -0
  189. package/transpiled/query.js +57 -0
  190. package/transpiled/query.js.map +1 -0
  191. package/transpiled/receiver.d.ts +20 -0
  192. package/transpiled/receiver.js +92 -0
  193. package/transpiled/receiver.js.map +1 -0
  194. package/transpiled/reflection.d.ts +9 -0
  195. package/transpiled/reflection.js +13 -0
  196. package/transpiled/reflection.js.map +1 -0
  197. package/transpiled/remote.d.ts +10 -0
  198. package/transpiled/remote.js +12 -0
  199. package/transpiled/remote.js.map +1 -0
  200. package/transpiled/state.d.ts +33 -0
  201. package/transpiled/state.js +126 -0
  202. package/transpiled/state.js.map +1 -0
  203. package/transpiled/transition.d.ts +14 -0
  204. package/transpiled/transition.js +51 -0
  205. package/transpiled/transition.js.map +1 -0
  206. package/transpiled/transmission.d.ts +8 -0
  207. package/transpiled/transmission.js +30 -0
  208. package/transpiled/transmission.js.map +1 -0
  209. package/transpiled/types/atomicity.d.ts +56 -0
  210. package/transpiled/types/atomicity.js +2 -0
  211. package/transpiled/types/atomicity.js.map +1 -0
  212. package/transpiled/types/bindings.d.ts +42 -0
  213. package/transpiled/types/bindings.js +2 -0
  214. package/transpiled/types/bindings.js.map +1 -0
  215. package/transpiled/types/bridges.d.ts +38 -0
  216. package/transpiled/types/bridges.js +2 -0
  217. package/transpiled/types/bridges.js.map +1 -0
  218. package/transpiled/types/extensions.d.ts +62 -0
  219. package/transpiled/types/extensions.js +2 -0
  220. package/transpiled/types/extensions.js.map +1 -0
  221. package/transpiled/types/index.d.ts +13 -0
  222. package/transpiled/types/index.js +8 -0
  223. package/transpiled/types/index.js.map +1 -0
  224. package/transpiled/types/message.d.ts +5 -0
  225. package/transpiled/types/message.js +2 -0
  226. package/transpiled/types/message.js.map +1 -0
  227. package/transpiled/types/operations.d.ts +15 -0
  228. package/transpiled/types/operations.js +2 -0
  229. package/transpiled/types/operations.js.map +1 -0
  230. package/transpiled/types/outbox.d.ts +28 -0
  231. package/transpiled/types/outbox.js +2 -0
  232. package/transpiled/types/outbox.js.map +1 -0
  233. package/transpiled/types/receiver.d.ts +9 -0
  234. package/transpiled/types/receiver.js +2 -0
  235. package/transpiled/types/receiver.js.map +1 -0
  236. package/transpiled/types/request.d.ts +55 -0
  237. package/transpiled/types/request.js +2 -0
  238. package/transpiled/types/request.js.map +1 -0
  239. package/transpiled/types/state.d.ts +9 -0
  240. package/transpiled/types/state.js +2 -0
  241. package/transpiled/types/state.js.map +1 -0
  242. package/transpiled/types/storages.d.ts +111 -0
  243. package/transpiled/types/storages.js +2 -0
  244. package/transpiled/types/storages.js.map +1 -0
  245. package/transpiled/unmanaged.d.ts +5 -0
  246. package/transpiled/unmanaged.js +7 -0
  247. package/transpiled/unmanaged.js.map +1 -0
  248. package/tsconfig.json +10 -0
  249. package/tsconfig.tsbuildinfo +1 -0
  250. package/src/assignment.js +0 -31
  251. package/src/call.js +0 -42
  252. package/src/cascade.js +0 -36
  253. package/src/component.js +0 -41
  254. package/src/composition.js +0 -25
  255. package/src/connector.js +0 -183
  256. package/src/context.js +0 -55
  257. package/src/contract/conditions.js +0 -21
  258. package/src/contract/index.js +0 -7
  259. package/src/contract/reply.js +0 -25
  260. package/src/contract/request.js +0 -67
  261. package/src/contract/schemas/error.yaml +0 -9
  262. package/src/contract/schemas/index.js +0 -7
  263. package/src/contract/schemas/query.yaml +0 -30
  264. package/src/discovery.js +0 -44
  265. package/src/emission.js +0 -23
  266. package/src/entities/changeset.js +0 -43
  267. package/src/entities/entity.js +0 -73
  268. package/src/entities/factory.js +0 -33
  269. package/src/entities/index.js +0 -5
  270. package/src/entities/set.js +0 -15
  271. package/src/event.js +0 -40
  272. package/src/exceptions.js +0 -100
  273. package/src/exposition.js +0 -27
  274. package/src/index.js +0 -47
  275. package/src/locator.js +0 -54
  276. package/src/observation.js +0 -20
  277. package/src/operation.js +0 -69
  278. package/src/query/criteria.js +0 -41
  279. package/src/query/options.js +0 -40
  280. package/src/query.js +0 -41
  281. package/src/receiver.js +0 -65
  282. package/src/reflection.js +0 -28
  283. package/src/remote.js +0 -17
  284. package/src/state.js +0 -99
  285. package/src/transition.js +0 -73
  286. package/src/transmission.js +0 -33
  287. package/types/bindings.d.ts +0 -40
  288. package/types/bridges.ts +0 -30
  289. package/types/component.d.ts +0 -9
  290. package/types/connector.d.ts +0 -18
  291. package/types/context.d.ts +0 -21
  292. package/types/entity.d.ts +0 -46
  293. package/types/event.d.ts +0 -11
  294. package/types/exception.d.ts +0 -4
  295. package/types/extensions.d.ts +0 -29
  296. package/types/index.ts +0 -14
  297. package/types/locator.d.ts +0 -13
  298. package/types/operations.d.ts +0 -2
  299. package/types/query.d.ts +0 -15
  300. package/types/receiver.d.ts +0 -12
  301. package/types/reflection.d.ts +0 -14
  302. package/types/request.d.ts +0 -23
  303. package/types/state.d.ts +0 -35
  304. package/types/storages.d.ts +0 -71
@@ -1,10 +1,11 @@
1
- 'use strict'
1
+ import { describe, it, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- const { Query } = require('../src/query')
4
- const fixtures = require('./query.fixtures')
4
+ import { Query } from '../source/query.js'
5
+ import * as fixtures from './query.fixtures.js'
5
6
 
6
7
  beforeEach(() => {
7
- jest.clearAllMocks()
8
+ resetCalls()
8
9
  })
9
10
 
10
11
  describe('criteria', () => {
@@ -12,34 +13,110 @@ describe('criteria', () => {
12
13
  const instance = new Query(fixtures.samples.simple.properties)
13
14
  const query = instance.parse({})
14
15
 
15
- expect(query.criteria).toBeUndefined()
16
+ assert.strictEqual(query.criteria, undefined)
16
17
  })
17
18
 
18
19
  it('should parse criteria', () => {
19
20
  const instance = new Query(fixtures.samples.simple.properties)
20
21
  const query = instance.parse(fixtures.samples.simple.query)
21
22
 
22
- expect(query.criteria).toEqual(fixtures.samples.simple.parsed.criteria)
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))
23
48
  })
24
49
 
25
50
  it('should parse criteria with type coercion', () => {
26
51
  const instance = new Query(fixtures.samples.extended.properties)
27
52
  const query = instance.parse(fixtures.samples.extended.query)
28
53
 
29
- expect(query.criteria).toEqual(fixtures.samples.extended.parsed.criteria)
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
+ )
30
104
  })
31
105
 
32
106
  it('should throw on unknown properties', () => {
33
107
  const instance = new Query(fixtures.samples.simple.properties)
34
108
 
35
- expect(() => instance.parse({ criteria: 'lastname==Johnson' })).toThrow(/not defined/)
109
+ assert.throws(
110
+ () => instance.parse({ criteria: 'lastname==Johnson' }),
111
+ (error) => /not defined/.test(error.message)
112
+ )
36
113
  })
37
114
 
38
115
  it('should parse id', () => {
39
116
  const instance = new Query(fixtures.samples.id.properties)
40
117
  const query = instance.parse({ ...fixtures.samples.id.query })
41
118
 
42
- expect(query).toStrictEqual(fixtures.samples.id.parsed)
119
+ assert.deepStrictEqual(query, fixtures.samples.id.parsed)
43
120
  })
44
121
  })
45
122
 
@@ -49,7 +126,7 @@ describe('options', () => {
49
126
  it('should not throw if no options', () => {
50
127
  const query = instance.parse({})
51
128
 
52
- expect(query.options).toBeUndefined()
129
+ assert.strictEqual(query.options, undefined)
53
130
  })
54
131
 
55
132
  describe('omit, limit', () => {
@@ -57,7 +134,7 @@ describe('options', () => {
57
134
  const input = { omit: 1, limit: 1 }
58
135
  const query = instance.parse(input)
59
136
 
60
- expect(query.options).toStrictEqual(input)
137
+ assert.deepStrictEqual(query.options, input)
61
138
  })
62
139
  })
63
140
 
@@ -66,13 +143,20 @@ describe('options', () => {
66
143
  const sort = ['a', 'b:desc', 'c']
67
144
  const query = instance.parse({ sort })
68
145
 
69
- expect(query.options.sort).toStrictEqual([['a', 'asc'], ['b', 'desc'], ['c', 'asc']])
146
+ assert.deepStrictEqual(query.options.sort, [
147
+ ['a', 'asc'],
148
+ ['b', 'desc'],
149
+ ['c', 'asc']
150
+ ])
70
151
  })
71
152
 
72
153
  it('should throw on unknown properties', () => {
73
154
  const sort = ['d:asc']
74
155
 
75
- expect(() => instance.parse({ sort })).toThrow(/not defined/)
156
+ assert.throws(
157
+ () => instance.parse({ sort }),
158
+ (error) => /not defined/.test(error.message)
159
+ )
76
160
  })
77
161
  })
78
162
 
@@ -80,7 +164,20 @@ describe('options', () => {
80
164
  it('should throw on unknown properties', () => {
81
165
  const projection = ['a', 'b', 'c', 'd']
82
166
 
83
- expect(() => instance.parse({ projection })).toThrow(/not defined/)
167
+ assert.throws(
168
+ () => instance.parse({ projection }),
169
+ (error) => /not defined/.test(error.message)
170
+ )
84
171
  })
85
172
  })
86
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,23 +1,20 @@
1
- 'use strict'
1
+ import { mock } from 'node:test'
2
2
 
3
- const { generate } = require('randomstring')
3
+ import { generate } from 'randomstring'
4
4
 
5
- const definition = /** @type {toa.norm.component.Receiver} */ {
5
+ export const definition = /** @type {toa.norm.component.Receiver} */ {
6
6
  operation: generate(),
7
7
  conditioned: false,
8
8
  adaptive: false
9
9
  }
10
10
 
11
- const local = /** @type {toa.core.Component} */ {
12
- invoke: jest.fn()
11
+ export const local = /** @type {import('@toa.io/core').Component} */ {
12
+ locator: { id: 'default.dummy' },
13
+ invoke: mock.fn()
13
14
  }
14
15
 
15
16
  // noinspection JSCheckFunctionSignatures
16
- const bridge = /** @type {toa.core.bridges.Event} */ {
17
- condition: jest.fn(async (payload) => !(payload.reject === true)),
18
- request: jest.fn(async () => ({ input: generate() }))
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() }))
19
20
  }
20
-
21
- exports.definition = definition
22
- exports.local = local
23
- exports.bridge = bridge
@@ -1,32 +1,41 @@
1
- 'use strict'
1
+ import { describe, it, beforeEach, mock } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { isDeepStrictEqual } from 'node:util'
2
4
 
3
- const clone = require('clone-deep')
4
- const { generate } = require('randomstring')
5
- const { merge } = require('@toa.io/generic')
5
+ import clone from 'clone-deep'
6
+ import { generate } from 'randomstring'
7
+ import { merge } from '@toa.io/generic'
6
8
 
7
- jest.mock('../src/connector')
9
+ import { Connector } from '../source/connector.js'
8
10
 
9
- const { Connector } = /** @type {{ Connector: jest.Mock<toa.core.Connector>}} */ require('../src/connector')
11
+ // the fixtures are not connectors, so a dependency is recorded rather than linked
12
+ const depends = mock.method(Connector.prototype, 'depends', () => undefined)
10
13
 
11
- const { Receiver } = require('../src/receiver')
12
- const fixtures = require('./receiver.fixtures')
14
+ const dependencies = (instance) =>
15
+ depends.mock.calls
16
+ .filter((call) => call.this === instance)
17
+ .map((call) => call.arguments[0])
13
18
 
14
- /** @type {toa.core.Receiver} */
19
+ import { Receiver } from '../source/receiver.js'
20
+ import * as fixtures from './receiver.fixtures.js'
21
+
22
+ /** @type {import('@toa.io/core/types').Receiver} */
15
23
  let receiver
16
24
 
17
25
  /** @type {toa.norm.component.Receiver} */
18
26
  let definition
19
27
 
20
28
  beforeEach(() => {
21
- jest.clearAllMocks()
29
+ resetCalls()
30
+ depends.mock.resetCalls()
22
31
 
23
32
  definition = clone(fixtures.definition)
24
33
  receiver = new Receiver(fixtures.definition, fixtures.local, fixtures.bridge)
25
34
  })
26
35
 
27
36
  it('should depend on local, bridge', () => {
28
- expect(Connector.mock.instances[0].depends).toHaveBeenCalledWith(fixtures.local)
29
- expect(Connector.mock.instances[0].depends).toHaveBeenCalledWith(fixtures.bridge)
37
+ assert.ok(dependencies(receiver).some((one) => isDeepStrictEqual(one, fixtures.local)))
38
+ assert.ok(dependencies(receiver).some((one) => isDeepStrictEqual(one, fixtures.bridge)))
30
39
  })
31
40
 
32
41
  it('should apply', async () => {
@@ -34,28 +43,38 @@ it('should apply', async () => {
34
43
 
35
44
  await receiver.receive({ payload })
36
45
 
37
- expect(fixtures.local.invoke).toHaveBeenCalledWith(definition.operation, { input: payload })
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
+ )
38
54
  })
39
55
 
40
- it.each([[false], [true]])('should pass UI extensions (adaptive: %s)', async (adaptive) => {
41
- jest.clearAllMocks()
56
+ for (const [adaptive] of [[false], [true]])
57
+ it(`should pass UI extensions (adaptive: ${adaptive})`, async () => {
58
+ resetCalls()
42
59
 
43
- definition.adaptive = adaptive
44
- receiver = new Receiver(definition, fixtures.local, fixtures.bridge)
60
+ definition.adaptive = adaptive
61
+ receiver = new Receiver(definition, fixtures.local, fixtures.bridge)
45
62
 
46
- const payload = { foo: generate() }
47
- const extension = { [generate()]: generate() }
48
- const message = { payload, ...extension }
63
+ const payload = { foo: generate() }
64
+ const extension = { [generate()]: generate() }
65
+ const message = { payload, ...extension }
49
66
 
50
- await receiver.receive(message)
67
+ await receiver.receive(message)
51
68
 
52
- const request = adaptive ? await fixtures.bridge.request.mock.results[0].value : { input: payload }
53
- const expected = merge(clone(request), extension)
69
+ const request = adaptive
70
+ ? await fixtures.bridge.request.mock.calls[0].result
71
+ : { input: payload }
72
+ const expected = merge(clone(request), extension)
54
73
 
55
- const argument = fixtures.local.invoke.mock.calls[0][1]
74
+ const argument = fixtures.local.invoke.mock.calls[0].arguments[1]
56
75
 
57
- expect(argument).toStrictEqual(expected)
58
- })
76
+ assert.deepStrictEqual(argument, expected)
77
+ })
59
78
 
60
79
  describe('conditioned', () => {
61
80
  beforeEach(() => {
@@ -67,15 +86,27 @@ describe('conditioned', () => {
67
86
  const payload = { foo: 'bar' }
68
87
  await receiver.receive({ payload })
69
88
 
70
- expect(fixtures.bridge.condition).toHaveBeenCalledWith(payload)
71
- expect(fixtures.local.invoke).toHaveBeenCalledWith(definition.operation, { input: payload })
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
+ )
72
103
  })
73
104
 
74
105
  it('should not apply if condition is false', async () => {
75
106
  const payload = { reject: true }
76
107
  await receiver.receive({ payload })
77
108
 
78
- expect(fixtures.local.invoke).not.toHaveBeenCalled()
109
+ assert.strictEqual(fixtures.local.invoke.mock.callCount(), 0)
79
110
  })
80
111
  })
81
112
 
@@ -89,7 +120,25 @@ describe('adaptive', () => {
89
120
  const payload = { reject: true }
90
121
  await receiver.receive({ payload })
91
122
 
92
- expect(fixtures.local.invoke)
93
- .toHaveBeenCalledWith(definition.operation, await fixtures.bridge.request.mock.results[0].value)
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
+ )
94
133
  })
95
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,18 +1,19 @@
1
- 'use strict'
1
+ import { it, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- const { generate } = require('randomstring')
4
- const { Reflection, Connector } = require('../')
4
+ import { generate } from 'randomstring'
5
+ import { Reflection, Connector } from '../source/index.js'
5
6
 
6
7
  it('should export', () => {
7
- expect(Reflection).toBeDefined()
8
+ assert.notStrictEqual(Reflection, undefined)
8
9
  })
9
10
 
10
- /** @type {toa.core.Reflection<string>} */
11
+ /** @type {import('@toa.io/core').Reflection<string>} */
11
12
  let reflection
12
13
 
13
14
  const value = generate()
14
15
 
15
- /** @type {toa.core.reflection.Source<string>} */
16
+ /** @type {import('@toa.io/core').ReflectionSource<string>} */
16
17
  const source = async () => value
17
18
 
18
19
  beforeEach(() => {
@@ -20,11 +21,11 @@ beforeEach(() => {
20
21
  })
21
22
 
22
23
  it('should be a Connector', () => {
23
- expect(reflection).toBeInstanceOf(Connector)
24
+ assert.ok(reflection instanceof Connector)
24
25
  })
25
26
 
26
27
  it('should reflect', async () => {
27
28
  await reflection.connect()
28
29
 
29
- expect(reflection.value).toStrictEqual(value)
30
+ assert.deepStrictEqual(reflection.value, value)
30
31
  })
@@ -1,47 +1,49 @@
1
- 'use strict'
1
+ import { mock } from 'node:test'
2
2
 
3
- const { generate } = require('randomstring')
3
+ import { generate } from 'randomstring'
4
4
 
5
- const storage = {
5
+ export const storage = {
6
6
  name: 'dummy',
7
- get: jest.fn(() => ({ id: generate() })),
8
- find: jest.fn(() => ([{ id: generate() }])),
9
- add: jest.fn(() => true),
10
- set: jest.fn(() => true),
11
- store: jest.fn(() => true)
7
+ get: mock.fn(() => ({ id: generate() })),
8
+ find: mock.fn(() => [{ id: generate() }]),
9
+ add: mock.fn(() => true),
10
+ set: mock.fn(() => true),
11
+ store: mock.fn(() => true),
12
+ massStore: mock.fn(() => true),
13
+ upsert: mock.fn(() => ({ id: generate() })),
14
+ ensure: mock.fn((query, properties, state) => state)
12
15
  }
13
16
 
14
- const factory = {
15
- object: jest.fn(() => ({ [generate()]: generate() })),
16
- objects: jest.fn(() => ({ [generate()]: generate() }))
17
+ export const factory = {
18
+ object: mock.fn(() => ({ [generate()]: generate() })),
19
+ objects: mock.fn(() => ({ [generate()]: generate() }))
17
20
  }
18
21
 
19
- const query = generate()
22
+ export const query = generate()
20
23
 
21
- const entity = {
22
- get: jest.fn(() => ({ [generate()]: generate() })),
23
- event: jest.fn(() => ({
24
- state: { [generate()]: generate() }, changeset: { [generate()]: generate() }
25
- }))
24
+ export const entity = {
25
+ get: mock.fn(() => ({ [generate()]: generate() })),
26
+ event: mock.fn(() => ({ state: { [generate()]: generate() } }))
26
27
  }
27
28
 
28
- const initial = {
29
- initial: true, ...entity
29
+ export const initial = {
30
+ initial: true,
31
+ ...entity
30
32
  }
31
33
 
32
- const unchanged = {
34
+ export const unchanged = {
33
35
  ...entity,
34
- event: jest.fn(() => ({ state: { [generate()]: generate() }, changeset: {} }))
36
+ event: mock.fn(() => ({ state: { [generate()]: generate() } }))
35
37
  }
36
38
 
37
- const emitter = {
38
- emit: jest.fn()
39
+ // a legacy outbox: no storage capability, so `publish` emits inline
40
+ export const outbox = {
41
+ row: mock.fn((event) => ({
42
+ id: generate(),
43
+ lane: 0,
44
+ published: false,
45
+ pending: 0,
46
+ event
47
+ })),
48
+ publish: mock.fn()
39
49
  }
40
-
41
- exports.storage = storage
42
- exports.factory = factory
43
- exports.emitter = emitter
44
- exports.query = query
45
- exports.entity = entity
46
- exports.initial = initial
47
- exports.unchanged = unchanged