@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,17 +1,25 @@
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
- jest.mock('../src/connector')
5
+ import clone from 'clone-deep'
4
6
 
5
- const clone = require('clone-deep')
7
+ import { Connector } from '../src/connector.js'
6
8
 
7
- const { Connector } = require('../src/connector')
8
- const { Emission } = require('../src/emission')
9
- const fixtures = require('./emission.fixtures')
9
+ // the fixtures are not connectors, so a dependency is recorded rather than linked
10
+ const depends = mock.method(Connector.prototype, 'depends', () => undefined)
11
+
12
+ const dependencies = (instance) => depends.mock.calls
13
+ .filter((call) => call.this === instance)
14
+ .map((call) => call.arguments[0])
15
+ import { Emission } from '../src/emission.js'
16
+ import * as fixtures from './emission.fixtures.js'
10
17
 
11
18
  let emission, event
12
19
 
13
20
  beforeEach(async () => {
14
- jest.clearAllMocks()
21
+ resetCalls()
22
+ depends.mock.resetCalls()
15
23
 
16
24
  emission = new Emission(fixtures.events)
17
25
  event = clone(fixtures.event)
@@ -20,16 +28,25 @@ beforeEach(async () => {
20
28
  })
21
29
 
22
30
  it('should depend on events', () => {
23
- expect(emission).toBeInstanceOf(Connector)
24
- expect(Connector.mock.instances[0].depends).toHaveBeenCalledWith(fixtures.events)
31
+ assert.ok(emission instanceof Connector)
32
+ assert.ok(dependencies(emission).some((one) => isDeepStrictEqual(one, fixtures.events)))
25
33
  })
26
34
 
27
35
  it('should emit events', async () => {
28
- expect.assertions(fixtures.events.length)
29
-
36
+
30
37
  await emission.emit(event)
31
38
 
32
39
  for (const evt of fixtures.events) {
33
- expect(evt.emit).toHaveBeenCalledWith(event)
40
+ assert.ok(evt.emit.mock.calls.some((call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], event)))
34
41
  }
35
42
  })
43
+
44
+ function resetCalls (target = [assert, clone, depends, dependencies, 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,16 +1,16 @@
1
- 'use strict'
1
+ import { mock } from 'node:test'
2
2
 
3
- const { generate } = require('randomstring')
3
+ import { generate } from 'randomstring'
4
4
 
5
5
  // noinspection JSCheckFunctionSignatures
6
- const schema = {
7
- fit: jest.fn((object) =>
6
+ export const schema = {
7
+ fit: mock.fn((object) =>
8
8
  (object.fail ? { [generate()]: generate() } : null)),
9
9
 
10
- defaults: jest.fn(() => ({ [generate()]: generate() }))
10
+ defaults: mock.fn(() => ({ [generate()]: generate() }))
11
11
  }
12
12
 
13
- const state = () => ({
13
+ export const state = () => ({
14
14
  id: generate(),
15
15
  foo: generate(),
16
16
  _created: generate(),
@@ -19,11 +19,7 @@ const state = () => ({
19
19
  _version: 0
20
20
  })
21
21
 
22
- const failed = () => ({
22
+ export const failed = () => ({
23
23
  ...state(),
24
24
  fail: true
25
25
  })
26
-
27
- exports.schema = schema
28
- exports.state = state
29
- exports.failed = failed
@@ -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 { Entity } = require('../../src/entities/entity')
4
- const fixtures = require('./entity.fixtures')
4
+ import { Entity } from '../../src/entities/entity.js'
5
+ import * as fixtures from './entity.fixtures.js'
5
6
 
6
7
  beforeEach(() => {
7
- jest.clearAllMocks()
8
+ resetCalls()
8
9
  })
9
10
 
10
11
  describe('argument', () => {
@@ -12,15 +13,15 @@ describe('argument', () => {
12
13
  const state = fixtures.state()
13
14
  const entity = new Entity(fixtures.schema, state)
14
15
 
15
- expect(entity.get()).toEqual(state)
16
+ assert.deepStrictEqual(entity.get(), state)
16
17
  })
17
18
 
18
19
  it('should snapshot the record it may commit', () => {
19
20
  const record = fixtures.state()
20
21
  const entity = new Entity(fixtures.schema, record)
21
22
 
22
- expect(entity.get()).not.toBe(record)
23
- expect(entity.event().origin).toBe(record)
23
+ assert.notStrictEqual(entity.get(), record)
24
+ assert.strictEqual(entity.event().origin, record)
24
25
  })
25
26
  })
26
27
 
@@ -30,20 +31,20 @@ describe('read-only', () => {
30
31
  const entity = new Entity(fixtures.schema, record, undefined, false)
31
32
 
32
33
  // no pre-image to diff against, hence no copy of it
33
- expect(entity.get()).toBe(record)
34
+ assert.strictEqual(entity.get(), record)
34
35
  })
35
36
 
36
37
  it('should still report a tombstone', () => {
37
38
  const record = { ...fixtures.state(), _deleted: Date.now() }
38
39
  const entity = new Entity(fixtures.schema, record, undefined, false)
39
40
 
40
- expect(entity.deleted).toBe(true)
41
+ assert.strictEqual(entity.deleted, true)
41
42
  })
42
43
 
43
44
  it('should refuse to be modified', () => {
44
45
  const entity = new Entity(fixtures.schema, fixtures.state(), undefined, false)
45
46
 
46
- expect(() => entity.set(entity.get())).toThrow('read-only')
47
+ assert.throws(() => entity.set(entity.get()), (error) => /read-only/.test(error.message))
47
48
  })
48
49
  })
49
50
 
@@ -56,9 +57,9 @@ describe('tombstone', () => {
56
57
  state.foo = 'revived'
57
58
  entity.set(state)
58
59
 
59
- expect(entity.get()._deleted).toBeNull()
60
- expect(entity.deleted).toBe(false)
61
- expect(entity.event().state._deleted).toBeNull()
60
+ assert.strictEqual(entity.get()._deleted, null)
61
+ assert.strictEqual(entity.deleted, false)
62
+ assert.strictEqual(entity.event().state._deleted, null)
62
63
  })
63
64
 
64
65
  it('should keep tombstone written by transition', () => {
@@ -70,8 +71,8 @@ describe('tombstone', () => {
70
71
  state._deleted = timestamp
71
72
  entity.set(state)
72
73
 
73
- expect(entity.get()._deleted).toBe(timestamp)
74
- expect(entity.deleted).toBe(true)
74
+ assert.strictEqual(entity.get()._deleted, timestamp)
75
+ assert.strictEqual(entity.deleted, true)
75
76
  })
76
77
  })
77
78
 
@@ -85,8 +86,18 @@ it('should provide event', () => {
85
86
 
86
87
  const event = entity.event()
87
88
 
88
- expect(event).toEqual(expect.objectContaining({ state, origin }))
89
- expect(event.state.foo).toBe('new value')
90
- expect(event.state._version).toBe(1)
91
- expect(event.origin.foo).not.toBe('new value')
89
+ assert.partialDeepStrictEqual(event, { state, origin })
90
+ assert.strictEqual(event.state.foo, 'new value')
91
+ assert.strictEqual(event.state._version, 1)
92
+ assert.notStrictEqual(event.origin.foo, 'new value')
92
93
  })
94
+
95
+ function resetCalls (target = [assert, fixtures], seen = new Set()) {
96
+ if (target === null || typeof target !== 'object' || seen.has(target)) return
97
+
98
+ seen.add(target)
99
+
100
+ for (const value of Object.values(target))
101
+ if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
102
+ else resetCalls(value, seen)
103
+ }
@@ -1,18 +1,30 @@
1
- 'use strict'
1
+ import { mock } from 'node:test'
2
2
 
3
- const randomstring = require('randomstring')
3
+ import randomstring from 'randomstring'
4
4
 
5
5
  const schema = { [randomstring.generate()]: randomstring.generate() }
6
- const storage = { id: jest.fn(() => randomstring.generate()) }
6
+ const storage = { id: mock.fn(() => randomstring.generate()) }
7
7
  const entity = { [randomstring.generate()]: randomstring.generate() }
8
8
  const set = Array.from(Array(5))
9
9
  .map((_, index) => ({ id: index, [randomstring.generate()]: randomstring.generate() }))
10
10
 
11
- const Entity = jest.fn().mockImplementation(function () { this.id = randomstring.generate() })
12
- const EntitySet = jest.fn().mockImplementation(function () {})
11
+ // node:test records a mock's calls but not the instances it constructed
12
+ const entities = []
13
13
 
14
- exports.schema = schema
15
- exports.storage = storage
16
- exports.entity = entity
17
- exports.set = set
18
- exports.mock = { Entity, EntitySet }
14
+ const Entity = mock.fn(function () {
15
+ this.id = randomstring.generate()
16
+ entities.push(this)
17
+ })
18
+
19
+ const EntitySet = mock.fn(function () {})
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+ // named `mock` for its consumers, which is what node:test calls its own tracker
28
+ const mocks = { Entity, EntitySet }
29
+
30
+ export { schema, storage, entity, set, entities, mocks as mock }
@@ -1,19 +1,23 @@
1
- 'use strict'
1
+ import { it, beforeEach, mock as mocking } 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 fixtures = require('./factory.fixtures')
7
+ import * as fixtures from './factory.fixtures.js'
6
8
  const mock = fixtures.mock
7
9
 
8
- jest.mock('../../src/entities/entity', () => ({ Entity: mock.Entity }))
9
- jest.mock('../../src/entities/set', () => ({ EntitySet: mock.EntitySet }))
10
+ mocking.module('../../src/entities/entity', { namedExports: ({ Entity: mock.Entity }) })
11
+ mocking.module('../../src/entities/set', { namedExports: ({ EntitySet: mock.EntitySet }) })
12
+
13
+ const { Factory } = await import('../../src/entities/factory.js')
10
14
 
11
- const { Factory } = require('../../src/entities/factory')
12
15
 
13
16
  let factory
14
17
 
15
18
  beforeEach(async () => {
16
- jest.clearAllMocks()
19
+ resetCalls()
20
+ fixtures.entities.length = 0
17
21
 
18
22
  factory = new Factory(fixtures.schema, () => fixtures.storage.id())
19
23
  })
@@ -22,29 +26,37 @@ it('should create initial', () => {
22
26
  const id = generate()
23
27
  const initial = factory.init(id)
24
28
 
25
- expect(initial).toBeInstanceOf(mock.Entity)
26
- expect(initial.constructor).toHaveBeenCalledWith(fixtures.schema, id, expect.any(Function))
29
+ assert.ok(initial instanceof mock.Entity)
30
+ assert.ok(mock.Entity.mock.calls.some((call) => call.arguments.length === 3 && isDeepStrictEqual(call.arguments[0], fixtures.schema) && isDeepStrictEqual(call.arguments[1], id) && typeof call.arguments[2] === 'function'))
27
31
  })
28
32
 
29
33
  it('should create instance', () => {
30
34
  const object = factory.object(fixtures.entity)
31
35
 
32
- expect(object).toBeInstanceOf(mock.Entity)
33
- expect(object.constructor)
34
- .toHaveBeenCalledWith(fixtures.schema, fixtures.entity, expect.any(Function), true)
36
+ assert.ok(object instanceof mock.Entity)
37
+ assert.ok(mock.Entity.mock.calls.some((call) => call.arguments.length === 4 && isDeepStrictEqual(call.arguments[0], fixtures.schema) && isDeepStrictEqual(call.arguments[1], fixtures.entity) && typeof call.arguments[2] === 'function' && isDeepStrictEqual(call.arguments[3], true)))
35
38
  })
36
39
 
37
40
  it('should create set', () => {
38
41
  const objects = factory.objects(fixtures.set)
39
42
 
40
- expect(objects).toBeInstanceOf(mock.EntitySet)
43
+ assert.ok(objects instanceof mock.EntitySet)
41
44
 
42
45
  const instances = fixtures.set.map((entity, index) => {
43
- expect(mock.Entity)
44
- .toHaveBeenNthCalledWith(index + 1, fixtures.schema, entity, expect.any(Function), true)
46
+ assert.ok(((call) => call.arguments.length === 4 && isDeepStrictEqual(call.arguments[0], fixtures.schema) && isDeepStrictEqual(call.arguments[1], entity) && typeof call.arguments[2] === 'function' && isDeepStrictEqual(call.arguments[3], true))(mock.Entity.mock.calls[index + 1 - 1] ?? { arguments: [] }))
45
47
 
46
- return mock.Entity.mock.instances[index]
48
+ return fixtures.entities[index]
47
49
  })
48
50
 
49
- expect(objects.constructor).toHaveBeenCalledWith(instances)
51
+ assert.ok(mock.EntitySet.mock.calls.some((call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], instances)))
50
52
  })
53
+
54
+ function resetCalls (target = [assert, fixtures, mock], seen = new Set()) {
55
+ if (target === null || typeof target !== 'object' || seen.has(target)) return
56
+
57
+ seen.add(target)
58
+
59
+ for (const value of Object.values(target))
60
+ if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
61
+ else resetCalls(value, seen)
62
+ }
@@ -1,11 +1,9 @@
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 set = [
6
- { get: jest.fn(() => ({ [generate()]: generate() })) },
7
- { get: jest.fn(() => ({ [generate()]: generate() })) },
8
- { get: jest.fn(() => ({ [generate()]: generate() })) }
5
+ export const set = [
6
+ { get: mock.fn(() => ({ [generate()]: generate() })) },
7
+ { get: mock.fn(() => ({ [generate()]: generate() })) },
8
+ { get: mock.fn(() => ({ [generate()]: generate() })) }
9
9
  ]
10
-
11
- exports.set = set
@@ -1,12 +1,13 @@
1
- 'use strict'
1
+ import { it } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- const { EntitySet } = require('../../src/entities/set')
4
- const fixtures = require('./set.fixtures')
4
+ import { EntitySet } from '../../src/entities/set.js'
5
+ import * as fixtures from './set.fixtures.js'
5
6
 
6
7
  it('should provide state', () => {
7
8
  const set = new EntitySet(fixtures.set)
8
9
  const state = set.get()
9
- const expected = fixtures.set.map((entity) => entity.get.mock.results[0].value)
10
+ const expected = fixtures.set.map((entity) => entity.get.mock.calls[0].result)
10
11
 
11
- expect(state).toStrictEqual(expected)
12
+ assert.deepStrictEqual(state, expected)
12
13
  })
@@ -1,29 +1,24 @@
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 = {
5
+ export const definition = {
6
6
  conditioned: true,
7
7
  subjective: true
8
8
  }
9
9
 
10
10
  // noinspection JSCheckFunctionSignatures
11
- const bridge = {
12
- condition: jest.fn(async (origin) => !origin.falsy),
13
- payload: jest.fn(async () => ({ [generate()]: generate() }))
11
+ export const bridge = {
12
+ condition: mock.fn(async (origin) => !origin.falsy),
13
+ payload: mock.fn(async () => ({ [generate()]: generate() }))
14
14
  }
15
15
 
16
- const binding = {
17
- emit: jest.fn()
16
+ export const binding = {
17
+ emit: mock.fn()
18
18
  }
19
19
 
20
- const event = {
20
+ export const event = {
21
21
  origin: { [generate()]: generate() },
22
22
  state: { [generate()]: generate() },
23
23
  changeset: { [generate()]: generate() }
24
24
  }
25
-
26
- exports.bridge = bridge
27
- exports.binding = binding
28
- exports.definition = definition
29
- exports.event = event
@@ -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')
5
+ import clone from 'clone-deep'
4
6
 
5
- jest.mock('../src/connector')
6
-
7
- const { Connector } = require('../src/connector')
8
- const { Event } = require('../src/event')
9
- const fixtures = require('./event.fixtures')
7
+ import { Connector } from '../src/connector.js'
8
+ import { Event } from '../src/event.js'
9
+ import * as fixtures from './event.fixtures.js'
10
10
 
11
11
  let event, emit
12
12
 
13
+ // the fixtures are not connectors, so the dependency is recorded rather than linked
14
+ const depends = mock.method(Connector.prototype, 'depends', () => undefined)
15
+
16
+ const dependencies = (instance) => depends.mock.calls
17
+ .filter((call) => call.this === instance)
18
+ .map((call) => call.arguments[0])
19
+
13
20
  beforeEach(() => {
14
- jest.clearAllMocks()
21
+ resetCalls()
22
+ depends.mock.resetCalls()
15
23
 
16
24
  event = new Event(fixtures.definition, fixtures.binding, fixtures.bridge)
17
25
  emit = () => event.emit(fixtures.event)
18
26
  })
19
27
 
20
28
  it('should depend on binding', () => {
21
- expect(event).toBeInstanceOf(Connector)
22
- expect(Connector.mock.instances[0].depends).toHaveBeenCalledWith(fixtures.binding)
29
+ assert.ok(event instanceof Connector)
30
+ assert.ok(dependencies(event).some((one) => isDeepStrictEqual(one, fixtures.binding)))
23
31
  })
24
32
 
25
33
  it('should depend on bridge if provided', () => {
26
- expect(Connector.mock.instances[0].depends).toHaveBeenCalledWith(fixtures.bridge)
34
+ assert.ok(dependencies(event).some((one) => isDeepStrictEqual(one, fixtures.bridge)))
35
+
36
+ const bridgeless = new Event(fixtures.definition, fixtures.binding)
27
37
 
28
- event = new Event(fixtures.definition, fixtures.binding)
29
- expect(Connector.mock.instances[1].depends).not.toHaveBeenCalledWith(fixtures.bridge)
38
+ assert.ok(!dependencies(bridgeless).some((one) => isDeepStrictEqual(one, fixtures.bridge)))
30
39
  })
31
40
 
32
41
  describe('condition', () => {
@@ -34,15 +43,14 @@ describe('condition', () => {
34
43
  it('should call condition', async () => {
35
44
  await emit()
36
45
 
37
- expect(fixtures.bridge.condition).toHaveBeenCalledWith(fixtures.event)
46
+ assert.ok(fixtures.bridge.condition.mock.calls.some((call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], fixtures.event)))
38
47
  })
39
48
 
40
49
  it('should emit if condition returns true', async () => {
41
50
  await emit()
42
51
 
43
- const payload = await fixtures.bridge.payload.mock.results[0].value
44
- const message = { payload, telemetry: expect.any(String) }
45
- expect(fixtures.binding.emit).toHaveBeenCalledWith(message)
52
+ const payload = await fixtures.bridge.payload.mock.calls[0].result
53
+ assertEmitted(payload)
46
54
  })
47
55
 
48
56
  it('should not emit if condition returns false', async () => {
@@ -52,7 +60,7 @@ describe('condition', () => {
52
60
 
53
61
  await event.emit(origin, fixtures.event.changeset, fixtures.event.state)
54
62
 
55
- expect(fixtures.binding.emit).not.toHaveBeenCalled()
63
+ assert.strictEqual(fixtures.binding.emit.mock.callCount(), 0)
56
64
  })
57
65
  })
58
66
 
@@ -68,12 +76,10 @@ describe('condition', () => {
68
76
  it('should not call condition', async () => {
69
77
  await event.emit(fixtures.event.origin, fixtures.event.changeset, fixtures.event.state)
70
78
 
71
- expect(fixtures.bridge.condition).not.toHaveBeenCalledWith()
79
+ assert.ok(!(fixtures.bridge.condition.mock.calls.some((call) => call.arguments.length === 0)))
72
80
 
73
- const payload = await fixtures.bridge.payload.mock.results[0].value
74
- const message = { payload, telemetry: expect.any(String) }
75
-
76
- expect(fixtures.binding.emit).toHaveBeenCalledWith(message)
81
+ const payload = await fixtures.bridge.payload.mock.calls[0].result
82
+ assertEmitted(payload)
77
83
  })
78
84
  })
79
85
  })
@@ -83,10 +89,8 @@ describe('payload', () => {
83
89
  it('should emit payload', async () => {
84
90
  await emit()
85
91
 
86
- const payload = await fixtures.bridge.payload.mock.results[0].value
87
- const message = { payload, telemetry: expect.any(String) }
88
-
89
- expect(fixtures.binding.emit).toHaveBeenCalledWith(message)
92
+ const payload = await fixtures.bridge.payload.mock.calls[0].result
93
+ assertEmitted(payload)
90
94
  })
91
95
  })
92
96
 
@@ -103,16 +107,38 @@ describe('payload', () => {
103
107
  it('should not call payload', async () => {
104
108
  await emit()
105
109
 
106
- expect(fixtures.bridge.payload).not.toHaveBeenCalled()
110
+ assert.strictEqual(fixtures.bridge.payload.mock.callCount(), 0)
107
111
  })
108
112
 
109
113
  it('should return state as payload', async () => {
110
114
  await emit()
111
115
 
112
116
  const payload = fixtures.event.state
113
- const message = { payload, telemetry: expect.any(String) }
114
-
115
- expect(fixtures.binding.emit).toHaveBeenCalledWith(message)
117
+ assertEmitted(payload)
116
118
  })
117
119
  })
118
120
  })
121
+
122
+ function resetCalls (target = [assert, clone, fixtures, depends, dependencies], seen = new Set()) {
123
+ if (target === null || typeof target !== 'object' || seen.has(target)) return
124
+
125
+ seen.add(target)
126
+
127
+ for (const value of Object.values(target))
128
+ if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
129
+ else resetCalls(value, seen)
130
+ }
131
+
132
+ /** The message carries the payload and a telemetry token generated per emission. */
133
+ function assertEmitted (payload) {
134
+ const emitted = fixtures.binding.emit.mock.calls
135
+ .map((call) => call.arguments[0])
136
+ .filter((message) => isDeepStrictEqual(message.payload, payload))
137
+
138
+ assert.notStrictEqual(emitted.length, 0)
139
+
140
+ for (const message of emitted) {
141
+ assert.strictEqual(typeof message.telemetry, 'string')
142
+ assert.deepStrictEqual(Object.keys(message).sort(), ['payload', 'telemetry'])
143
+ }
144
+ }