cojson 0.13.2 → 0.13.7

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 (87) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +16 -0
  3. package/LICENSE.txt +1 -1
  4. package/dist/PeerState.d.ts +6 -0
  5. package/dist/PeerState.d.ts.map +1 -1
  6. package/dist/PeerState.js +43 -0
  7. package/dist/PeerState.js.map +1 -1
  8. package/dist/coValueCore.d.ts.map +1 -1
  9. package/dist/coValueCore.js +1 -0
  10. package/dist/coValueCore.js.map +1 -1
  11. package/dist/coValueState.d.ts +1 -0
  12. package/dist/coValueState.d.ts.map +1 -1
  13. package/dist/coValueState.js +27 -2
  14. package/dist/coValueState.js.map +1 -1
  15. package/dist/coValues/group.d.ts +1 -0
  16. package/dist/coValues/group.d.ts.map +1 -1
  17. package/dist/coValues/group.js +45 -21
  18. package/dist/coValues/group.js.map +1 -1
  19. package/dist/crypto/crypto.d.ts +2 -2
  20. package/dist/crypto/crypto.d.ts.map +1 -1
  21. package/dist/permissions.d.ts +1 -0
  22. package/dist/permissions.d.ts.map +1 -1
  23. package/dist/permissions.js +19 -3
  24. package/dist/permissions.js.map +1 -1
  25. package/dist/storage/FileSystem.d.ts +2 -2
  26. package/dist/storage/FileSystem.d.ts.map +1 -1
  27. package/dist/sync.d.ts +14 -4
  28. package/dist/sync.d.ts.map +1 -1
  29. package/dist/sync.js +146 -146
  30. package/dist/sync.js.map +1 -1
  31. package/dist/tests/SyncStateManager.test.js +51 -46
  32. package/dist/tests/SyncStateManager.test.js.map +1 -1
  33. package/dist/tests/coValueCore.test.js +51 -2
  34. package/dist/tests/coValueCore.test.js.map +1 -1
  35. package/dist/tests/coValueState.test.js +31 -4
  36. package/dist/tests/coValueState.test.js.map +1 -1
  37. package/dist/tests/group.test.js +135 -2
  38. package/dist/tests/group.test.js.map +1 -1
  39. package/dist/tests/messagesTestUtils.d.ts +13 -0
  40. package/dist/tests/messagesTestUtils.d.ts.map +1 -0
  41. package/dist/tests/messagesTestUtils.js +42 -0
  42. package/dist/tests/messagesTestUtils.js.map +1 -0
  43. package/dist/tests/sync.load.test.d.ts +2 -0
  44. package/dist/tests/sync.load.test.d.ts.map +1 -0
  45. package/dist/tests/sync.load.test.js +249 -0
  46. package/dist/tests/sync.load.test.js.map +1 -0
  47. package/dist/tests/sync.mesh.test.d.ts +2 -0
  48. package/dist/tests/sync.mesh.test.d.ts.map +1 -0
  49. package/dist/tests/sync.mesh.test.js +157 -0
  50. package/dist/tests/sync.mesh.test.js.map +1 -0
  51. package/dist/tests/sync.peerReconciliation.test.d.ts +2 -0
  52. package/dist/tests/sync.peerReconciliation.test.d.ts.map +1 -0
  53. package/dist/tests/sync.peerReconciliation.test.js +130 -0
  54. package/dist/tests/sync.peerReconciliation.test.js.map +1 -0
  55. package/dist/tests/sync.storage.test.d.ts +2 -0
  56. package/dist/tests/sync.storage.test.d.ts.map +1 -0
  57. package/dist/tests/sync.storage.test.js +201 -0
  58. package/dist/tests/sync.storage.test.js.map +1 -0
  59. package/dist/tests/sync.test.js +139 -1048
  60. package/dist/tests/sync.test.js.map +1 -1
  61. package/dist/tests/sync.upload.test.d.ts +2 -0
  62. package/dist/tests/sync.upload.test.d.ts.map +1 -0
  63. package/dist/tests/sync.upload.test.js +156 -0
  64. package/dist/tests/sync.upload.test.js.map +1 -0
  65. package/dist/tests/testUtils.d.ts +76 -33
  66. package/dist/tests/testUtils.d.ts.map +1 -1
  67. package/dist/tests/testUtils.js +153 -47
  68. package/dist/tests/testUtils.js.map +1 -1
  69. package/package.json +3 -3
  70. package/src/PeerState.ts +59 -1
  71. package/src/coValueCore.ts +1 -0
  72. package/src/coValueState.ts +34 -3
  73. package/src/coValues/group.ts +83 -45
  74. package/src/permissions.ts +31 -3
  75. package/src/sync.ts +169 -185
  76. package/src/tests/SyncStateManager.test.ts +58 -70
  77. package/src/tests/coValueCore.test.ts +70 -1
  78. package/src/tests/coValueState.test.ts +59 -5
  79. package/src/tests/group.test.ts +250 -2
  80. package/src/tests/messagesTestUtils.ts +75 -0
  81. package/src/tests/sync.load.test.ts +327 -0
  82. package/src/tests/sync.mesh.test.ts +219 -0
  83. package/src/tests/sync.peerReconciliation.test.ts +201 -0
  84. package/src/tests/sync.storage.test.ts +259 -0
  85. package/src/tests/sync.test.ts +170 -1245
  86. package/src/tests/sync.upload.test.ts +202 -0
  87. package/src/tests/testUtils.ts +213 -61
@@ -6,54 +6,53 @@ import {
6
6
  import { connectedPeers } from "../streamUtils.js";
7
7
  import { emptyKnownState } from "../sync.js";
8
8
  import {
9
+ SyncMessagesLog,
9
10
  blockMessageTypeOnOutgoingPeer,
10
- connectNodeToSyncServer,
11
11
  createTestNode,
12
12
  loadCoValueOrFail,
13
- setupSyncServer,
13
+ setupTestNode,
14
14
  waitFor,
15
15
  } from "./testUtils.js";
16
16
 
17
- let jazzCloud = setupSyncServer();
17
+ let jazzCloud = setupTestNode({ isSyncServer: true });
18
18
 
19
19
  beforeEach(async () => {
20
- jazzCloud = setupSyncServer();
20
+ SyncMessagesLog.clear();
21
+ jazzCloud = setupTestNode({ isSyncServer: true });
21
22
  });
22
23
 
23
24
  describe("SyncStateManager", () => {
24
25
  test("subscribeToUpdates receives updates when peer state changes", async () => {
25
26
  // Setup nodes
26
- const client = createTestNode();
27
- const { nodeToServerPeer } = connectNodeToSyncServer(client);
27
+ const client = setupTestNode({ connected: true });
28
+ const { peerState } = client.connectToSyncServer();
28
29
 
29
30
  // Create test data
30
- const group = client.createGroup();
31
+ const group = client.node.createGroup();
31
32
  const map = group.createMap();
32
33
  map.set("key1", "value1", "trusting");
33
34
 
34
- const subscriptionManager = client.syncManager.syncState;
35
+ const subscriptionManager = client.node.syncManager.syncState;
35
36
 
36
37
  const updateSpy: GlobalSyncStateListenerCallback = vi.fn();
37
38
  const unsubscribe = subscriptionManager.subscribeToUpdates(updateSpy);
38
39
 
39
- await client.syncManager.actuallySyncCoValue(map.core);
40
+ await client.node.syncManager.actuallySyncCoValue(map.core);
40
41
 
41
42
  expect(updateSpy).toHaveBeenCalledWith(
42
- nodeToServerPeer.id,
43
+ peerState.id,
43
44
  emptyKnownState(map.core.id),
44
45
  { uploaded: false },
45
46
  );
46
47
 
47
48
  await waitFor(() => {
48
- return subscriptionManager.getCurrentSyncState(
49
- nodeToServerPeer.id,
50
- map.core.id,
51
- ).uploaded;
49
+ return subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
50
+ .uploaded;
52
51
  });
53
52
 
54
53
  expect(updateSpy).toHaveBeenCalledWith(
55
- nodeToServerPeer.id,
56
- client.syncManager.peers[nodeToServerPeer.id]!.knownStates.get(
54
+ peerState.id,
55
+ client.node.syncManager.peers[peerState.id]!.knownStates.get(
57
56
  map.core.id,
58
57
  )!,
59
58
  { uploaded: true },
@@ -65,11 +64,11 @@ describe("SyncStateManager", () => {
65
64
 
66
65
  test("subscribeToPeerUpdates receives updates only for specific peer", async () => {
67
66
  // Setup nodes
68
- const client = createTestNode();
69
- const { nodeToServerPeer } = connectNodeToSyncServer(client);
67
+ const client = setupTestNode({ connected: true });
68
+ const { peerState } = client.connectToSyncServer();
70
69
 
71
70
  // Create test data
72
- const group = client.createGroup();
71
+ const group = client.node.createGroup();
73
72
  const map = group.createMap();
74
73
  map.set("key1", "value1", "trusting");
75
74
 
@@ -78,14 +77,14 @@ describe("SyncStateManager", () => {
78
77
  peer2role: "server",
79
78
  });
80
79
 
81
- client.syncManager.addPeer(clientStoragePeer);
80
+ client.node.syncManager.addPeer(clientStoragePeer);
82
81
 
83
- const subscriptionManager = client.syncManager.syncState;
82
+ const subscriptionManager = client.node.syncManager.syncState;
84
83
 
85
84
  const updateToJazzCloudSpy: PeerSyncStateListenerCallback = vi.fn();
86
85
  const updateToStorageSpy: PeerSyncStateListenerCallback = vi.fn();
87
86
  const unsubscribe1 = subscriptionManager.subscribeToPeerUpdates(
88
- nodeToServerPeer.id,
87
+ peerState.id,
89
88
  updateToJazzCloudSpy,
90
89
  );
91
90
  const unsubscribe2 = subscriptionManager.subscribeToPeerUpdates(
@@ -98,7 +97,7 @@ describe("SyncStateManager", () => {
98
97
  unsubscribe2();
99
98
  });
100
99
 
101
- await client.syncManager.actuallySyncCoValue(map.core);
100
+ await client.node.syncManager.actuallySyncCoValue(map.core);
102
101
 
103
102
  expect(updateToJazzCloudSpy).toHaveBeenCalledWith(
104
103
  emptyKnownState(map.core.id),
@@ -106,14 +105,12 @@ describe("SyncStateManager", () => {
106
105
  );
107
106
 
108
107
  await waitFor(() => {
109
- return subscriptionManager.getCurrentSyncState(
110
- nodeToServerPeer.id,
111
- map.core.id,
112
- ).uploaded;
108
+ return subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
109
+ .uploaded;
113
110
  });
114
111
 
115
112
  expect(updateToJazzCloudSpy).toHaveBeenLastCalledWith(
116
- client.syncManager.peers[nodeToServerPeer.id]!.knownStates.get(
113
+ client.node.syncManager.peers[peerState.id]!.knownStates.get(
117
114
  map.core.id,
118
115
  )!,
119
116
  { uploaded: true },
@@ -127,66 +124,62 @@ describe("SyncStateManager", () => {
127
124
 
128
125
  test("getIsCoValueFullyUploadedIntoPeer returns correct status", async () => {
129
126
  // Setup nodes
130
- const client = createTestNode();
131
- const { nodeToServerPeer } = connectNodeToSyncServer(client);
127
+ const client = setupTestNode({ connected: true });
128
+ const { peerState } = client.connectToSyncServer();
132
129
 
133
130
  // Create test data
134
- const group = client.createGroup();
131
+ const group = client.node.createGroup();
135
132
  const map = group.createMap();
136
133
  map.set("key1", "value1", "trusting");
137
134
 
138
- await client.syncManager.actuallySyncCoValue(map.core);
135
+ await client.node.syncManager.actuallySyncCoValue(map.core);
139
136
 
140
- const subscriptionManager = client.syncManager.syncState;
137
+ const subscriptionManager = client.node.syncManager.syncState;
141
138
 
142
139
  expect(
143
- subscriptionManager.getCurrentSyncState(nodeToServerPeer.id, map.core.id)
140
+ subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
144
141
  .uploaded,
145
142
  ).toBe(false);
146
143
 
147
144
  await waitFor(() => {
148
- return subscriptionManager.getCurrentSyncState(
149
- nodeToServerPeer.id,
150
- map.core.id,
151
- ).uploaded;
145
+ return subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
146
+ .uploaded;
152
147
  });
153
148
 
154
149
  expect(
155
- subscriptionManager.getCurrentSyncState(nodeToServerPeer.id, map.core.id)
150
+ subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
156
151
  .uploaded,
157
152
  ).toBe(true);
158
153
  });
159
154
 
160
155
  test("unsubscribe stops receiving updates", async () => {
161
156
  // Setup nodes
162
- const client = createTestNode();
163
- const { nodeToServerPeer } = connectNodeToSyncServer(client);
157
+ const client = setupTestNode({ connected: true });
158
+ const { peerState } = client.connectToSyncServer();
164
159
 
165
160
  // Create test data
166
- const group = client.createGroup();
161
+ const group = client.node.createGroup();
167
162
  const map = group.createMap();
168
163
  map.set("key1", "value1", "trusting");
169
164
 
170
- const subscriptionManager = client.syncManager.syncState;
165
+ const subscriptionManager = client.node.syncManager.syncState;
171
166
  const anyUpdateSpy = vi.fn();
172
167
  const unsubscribe1 = subscriptionManager.subscribeToUpdates(anyUpdateSpy);
173
168
  const unsubscribe2 = subscriptionManager.subscribeToPeerUpdates(
174
- nodeToServerPeer.id,
169
+ peerState.id,
175
170
  anyUpdateSpy,
176
171
  );
177
172
 
178
173
  unsubscribe1();
179
174
  unsubscribe2();
180
175
 
181
- await client.syncManager.actuallySyncCoValue(map.core);
176
+ await client.node.syncManager.actuallySyncCoValue(map.core);
182
177
 
183
178
  anyUpdateSpy.mockClear();
184
179
 
185
180
  await waitFor(() => {
186
- return subscriptionManager.getCurrentSyncState(
187
- nodeToServerPeer.id,
188
- map.core.id,
189
- ).uploaded;
181
+ return subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
182
+ .uploaded;
190
183
  });
191
184
 
192
185
  expect(anyUpdateSpy).not.toHaveBeenCalled();
@@ -194,22 +187,20 @@ describe("SyncStateManager", () => {
194
187
 
195
188
  test("getCurrentSyncState should return the correct state", async () => {
196
189
  // Setup nodes
197
- const clientNode = createTestNode();
198
- const serverNode = jazzCloud;
199
- const {
200
- nodeToServerPeer: clientToServerPeer,
201
- serverToNodePeer: serverToClientPeer,
202
- } = connectNodeToSyncServer(clientNode);
190
+ const client = setupTestNode({ connected: true });
191
+ const serverNode = jazzCloud.node;
192
+ const { peer, peerOnServer } = client.connectToSyncServer();
193
+
203
194
  // Create test data
204
- const group = clientNode.createGroup();
195
+ const group = client.node.createGroup();
205
196
  const map = group.createMap();
206
197
  map.set("key1", "value1", "trusting");
207
198
  group.addMember("everyone", "writer");
208
199
 
209
200
  // Initially should not be synced
210
201
  expect(
211
- clientNode.syncManager.syncState.getCurrentSyncState(
212
- clientToServerPeer.id,
202
+ client.node.syncManager.syncState.getCurrentSyncState(
203
+ peer.id,
213
204
  map.core.id,
214
205
  ),
215
206
  ).toEqual({ uploaded: false });
@@ -218,8 +209,8 @@ describe("SyncStateManager", () => {
218
209
  await map.core.waitForSync();
219
210
 
220
211
  expect(
221
- clientNode.syncManager.syncState.getCurrentSyncState(
222
- clientToServerPeer.id,
212
+ client.node.syncManager.syncState.getCurrentSyncState(
213
+ peer.id,
223
214
  map.core.id,
224
215
  ),
225
216
  ).toEqual({ uploaded: true });
@@ -227,23 +218,20 @@ describe("SyncStateManager", () => {
227
218
  const mapOnServer = await loadCoValueOrFail(serverNode, map.id);
228
219
 
229
220
  // Block the content messages so the client won't fully sync immediately
230
- const outgoing = blockMessageTypeOnOutgoingPeer(
231
- serverToClientPeer,
232
- "content",
233
- );
221
+ const outgoing = blockMessageTypeOnOutgoingPeer(peerOnServer, "content");
234
222
 
235
223
  mapOnServer.set("key2", "value2", "trusting");
236
224
 
237
225
  expect(
238
- clientNode.syncManager.syncState.getCurrentSyncState(
239
- clientToServerPeer.id,
226
+ client.node.syncManager.syncState.getCurrentSyncState(
227
+ peer.id,
240
228
  map.core.id,
241
229
  ),
242
230
  ).toEqual({ uploaded: true });
243
231
 
244
232
  expect(
245
233
  serverNode.syncManager.syncState.getCurrentSyncState(
246
- serverToClientPeer.id,
234
+ peerOnServer.id,
247
235
  map.core.id,
248
236
  ),
249
237
  ).toEqual({ uploaded: false });
@@ -254,15 +242,15 @@ describe("SyncStateManager", () => {
254
242
  await mapOnServer.core.waitForSync();
255
243
 
256
244
  expect(
257
- clientNode.syncManager.syncState.getCurrentSyncState(
258
- clientToServerPeer.id,
245
+ client.node.syncManager.syncState.getCurrentSyncState(
246
+ peer.id,
259
247
  map.core.id,
260
248
  ),
261
249
  ).toEqual({ uploaded: true });
262
250
 
263
251
  expect(
264
252
  serverNode.syncManager.syncState.getCurrentSyncState(
265
- serverToClientPeer.id,
253
+ peerOnServer.id,
266
254
  map.core.id,
267
255
  ),
268
256
  ).toEqual({ uploaded: true });
@@ -1,4 +1,4 @@
1
- import { expect, test, vi } from "vitest";
1
+ import { assert, afterEach, beforeEach, expect, test, vi } from "vitest";
2
2
  import { CoValueCore, Transaction } from "../coValueCore.js";
3
3
  import { MapOpPayload } from "../coValues/coMap.js";
4
4
  import { WasmCrypto } from "../crypto/WasmCrypto.js";
@@ -6,14 +6,26 @@ import { stableStringify } from "../jsonStringify.js";
6
6
  import { LocalNode } from "../localNode.js";
7
7
  import { Role } from "../permissions.js";
8
8
  import {
9
+ createTestMetricReader,
9
10
  createTestNode,
10
11
  createTwoConnectedNodes,
11
12
  loadCoValueOrFail,
12
13
  randomAnonymousAccountAndSessionID,
14
+ tearDownTestMetricReader,
13
15
  } from "./testUtils.js";
14
16
 
15
17
  const Crypto = await WasmCrypto.create();
16
18
 
19
+ let metricReader: ReturnType<typeof createTestMetricReader>;
20
+
21
+ beforeEach(() => {
22
+ metricReader = createTestMetricReader();
23
+ });
24
+
25
+ afterEach(() => {
26
+ tearDownTestMetricReader();
27
+ });
28
+
17
29
  test("Can create coValue with new agent credentials and add transaction to it", () => {
18
30
  const [account, sessionID] = randomAnonymousAccountAndSessionID();
19
31
  const node = new LocalNode(account, sessionID, Crypto);
@@ -197,6 +209,63 @@ test("New transactions in a group correctly update owned values, including subsc
197
209
  expect(map.core.getValidSortedTransactions().length).toBe(0);
198
210
  });
199
211
 
212
+ test("correctly records transactions", async () => {
213
+ const [account, sessionID] = randomAnonymousAccountAndSessionID();
214
+ const node = new LocalNode(account, sessionID, Crypto);
215
+
216
+ const changes1 = stableStringify([{ hello: "world" }]);
217
+ node.syncManager.recordTransactionsSize(
218
+ [
219
+ {
220
+ privacy: "trusting",
221
+ changes: changes1,
222
+ madeAt: Date.now(),
223
+ },
224
+ ],
225
+ "server",
226
+ );
227
+
228
+ let value = await metricReader.getMetricValue("jazz.transactions.size", {
229
+ source: "server",
230
+ });
231
+ assert(typeof value !== "number" && !!value?.count);
232
+ expect(value.count).toBe(1);
233
+ expect(value.sum).toBe(changes1.length);
234
+
235
+ const changes2 = stableStringify([{ foo: "bar" }]);
236
+ node.syncManager.recordTransactionsSize(
237
+ [
238
+ {
239
+ privacy: "trusting",
240
+ changes: changes2,
241
+ madeAt: Date.now(),
242
+ },
243
+ ],
244
+ "server",
245
+ );
246
+
247
+ value = await metricReader.getMetricValue("jazz.transactions.size", {
248
+ source: "server",
249
+ });
250
+ assert(typeof value !== "number" && !!value?.count);
251
+ expect(value.count).toBe(2);
252
+ expect(value.sum).toBe(changes1.length + changes2.length);
253
+ });
254
+
255
+ test("(smoke test) records transactions from local node", async () => {
256
+ const [account, sessionID] = randomAnonymousAccountAndSessionID();
257
+ const node = new LocalNode(account, sessionID, Crypto);
258
+
259
+ node.createGroup();
260
+
261
+ let value = await metricReader.getMetricValue("jazz.transactions.size", {
262
+ source: "local",
263
+ });
264
+
265
+ assert(typeof value !== "number" && !!value?.count);
266
+ expect(value.count).toBe(3);
267
+ });
268
+
200
269
  test("creating a coValue with a group should't trigger automatically a content creation (performance)", () => {
201
270
  const node = createTestNode();
202
271
 
@@ -1,9 +1,19 @@
1
- import { beforeEach, describe, expect, onTestFinished, test, vi } from "vitest";
1
+ import {
2
+ assert,
3
+ afterEach,
4
+ beforeEach,
5
+ describe,
6
+ expect,
7
+ onTestFinished,
8
+ test,
9
+ vi,
10
+ } from "vitest";
2
11
  import { PeerState } from "../PeerState";
3
12
  import { CoValueCore } from "../coValueCore";
4
13
  import { CO_VALUE_LOADING_CONFIG, CoValueState } from "../coValueState";
5
14
  import { RawCoID } from "../ids";
6
15
  import { Peer } from "../sync";
16
+ import { createTestMetricReader, tearDownTestMetricReader } from "./testUtils";
7
17
 
8
18
  const initialMaxRetries = CO_VALUE_LOADING_CONFIG.MAX_RETRIES;
9
19
 
@@ -15,26 +25,43 @@ function mockMaxRetries(maxRetries: number) {
15
25
  });
16
26
  }
17
27
 
28
+ let metricReader: ReturnType<typeof createTestMetricReader>;
29
+
18
30
  beforeEach(() => {
31
+ metricReader = createTestMetricReader();
19
32
  mockMaxRetries(5);
20
33
  });
21
34
 
35
+ afterEach(() => {
36
+ tearDownTestMetricReader();
37
+ });
38
+
22
39
  describe("CoValueState", () => {
23
40
  const mockCoValueId = "co_test123" as RawCoID;
24
41
 
25
- test("should create unknown state", () => {
42
+ test("should create unknown state", async () => {
26
43
  const state = CoValueState.Unknown(mockCoValueId);
27
44
 
28
45
  expect(state.id).toBe(mockCoValueId);
29
46
  expect(state.state.type).toBe("unknown");
47
+ expect(
48
+ await metricReader.getMetricValue("jazz.covalues.loaded", {
49
+ state: "unknown",
50
+ }),
51
+ ).toBe(1);
30
52
  });
31
53
 
32
- test("should create loading state", () => {
54
+ test("should create loading state", async () => {
33
55
  const peerIds = ["peer1", "peer2"];
34
56
  const state = CoValueState.Loading(mockCoValueId, peerIds);
35
57
 
36
58
  expect(state.id).toBe(mockCoValueId);
37
59
  expect(state.state.type).toBe("loading");
60
+ expect(
61
+ await metricReader.getMetricValue("jazz.covalues.loaded", {
62
+ state: "loading",
63
+ }),
64
+ ).toBe(1);
38
65
  });
39
66
 
40
67
  test("should create available state", async () => {
@@ -42,15 +69,31 @@ describe("CoValueState", () => {
42
69
  const state = CoValueState.Available(mockCoValue);
43
70
 
44
71
  expect(state.id).toBe(mockCoValueId);
45
- expect(state.state.type).toBe("available");
46
- expect((state.state as any).coValue).toBe(mockCoValue);
72
+ assert(state.state.type === "available");
73
+ expect(state.state.coValue).toBe(mockCoValue);
47
74
  await expect(state.getCoValue()).resolves.toEqual(mockCoValue);
75
+ expect(
76
+ await metricReader.getMetricValue("jazz.covalues.loaded", {
77
+ state: "available",
78
+ }),
79
+ ).toBe(1);
48
80
  });
49
81
 
50
82
  test("should handle found action", async () => {
51
83
  const mockCoValue = createMockCoValueCore(mockCoValueId);
52
84
  const state = CoValueState.Loading(mockCoValueId, ["peer1", "peer2"]);
53
85
 
86
+ expect(
87
+ await metricReader.getMetricValue("jazz.covalues.loaded", {
88
+ state: "available",
89
+ }),
90
+ ).toBe(undefined);
91
+ expect(
92
+ await metricReader.getMetricValue("jazz.covalues.loaded", {
93
+ state: "loading",
94
+ }),
95
+ ).toBe(1);
96
+
54
97
  const stateValuePromise = state.getCoValue();
55
98
 
56
99
  state.dispatch({
@@ -61,6 +104,17 @@ describe("CoValueState", () => {
61
104
  const result = await state.getCoValue();
62
105
  expect(result).toBe(mockCoValue);
63
106
  await expect(stateValuePromise).resolves.toBe(mockCoValue);
107
+
108
+ expect(
109
+ await metricReader.getMetricValue("jazz.covalues.loaded", {
110
+ state: "available",
111
+ }),
112
+ ).toBe(1);
113
+ expect(
114
+ await metricReader.getMetricValue("jazz.covalues.loaded", {
115
+ state: "loading",
116
+ }),
117
+ ).toBe(0);
64
118
  });
65
119
 
66
120
  test("should ignore actions when not in loading state", () => {