@syncular/testkit 0.0.6-96 → 0.1.1

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 (68) hide show
  1. package/dist/audit.d.ts +22 -0
  2. package/dist/audit.d.ts.map +1 -0
  3. package/dist/audit.js +40 -0
  4. package/dist/audit.js.map +1 -0
  5. package/dist/client-bridge.d.ts +77 -0
  6. package/dist/client-bridge.d.ts.map +1 -0
  7. package/dist/client-bridge.js +540 -0
  8. package/dist/client-bridge.js.map +1 -0
  9. package/dist/deterministic.js.map +1 -1
  10. package/dist/disposable.js.map +1 -1
  11. package/dist/faults.d.ts +14 -2
  12. package/dist/faults.d.ts.map +1 -1
  13. package/dist/faults.js +104 -42
  14. package/dist/faults.js.map +1 -1
  15. package/dist/hono-node-server.js +1 -1
  16. package/dist/hono-node-server.js.map +1 -1
  17. package/dist/http-fixtures.d.ts +1 -30
  18. package/dist/http-fixtures.d.ts.map +1 -1
  19. package/dist/http-fixtures.js +5 -65
  20. package/dist/http-fixtures.js.map +1 -1
  21. package/dist/index.d.ts +2 -4
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2 -4
  24. package/dist/index.js.map +1 -1
  25. package/dist/project-scoped-tasks.d.ts.map +1 -1
  26. package/dist/project-scoped-tasks.js +6 -4
  27. package/dist/project-scoped-tasks.js.map +1 -1
  28. package/dist/realtime-ws.js.map +1 -1
  29. package/dist/runtime-process.js.map +1 -1
  30. package/dist/sync-builders.d.ts +5 -3
  31. package/dist/sync-builders.d.ts.map +1 -1
  32. package/dist/sync-builders.js +9 -3
  33. package/dist/sync-builders.js.map +1 -1
  34. package/dist/sync-http.js.map +1 -1
  35. package/dist/sync-parse.js.map +1 -1
  36. package/dist/sync-response.d.ts +3 -4
  37. package/dist/sync-response.d.ts.map +1 -1
  38. package/dist/sync-response.js.map +1 -1
  39. package/package.json +14 -15
  40. package/src/audit.ts +74 -0
  41. package/src/client-bridge.ts +841 -0
  42. package/src/faults.ts +178 -55
  43. package/src/hono-node-server.ts +1 -1
  44. package/src/http-fixtures.ts +6 -127
  45. package/src/index.ts +2 -4
  46. package/src/project-scoped-tasks.ts +6 -4
  47. package/src/sync-builders.ts +14 -6
  48. package/src/sync-response.ts +3 -5
  49. package/dist/assertions.d.ts +0 -61
  50. package/dist/assertions.d.ts.map +0 -1
  51. package/dist/assertions.js +0 -239
  52. package/dist/assertions.js.map +0 -1
  53. package/dist/fixtures.d.ts +0 -104
  54. package/dist/fixtures.d.ts.map +0 -1
  55. package/dist/fixtures.js +0 -558
  56. package/dist/fixtures.js.map +0 -1
  57. package/dist/resources.d.ts +0 -25
  58. package/dist/resources.d.ts.map +0 -1
  59. package/dist/resources.js +0 -64
  60. package/dist/resources.js.map +0 -1
  61. package/dist/scenario-flow.d.ts +0 -39
  62. package/dist/scenario-flow.d.ts.map +0 -1
  63. package/dist/scenario-flow.js +0 -41
  64. package/dist/scenario-flow.js.map +0 -1
  65. package/src/assertions.ts +0 -432
  66. package/src/fixtures.ts +0 -867
  67. package/src/resources.ts +0 -186
  68. package/src/scenario-flow.ts +0 -143
package/dist/resources.js DELETED
@@ -1,64 +0,0 @@
1
- import { createAsyncDisposableResource, withAsyncDisposableFactory, } from './disposable.js';
2
- import { createEngineTestClient, createSyncFixture, createTestClient, createTestServer, createTestSqliteServer, } from './fixtures.js';
3
- import { createHttpClientFixture, createHttpServerFixture, } from './http-fixtures.js';
4
- export async function createTestServerResource(serverDialect) {
5
- const server = await createTestServer(serverDialect);
6
- return createAsyncDisposableResource(server, () => server.destroy());
7
- }
8
- export async function withTestServer(serverDialect, run) {
9
- return withAsyncDisposableFactory(() => createTestServerResource(serverDialect), run);
10
- }
11
- export async function createTestSqliteServerResource(dialect) {
12
- const server = await createTestSqliteServer(dialect);
13
- return createAsyncDisposableResource(server, () => server.destroy());
14
- }
15
- export async function withTestSqliteServer(dialect, run) {
16
- return withAsyncDisposableFactory(() => createTestSqliteServerResource(dialect), run);
17
- }
18
- export async function createTestClientResource(clientDialect, server, options) {
19
- const client = await createTestClient(clientDialect, server, options);
20
- return createAsyncDisposableResource(client, () => client.destroy());
21
- }
22
- export async function withTestClient(clientDialect, server, options, run) {
23
- return withAsyncDisposableFactory(() => createTestClientResource(clientDialect, server, options), run);
24
- }
25
- export async function createEngineTestClientResource(server, options) {
26
- const client = await createEngineTestClient(server, options);
27
- return createAsyncDisposableResource(client, () => client.destroy());
28
- }
29
- export async function withEngineTestClient(server, options, run) {
30
- return withAsyncDisposableFactory(() => createEngineTestClientResource(server, options), run);
31
- }
32
- export async function createSyncFixtureResource(options) {
33
- const fixture = await createSyncFixture(options);
34
- return createAsyncDisposableResource(fixture, () => fixture.destroyAll());
35
- }
36
- export async function withSyncFixture(options, run) {
37
- return withAsyncDisposableFactory(() => createSyncFixtureResource(options), run);
38
- }
39
- export async function createHttpServerFixtureResource(options) {
40
- const fixture = await createHttpServerFixture(options);
41
- return createAsyncDisposableResource(fixture, () => fixture.destroy());
42
- }
43
- export async function withHttpServerFixture(options, run) {
44
- return withAsyncDisposableFactory(() => createHttpServerFixtureResource(options), run);
45
- }
46
- export async function createHttpClientFixtureResource(options) {
47
- const fixture = await createHttpClientFixture(options);
48
- return createAsyncDisposableResource(fixture, () => fixture.destroy());
49
- }
50
- export async function withHttpClientFixture(options, run) {
51
- return withAsyncDisposableFactory(() => createHttpClientFixtureResource(options), run);
52
- }
53
- export async function createEngineSessionResource(client, options = {}) {
54
- if (options.start ?? true) {
55
- await client.startEngine();
56
- }
57
- return createAsyncDisposableResource(client, () => {
58
- client.stopEngine();
59
- });
60
- }
61
- export async function withEngineSession(client, run, options = {}) {
62
- return withAsyncDisposableFactory(() => createEngineSessionResource(client, options), run);
63
- }
64
- //# sourceMappingURL=resources.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
@@ -1,39 +0,0 @@
1
- import { type ClientHandlerCollection, enqueueOutboxCommit, type SyncClientDb, type SyncOnceOptions, type SyncOnceResult, type SyncPullOnceOptions, type SyncPullResponse, type SyncPushOnceOptions, type SyncPushOnceResult } from '@syncular/client';
2
- import type { SyncCombinedRequest, SyncCombinedResponse, SyncTransport } from '@syncular/core';
3
- import type { Kysely } from 'kysely';
4
- export interface ScenarioFlowClient<DB extends SyncClientDb> {
5
- db: Kysely<DB>;
6
- transport: SyncTransport;
7
- handlers: ClientHandlerCollection<DB>;
8
- clientId: string;
9
- actorId?: string;
10
- }
11
- export interface PushThenPullOptions<DB extends SyncClientDb> {
12
- enqueue?: Parameters<typeof enqueueOutboxCommit<DB>>[1];
13
- push?: Omit<SyncPushOnceOptions, 'clientId' | 'actorId'>;
14
- pull: Omit<SyncPullOnceOptions, 'clientId' | 'actorId'>;
15
- }
16
- export interface PushThenPullResult<DB extends SyncClientDb> {
17
- enqueueResult?: {
18
- id: string;
19
- clientCommitId: string;
20
- };
21
- pushResult: SyncPushOnceResult;
22
- pullResult: SyncPullResponse;
23
- client: ScenarioFlowClient<DB>;
24
- }
25
- export interface ScenarioFlow<DB extends SyncClientDb> {
26
- client: ScenarioFlowClient<DB>;
27
- enqueue: (args: Parameters<typeof enqueueOutboxCommit<DB>>[1]) => Promise<{
28
- id: string;
29
- clientCommitId: string;
30
- }>;
31
- push: (options?: Omit<SyncPushOnceOptions, 'clientId' | 'actorId'>) => Promise<SyncPushOnceResult>;
32
- pull: (options: Omit<SyncPullOnceOptions, 'clientId' | 'actorId'>) => Promise<SyncPullResponse>;
33
- sync: (options: Omit<SyncOnceOptions, 'clientId' | 'actorId'>) => Promise<SyncOnceResult>;
34
- transportSync: (request: Omit<SyncCombinedRequest, 'clientId'>) => Promise<SyncCombinedResponse>;
35
- pushThenPull: (options: PushThenPullOptions<DB>) => Promise<PushThenPullResult<DB>>;
36
- }
37
- export declare function createScenarioFlow<DB extends SyncClientDb>(client: ScenarioFlowClient<DB>): ScenarioFlow<DB>;
38
- export declare function runPushPullCycle<DB extends SyncClientDb>(client: ScenarioFlowClient<DB>, options: PushThenPullOptions<DB>): Promise<PushThenPullResult<DB>>;
39
- //# sourceMappingURL=scenario-flow.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scenario-flow.d.ts","sourceRoot":"","sources":["../src/scenario-flow.ts"],"names":[],"mappings":"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"}
@@ -1,41 +0,0 @@
1
- import { enqueueOutboxCommit, syncOnce, syncPullOnce, syncPushOnce, } from '@syncular/client';
2
- function withClientIdentity(values, client) {
3
- return {
4
- ...values,
5
- clientId: client.clientId,
6
- ...(client.actorId ? { actorId: client.actorId } : {}),
7
- };
8
- }
9
- export function createScenarioFlow(client) {
10
- const enqueue = (args) => enqueueOutboxCommit(client.db, args);
11
- const push = (options) => syncPushOnce(client.db, client.transport, withClientIdentity(options ?? {}, client));
12
- const pull = (options) => syncPullOnce(client.db, client.transport, client.handlers, withClientIdentity(options, client));
13
- const sync = (options) => syncOnce(client.db, client.transport, client.handlers, withClientIdentity(options, client));
14
- const transportSync = (request) => client.transport.sync({ clientId: client.clientId, ...request });
15
- const pushThenPull = async (options) => {
16
- const enqueueResult = options.enqueue
17
- ? await enqueueOutboxCommit(client.db, options.enqueue)
18
- : undefined;
19
- const pushResult = await push(options.push);
20
- const pullResult = await pull(options.pull);
21
- return {
22
- enqueueResult,
23
- pushResult,
24
- pullResult,
25
- client,
26
- };
27
- };
28
- return {
29
- client,
30
- enqueue,
31
- push,
32
- pull,
33
- sync,
34
- transportSync,
35
- pushThenPull,
36
- };
37
- }
38
- export async function runPushPullCycle(client, options) {
39
- return createScenarioFlow(client).pushThenPull(options);
40
- }
41
- //# sourceMappingURL=scenario-flow.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scenario-flow.js","sourceRoot":"","sources":["../src/scenario-flow.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,mBAAmB,EAQnB,QAAQ,EACR,YAAY,EACZ,YAAY,GACb,MAAM,kBAAkB,CAAC;AAmD1B,SAAS,kBAAkB,CAIzB,MAAS,EACT,MAA8B,EACc;IAC5C,OAAO;QACL,GAAG,MAAM;QACT,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvD,CAAC;AAAA,CACH;AAED,MAAM,UAAU,kBAAkB,CAChC,MAA8B,EACZ;IAClB,MAAM,OAAO,GAAgC,CAAC,IAAI,EAAE,EAAE,CACpD,mBAAmB,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAEvC,MAAM,IAAI,GAA6B,CAAC,OAAO,EAAE,EAAE,CACjD,YAAY,CACV,MAAM,CAAC,EAAE,EACT,MAAM,CAAC,SAAS,EAChB,kBAAkB,CAAC,OAAO,IAAI,EAAE,EAAE,MAAM,CAAC,CAC1C,CAAC;IAEJ,MAAM,IAAI,GAA6B,CAAC,OAAO,EAAE,EAAE,CACjD,YAAY,CACV,MAAM,CAAC,EAAE,EACT,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,QAAQ,EACf,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CACpC,CAAC;IAEJ,MAAM,IAAI,GAA6B,CAAC,OAAO,EAAE,EAAE,CACjD,QAAQ,CACN,MAAM,CAAC,EAAE,EACT,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,QAAQ,EACf,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CACpC,CAAC;IAEJ,MAAM,aAAa,GAAsC,CAAC,OAAO,EAAE,EAAE,CACnE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IAEnE,MAAM,YAAY,GAAqC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;QACxE,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO;YACnC,CAAC,CAAC,MAAM,mBAAmB,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC;YACvD,CAAC,CAAC,SAAS,CAAC;QAEd,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAE5C,OAAO;YACL,aAAa;YACb,UAAU;YACV,UAAU;YACV,MAAM;SACP,CAAC;IAAA,CACH,CAAC;IAEF,OAAO;QACL,MAAM;QACN,OAAO;QACP,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,aAAa;QACb,YAAY;KACb,CAAC;AAAA,CACH;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAA8B,EAC9B,OAAgC,EACC;IACjC,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;AAAA,CACzD"}
package/src/assertions.ts DELETED
@@ -1,432 +0,0 @@
1
- import { isDeepStrictEqual } from 'node:util';
2
- import type { OutboxCommitStatus, SyncClientDb } from '@syncular/client';
3
- import type { SyncCoreDb } from '@syncular/server';
4
- import type { Kysely } from 'kysely';
5
-
6
- function formatValue(value: unknown): string {
7
- if (typeof value === 'string') {
8
- return value;
9
- }
10
-
11
- try {
12
- return JSON.stringify(value);
13
- } catch {
14
- return String(value);
15
- }
16
- }
17
-
18
- function fail(message: string): never {
19
- throw new Error(message);
20
- }
21
-
22
- function assertEqual(
23
- actual: unknown,
24
- expected: unknown,
25
- message: string
26
- ): void {
27
- if (!isDeepStrictEqual(actual, expected)) {
28
- fail(
29
- `${message} (expected=${formatValue(expected)} actual=${formatValue(actual)})`
30
- );
31
- }
32
- }
33
-
34
- function assertDefined<T>(
35
- value: T | null | undefined,
36
- message: string
37
- ): asserts value is T {
38
- if (value == null) {
39
- fail(message);
40
- }
41
- }
42
-
43
- export async function outboxCount(db: Kysely<SyncClientDb>): Promise<number> {
44
- const count = await db
45
- .selectFrom('sync_outbox_commits')
46
- .select(({ fn }) => fn.countAll().as('count'))
47
- .executeTakeFirstOrThrow();
48
-
49
- return Number(count.count);
50
- }
51
-
52
- export async function conflictCount(db: Kysely<SyncClientDb>): Promise<number> {
53
- const count = await db
54
- .selectFrom('sync_conflicts')
55
- .where('resolved_at', 'is', null)
56
- .select(({ fn }) => fn.countAll().as('count'))
57
- .executeTakeFirstOrThrow();
58
-
59
- return Number(count.count);
60
- }
61
-
62
- export async function serverCommitCount(
63
- db: Kysely<SyncCoreDb>
64
- ): Promise<number> {
65
- const count = await db
66
- .selectFrom('sync_commits')
67
- .select(({ fn }) => fn.countAll().as('count'))
68
- .executeTakeFirstOrThrow();
69
-
70
- return Number(count.count);
71
- }
72
-
73
- export async function serverChangeCount(
74
- db: Kysely<SyncCoreDb>
75
- ): Promise<number> {
76
- const count = await db
77
- .selectFrom('sync_changes')
78
- .select(({ fn }) => fn.countAll().as('count'))
79
- .executeTakeFirstOrThrow();
80
-
81
- return Number(count.count);
82
- }
83
-
84
- export async function assertOutboxEmpty(
85
- db: Kysely<SyncClientDb>
86
- ): Promise<void> {
87
- const count = await outboxCount(db);
88
- assertEqual(count, 0, 'Outbox is not empty');
89
- }
90
-
91
- export async function assertOutboxHas(
92
- db: Kysely<SyncClientDb>,
93
- expectedCount: number
94
- ): Promise<void> {
95
- const count = await outboxCount(db);
96
- assertEqual(count, expectedCount, 'Unexpected outbox commit count');
97
- }
98
-
99
- export async function assertOutboxStatus(
100
- db: Kysely<SyncClientDb>,
101
- status: OutboxCommitStatus,
102
- expectedCount: number
103
- ): Promise<void> {
104
- const count = await db
105
- .selectFrom('sync_outbox_commits')
106
- .where('status', '=', status)
107
- .select(({ fn }) => fn.countAll().as('count'))
108
- .executeTakeFirstOrThrow();
109
-
110
- assertEqual(
111
- Number(count.count),
112
- expectedCount,
113
- `Unexpected outbox count for status=${status}`
114
- );
115
- }
116
-
117
- export async function assertConflictCount(
118
- db: Kysely<SyncClientDb>,
119
- expectedCount: number
120
- ): Promise<void> {
121
- const count = await conflictCount(db);
122
- assertEqual(count, expectedCount, 'Unexpected unresolved conflict count');
123
- }
124
-
125
- export async function assertConflictExists(
126
- db: Kysely<SyncClientDb>,
127
- options: {
128
- clientCommitId: string;
129
- resultStatus?: 'conflict' | 'error';
130
- resolved?: boolean;
131
- }
132
- ): Promise<void> {
133
- let query = db
134
- .selectFrom('sync_conflicts')
135
- .where('client_commit_id', '=', options.clientCommitId);
136
-
137
- if (options.resultStatus) {
138
- query = query.where('result_status', '=', options.resultStatus);
139
- }
140
-
141
- if (options.resolved !== undefined) {
142
- query = options.resolved
143
- ? query.where('resolved_at', 'is not', null)
144
- : query.where('resolved_at', 'is', null);
145
- }
146
-
147
- const conflict = await query.selectAll().executeTakeFirst();
148
- assertDefined(
149
- conflict,
150
- `Expected conflict for client_commit_id=${options.clientCommitId}`
151
- );
152
- }
153
-
154
- export async function assertRowExists<
155
- DB extends SyncClientDb,
156
- T extends keyof DB & string,
157
- >(
158
- db: Kysely<DB>,
159
- table: T,
160
- rowId: string,
161
- expected?: Partial<DB[T]>,
162
- idColumn = 'id'
163
- ): Promise<void> {
164
- const row = await db
165
- .selectFrom(table)
166
- // @ts-expect-error - dynamic column name
167
- .where(idColumn, '=', rowId)
168
- .selectAll()
169
- .executeTakeFirst();
170
-
171
- assertDefined(row, `Expected row ${rowId} to exist in table ${table}`);
172
-
173
- if (!expected) {
174
- return;
175
- }
176
-
177
- const rowRecord = row as Record<string, unknown>;
178
- for (const [key, value] of Object.entries(expected)) {
179
- assertEqual(
180
- rowRecord[key],
181
- value,
182
- `Unexpected value for ${table}.${key} (row ${rowId})`
183
- );
184
- }
185
- }
186
-
187
- export async function assertRowNotExists<
188
- DB extends SyncClientDb,
189
- T extends keyof DB & string,
190
- >(db: Kysely<DB>, table: T, rowId: string, idColumn = 'id'): Promise<void> {
191
- const row = await db
192
- .selectFrom(table)
193
- // @ts-expect-error - dynamic column name
194
- .where(idColumn, '=', rowId)
195
- .selectAll()
196
- .executeTakeFirst();
197
-
198
- if (row !== undefined) {
199
- fail(`Expected row ${rowId} to be absent in table ${table}`);
200
- }
201
- }
202
-
203
- export async function assertRowVersion<
204
- DB extends SyncClientDb,
205
- T extends keyof DB & string,
206
- >(
207
- db: Kysely<DB>,
208
- table: T,
209
- rowId: string,
210
- expectedVersion: number,
211
- versionColumn = 'server_version',
212
- idColumn = 'id'
213
- ): Promise<void> {
214
- const row = await db
215
- .selectFrom(table)
216
- // @ts-expect-error - dynamic column name
217
- .where(idColumn, '=', rowId)
218
- .select(versionColumn)
219
- .executeTakeFirst();
220
-
221
- assertDefined(row, `Expected row ${rowId} to exist in table ${table}`);
222
- const rowRecord = row as Record<string, unknown>;
223
- assertEqual(
224
- rowRecord[versionColumn],
225
- expectedVersion,
226
- `Unexpected version for ${table}.${rowId}`
227
- );
228
- }
229
-
230
- export async function assertSubscriptionCursor(
231
- db: Kysely<SyncClientDb>,
232
- subscriptionId: string,
233
- expectedCursor: number,
234
- stateId = 'default'
235
- ): Promise<void> {
236
- const sub = await db
237
- .selectFrom('sync_subscription_state')
238
- .where('state_id', '=', stateId)
239
- .where('subscription_id', '=', subscriptionId)
240
- .select(['cursor'])
241
- .executeTakeFirst();
242
-
243
- assertDefined(
244
- sub,
245
- `Expected subscription state row for ${stateId}/${subscriptionId}`
246
- );
247
- assertEqual(
248
- sub.cursor,
249
- expectedCursor,
250
- `Unexpected cursor for subscription ${subscriptionId}`
251
- );
252
- }
253
-
254
- export async function assertSubscriptionStatus(
255
- db: Kysely<SyncClientDb>,
256
- subscriptionId: string,
257
- expectedStatus: 'active' | 'revoked',
258
- stateId = 'default'
259
- ): Promise<void> {
260
- const sub = await db
261
- .selectFrom('sync_subscription_state')
262
- .where('state_id', '=', stateId)
263
- .where('subscription_id', '=', subscriptionId)
264
- .select(['status'])
265
- .executeTakeFirst();
266
-
267
- assertDefined(
268
- sub,
269
- `Expected subscription state row for ${stateId}/${subscriptionId}`
270
- );
271
- assertEqual(
272
- sub.status,
273
- expectedStatus,
274
- `Unexpected status for subscription ${subscriptionId}`
275
- );
276
- }
277
-
278
- export async function assertServerCommitCount(
279
- db: Kysely<SyncCoreDb>,
280
- expectedCount: number
281
- ): Promise<void> {
282
- const count = await serverCommitCount(db);
283
- assertEqual(count, expectedCount, 'Unexpected server commit count');
284
- }
285
-
286
- export async function assertServerChangeCount(
287
- db: Kysely<SyncCoreDb>,
288
- expectedCount: number
289
- ): Promise<void> {
290
- const count = await serverChangeCount(db);
291
- assertEqual(count, expectedCount, 'Unexpected server change count');
292
- }
293
-
294
- export async function assertServerChangeExists(
295
- db: Kysely<SyncCoreDb>,
296
- options: {
297
- table: string;
298
- rowId: string;
299
- op?: 'upsert' | 'delete';
300
- commitSeq?: number;
301
- }
302
- ): Promise<void> {
303
- let query = db
304
- .selectFrom('sync_changes')
305
- .where('table', '=', options.table)
306
- .where('row_id', '=', options.rowId);
307
-
308
- if (options.op) {
309
- query = query.where('op', '=', options.op);
310
- }
311
-
312
- if (options.commitSeq) {
313
- query = query.where('commit_seq', '=', options.commitSeq);
314
- }
315
-
316
- const change = await query.selectAll().executeTakeFirst();
317
- assertDefined(
318
- change,
319
- `Expected server change for table=${options.table} rowId=${options.rowId}`
320
- );
321
- }
322
-
323
- export async function assertServerClientCursor(
324
- db: Kysely<SyncCoreDb>,
325
- clientId: string,
326
- expectedCursor: number
327
- ): Promise<void> {
328
- const cursor = await db
329
- .selectFrom('sync_client_cursors')
330
- .where('client_id', '=', clientId)
331
- .select(['cursor'])
332
- .executeTakeFirst();
333
-
334
- assertDefined(cursor, `Expected sync_client_cursors row for ${clientId}`);
335
- assertEqual(
336
- cursor.cursor,
337
- expectedCursor,
338
- `Unexpected cursor for ${clientId}`
339
- );
340
- }
341
-
342
- async function waitFor(
343
- condition: () => Promise<boolean>,
344
- options?: {
345
- timeoutMs?: number;
346
- intervalMs?: number;
347
- message?: string;
348
- }
349
- ): Promise<void> {
350
- const timeoutMs = options?.timeoutMs ?? 5000;
351
- const intervalMs = options?.intervalMs ?? 50;
352
- const message = options?.message ?? 'Condition not met within timeout';
353
-
354
- const startTime = Date.now();
355
-
356
- while (Date.now() - startTime < timeoutMs) {
357
- if (await condition()) {
358
- return;
359
- }
360
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
361
- }
362
-
363
- fail(message);
364
- }
365
-
366
- export async function waitForOutboxEmpty(
367
- db: Kysely<SyncClientDb>,
368
- timeoutMs = 5000
369
- ): Promise<void> {
370
- await waitFor(
371
- async () => {
372
- const count = await outboxCount(db);
373
- return count === 0;
374
- },
375
- { timeoutMs, message: 'Outbox not empty within timeout' }
376
- );
377
- }
378
-
379
- export async function waitForAckedCommits(
380
- db: Kysely<SyncClientDb>,
381
- expectedCount: number,
382
- timeoutMs = 5000
383
- ): Promise<void> {
384
- await waitFor(
385
- async () => {
386
- const count = await db
387
- .selectFrom('sync_outbox_commits')
388
- .where('status', '=', 'acked')
389
- .select(({ fn }) => fn.countAll().as('count'))
390
- .executeTakeFirstOrThrow();
391
- return Number(count.count) >= expectedCount;
392
- },
393
- {
394
- timeoutMs,
395
- message: `Expected ${expectedCount} acked commits within timeout`,
396
- }
397
- );
398
- }
399
-
400
- export const assertOutbox = {
401
- empty: assertOutboxEmpty,
402
- count: assertOutboxHas,
403
- status: assertOutboxStatus,
404
- };
405
-
406
- export const assertConflicts = {
407
- count: assertConflictCount,
408
- exists: assertConflictExists,
409
- };
410
-
411
- export const assertRows = {
412
- exists: assertRowExists,
413
- missing: assertRowNotExists,
414
- version: assertRowVersion,
415
- };
416
-
417
- export const assertServer = {
418
- commits: assertServerCommitCount,
419
- changes: assertServerChangeCount,
420
- changeExists: assertServerChangeExists,
421
- clientCursor: assertServerClientCursor,
422
- };
423
-
424
- export const assertSubscription = {
425
- cursor: assertSubscriptionCursor,
426
- status: assertSubscriptionStatus,
427
- };
428
-
429
- export const waitForSync = {
430
- outboxEmpty: waitForOutboxEmpty,
431
- ackedCommits: waitForAckedCommits,
432
- };