@toa.io/core 1.0.0-alpha.28 → 1.0.0-alpha.283

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 (100) hide show
  1. package/CHANGELOG.md +180 -0
  2. package/package.json +8 -10
  3. package/src/assignment.js +5 -8
  4. package/src/call.js +35 -9
  5. package/src/cascade.js +9 -11
  6. package/src/component.js +61 -21
  7. package/src/composition.js +3 -7
  8. package/src/connector.js +29 -22
  9. package/src/context.js +8 -6
  10. package/src/contract/contract.js +18 -0
  11. package/src/contract/index.js +2 -7
  12. package/src/contract/reply.js +39 -15
  13. package/src/contract/request.js +20 -10
  14. package/src/contract/schemas/index.js +9 -5
  15. package/src/contract/schemas/query.yaml +14 -1
  16. package/src/contract/schemas/source.yaml +23 -0
  17. package/src/discovery.js +15 -13
  18. package/src/effect.js +15 -0
  19. package/src/emission.js +2 -6
  20. package/src/entities/changeset.js +7 -14
  21. package/src/entities/entity.js +75 -29
  22. package/src/entities/factory.js +21 -14
  23. package/src/entities/index.js +1 -5
  24. package/src/entities/newid.js +9 -0
  25. package/src/entities/set.js +13 -4
  26. package/src/event.js +21 -7
  27. package/src/exceptions.js +53 -39
  28. package/src/exposition.js +5 -8
  29. package/src/guard.js +13 -0
  30. package/src/index.js +28 -47
  31. package/src/locator.js +2 -6
  32. package/src/observation.js +3 -15
  33. package/src/operation.js +40 -14
  34. package/src/outbox/index.js +1 -0
  35. package/src/outbox/outbox.js +296 -0
  36. package/src/query/criteria.js +3 -7
  37. package/src/query/options.js +5 -8
  38. package/src/query.js +36 -7
  39. package/src/receiver.js +76 -18
  40. package/src/reflection.js +2 -6
  41. package/src/remote.js +9 -12
  42. package/src/state.js +89 -50
  43. package/src/transition.js +13 -25
  44. package/src/transmission.js +15 -10
  45. package/src/unmanaged.js +7 -0
  46. package/test/call.fixtures.js +8 -12
  47. package/test/call.test.js +21 -9
  48. package/test/component.fixtures.js +5 -8
  49. package/test/component.test.js +22 -10
  50. package/test/connector.fixtures.js +10 -8
  51. package/test/connector.test.js +59 -38
  52. package/test/context.fixtures.js +8 -12
  53. package/test/context.test.js +18 -7
  54. package/test/contract/conditions.test.js +11 -9
  55. package/test/contract/contract.fixtures.js +12 -16
  56. package/test/contract/request.test.js +84 -34
  57. package/test/discovery.test.js +64 -0
  58. package/test/emission.fixtures.js +6 -10
  59. package/test/emission.test.js +29 -12
  60. package/test/entities/entity.fixtures.js +7 -11
  61. package/test/entities/entity.test.js +70 -49
  62. package/test/entities/factory.fixtures.js +22 -10
  63. package/test/entities/factory.test.js +29 -15
  64. package/test/entities/set.fixtures.js +6 -8
  65. package/test/entities/set.test.js +6 -5
  66. package/test/event.fixtures.js +9 -14
  67. package/test/event.test.js +57 -31
  68. package/test/locator.test.js +25 -24
  69. package/test/outbox.test.js +121 -0
  70. package/test/query.fixtures.js +1 -5
  71. package/test/query.test.js +42 -14
  72. package/test/receiver.fixtures.js +9 -12
  73. package/test/receiver.test.js +45 -22
  74. package/test/reflection.test.js +7 -6
  75. package/test/state.fixtures.js +25 -30
  76. package/test/state.test.js +72 -19
  77. package/test/transmission.fixtures.js +4 -6
  78. package/test/transmission.test.js +33 -15
  79. package/types/atomicity.d.ts +58 -0
  80. package/types/bindings.d.ts +8 -6
  81. package/types/bridges.ts +5 -2
  82. package/types/call.d.ts +13 -0
  83. package/types/component.d.ts +7 -4
  84. package/types/context.d.ts +6 -3
  85. package/types/entity.d.ts +4 -4
  86. package/types/event.d.ts +1 -1
  87. package/types/extensions.d.ts +54 -10
  88. package/types/guard.d.ts +5 -0
  89. package/types/index.ts +20 -13
  90. package/types/message.d.ts +1 -0
  91. package/types/operations.d.ts +6 -0
  92. package/types/outbox.d.ts +53 -0
  93. package/types/query.d.ts +2 -0
  94. package/types/receiver.d.ts +2 -2
  95. package/types/reflection.d.ts +1 -1
  96. package/types/remote.d.ts +18 -0
  97. package/types/request.d.ts +38 -6
  98. package/types/state.d.ts +14 -11
  99. package/types/storages.d.ts +36 -11
  100. package/src/contract/conditions.js +0 -21
package/test/call.test.js CHANGED
@@ -1,18 +1,20 @@
1
- 'use strict'
1
+ import { it, beforeEach, mock } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { isDeepStrictEqual } from 'node:util'
2
4
 
3
- const fixtures = require('./call.fixtures')
4
- const { Call } = require('../src/call')
5
+ import * as fixtures from './call.fixtures.js'
6
+ import { Call } from '../src/call.js'
5
7
 
6
8
  let call
7
9
 
8
10
  beforeEach(() => {
9
- jest.clearAllMocks()
11
+ resetCalls()
10
12
 
11
13
  call = new Call(fixtures.transmission, fixtures.contract)
12
14
  })
13
15
 
14
16
  it('should depend on transmission', () => {
15
- expect(fixtures.transmission.link).toHaveBeenLastCalledWith(call)
17
+ assert.ok(((invocation) => invocation.arguments.length === 1 && isDeepStrictEqual(invocation.arguments[0], call))(fixtures.transmission.link.mock.calls.at(-1) ?? { arguments: [] }))
16
18
  })
17
19
 
18
20
  it('should call transmission', async () => {
@@ -20,7 +22,7 @@ it('should call transmission', async () => {
20
22
 
21
23
  await call.invoke(request)
22
24
 
23
- expect(fixtures.transmission.request).toHaveBeenCalledWith(request)
25
+ assert.ok(fixtures.transmission.request.mock.calls.some((invocation) => invocation.arguments.length === 1 && isDeepStrictEqual(invocation.arguments[0], request)))
24
26
  })
25
27
 
26
28
  it('should fit request', async () => {
@@ -28,7 +30,7 @@ it('should fit request', async () => {
28
30
 
29
31
  await call.invoke(request)
30
32
 
31
- expect(fixtures.contract.fit).toHaveBeenLastCalledWith(request)
33
+ assert.ok(((invocation) => invocation.arguments.length === 1 && isDeepStrictEqual(invocation.arguments[0], request))(fixtures.contract.fit.mock.calls.at(-1) ?? { arguments: [] }))
32
34
  })
33
35
 
34
36
  it('should return reply', async () => {
@@ -36,11 +38,21 @@ it('should return reply', async () => {
36
38
 
37
39
  const reply = await call.invoke(request)
38
40
 
39
- expect(reply).toStrictEqual(fixtures.transmission.request.mock.results[0].value.output)
41
+ assert.deepStrictEqual(reply, fixtures.transmission.request.mock.calls[0].result.output)
40
42
  })
41
43
 
42
44
  it('should throw received exceptions', async () => {
43
45
  const request = fixtures.request().bad
44
46
 
45
- await expect(call.invoke(request)).rejects.toBeDefined()
47
+ await assert.rejects(call.invoke(request), (error) => { assert.notStrictEqual(error, undefined); return true })
46
48
  })
49
+
50
+ function resetCalls (target = [assert, fixtures], seen = new Set()) {
51
+ if (target === null || typeof target !== 'object' || seen.has(target)) return
52
+
53
+ seen.add(target)
54
+
55
+ for (const value of Object.values(target))
56
+ if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
57
+ else resetCalls(value, seen)
58
+ }
@@ -1,10 +1,10 @@
1
- 'use strict'
1
+ import { mock } from 'node:test'
2
2
 
3
- const randomstring = require('randomstring')
3
+ import randomstring from 'randomstring'
4
4
 
5
- const invocation = () => jest.fn(() => randomstring.generate())
5
+ const invocation = () => mock.fn(() => randomstring.generate())
6
6
 
7
- const invocations = {
7
+ export const invocations = {
8
8
  foo: {
9
9
  invoke: invocation('foo'),
10
10
  link: () => null
@@ -15,7 +15,4 @@ const invocations = {
15
15
  }
16
16
  }
17
17
 
18
- const locator = {}
19
-
20
- exports.invocations = invocations
21
- exports.locator = locator
18
+ export const locator = {}
@@ -1,8 +1,11 @@
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 { Component } = require('../src/component')
4
- const { codes } = require('../src/exceptions')
5
- const fixtures = require('./component.fixtures')
5
+ import { Component } from '../src/component.js'
6
+ import { codes } from '../src/exceptions.js'
7
+ import * as fixtures from './component.fixtures.js'
8
+ import { AssertionError } from 'node:assert'
6
9
 
7
10
  describe('Invocations', () => {
8
11
  const name = ['foo', 'bar'][Math.floor(2 * Math.random())]
@@ -10,18 +13,17 @@ describe('Invocations', () => {
10
13
  const component = new Component(fixtures.locator, fixtures.invocations)
11
14
 
12
15
  beforeEach(() => {
13
- jest.clearAllMocks()
16
+ resetCalls()
14
17
  })
15
18
 
16
19
  it('should invoke', async () => {
17
20
  await component.invoke(name)
18
21
 
19
- expect(invocation.invoke).toBeCalled()
22
+ assert.ok(invocation.invoke.mock.callCount() > 0)
20
23
  })
21
24
 
22
25
  it('should throw on unknown invocation name', async () => {
23
- await expect(() => component.invoke('baz'))
24
- .rejects.toMatchObject({ code: codes.NotImplemented })
26
+ await assert.rejects(() => component.invoke('baz'), AssertionError)
25
27
  })
26
28
 
27
29
  it('should invoke input and query', async () => {
@@ -29,12 +31,22 @@ describe('Invocations', () => {
29
31
  const query = { test: Math.random() }
30
32
  await component.invoke(name, { input, query })
31
33
 
32
- expect(invocation.invoke).toBeCalledWith({ input, query })
34
+ assert.ok(invocation.invoke.mock.calls.some((call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], { input, query })))
33
35
  })
34
36
 
35
37
  it('should return io', async () => {
36
38
  const io = await component.invoke(name)
37
39
 
38
- expect(io).toBe(fixtures.invocations[name].invoke.mock.results[0].value)
40
+ assert.strictEqual(io, fixtures.invocations[name].invoke.mock.calls[0].result)
39
41
  })
40
42
  })
43
+
44
+ function resetCalls (target = [assert, fixtures], seen = new Set()) {
45
+ if (target === null || typeof target !== 'object' || seen.has(target)) return
46
+
47
+ seen.add(target)
48
+
49
+ for (const value of Object.values(target))
50
+ if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
51
+ else resetCalls(value, seen)
52
+ }
@@ -1,9 +1,7 @@
1
- 'use strict'
1
+ import { random, timeout } from '@toa.io/generic'
2
+ import { Connector } from '../src/connector.js'
2
3
 
3
- const { random, timeout } = require('@toa.io/generic')
4
- const { Connector } = require('../src/connector')
5
-
6
- class TestConnector extends Connector {
4
+ export class TestConnector extends Connector {
7
5
  #label
8
6
  #seq
9
7
 
@@ -29,12 +27,16 @@ class TestConnector extends Connector {
29
27
  }
30
28
  }
31
29
 
32
- class FailingConnector extends Connector {
30
+ export class FailingConnector extends Connector {
33
31
  async open () {
34
32
  await timeout(random(10))
35
33
  throw new Error('FailingConnector')
36
34
  }
37
35
  }
38
36
 
39
- exports.TestConnector = TestConnector
40
- exports.FailingConnector = FailingConnector
37
+ /** Stands for a connector waiting for something that never arrives. */
38
+ export class StuckConnector extends Connector {
39
+ async open () {
40
+ return new Promise(() => undefined)
41
+ }
42
+ }
@@ -1,6 +1,9 @@
1
- 'use strict'
1
+ import { describe, it, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- const fixtures = require('./connector.fixtures')
4
+ import { timeout } from '@toa.io/generic'
5
+
6
+ import * as fixtures from './connector.fixtures.js'
4
7
 
5
8
  let sequence
6
9
 
@@ -17,14 +20,14 @@ describe('callbacks', () => {
17
20
 
18
21
  it('should call connection', async () => {
19
22
  await a.connect()
20
- expect(sequence).toEqual(['+a'])
23
+ assert.deepStrictEqual(sequence, ['+a'])
21
24
  })
22
25
 
23
26
  it('should call disconnection', async () => {
24
27
  await a.connect()
25
28
  await a.disconnect()
26
29
 
27
- expect(sequence.indexOf('+a')).toBeLessThan(sequence.indexOf('-a'))
30
+ assert.ok(sequence.indexOf('+a') < sequence.indexOf('-a'))
28
31
  })
29
32
 
30
33
  it('should reconnect', async () => {
@@ -32,7 +35,7 @@ describe('callbacks', () => {
32
35
  await a.reconnect()
33
36
  await a.reconnect()
34
37
 
35
- expect(sequence).toEqual(['+a', '-a', '*a', '+a', '-a', '*a', '+a'])
38
+ assert.deepStrictEqual(sequence, ['+a', '-a', '*a', '+a', '-a', '*a', '+a'])
36
39
  })
37
40
  })
38
41
 
@@ -55,9 +58,9 @@ describe('dependencies', () => {
55
58
 
56
59
  await a.connect()
57
60
 
58
- expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+b'))
59
- expect(sequence.indexOf('+b')).toBeLessThan(sequence.indexOf('+a'))
60
- expect(sequence.indexOf('+d')).toBeLessThan(sequence.indexOf('+a'))
61
+ assert.ok(sequence.indexOf('+c') < sequence.indexOf('+b'))
62
+ assert.ok(sequence.indexOf('+b') < sequence.indexOf('+a'))
63
+ assert.ok(sequence.indexOf('+d') < sequence.indexOf('+a'))
61
64
  })
62
65
 
63
66
  it('should wait array of connectors', async () => {
@@ -67,10 +70,10 @@ describe('dependencies', () => {
67
70
 
68
71
  await a.connect()
69
72
 
70
- expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+b'))
71
- expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+d'))
72
- expect(sequence.indexOf('+b')).toBeLessThan(sequence.indexOf('+a'))
73
- expect(sequence.indexOf('+d')).toBeLessThan(sequence.indexOf('+a'))
73
+ assert.ok(sequence.indexOf('+c') < sequence.indexOf('+b'))
74
+ assert.ok(sequence.indexOf('+c') < sequence.indexOf('+d'))
75
+ assert.ok(sequence.indexOf('+b') < sequence.indexOf('+a'))
76
+ assert.ok(sequence.indexOf('+d') < sequence.indexOf('+a'))
74
77
  })
75
78
 
76
79
  it('should wait array(1) of connectors', async () => {
@@ -79,12 +82,12 @@ describe('dependencies', () => {
79
82
 
80
83
  await a.connect()
81
84
 
82
- expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+b'))
83
- expect(sequence.indexOf('+b')).toBeLessThan(sequence.indexOf('+a'))
85
+ assert.ok(sequence.indexOf('+c') < sequence.indexOf('+b'))
86
+ assert.ok(sequence.indexOf('+b') < sequence.indexOf('+a'))
84
87
  })
85
88
 
86
89
  it('should throw on empty array', async () => {
87
- expect(() => a.depends([])).toThrow(/must not be empty/)
90
+ assert.throws(() => a.depends([]), (error) => /must not be empty/.test(error.message))
88
91
  })
89
92
 
90
93
  it('should await 2-way dependencies', async () => {
@@ -93,23 +96,24 @@ describe('dependencies', () => {
93
96
 
94
97
  await a.connect()
95
98
 
96
- expect(sequence.indexOf('+b')).toBeLessThan(sequence.indexOf('+a'))
97
- expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+a'))
98
- expect(sequence.indexOf('+d')).toBeLessThan(sequence.indexOf('+a'))
99
+ assert.ok(sequence.indexOf('+b') < sequence.indexOf('+a'))
100
+ assert.ok(sequence.indexOf('+c') < sequence.indexOf('+a'))
101
+ assert.ok(sequence.indexOf('+d') < sequence.indexOf('+a'))
99
102
 
100
- expect(sequence.indexOf('+b')).toBeLessThan(sequence.indexOf('+d'))
101
- expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+d'))
103
+ assert.ok(sequence.indexOf('+b') < sequence.indexOf('+d'))
104
+ assert.ok(sequence.indexOf('+c') < sequence.indexOf('+d'))
102
105
  })
103
106
 
104
107
  it('should disconnect before dependencies', async () => {
105
108
  a.depends(b).depends(c)
106
109
  b.depends(d)
107
110
 
111
+ await a.connect()
108
112
  await a.disconnect()
109
113
 
110
- expect(sequence.indexOf('-a')).toBeLessThan(sequence.indexOf('-b'))
111
- expect(sequence.indexOf('-b')).toBeLessThan(sequence.indexOf('-c'))
112
- expect(sequence.indexOf('-b')).toBeLessThan(sequence.indexOf('-d'))
114
+ assert.ok(sequence.indexOf('-a') < sequence.indexOf('-b'))
115
+ assert.ok(sequence.indexOf('-b') < sequence.indexOf('-c'))
116
+ assert.ok(sequence.indexOf('-b') < sequence.indexOf('-d'))
113
117
  })
114
118
 
115
119
  it('should call disconnected', async () => {
@@ -118,10 +122,10 @@ describe('dependencies', () => {
118
122
 
119
123
  await a.disconnect()
120
124
 
121
- expect(sequence.indexOf('*c')).toBeLessThan(sequence.indexOf('*b'))
122
- expect(sequence.indexOf('*b')).toBeLessThan(sequence.indexOf('*a'))
123
- expect(sequence.indexOf('*d')).toBeLessThan(sequence.indexOf('*b'))
124
- expect(sequence.indexOf('*a')).toBe(sequence.length - 1)
125
+ assert.ok(sequence.indexOf('*c') < sequence.indexOf('*b'))
126
+ assert.ok(sequence.indexOf('*b') < sequence.indexOf('*a'))
127
+ assert.ok(sequence.indexOf('*d') < sequence.indexOf('*b'))
128
+ assert.strictEqual(sequence.indexOf('*a'), sequence.length - 1)
125
129
  })
126
130
 
127
131
  it('should disconnect if no parents left', async () => {
@@ -131,19 +135,36 @@ describe('dependencies', () => {
131
135
  await a.connect()
132
136
  await b.connect()
133
137
 
134
- expect(sequence).toEqual(['+c', '+a', '+b'])
138
+ assert.deepStrictEqual(sequence, ['+c', '+a', '+b'])
135
139
 
136
140
  await a.disconnect()
137
141
 
138
- expect(sequence).toEqual(['+c', '+a', '+b', '-a', '*a'])
142
+ assert.deepStrictEqual(sequence, ['+c', '+a', '+b', '-a', '*a'])
139
143
 
140
144
  await b.disconnect()
141
145
 
142
- expect(sequence).toEqual(['+c', '+a', '+b', '-a', '*a', '-b', '-c', '*c', '*b'])
146
+ assert.deepStrictEqual(sequence, ['+c', '+a', '+b', '-a', '*a', '-b', '-c', '*c', '*b'])
143
147
  })
144
148
 
145
149
  it('should throw if depends not on Connector', async () => {
146
- expect(() => a.depends({})).toThrow()
150
+ assert.throws(() => a.depends({}))
151
+ })
152
+
153
+ it('should disconnect while still connecting', async () => {
154
+ const stuck = new fixtures.StuckConnector()
155
+
156
+ a.depends(stuck).depends(b)
157
+
158
+ void a.connect()
159
+
160
+ while (b.connected !== true) await timeout(1)
161
+
162
+ // `a` never connects, and disconnecting must not wait for it to
163
+ assert.deepStrictEqual(a.connected, false)
164
+
165
+ await a.disconnect()
166
+
167
+ assert.deepStrictEqual(sequence, ['+b', '-b', '*b', '*a'])
147
168
  })
148
169
 
149
170
  describe('errors', () => {
@@ -156,21 +177,21 @@ describe('dependencies', () => {
156
177
  it('should disconnect on fail', async () => {
157
178
  f.depends(b).depends(c)
158
179
 
159
- await expect(f.connect()).rejects.toThrow('FailingConnector')
160
- expect(sequence).toEqual(['+c', '+b', '-b', '-c', '*c', '*b'])
180
+ await assert.rejects(f.connect(), (error) => /FailingConnector/.test(error.message))
181
+ assert.deepStrictEqual(sequence, ['+c', '+b', '-b', '-c', '*c', '*b'])
161
182
  })
162
183
 
163
184
  it('should interrupt connection chain', async () => {
164
185
  a.depends(f).depends(c)
165
186
  f.depends(d)
166
187
 
167
- await expect(a.connect()).rejects.toThrow('FailingConnector')
188
+ await assert.rejects(a.connect(), (error) => /FailingConnector/.test(error.message))
168
189
 
169
- expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('-c'))
170
- expect(sequence.indexOf('+d')).toBeLessThan(sequence.indexOf('-d'))
190
+ assert.ok(sequence.indexOf('+c') < sequence.indexOf('-c'))
191
+ assert.ok(sequence.indexOf('+d') < sequence.indexOf('-d'))
171
192
 
172
- expect(sequence.indexOf('+a')).toBe(-1)
173
- expect(sequence.indexOf('-a')).toBe(-1)
193
+ assert.strictEqual(sequence.indexOf('+a'), -1)
194
+ assert.strictEqual(sequence.indexOf('-a'), -1)
174
195
  })
175
196
  })
176
197
  })
@@ -1,18 +1,14 @@
1
- 'use strict'
1
+ import { mock } from 'node:test'
2
2
 
3
- const { Connector } = require('../src/connector')
3
+ import { Connector } from '../src/connector.js'
4
4
 
5
- const local = {
6
- link: jest.fn()
5
+ export const local = {
6
+ link: mock.fn()
7
7
  }
8
8
 
9
- const discover = jest.fn(() => ({
10
- invoke: jest.fn(),
11
- link: jest.fn()
9
+ export const discover = mock.fn(() => ({
10
+ invoke: mock.fn(),
11
+ link: mock.fn()
12
12
  }))
13
13
 
14
- const aspects = [new Connector(), new Connector()]
15
-
16
- exports.local = local
17
- exports.discover = discover
18
- exports.aspects = aspects
14
+ export const aspects = [new Connector(), new Connector()]
@@ -1,20 +1,21 @@
1
- 'use strict'
1
+ import { describe, it, beforeEach, mock } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- const fixtures = require('./context.fixtures')
4
- const { Context } = require('../src/context')
4
+ import * as fixtures from './context.fixtures.js'
5
+ import { Context } from '../src/context.js'
5
6
 
6
7
  /** @type {toa.core.Context} */
7
8
  let context
8
9
 
9
10
  beforeEach(() => {
10
- jest.clearAllMocks()
11
+ resetCalls()
11
12
 
12
13
  context = new Context(fixtures.local, fixtures.discover, fixtures.aspects)
13
14
  })
14
15
 
15
16
  it('should expose aspects', () => {
16
- expect(context.aspects).toBeDefined()
17
- expect(context.aspects).toStrictEqual(fixtures.aspects)
17
+ assert.notStrictEqual(context.aspects, undefined)
18
+ assert.deepStrictEqual(context.aspects, fixtures.aspects)
18
19
  })
19
20
 
20
21
  describe('call', () => {
@@ -24,6 +25,16 @@ describe('call', () => {
24
25
  await context.call('a', 'b', 'c', request)
25
26
  await context.call('a', 'b', 'c', request)
26
27
 
27
- expect(fixtures.discover).toHaveBeenCalledTimes(1)
28
+ assert.strictEqual(fixtures.discover.mock.callCount(), 1)
28
29
  })
29
30
  })
31
+
32
+ function resetCalls (target = [assert, fixtures], seen = new Set()) {
33
+ if (target === null || typeof target !== 'object' || seen.has(target)) return
34
+
35
+ seen.add(target)
36
+
37
+ for (const value of Object.values(target))
38
+ if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
39
+ else resetCalls(value, seen)
40
+ }
@@ -1,26 +1,28 @@
1
- 'use strict'
1
+ import { it, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { isDeepStrictEqual } from 'node:util'
2
4
 
3
- const { generate } = require('randomstring')
5
+ import { generate } from 'randomstring'
4
6
 
5
- const { Conditions } = require('../../src/contract/conditions')
6
- const fixtures = require('./contract.fixtures')
7
+ import { Contract } from '../../src/contract/contract.js'
8
+ import * as fixtures from './contract.fixtures.js'
7
9
 
8
- let conditions
10
+ let contract
9
11
 
10
12
  beforeEach(() => {
11
- conditions = new Conditions(fixtures.schema)
13
+ contract = new Contract(fixtures.schema)
12
14
  })
13
15
 
14
16
  it('should fit value', () => {
15
17
  const value = { foo: generate() }
16
18
 
17
- conditions.fit(value)
19
+ contract.fit(value)
18
20
 
19
- expect(fixtures.schema.fit).toHaveBeenCalledWith(value)
21
+ assert.ok(fixtures.schema.fit.mock.calls.some((call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], value)))
20
22
  })
21
23
 
22
24
  it('should throw on invalid value', () => {
23
25
  const value = { invalid: true }
24
26
 
25
- expect(() => conditions.fit(value)).toThrow()
27
+ assert.throws(() => contract.fit(value))
26
28
  })
@@ -1,33 +1,29 @@
1
- 'use strict'
1
+ import { mock } from 'node:test'
2
2
 
3
- const { generate } = require('randomstring')
4
- const { load } = require('@toa.io/yaml')
5
- const { resolve } = require('path')
3
+ import { generate } from 'randomstring'
4
+ import { readFileSync } from 'node:fs'
5
+ import { load as parseYAML } from 'js-yaml'
6
+ import { resolve } from 'path'
6
7
 
7
8
  // noinspection JSCheckFunctionSignatures
8
- const schema = {
9
- fit: jest.fn((input) => (input.invalid ? { message: generate() } : null))
9
+ export const schema = {
10
+ fit: mock.fn((input) => (input.invalid ? { message: generate() } : null))
10
11
  }
11
12
 
12
- const query = {
13
- parse: jest.fn(() => ({ [generate()]: generate() }))
13
+ export const query = {
14
+ parse: mock.fn(() => ({ [generate()]: generate() }))
14
15
  }
15
16
 
16
- const declaration = {}
17
+ export const declaration = {}
17
18
 
18
- const schemas = {
19
+ export const schemas = {
19
20
  request: {
20
21
  type: 'object',
21
22
  properties: {
22
23
  input: { type: 'null' },
23
- query: load.sync(resolve(__dirname, '../../src/contract/schemas/query.yaml')),
24
+ query: parseYAML(readFileSync(resolve(import.meta.dirname, '../../src/contract/schemas/query.yaml'), 'utf8')),
24
25
  authentic: { type: 'boolean' }
25
26
  },
26
27
  additionalProperties: true
27
28
  }
28
29
  }
29
-
30
- exports.schema = schema
31
- exports.query = query
32
- exports.declaration = declaration
33
- exports.schemas = schemas