@toa.io/core 1.0.0-alpha.273 → 1.0.0-alpha.277

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 (93) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +8 -7
  3. package/src/assignment.js +2 -6
  4. package/src/call.js +5 -7
  5. package/src/cascade.js +2 -6
  6. package/src/component.js +4 -8
  7. package/src/composition.js +3 -7
  8. package/src/connector.js +2 -6
  9. package/src/context.js +2 -6
  10. package/src/contract/contract.js +2 -6
  11. package/src/contract/index.js +2 -7
  12. package/src/contract/reply.js +4 -8
  13. package/src/contract/request.js +4 -8
  14. package/src/contract/schemas/index.js +7 -9
  15. package/src/discovery.js +3 -7
  16. package/src/effect.js +2 -6
  17. package/src/emission.js +2 -6
  18. package/src/entities/changeset.js +2 -6
  19. package/src/entities/entity.js +3 -7
  20. package/src/entities/factory.js +5 -9
  21. package/src/entities/index.js +1 -5
  22. package/src/entities/newid.js +2 -4
  23. package/src/entities/set.js +2 -6
  24. package/src/event.js +3 -7
  25. package/src/exceptions.js +37 -30
  26. package/src/exposition.js +2 -6
  27. package/src/guard.js +1 -5
  28. package/src/index.js +28 -55
  29. package/src/locator.js +2 -6
  30. package/src/observation.js +2 -6
  31. package/src/operation.js +4 -8
  32. package/src/outbox/index.js +1 -6
  33. package/src/outbox/outbox.js +5 -10
  34. package/src/query/criteria.js +3 -7
  35. package/src/query/options.js +2 -6
  36. package/src/query.js +5 -6
  37. package/src/receiver.js +4 -8
  38. package/src/reflection.js +2 -6
  39. package/src/remote.js +3 -7
  40. package/src/state.js +2 -6
  41. package/src/transition.js +4 -8
  42. package/src/transmission.js +3 -7
  43. package/src/unmanaged.js +2 -6
  44. package/test/call.fixtures.js +8 -12
  45. package/test/call.test.js +21 -9
  46. package/test/component.fixtures.js +5 -8
  47. package/test/component.test.js +22 -11
  48. package/test/connector.fixtures.js +5 -11
  49. package/test/connector.test.js +42 -41
  50. package/test/context.fixtures.js +8 -12
  51. package/test/context.test.js +18 -7
  52. package/test/contract/conditions.test.js +8 -6
  53. package/test/contract/contract.fixtures.js +12 -17
  54. package/test/contract/request.test.js +51 -40
  55. package/test/discovery.test.js +25 -17
  56. package/test/emission.fixtures.js +5 -8
  57. package/test/emission.test.js +29 -12
  58. package/test/entities/entity.fixtures.js +7 -11
  59. package/test/entities/entity.test.js +30 -19
  60. package/test/entities/factory.fixtures.js +22 -10
  61. package/test/entities/factory.test.js +29 -17
  62. package/test/entities/set.fixtures.js +6 -8
  63. package/test/entities/set.test.js +6 -5
  64. package/test/event.fixtures.js +9 -14
  65. package/test/event.test.js +57 -31
  66. package/test/locator.test.js +25 -24
  67. package/test/outbox.test.js +44 -37
  68. package/test/query.fixtures.js +1 -5
  69. package/test/query.test.js +28 -17
  70. package/test/receiver.fixtures.js +8 -12
  71. package/test/receiver.test.js +45 -22
  72. package/test/reflection.test.js +7 -6
  73. package/test/state.fixtures.js +24 -32
  74. package/test/state.test.js +35 -30
  75. package/test/transmission.fixtures.js +4 -6
  76. package/test/transmission.test.js +33 -15
  77. package/types/atomicity.d.ts +1 -1
  78. package/types/bindings.d.ts +1 -1
  79. package/types/bridges.ts +3 -3
  80. package/types/component.d.ts +4 -4
  81. package/types/context.d.ts +4 -4
  82. package/types/entity.d.ts +2 -2
  83. package/types/event.d.ts +1 -1
  84. package/types/extensions.d.ts +8 -7
  85. package/types/index.ts +16 -16
  86. package/types/operations.d.ts +1 -1
  87. package/types/outbox.d.ts +2 -2
  88. package/types/receiver.d.ts +2 -2
  89. package/types/reflection.d.ts +1 -1
  90. package/types/remote.d.ts +1 -1
  91. package/types/request.d.ts +1 -1
  92. package/types/state.d.ts +2 -2
  93. package/types/storages.d.ts +3 -3
@@ -1,7 +1,8 @@
1
- 'use strict'
1
+ import { describe, it, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- const { generate } = require('randomstring')
4
- const { Locator } = require('../src/locator')
4
+ import { generate } from 'randomstring'
5
+ import { Locator } from '../src/locator.js'
5
6
 
6
7
  /** @type {string} */
7
8
  let name
@@ -20,37 +21,37 @@ beforeEach(() => {
20
21
  })
21
22
 
22
23
  it('should expose name and namespace', () => {
23
- expect(locator.name).toStrictEqual(name)
24
- expect(locator.namespace).toStrictEqual(namespace)
24
+ assert.deepStrictEqual(locator.name, name)
25
+ assert.deepStrictEqual(locator.namespace, namespace)
25
26
  })
26
27
 
27
28
  it('should expose id, label', () => {
28
29
  const id = locator.namespace + '.' + locator.name
29
30
  const label = locator.namespace.toLowerCase() + '-' + locator.name.toLowerCase()
30
31
 
31
- expect(locator.id).toStrictEqual(id)
32
- expect(locator.label).toStrictEqual(label)
32
+ assert.deepStrictEqual(locator.id, id)
33
+ assert.deepStrictEqual(locator.label, label)
33
34
  })
34
35
 
35
36
  it('should expose uppercase', () => {
36
- expect(locator.uppercase).toStrictEqual((locator.namespace + '_' + locator.name).toUpperCase())
37
+ assert.deepStrictEqual(locator.uppercase, (locator.namespace + '_' + locator.name).toUpperCase())
37
38
  })
38
39
 
39
40
  it('should throw if name is undefined', () => {
40
- expect(() => new Locator(undefined, namespace)).toThrow(TypeError)
41
+ assert.throws(() => new Locator(undefined, namespace), TypeError)
41
42
 
42
43
  // noinspection JSCheckFunctionSignatures
43
- expect(() => new Locator()).toThrow(TypeError)
44
+ assert.throws(() => new Locator(), TypeError)
44
45
  })
45
46
 
46
47
  it('should expose host', () => {
47
- expect(locator.hostname()).toStrictEqual((namespace + '-' + name).toLowerCase())
48
+ assert.deepStrictEqual(locator.hostname(), (namespace + '-' + name).toLowerCase())
48
49
  })
49
50
 
50
51
  it('should expose host with given prefix', () => {
51
52
  const prefix = generate()
52
53
 
53
- expect(locator.hostname(prefix)).toStrictEqual((prefix + '-' + namespace + '-' + name).toLowerCase())
54
+ assert.deepStrictEqual(locator.hostname(prefix), (prefix + '-' + namespace + '-' + name).toLowerCase())
54
55
  })
55
56
 
56
57
  describe('global', () => {
@@ -61,28 +62,28 @@ describe('global', () => {
61
62
  it('should not throw', () => undefined)
62
63
 
63
64
  it('should expose id', () => {
64
- expect(locator.id).toStrictEqual(name)
65
+ assert.deepStrictEqual(locator.id, name)
65
66
  })
66
67
 
67
68
  it('should expose label', () => {
68
- expect(locator.label).toStrictEqual(name.toLowerCase())
69
+ assert.deepStrictEqual(locator.label, name.toLowerCase())
69
70
  })
70
71
 
71
72
  it('should expose uppercase', () => {
72
- expect(locator.uppercase).toStrictEqual(name.toUpperCase())
73
+ assert.deepStrictEqual(locator.uppercase, name.toUpperCase())
73
74
  })
74
75
 
75
76
  it('should expose hostname', () => {
76
77
  const type = generate()
77
78
 
78
- expect(locator.hostname(type)).toStrictEqual((type + '-' + name).toLowerCase())
79
- expect(locator.hostname()).toStrictEqual(name.toLowerCase())
79
+ assert.deepStrictEqual(locator.hostname(type), (type + '-' + name).toLowerCase())
80
+ assert.deepStrictEqual(locator.hostname(), name.toLowerCase())
80
81
  })
81
82
  })
82
83
 
83
84
  describe('parse', () => {
84
85
  it('should be', async () => {
85
- expect(Locator.parse).toBeInstanceOf(Function)
86
+ assert.ok(Locator.parse instanceof Function)
86
87
  })
87
88
 
88
89
  const namespace = generate()
@@ -92,22 +93,22 @@ describe('parse', () => {
92
93
  it('should parse id', async () => {
93
94
  const locator = Locator.parse(id)
94
95
 
95
- expect(locator.namespace).toStrictEqual(namespace)
96
- expect(locator.name).toStrictEqual(name)
96
+ assert.deepStrictEqual(locator.namespace, namespace)
97
+ assert.deepStrictEqual(locator.name, name)
97
98
  })
98
99
 
99
100
  it('should parse endpoint', async () => {
100
101
  const endpoint = `${id}.${generate()}`
101
102
  const locator = Locator.parse(endpoint)
102
103
 
103
- expect(locator.namespace).toStrictEqual(namespace)
104
- expect(locator.name).toStrictEqual(name)
104
+ assert.deepStrictEqual(locator.namespace, namespace)
105
+ assert.deepStrictEqual(locator.name, name)
105
106
  })
106
107
 
107
108
  it('should parse token as global', async () => {
108
109
  const locator = Locator.parse(name)
109
110
 
110
- expect(locator.namespace).toBeUndefined()
111
- expect(locator.name).toStrictEqual(name)
111
+ assert.strictEqual(locator.namespace, undefined)
112
+ assert.deepStrictEqual(locator.name, name)
112
113
  })
113
114
  })
@@ -1,6 +1,7 @@
1
- 'use strict'
1
+ import { it, beforeEach, afterEach, mock } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- const { Outbox } = require('../src/outbox')
4
+ import { Outbox } from '../src/outbox/index.js'
4
5
 
5
6
  let emission, storage, atom, outbox
6
7
 
@@ -14,101 +15,107 @@ const page = (from, count) =>
14
15
  }))
15
16
 
16
17
  beforeEach(() => {
17
- jest.clearAllMocks()
18
- jest.useFakeTimers()
18
+ resetCalls()
19
+ mock.timers.enable()
19
20
 
20
- emission = { emit: jest.fn(async () => undefined), link: jest.fn() }
21
+ emission = { emit: mock.fn(async () => undefined), link: mock.fn() }
21
22
 
22
23
  storage = {
23
- link: jest.fn(),
24
+ link: mock.fn(),
24
25
  outbox: {
25
- pending: jest.fn(async () => []),
26
- settle: jest.fn(async () => undefined)
26
+ pending: mock.fn(async () => []),
27
+ settle: mock.fn(async () => undefined)
27
28
  }
28
29
  }
29
30
 
30
- atom = { slots: jest.fn(() => [0]), link: jest.fn() }
31
+ atom = { slots: mock.fn(() => [0]), link: mock.fn() }
31
32
  outbox = new Outbox(emission, storage, atom, { interval: 1000, batch: BATCH })
32
33
  })
33
34
 
34
35
  afterEach(() => {
35
- jest.useRealTimers()
36
+ mock.timers.reset()
36
37
  })
37
38
 
38
39
  /** one cycle, and everything it awaited */
39
40
  const cycle = async () => {
40
- jest.advanceTimersByTime(1000)
41
+ mock.timers.tick(1000)
41
42
 
42
43
  for (let i = 0; i < 20; i++) await Promise.resolve()
43
44
  }
44
45
 
45
46
  it('should read nothing more when the first page is short', async () => {
46
- storage.outbox.pending.mockResolvedValueOnce(page(0, 3))
47
+ storage.outbox.pending.mock.mockImplementationOnce(async () => page(0, 3))
47
48
 
48
49
  await outbox.open()
49
50
  await cycle()
50
51
 
51
- expect(storage.outbox.pending).toHaveBeenCalledTimes(1)
52
- expect(emission.emit).toHaveBeenCalledTimes(3)
52
+ assert.strictEqual(storage.outbox.pending.mock.callCount(), 1)
53
+ assert.strictEqual(emission.emit.mock.callCount(), 3)
53
54
  })
54
55
 
55
56
  it('should keep reading while a page comes back full', async () => {
56
- storage.outbox.pending
57
- .mockResolvedValueOnce(page(0, BATCH))
58
- .mockResolvedValueOnce(page(BATCH, BATCH))
59
- .mockResolvedValueOnce(page(2 * BATCH, 5))
57
+ storage.outbox.pending.mock.mockImplementationOnce(async () => page(0, BATCH), storage.outbox.pending.mock.callCount())
58
+ storage.outbox.pending.mock.mockImplementationOnce(async () => page(BATCH, BATCH), storage.outbox.pending.mock.callCount() + 1)
59
+ storage.outbox.pending.mock.mockImplementationOnce(async () => page(2 * BATCH, 5), storage.outbox.pending.mock.callCount() + 2)
60
60
 
61
61
  await outbox.open()
62
62
  await cycle()
63
63
 
64
- expect(storage.outbox.pending).toHaveBeenCalledTimes(3)
65
- expect(emission.emit).toHaveBeenCalledTimes(2 * BATCH + 5)
64
+ assert.strictEqual(storage.outbox.pending.mock.callCount(), 3)
65
+ assert.strictEqual(emission.emit.mock.callCount(), 2 * BATCH + 5)
66
66
  })
67
67
 
68
68
  it('should continue each page from the id the one before ended on', async () => {
69
- storage.outbox.pending
70
- .mockResolvedValueOnce(page(0, BATCH))
71
- .mockResolvedValueOnce(page(BATCH, 1))
69
+ storage.outbox.pending.mock.mockImplementationOnce(async () => page(0, BATCH), storage.outbox.pending.mock.callCount())
70
+ storage.outbox.pending.mock.mockImplementationOnce(async () => page(BATCH, 1), storage.outbox.pending.mock.callCount() + 1)
72
71
 
73
72
  await outbox.open()
74
73
  await cycle()
75
74
 
76
75
  const [, second] = storage.outbox.pending.mock.calls
77
76
 
78
- expect(storage.outbox.pending.mock.calls[0][3]).toBeUndefined()
79
- expect(second[3]).toStrictEqual(String(BATCH - 1).padStart(4, '0'))
77
+ assert.strictEqual(storage.outbox.pending.mock.calls[0].arguments[3], undefined)
78
+ assert.deepStrictEqual(second.arguments[3], String(BATCH - 1).padStart(4, '0'))
80
79
  })
81
80
 
82
81
  it('should mark what it published, once, after the last page', async () => {
83
- storage.outbox.pending
84
- .mockResolvedValueOnce(page(0, BATCH))
85
- .mockResolvedValueOnce(page(BATCH, 2))
82
+ storage.outbox.pending.mock.mockImplementationOnce(async () => page(0, BATCH), storage.outbox.pending.mock.callCount())
83
+ storage.outbox.pending.mock.mockImplementationOnce(async () => page(BATCH, 2), storage.outbox.pending.mock.callCount() + 1)
86
84
 
87
85
  await outbox.open()
88
86
  await cycle()
89
87
 
90
- expect(storage.outbox.settle).toHaveBeenCalledTimes(1)
91
- expect(storage.outbox.settle.mock.calls[0][0]).toHaveLength(BATCH + 2)
88
+ assert.strictEqual(storage.outbox.settle.mock.callCount(), 1)
89
+ assert.strictEqual(storage.outbox.settle.mock.calls[0].arguments[0].length, BATCH + 2)
92
90
  })
93
91
 
94
92
  it('should not publish a row it has published and not yet marked', async () => {
95
- storage.outbox.settle.mockRejectedValueOnce(new Error('mongo is out'))
96
- storage.outbox.pending
97
- .mockResolvedValueOnce(page(0, 2))
98
- .mockResolvedValueOnce(page(0, 2))
93
+ storage.outbox.settle.mock.mockImplementationOnce(async () => { throw new Error('mongo is out') })
94
+ storage.outbox.pending.mock.mockImplementationOnce(async () => page(0, 2), storage.outbox.pending.mock.callCount())
95
+ storage.outbox.pending.mock.mockImplementationOnce(async () => page(0, 2), storage.outbox.pending.mock.callCount() + 1)
99
96
 
100
97
  await outbox.open()
101
98
  await cycle()
102
99
  await cycle()
103
100
 
104
- expect(emission.emit).toHaveBeenCalledTimes(2)
101
+ assert.strictEqual(emission.emit.mock.callCount(), 2)
105
102
  })
106
103
 
107
104
  it('should read nothing while it owns no slots', async () => {
108
- atom.slots.mockReturnValue(null)
105
+ atom.slots.mock.mockImplementation(() => null)
109
106
 
110
107
  await outbox.open()
111
108
  await cycle()
112
109
 
113
- expect(storage.outbox.pending).not.toHaveBeenCalled()
110
+ assert.strictEqual(storage.outbox.pending.mock.callCount(), 0)
114
111
  })
112
+
113
+ function resetCalls (target = [assert, BATCH, page, cycle], seen = new Set()) {
114
+ if (target === null || typeof target !== 'object' || seen.has(target)) return
115
+
116
+ seen.add(target)
117
+
118
+ for (const value of Object.values(target))
119
+ if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
120
+ else resetCalls(value, seen)
121
+ }
@@ -1,6 +1,4 @@
1
- 'use strict'
2
-
3
- const samples = {
1
+ export const samples = {
4
2
  simple: {
5
3
  query: {
6
4
  criteria: 'name==Eddie'
@@ -96,5 +94,3 @@ const samples = {
96
94
  }
97
95
  }
98
96
  }
99
-
100
- exports.samples = samples
@@ -1,10 +1,11 @@
1
- 'use strict'
1
+ import { describe, it, beforeEach, mock } 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 '../src/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,14 +13,14 @@ 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)
23
24
  })
24
25
 
25
26
  it('should keep a parsed criteria', () => {
@@ -28,35 +29,35 @@ describe('criteria', () => {
28
29
  const first = instance.parse(fixtures.samples.simple.query).criteria
29
30
  const second = instance.parse(fixtures.samples.simple.query).criteria
30
31
 
31
- expect(second).toBe(first)
32
+ assert.strictEqual(second, first)
32
33
  })
33
34
 
34
35
  it('should not keep an invalid criteria', () => {
35
36
  const instance = new Query(fixtures.samples.simple.properties)
36
37
  const query = { criteria: 'nonexistent==1' }
37
38
 
38
- expect(() => instance.parse(query)).toThrow()
39
- expect(() => instance.parse(query)).toThrow()
39
+ assert.throws(() => instance.parse(query))
40
+ assert.throws(() => instance.parse(query))
40
41
  })
41
42
 
42
43
  it('should parse criteria with type coercion', () => {
43
44
  const instance = new Query(fixtures.samples.extended.properties)
44
45
  const query = instance.parse(fixtures.samples.extended.query)
45
46
 
46
- expect(query.criteria).toEqual(fixtures.samples.extended.parsed.criteria)
47
+ assert.deepStrictEqual(query.criteria, fixtures.samples.extended.parsed.criteria)
47
48
  })
48
49
 
49
50
  it('should throw on unknown properties', () => {
50
51
  const instance = new Query(fixtures.samples.simple.properties)
51
52
 
52
- expect(() => instance.parse({ criteria: 'lastname==Johnson' })).toThrow(/not defined/)
53
+ assert.throws(() => instance.parse({ criteria: 'lastname==Johnson' }), (error) => /not defined/.test(error.message))
53
54
  })
54
55
 
55
56
  it('should parse id', () => {
56
57
  const instance = new Query(fixtures.samples.id.properties)
57
58
  const query = instance.parse({ ...fixtures.samples.id.query })
58
59
 
59
- expect(query).toStrictEqual(fixtures.samples.id.parsed)
60
+ assert.deepStrictEqual(query, fixtures.samples.id.parsed)
60
61
  })
61
62
  })
62
63
 
@@ -66,7 +67,7 @@ describe('options', () => {
66
67
  it('should not throw if no options', () => {
67
68
  const query = instance.parse({})
68
69
 
69
- expect(query.options).toBeUndefined()
70
+ assert.strictEqual(query.options, undefined)
70
71
  })
71
72
 
72
73
  describe('omit, limit', () => {
@@ -74,7 +75,7 @@ describe('options', () => {
74
75
  const input = { omit: 1, limit: 1 }
75
76
  const query = instance.parse(input)
76
77
 
77
- expect(query.options).toStrictEqual(input)
78
+ assert.deepStrictEqual(query.options, input)
78
79
  })
79
80
  })
80
81
 
@@ -83,13 +84,13 @@ describe('options', () => {
83
84
  const sort = ['a', 'b:desc', 'c']
84
85
  const query = instance.parse({ sort })
85
86
 
86
- expect(query.options.sort).toStrictEqual([['a', 'asc'], ['b', 'desc'], ['c', 'asc']])
87
+ assert.deepStrictEqual(query.options.sort, [['a', 'asc'], ['b', 'desc'], ['c', 'asc']])
87
88
  })
88
89
 
89
90
  it('should throw on unknown properties', () => {
90
91
  const sort = ['d:asc']
91
92
 
92
- expect(() => instance.parse({ sort })).toThrow(/not defined/)
93
+ assert.throws(() => instance.parse({ sort }), (error) => /not defined/.test(error.message))
93
94
  })
94
95
  })
95
96
 
@@ -97,7 +98,17 @@ describe('options', () => {
97
98
  it('should throw on unknown properties', () => {
98
99
  const projection = ['a', 'b', 'c', 'd']
99
100
 
100
- expect(() => instance.parse({ projection })).toThrow(/not defined/)
101
+ assert.throws(() => instance.parse({ projection }), (error) => /not defined/.test(error.message))
101
102
  })
102
103
  })
103
104
  })
105
+
106
+ function resetCalls (target = [assert, fixtures], seen = new Set()) {
107
+ if (target === null || typeof target !== 'object' || seen.has(target)) return
108
+
109
+ seen.add(target)
110
+
111
+ for (const value of Object.values(target))
112
+ if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
113
+ else resetCalls(value, seen)
114
+ }
@@ -1,24 +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} */ {
11
+ export const local = /** @type {toa.core.Component} */ {
12
12
  locator: { id: 'default.dummy' },
13
- invoke: jest.fn()
13
+ invoke: mock.fn()
14
14
  }
15
15
 
16
16
  // noinspection JSCheckFunctionSignatures
17
- const bridge = /** @type {toa.core.bridges.Event} */ {
18
- condition: jest.fn(async (payload) => !(payload.reject === true)),
19
- request: jest.fn(async () => ({ input: generate() }))
17
+ export const bridge = /** @type {toa.core.bridges.Event} */ {
18
+ condition: mock.fn(async (payload) => !(payload.reject === true)),
19
+ request: mock.fn(async () => ({ input: generate() }))
20
20
  }
21
-
22
- exports.definition = definition
23
- exports.local = local
24
- exports.bridge = bridge
@@ -1,15 +1,22 @@
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 '../src/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) => depends.mock.calls
15
+ .filter((call) => call.this === instance)
16
+ .map((call) => call.arguments[0])
17
+
18
+ import { Receiver } from '../src/receiver.js'
19
+ import * as fixtures from './receiver.fixtures.js'
13
20
 
14
21
  /** @type {toa.core.Receiver} */
15
22
  let receiver
@@ -18,15 +25,16 @@ let receiver
18
25
  let definition
19
26
 
20
27
  beforeEach(() => {
21
- jest.clearAllMocks()
28
+ resetCalls()
29
+ depends.mock.resetCalls()
22
30
 
23
31
  definition = clone(fixtures.definition)
24
32
  receiver = new Receiver(fixtures.definition, fixtures.local, fixtures.bridge)
25
33
  })
26
34
 
27
35
  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)
36
+ assert.ok(dependencies(receiver).some((one) => isDeepStrictEqual(one, fixtures.local)))
37
+ assert.ok(dependencies(receiver).some((one) => isDeepStrictEqual(one, fixtures.bridge)))
30
38
  })
31
39
 
32
40
  it('should apply', async () => {
@@ -34,11 +42,12 @@ it('should apply', async () => {
34
42
 
35
43
  await receiver.receive({ payload })
36
44
 
37
- expect(fixtures.local.invoke).toHaveBeenCalledWith(definition.operation, { input: payload })
45
+ assert.ok(fixtures.local.invoke.mock.calls.some((call) => call.arguments.length === 2 && isDeepStrictEqual(call.arguments[0], definition.operation) && isDeepStrictEqual(call.arguments[1], { input: payload })))
38
46
  })
39
47
 
40
- it.each([[false], [true]])('should pass UI extensions (adaptive: %s)', async (adaptive) => {
41
- jest.clearAllMocks()
48
+ for (const [adaptive] of [[false], [true]])
49
+ it(`should pass UI extensions (adaptive: ${adaptive})`, async () => {
50
+ resetCalls()
42
51
 
43
52
  definition.adaptive = adaptive
44
53
  receiver = new Receiver(definition, fixtures.local, fixtures.bridge)
@@ -49,12 +58,12 @@ it.each([[false], [true]])('should pass UI extensions (adaptive: %s)', async (ad
49
58
 
50
59
  await receiver.receive(message)
51
60
 
52
- const request = adaptive ? await fixtures.bridge.request.mock.results[0].value : { input: payload }
61
+ const request = adaptive ? await fixtures.bridge.request.mock.calls[0].result : { input: payload }
53
62
  const expected = merge(clone(request), extension)
54
63
 
55
- const argument = fixtures.local.invoke.mock.calls[0][1]
64
+ const argument = fixtures.local.invoke.mock.calls[0].arguments[1]
56
65
 
57
- expect(argument).toStrictEqual(expected)
66
+ assert.deepStrictEqual(argument, expected)
58
67
  })
59
68
 
60
69
  describe('conditioned', () => {
@@ -67,15 +76,15 @@ describe('conditioned', () => {
67
76
  const payload = { foo: 'bar' }
68
77
  await receiver.receive({ payload })
69
78
 
70
- expect(fixtures.bridge.condition).toHaveBeenCalledWith(payload)
71
- expect(fixtures.local.invoke).toHaveBeenCalledWith(definition.operation, { input: payload })
79
+ assert.ok(fixtures.bridge.condition.mock.calls.some((call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], payload)))
80
+ assert.ok(fixtures.local.invoke.mock.calls.some((call) => call.arguments.length === 2 && isDeepStrictEqual(call.arguments[0], definition.operation) && isDeepStrictEqual(call.arguments[1], { input: payload })))
72
81
  })
73
82
 
74
83
  it('should not apply if condition is false', async () => {
75
84
  const payload = { reject: true }
76
85
  await receiver.receive({ payload })
77
86
 
78
- expect(fixtures.local.invoke).not.toHaveBeenCalled()
87
+ assert.strictEqual(fixtures.local.invoke.mock.callCount(), 0)
79
88
  })
80
89
  })
81
90
 
@@ -89,7 +98,21 @@ describe('adaptive', () => {
89
98
  const payload = { reject: true }
90
99
  await receiver.receive({ payload })
91
100
 
92
- expect(fixtures.local.invoke)
93
- .toHaveBeenCalledWith(definition.operation, await fixtures.bridge.request.mock.results[0].value)
101
+ const request = await fixtures.bridge.request.mock.calls[0].result
102
+
103
+ assert.ok(fixtures.local.invoke.mock.calls.some((call) =>
104
+ call.arguments.length === 2 &&
105
+ isDeepStrictEqual(call.arguments[0], definition.operation) &&
106
+ isDeepStrictEqual(call.arguments[1], request)))
94
107
  })
95
108
  })
109
+
110
+ function resetCalls (target = [assert, clone, fixtures], seen = new Set()) {
111
+ if (target === null || typeof target !== 'object' || seen.has(target)) return
112
+
113
+ seen.add(target)
114
+
115
+ for (const value of Object.values(target))
116
+ if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
117
+ else resetCalls(value, seen)
118
+ }
@@ -1,10 +1,11 @@
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 '../src/index.js'
5
6
 
6
7
  it('should export', () => {
7
- expect(Reflection).toBeDefined()
8
+ assert.notStrictEqual(Reflection, undefined)
8
9
  })
9
10
 
10
11
  /** @type {toa.core.Reflection<string>} */
@@ -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
  })