@fedify/testing 2.4.0-dev.1909 → 2.4.0-dev.1919

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.
package/README.md CHANGED
@@ -95,6 +95,33 @@ The package also exports helper functions for creating various context types:
95
95
  - `createRequestContext()`: Creates a request context
96
96
  - `createInboxContext()`: Creates an inbox context
97
97
 
98
+ ### Store conformance tests
99
+
100
+ The package provides reusable conformance suites for Fedify storage adapters.
101
+ Use `testKvStore()` to check a `KvStore` implementation and
102
+ `testMessageQueue()` to check a `MessageQueue` implementation:
103
+
104
+ ~~~~ typescript
105
+ import { test } from "@fedify/fixture";
106
+ import { testKvStore, testMessageQueue } from "@fedify/testing";
107
+
108
+ test("MyKvStore", () =>
109
+ testKvStore(
110
+ () => new MyKvStore(),
111
+ async ({ store }) => await store.close(),
112
+ ));
113
+
114
+ test("MyMessageQueue", () =>
115
+ testMessageQueue(
116
+ () => new MyMessageQueue(),
117
+ async ({ mq1, mq2, controller }) => {
118
+ controller.abort();
119
+ await mq1.close();
120
+ await mq2.close();
121
+ },
122
+ ));
123
+ ~~~~
124
+
98
125
 
99
126
  Features
100
127
  --------
package/dist/mod.cjs CHANGED
@@ -4523,7 +4523,7 @@ const Now = /*@__PURE__*/ Object.defineProperties({}, {
4523
4523
  }
4524
4524
  })
4525
4525
  });
4526
- const Temporal$2 = /*@__PURE__*/ Object.defineProperties({}, {
4526
+ const Temporal$3 = /*@__PURE__*/ Object.defineProperties({}, {
4527
4527
  ...createStringTagDescriptors("Temporal"),
4528
4528
  ...createPropDescriptors({
4529
4529
  PlainYearMonth,
@@ -4539,11 +4539,153 @@ const Temporal$2 = /*@__PURE__*/ Object.defineProperties({}, {
4539
4539
  });
4540
4540
  //#endregion
4541
4541
  //#region ../../node_modules/.pnpm/temporal-polyfill@1.0.1/node_modules/temporal-polyfill/index.js
4542
- const Temporal$1 = NativeTemporal || Temporal$2;
4542
+ const Temporal$2 = NativeTemporal || Temporal$3;
4543
4543
  NativeTemporal && Date.prototype.toTemporalInstant;
4544
4544
  //#endregion
4545
+ //#region src/kv-tester.ts
4546
+ const Temporal$1 = Temporal$2;
4547
+ /**
4548
+ * Tests a {@link KvStore} implementation with a standard set of tests.
4549
+ *
4550
+ * The suite covers reads and writes, deletion, structured keys and values,
4551
+ * prefix listing, TTL expiration, and optional compare-and-swap behavior.
4552
+ * Every key is isolated below a random prefix and is deleted after the suite.
4553
+ *
4554
+ * @example
4555
+ * ```typescript ignore
4556
+ * import { test } from "@fedify/fixture";
4557
+ * import { testKvStore } from "@fedify/testing";
4558
+ * import { MyKvStore } from "./my-kv.ts";
4559
+ *
4560
+ * test("MyKvStore", () =>
4561
+ * testKvStore(
4562
+ * () => new MyKvStore(),
4563
+ * async ({ store }) => await store.close(),
4564
+ * )
4565
+ * );
4566
+ * ```
4567
+ *
4568
+ * @param getKvStore A factory that creates the store to test.
4569
+ * @param onFinally A cleanup function called after the suite completes.
4570
+ * @param options Optional configuration for the suite.
4571
+ */
4572
+ async function testKvStore(getKvStore, onFinally, options = {}) {
4573
+ const store = await getKvStore();
4574
+ const prefix = [`fedify_test_${crypto.randomUUID()}`];
4575
+ const key = (...segments) => [...prefix, ...segments];
4576
+ try {
4577
+ (0, node_assert_strict.strictEqual)(await store.get(key("missing")), void 0);
4578
+ for (const [index, value] of [
4579
+ "text",
4580
+ 42,
4581
+ true,
4582
+ null,
4583
+ [
4584
+ 1,
4585
+ "two",
4586
+ false
4587
+ ],
4588
+ { nested: { value: "test" } }
4589
+ ].entries()) {
4590
+ const valueKey = key("values", index.toString());
4591
+ await store.set(valueKey, value);
4592
+ (0, node_assert_strict.deepStrictEqual)(await store.get(valueKey), value);
4593
+ }
4594
+ const overwriteKey = key("overwrite");
4595
+ await store.set(overwriteKey, "before");
4596
+ await store.set(overwriteKey, "after");
4597
+ (0, node_assert_strict.strictEqual)(await store.get(overwriteKey), "after");
4598
+ const deleteKey = key("delete");
4599
+ await store.set(deleteKey, "value");
4600
+ await store.delete(deleteKey);
4601
+ (0, node_assert_strict.strictEqual)(await store.get(deleteKey), void 0);
4602
+ await store.delete(deleteKey);
4603
+ const isolatedKeys = [
4604
+ key("a", "b"),
4605
+ key("a,b"),
4606
+ key("a:b")
4607
+ ];
4608
+ for (const [index, isolatedKey] of isolatedKeys.entries()) await store.set(isolatedKey, index);
4609
+ for (const [index, isolatedKey] of isolatedKeys.entries()) (0, node_assert_strict.strictEqual)(await store.get(isolatedKey), index);
4610
+ if (options.testTtl ?? true) {
4611
+ const expiringKey = key("ttl", "expiring");
4612
+ await store.set(expiringKey, "expired", { ttl: Temporal$1.Duration.from({ milliseconds: 50 }) });
4613
+ await (0, es_toolkit.delay)(100);
4614
+ (0, node_assert_strict.strictEqual)(await store.get(expiringKey), void 0);
4615
+ (0, node_assert_strict.deepStrictEqual)(await collect(store.list(key("ttl"))), []);
4616
+ const refreshedKey = key("ttl", "refreshed");
4617
+ await store.set(refreshedKey, "temporary", { ttl: Temporal$1.Duration.from({ milliseconds: 50 }) });
4618
+ await store.set(refreshedKey, "persistent");
4619
+ await (0, es_toolkit.delay)(100);
4620
+ (0, node_assert_strict.strictEqual)(await store.get(refreshedKey), "persistent");
4621
+ }
4622
+ const listPrefix = key("list");
4623
+ const listEntries = [
4624
+ {
4625
+ key: listPrefix,
4626
+ value: "exact"
4627
+ },
4628
+ {
4629
+ key: key("list", "child"),
4630
+ value: "child"
4631
+ },
4632
+ {
4633
+ key: key("list", "child", "nested"),
4634
+ value: "nested"
4635
+ },
4636
+ {
4637
+ key: key("list-other"),
4638
+ value: "other"
4639
+ }
4640
+ ];
4641
+ for (const entry of listEntries) await store.set(entry.key, entry.value);
4642
+ (0, node_assert_strict.deepStrictEqual)(normalize(await collect(store.list(listPrefix))), normalize(listEntries.slice(0, 3)));
4643
+ const prefixedEntries = await collect(store.list(prefix));
4644
+ (0, node_assert_strict.deepStrictEqual)(normalize(filterByPrefix(await collect(store.list()), prefix)), normalize(prefixedEntries));
4645
+ (0, node_assert_strict.deepStrictEqual)(normalize(filterByPrefix(await collect(store.list([])), prefix)), normalize(prefixedEntries));
4646
+ if (options.testCas ?? store.cas != null) {
4647
+ if (store.cas == null) throw new TypeError("KvStore.cas is not implemented");
4648
+ const cas = store.cas.bind(store);
4649
+ const casKey = key("cas", "value");
4650
+ (0, node_assert_strict.strictEqual)(await cas(casKey, "wrong", "value"), false);
4651
+ (0, node_assert_strict.strictEqual)(await cas(casKey, void 0, "created"), true);
4652
+ (0, node_assert_strict.strictEqual)(await cas(casKey, "wrong", "updated"), false);
4653
+ (0, node_assert_strict.strictEqual)(await cas(casKey, "created", "updated"), true);
4654
+ (0, node_assert_strict.strictEqual)(await store.get(casKey), "updated");
4655
+ (0, node_assert_strict.strictEqual)(await cas(casKey, "updated", void 0), true);
4656
+ (0, node_assert_strict.strictEqual)(await store.get(casKey), void 0);
4657
+ if (options.testTtl ?? true) {
4658
+ const expiredCasKey = key("cas", "expired");
4659
+ await store.set(expiredCasKey, "old", { ttl: Temporal$1.Duration.from({ milliseconds: 50 }) });
4660
+ await (0, es_toolkit.delay)(100);
4661
+ (0, node_assert_strict.strictEqual)(await cas(expiredCasKey, void 0, "replaced"), true);
4662
+ const ttlCasKey = key("cas", "ttl");
4663
+ (0, node_assert_strict.strictEqual)(await cas(ttlCasKey, void 0, "temporary", { ttl: Temporal$1.Duration.from({ milliseconds: 50 }) }), true);
4664
+ await (0, es_toolkit.delay)(100);
4665
+ (0, node_assert_strict.strictEqual)(await store.get(ttlCasKey), void 0);
4666
+ }
4667
+ const concurrentKey = key("cas", "concurrent");
4668
+ (0, node_assert_strict.strictEqual)((await Promise.all(Array.from({ length: 8 }, (_, index) => cas(concurrentKey, void 0, index)))).filter(Boolean).length, 1);
4669
+ }
4670
+ } finally {
4671
+ for await (const entry of store.list(prefix)) await store.delete(entry.key);
4672
+ await onFinally({ store });
4673
+ }
4674
+ }
4675
+ async function collect(entries) {
4676
+ const results = [];
4677
+ for await (const entry of entries) results.push(entry);
4678
+ return results;
4679
+ }
4680
+ function normalize(entries) {
4681
+ return entries.map((entry) => JSON.stringify(entry)).sort();
4682
+ }
4683
+ function filterByPrefix(entries, prefix) {
4684
+ return entries.filter((entry) => prefix.every((segment, index) => entry.key[index] === segment));
4685
+ }
4686
+ //#endregion
4545
4687
  //#region src/mq-tester.ts
4546
- const Temporal = Temporal$1;
4688
+ const Temporal = Temporal$2;
4547
4689
  /**
4548
4690
  * Tests a {@link MessageQueue} implementation with a standard set of tests.
4549
4691
  *
@@ -4729,5 +4871,6 @@ exports.createInboxContext = createInboxContext;
4729
4871
  exports.createOutboxContext = createOutboxContext;
4730
4872
  exports.createRequestContext = createRequestContext;
4731
4873
  exports.getRandomKey = getRandomKey;
4874
+ exports.testKvStore = testKvStore;
4732
4875
  exports.testMessageQueue = testMessageQueue;
4733
4876
  exports.waitFor = waitFor;
package/dist/mod.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference lib="esnext.temporal" />
2
2
  import { Context, Federation, InboxContext, OutboxContext, RequestContext } from "@fedify/fedify/federation";
3
3
  import { Activity } from "@fedify/vocab";
4
- import { MessageQueue } from "@fedify/fedify";
4
+ import { KvStore, MessageQueue } from "@fedify/fedify";
5
5
 
6
6
  //#region src/context.d.ts
7
7
  declare function createContext<TContextData>(values: Partial<Context<TContextData>> & {
@@ -153,6 +153,53 @@ declare function createFederation<TContextData>(options?: {
153
153
  tracerProvider?: any;
154
154
  }): TestFederation<TContextData>;
155
155
  //#endregion
156
+ //#region src/kv-tester.d.ts
157
+ /**
158
+ * Options for {@link testKvStore}.
159
+ */
160
+ interface TestKvStoreOptions {
161
+ /**
162
+ * Whether to test compare-and-swap support. By default, these tests run
163
+ * when the store implements {@link KvStore.cas}.
164
+ */
165
+ readonly testCas?: boolean;
166
+ /**
167
+ * Whether to test time-to-live support. `true` by default.
168
+ * @default true
169
+ */
170
+ readonly testTtl?: boolean;
171
+ }
172
+ /**
173
+ * Tests a {@link KvStore} implementation with a standard set of tests.
174
+ *
175
+ * The suite covers reads and writes, deletion, structured keys and values,
176
+ * prefix listing, TTL expiration, and optional compare-and-swap behavior.
177
+ * Every key is isolated below a random prefix and is deleted after the suite.
178
+ *
179
+ * @example
180
+ * ```typescript ignore
181
+ * import { test } from "@fedify/fixture";
182
+ * import { testKvStore } from "@fedify/testing";
183
+ * import { MyKvStore } from "./my-kv.ts";
184
+ *
185
+ * test("MyKvStore", () =>
186
+ * testKvStore(
187
+ * () => new MyKvStore(),
188
+ * async ({ store }) => await store.close(),
189
+ * )
190
+ * );
191
+ * ```
192
+ *
193
+ * @param getKvStore A factory that creates the store to test.
194
+ * @param onFinally A cleanup function called after the suite completes.
195
+ * @param options Optional configuration for the suite.
196
+ */
197
+ declare function testKvStore<KV extends KvStore>(getKvStore: () => KV | Promise<KV>, onFinally: ({
198
+ store
199
+ }: {
200
+ store: KV;
201
+ }) => Promise<void> | void, options?: TestKvStoreOptions): Promise<void>;
202
+ //#endregion
156
203
  //#region src/mq-tester.d.ts
157
204
  /**
158
205
  * Options for {@link testMessageQueue}.
@@ -223,4 +270,4 @@ declare function testMessageQueue<MQ extends MessageQueue>(getMessageQueue: () =
223
270
  declare function waitFor(predicate: () => boolean, timeoutMs: number): Promise<void>;
224
271
  declare const getRandomKey: (prefix: string) => string;
225
272
  //#endregion
226
- export { type TestMessageQueueOptions, createContext, createFederation, createInboxContext, createOutboxContext, createRequestContext, getRandomKey, testMessageQueue, waitFor };
273
+ export { type TestKvStoreOptions, type TestMessageQueueOptions, createContext, createFederation, createInboxContext, createOutboxContext, createRequestContext, getRandomKey, testKvStore, testMessageQueue, waitFor };
package/dist/mod.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference lib="esnext.temporal" />
2
2
  import { Activity } from "@fedify/vocab";
3
3
  import { Context, Federation, InboxContext, OutboxContext, RequestContext } from "@fedify/fedify/federation";
4
- import { MessageQueue } from "@fedify/fedify";
4
+ import { KvStore, MessageQueue } from "@fedify/fedify";
5
5
 
6
6
  //#region src/context.d.ts
7
7
  declare function createContext<TContextData>(values: Partial<Context<TContextData>> & {
@@ -153,6 +153,53 @@ declare function createFederation<TContextData>(options?: {
153
153
  tracerProvider?: any;
154
154
  }): TestFederation<TContextData>;
155
155
  //#endregion
156
+ //#region src/kv-tester.d.ts
157
+ /**
158
+ * Options for {@link testKvStore}.
159
+ */
160
+ interface TestKvStoreOptions {
161
+ /**
162
+ * Whether to test compare-and-swap support. By default, these tests run
163
+ * when the store implements {@link KvStore.cas}.
164
+ */
165
+ readonly testCas?: boolean;
166
+ /**
167
+ * Whether to test time-to-live support. `true` by default.
168
+ * @default true
169
+ */
170
+ readonly testTtl?: boolean;
171
+ }
172
+ /**
173
+ * Tests a {@link KvStore} implementation with a standard set of tests.
174
+ *
175
+ * The suite covers reads and writes, deletion, structured keys and values,
176
+ * prefix listing, TTL expiration, and optional compare-and-swap behavior.
177
+ * Every key is isolated below a random prefix and is deleted after the suite.
178
+ *
179
+ * @example
180
+ * ```typescript ignore
181
+ * import { test } from "@fedify/fixture";
182
+ * import { testKvStore } from "@fedify/testing";
183
+ * import { MyKvStore } from "./my-kv.ts";
184
+ *
185
+ * test("MyKvStore", () =>
186
+ * testKvStore(
187
+ * () => new MyKvStore(),
188
+ * async ({ store }) => await store.close(),
189
+ * )
190
+ * );
191
+ * ```
192
+ *
193
+ * @param getKvStore A factory that creates the store to test.
194
+ * @param onFinally A cleanup function called after the suite completes.
195
+ * @param options Optional configuration for the suite.
196
+ */
197
+ declare function testKvStore<KV extends KvStore>(getKvStore: () => KV | Promise<KV>, onFinally: ({
198
+ store
199
+ }: {
200
+ store: KV;
201
+ }) => Promise<void> | void, options?: TestKvStoreOptions): Promise<void>;
202
+ //#endregion
156
203
  //#region src/mq-tester.d.ts
157
204
  /**
158
205
  * Options for {@link testMessageQueue}.
@@ -223,4 +270,4 @@ declare function testMessageQueue<MQ extends MessageQueue>(getMessageQueue: () =
223
270
  declare function waitFor(predicate: () => boolean, timeoutMs: number): Promise<void>;
224
271
  declare const getRandomKey: (prefix: string) => string;
225
272
  //#endregion
226
- export { type TestMessageQueueOptions, createContext, createFederation, createInboxContext, createOutboxContext, createRequestContext, getRandomKey, testMessageQueue, waitFor };
273
+ export { type TestKvStoreOptions, type TestMessageQueueOptions, createContext, createFederation, createInboxContext, createOutboxContext, createRequestContext, getRandomKey, testKvStore, testMessageQueue, waitFor };
package/dist/mod.js CHANGED
@@ -977,6 +977,147 @@ var MockContext = class MockContext {
977
977
  }
978
978
  };
979
979
  //#endregion
980
+ //#region src/kv-tester.ts
981
+ /**
982
+ * Tests a {@link KvStore} implementation with a standard set of tests.
983
+ *
984
+ * The suite covers reads and writes, deletion, structured keys and values,
985
+ * prefix listing, TTL expiration, and optional compare-and-swap behavior.
986
+ * Every key is isolated below a random prefix and is deleted after the suite.
987
+ *
988
+ * @example
989
+ * ```typescript ignore
990
+ * import { test } from "@fedify/fixture";
991
+ * import { testKvStore } from "@fedify/testing";
992
+ * import { MyKvStore } from "./my-kv.ts";
993
+ *
994
+ * test("MyKvStore", () =>
995
+ * testKvStore(
996
+ * () => new MyKvStore(),
997
+ * async ({ store }) => await store.close(),
998
+ * )
999
+ * );
1000
+ * ```
1001
+ *
1002
+ * @param getKvStore A factory that creates the store to test.
1003
+ * @param onFinally A cleanup function called after the suite completes.
1004
+ * @param options Optional configuration for the suite.
1005
+ */
1006
+ async function testKvStore(getKvStore, onFinally, options = {}) {
1007
+ const store = await getKvStore();
1008
+ const prefix = [`fedify_test_${crypto.randomUUID()}`];
1009
+ const key = (...segments) => [...prefix, ...segments];
1010
+ try {
1011
+ strictEqual(await store.get(key("missing")), void 0);
1012
+ for (const [index, value] of [
1013
+ "text",
1014
+ 42,
1015
+ true,
1016
+ null,
1017
+ [
1018
+ 1,
1019
+ "two",
1020
+ false
1021
+ ],
1022
+ { nested: { value: "test" } }
1023
+ ].entries()) {
1024
+ const valueKey = key("values", index.toString());
1025
+ await store.set(valueKey, value);
1026
+ deepStrictEqual(await store.get(valueKey), value);
1027
+ }
1028
+ const overwriteKey = key("overwrite");
1029
+ await store.set(overwriteKey, "before");
1030
+ await store.set(overwriteKey, "after");
1031
+ strictEqual(await store.get(overwriteKey), "after");
1032
+ const deleteKey = key("delete");
1033
+ await store.set(deleteKey, "value");
1034
+ await store.delete(deleteKey);
1035
+ strictEqual(await store.get(deleteKey), void 0);
1036
+ await store.delete(deleteKey);
1037
+ const isolatedKeys = [
1038
+ key("a", "b"),
1039
+ key("a,b"),
1040
+ key("a:b")
1041
+ ];
1042
+ for (const [index, isolatedKey] of isolatedKeys.entries()) await store.set(isolatedKey, index);
1043
+ for (const [index, isolatedKey] of isolatedKeys.entries()) strictEqual(await store.get(isolatedKey), index);
1044
+ if (options.testTtl ?? true) {
1045
+ const expiringKey = key("ttl", "expiring");
1046
+ await store.set(expiringKey, "expired", { ttl: Temporal.Duration.from({ milliseconds: 50 }) });
1047
+ await delay(100);
1048
+ strictEqual(await store.get(expiringKey), void 0);
1049
+ deepStrictEqual(await collect(store.list(key("ttl"))), []);
1050
+ const refreshedKey = key("ttl", "refreshed");
1051
+ await store.set(refreshedKey, "temporary", { ttl: Temporal.Duration.from({ milliseconds: 50 }) });
1052
+ await store.set(refreshedKey, "persistent");
1053
+ await delay(100);
1054
+ strictEqual(await store.get(refreshedKey), "persistent");
1055
+ }
1056
+ const listPrefix = key("list");
1057
+ const listEntries = [
1058
+ {
1059
+ key: listPrefix,
1060
+ value: "exact"
1061
+ },
1062
+ {
1063
+ key: key("list", "child"),
1064
+ value: "child"
1065
+ },
1066
+ {
1067
+ key: key("list", "child", "nested"),
1068
+ value: "nested"
1069
+ },
1070
+ {
1071
+ key: key("list-other"),
1072
+ value: "other"
1073
+ }
1074
+ ];
1075
+ for (const entry of listEntries) await store.set(entry.key, entry.value);
1076
+ deepStrictEqual(normalize(await collect(store.list(listPrefix))), normalize(listEntries.slice(0, 3)));
1077
+ const prefixedEntries = await collect(store.list(prefix));
1078
+ deepStrictEqual(normalize(filterByPrefix(await collect(store.list()), prefix)), normalize(prefixedEntries));
1079
+ deepStrictEqual(normalize(filterByPrefix(await collect(store.list([])), prefix)), normalize(prefixedEntries));
1080
+ if (options.testCas ?? store.cas != null) {
1081
+ if (store.cas == null) throw new TypeError("KvStore.cas is not implemented");
1082
+ const cas = store.cas.bind(store);
1083
+ const casKey = key("cas", "value");
1084
+ strictEqual(await cas(casKey, "wrong", "value"), false);
1085
+ strictEqual(await cas(casKey, void 0, "created"), true);
1086
+ strictEqual(await cas(casKey, "wrong", "updated"), false);
1087
+ strictEqual(await cas(casKey, "created", "updated"), true);
1088
+ strictEqual(await store.get(casKey), "updated");
1089
+ strictEqual(await cas(casKey, "updated", void 0), true);
1090
+ strictEqual(await store.get(casKey), void 0);
1091
+ if (options.testTtl ?? true) {
1092
+ const expiredCasKey = key("cas", "expired");
1093
+ await store.set(expiredCasKey, "old", { ttl: Temporal.Duration.from({ milliseconds: 50 }) });
1094
+ await delay(100);
1095
+ strictEqual(await cas(expiredCasKey, void 0, "replaced"), true);
1096
+ const ttlCasKey = key("cas", "ttl");
1097
+ strictEqual(await cas(ttlCasKey, void 0, "temporary", { ttl: Temporal.Duration.from({ milliseconds: 50 }) }), true);
1098
+ await delay(100);
1099
+ strictEqual(await store.get(ttlCasKey), void 0);
1100
+ }
1101
+ const concurrentKey = key("cas", "concurrent");
1102
+ strictEqual((await Promise.all(Array.from({ length: 8 }, (_, index) => cas(concurrentKey, void 0, index)))).filter(Boolean).length, 1);
1103
+ }
1104
+ } finally {
1105
+ for await (const entry of store.list(prefix)) await store.delete(entry.key);
1106
+ await onFinally({ store });
1107
+ }
1108
+ }
1109
+ async function collect(entries) {
1110
+ const results = [];
1111
+ for await (const entry of entries) results.push(entry);
1112
+ return results;
1113
+ }
1114
+ function normalize(entries) {
1115
+ return entries.map((entry) => JSON.stringify(entry)).sort();
1116
+ }
1117
+ function filterByPrefix(entries, prefix) {
1118
+ return entries.filter((entry) => prefix.every((segment, index) => entry.key[index] === segment));
1119
+ }
1120
+ //#endregion
980
1121
  //#region src/mq-tester.ts
981
1122
  /**
982
1123
  * Tests a {@link MessageQueue} implementation with a standard set of tests.
@@ -1157,4 +1298,4 @@ async function waitFor(predicate, timeoutMs) {
1157
1298
  }
1158
1299
  const getRandomKey = (prefix) => `fedify_test_${prefix}_${crypto.randomUUID()}`;
1159
1300
  //#endregion
1160
- export { createContext, createFederation, createInboxContext, createOutboxContext, createRequestContext, getRandomKey, testMessageQueue, waitFor };
1301
+ export { createContext, createFederation, createInboxContext, createOutboxContext, createRequestContext, getRandomKey, testKvStore, testMessageQueue, waitFor };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/testing",
3
- "version": "2.4.0-dev.1909+065da803",
3
+ "version": "2.4.0-dev.1919+b6fdaec9",
4
4
  "description": "Testing utilities for Fedify applications",
5
5
  "keywords": [
6
6
  "fedify",
@@ -47,13 +47,13 @@
47
47
  "package.json"
48
48
  ],
49
49
  "peerDependencies": {
50
- "@fedify/fedify": "^2.4.0-dev.1909+065da803"
50
+ "@fedify/fedify": "^2.4.0-dev.1919+b6fdaec9"
51
51
  },
52
52
  "dependencies": {
53
53
  "es-toolkit": "1.46.1",
54
54
  "temporal-polyfill": "^1.0.1",
55
- "@fedify/vocab": "2.4.0-dev.1909+065da803",
56
- "@fedify/vocab-runtime": "^2.4.0-dev.1909+065da803"
55
+ "@fedify/vocab-runtime": "^2.4.0-dev.1919+b6fdaec9",
56
+ "@fedify/vocab": "2.4.0-dev.1919+b6fdaec9"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@standard-schema/spec": "^1.1.0",