@fedify/testing 2.0.0-dev.237 → 2.0.0-dev.279

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/dist/mod.cjs CHANGED
@@ -44,7 +44,7 @@ const noopTracerProvider$1 = { getTracer: () => ({
44
44
  }) };
45
45
  function createContext(values) {
46
46
  const { federation, url = new URL("http://example.com/"), canonicalOrigin, data, documentLoader, contextLoader, tracerProvider, clone, getNodeInfoUri, getActorUri, getObjectUri, getCollectionUri, getOutboxUri, getInboxUri, getFollowingUri, getFollowersUri, getLikedUri, getFeaturedUri, getFeaturedTagsUri, parseUri, getActorKeyPairs, getDocumentLoader, lookupObject, traverseCollection, lookupNodeInfo, lookupWebFinger, sendActivity, routeActivity } = values;
47
- function throwRouteError() {
47
+ function throwRouterError() {
48
48
  throw new __fedify_fedify_federation.RouterError("Not implemented");
49
49
  }
50
50
  return {
@@ -61,17 +61,17 @@ function createContext(values) {
61
61
  ...values,
62
62
  data: data$1
63
63
  })),
64
- getNodeInfoUri: getNodeInfoUri ?? throwRouteError,
65
- getActorUri: getActorUri ?? throwRouteError,
66
- getObjectUri: getObjectUri ?? throwRouteError,
67
- getCollectionUri: getCollectionUri ?? throwRouteError,
68
- getOutboxUri: getOutboxUri ?? throwRouteError,
69
- getInboxUri: getInboxUri ?? throwRouteError,
70
- getFollowingUri: getFollowingUri ?? throwRouteError,
71
- getFollowersUri: getFollowersUri ?? throwRouteError,
72
- getLikedUri: getLikedUri ?? throwRouteError,
73
- getFeaturedUri: getFeaturedUri ?? throwRouteError,
74
- getFeaturedTagsUri: getFeaturedTagsUri ?? throwRouteError,
64
+ getNodeInfoUri: getNodeInfoUri ?? throwRouterError,
65
+ getActorUri: getActorUri ?? throwRouterError,
66
+ getObjectUri: getObjectUri ?? throwRouterError,
67
+ getCollectionUri: getCollectionUri ?? throwRouterError,
68
+ getOutboxUri: getOutboxUri ?? throwRouterError,
69
+ getInboxUri: getInboxUri ?? throwRouterError,
70
+ getFollowingUri: getFollowingUri ?? throwRouterError,
71
+ getFollowersUri: getFollowersUri ?? throwRouterError,
72
+ getLikedUri: getLikedUri ?? throwRouterError,
73
+ getFeaturedUri: getFeaturedUri ?? throwRouterError,
74
+ getFeaturedTagsUri: getFeaturedTagsUri ?? throwRouterError,
75
75
  parseUri: parseUri ?? ((_uri) => {
76
76
  throw new Error("Not implemented");
77
77
  }),
@@ -774,6 +774,8 @@ var MockContext = class MockContext {
774
774
  * - `enqueueMany()`: Bulk message enqueueing
775
775
  * - `enqueueMany()` with delay: Delayed bulk message enqueueing
776
776
  * - Multiple listeners: Ensures messages are processed by only one listener
777
+ * - Ordering key support (optional): Ensures messages with the same ordering
778
+ * key are processed in order
777
779
  *
778
780
  * @example
779
781
  * ```typescript ignore
@@ -789,6 +791,7 @@ var MockContext = class MockContext {
789
791
  * await mq1.close();
790
792
  * await mq2.close();
791
793
  * },
794
+ * { testOrderingKey: true }, // Enable ordering key tests
792
795
  * )
793
796
  * );
794
797
  * ```
@@ -800,9 +803,10 @@ var MockContext = class MockContext {
800
803
  * @param onFinally A cleanup function called after all tests complete.
801
804
  * It receives both message queue instances and the abort
802
805
  * controller used for the listeners.
806
+ * @param options Optional configuration for the test suite.
803
807
  * @returns A promise that resolves when all tests pass.
804
808
  */
805
- async function testMessageQueue(getMessageQueue, onFinally) {
809
+ async function testMessageQueue(getMessageQueue, onFinally, options = {}) {
806
810
  const mq1 = await getMessageQueue();
807
811
  const mq2 = await getMessageQueue();
808
812
  const controller = new AbortController();
@@ -846,9 +850,81 @@ async function testMessageQueue(getMessageQueue, onFinally) {
846
850
  await waitFor(() => messages.length >= bulkCount, 3e4);
847
851
  const expectedMessages = new Set(Array.from({ length: bulkCount }, (_, i) => `message-${i}`));
848
852
  (0, node_assert_strict.deepStrictEqual)(new Set(messages), expectedMessages);
849
- controller.abort();
850
- await listening1;
851
- await listening2;
853
+ if (options.testOrderingKey) {
854
+ while (messages.length > 0) messages.pop();
855
+ const orderTracker = {
856
+ keyA: [],
857
+ keyB: [],
858
+ noKey: []
859
+ };
860
+ controller.abort();
861
+ await listening1;
862
+ await listening2;
863
+ const orderController = new AbortController();
864
+ const orderMessages = [];
865
+ const orderListening1 = mq1.listen((message) => {
866
+ orderMessages.push(message);
867
+ const trackKey = message.key ?? "noKey";
868
+ if (trackKey in orderTracker) orderTracker[trackKey].push(message.value);
869
+ }, { signal: orderController.signal });
870
+ const orderListening2 = mq2.listen((message) => {
871
+ orderMessages.push(message);
872
+ const trackKey = message.key ?? "noKey";
873
+ if (trackKey in orderTracker) orderTracker[trackKey].push(message.value);
874
+ }, { signal: orderController.signal });
875
+ await mq1.enqueue({
876
+ key: "keyA",
877
+ value: 1
878
+ }, { orderingKey: "keyA" });
879
+ await mq1.enqueue({
880
+ key: "keyB",
881
+ value: 1
882
+ }, { orderingKey: "keyB" });
883
+ await mq1.enqueue({
884
+ key: "keyA",
885
+ value: 2
886
+ }, { orderingKey: "keyA" });
887
+ await mq1.enqueue({
888
+ key: "keyB",
889
+ value: 2
890
+ }, { orderingKey: "keyB" });
891
+ await mq1.enqueue({
892
+ key: "keyA",
893
+ value: 3
894
+ }, { orderingKey: "keyA" });
895
+ await mq1.enqueue({
896
+ key: "keyB",
897
+ value: 3
898
+ }, { orderingKey: "keyB" });
899
+ await mq1.enqueue({
900
+ key: null,
901
+ value: 1
902
+ });
903
+ await mq1.enqueue({
904
+ key: null,
905
+ value: 2
906
+ });
907
+ await waitFor(() => orderMessages.length >= 8, 3e4);
908
+ (0, node_assert_strict.deepStrictEqual)(orderTracker.keyA, [
909
+ 1,
910
+ 2,
911
+ 3
912
+ ], "Messages with orderingKey 'keyA' should be processed in order");
913
+ (0, node_assert_strict.deepStrictEqual)(orderTracker.keyB, [
914
+ 1,
915
+ 2,
916
+ 3
917
+ ], "Messages with orderingKey 'keyB' should be processed in order");
918
+ (0, node_assert_strict.strictEqual)(orderTracker.noKey.length, 2, "Messages without ordering key should all be received");
919
+ (0, node_assert_strict.ok)(orderTracker.noKey.includes(1) && orderTracker.noKey.includes(2), "Messages without ordering key should contain values 1 and 2");
920
+ orderController.abort();
921
+ await orderListening1;
922
+ await orderListening2;
923
+ } else {
924
+ controller.abort();
925
+ await listening1;
926
+ await listening2;
927
+ }
852
928
  } finally {
853
929
  await onFinally({
854
930
  mq1,
package/dist/mod.d.cts CHANGED
@@ -125,6 +125,22 @@ declare function createFederation<TContextData>(options?: {
125
125
  }): TestFederation<TContextData>;
126
126
  //#endregion
127
127
  //#region src/mq-tester.d.ts
128
+ /**
129
+ * Options for {@link testMessageQueue}.
130
+ */
131
+ interface TestMessageQueueOptions {
132
+ /**
133
+ * Whether to test ordering key support. If `true`, tests will verify that
134
+ * messages with the same ordering key are processed in order, while messages
135
+ * with different ordering keys can be processed in parallel.
136
+ *
137
+ * Set this to `true` only if your message queue implementation supports
138
+ * the `orderingKey` option.
139
+ *
140
+ * @default false
141
+ */
142
+ readonly testOrderingKey?: boolean;
143
+ }
128
144
  /**
129
145
  * Tests a {@link MessageQueue} implementation with a standard set of tests.
130
146
  *
@@ -134,6 +150,8 @@ declare function createFederation<TContextData>(options?: {
134
150
  * - `enqueueMany()`: Bulk message enqueueing
135
151
  * - `enqueueMany()` with delay: Delayed bulk message enqueueing
136
152
  * - Multiple listeners: Ensures messages are processed by only one listener
153
+ * - Ordering key support (optional): Ensures messages with the same ordering
154
+ * key are processed in order
137
155
  *
138
156
  * @example
139
157
  * ```typescript ignore
@@ -149,6 +167,7 @@ declare function createFederation<TContextData>(options?: {
149
167
  * await mq1.close();
150
168
  * await mq2.close();
151
169
  * },
170
+ * { testOrderingKey: true }, // Enable ordering key tests
152
171
  * )
153
172
  * );
154
173
  * ```
@@ -160,6 +179,7 @@ declare function createFederation<TContextData>(options?: {
160
179
  * @param onFinally A cleanup function called after all tests complete.
161
180
  * It receives both message queue instances and the abort
162
181
  * controller used for the listeners.
182
+ * @param options Optional configuration for the test suite.
163
183
  * @returns A promise that resolves when all tests pass.
164
184
  */
165
185
  declare function testMessageQueue<MQ extends MessageQueue>(getMessageQueue: () => MQ | Promise<MQ>, onFinally: ({
@@ -170,8 +190,8 @@ declare function testMessageQueue<MQ extends MessageQueue>(getMessageQueue: () =
170
190
  mq1: MQ;
171
191
  mq2: MQ;
172
192
  controller: AbortController;
173
- }) => Promise<void> | void): Promise<void>;
193
+ }) => Promise<void> | void, options?: TestMessageQueueOptions): Promise<void>;
174
194
  declare function waitFor(predicate: () => boolean, timeoutMs: number): Promise<void>;
175
195
  declare const getRandomKey: (prefix: string) => string;
176
196
  //#endregion
177
- export { createContext, createFederation, createInboxContext, createRequestContext, getRandomKey, testMessageQueue, waitFor };
197
+ export { TestMessageQueueOptions, createContext, createFederation, createInboxContext, createRequestContext, getRandomKey, testMessageQueue, waitFor };
package/dist/mod.d.ts CHANGED
@@ -126,6 +126,22 @@ declare function createFederation<TContextData>(options?: {
126
126
  }): TestFederation<TContextData>;
127
127
  //#endregion
128
128
  //#region src/mq-tester.d.ts
129
+ /**
130
+ * Options for {@link testMessageQueue}.
131
+ */
132
+ interface TestMessageQueueOptions {
133
+ /**
134
+ * Whether to test ordering key support. If `true`, tests will verify that
135
+ * messages with the same ordering key are processed in order, while messages
136
+ * with different ordering keys can be processed in parallel.
137
+ *
138
+ * Set this to `true` only if your message queue implementation supports
139
+ * the `orderingKey` option.
140
+ *
141
+ * @default false
142
+ */
143
+ readonly testOrderingKey?: boolean;
144
+ }
129
145
  /**
130
146
  * Tests a {@link MessageQueue} implementation with a standard set of tests.
131
147
  *
@@ -135,6 +151,8 @@ declare function createFederation<TContextData>(options?: {
135
151
  * - `enqueueMany()`: Bulk message enqueueing
136
152
  * - `enqueueMany()` with delay: Delayed bulk message enqueueing
137
153
  * - Multiple listeners: Ensures messages are processed by only one listener
154
+ * - Ordering key support (optional): Ensures messages with the same ordering
155
+ * key are processed in order
138
156
  *
139
157
  * @example
140
158
  * ```typescript ignore
@@ -150,6 +168,7 @@ declare function createFederation<TContextData>(options?: {
150
168
  * await mq1.close();
151
169
  * await mq2.close();
152
170
  * },
171
+ * { testOrderingKey: true }, // Enable ordering key tests
153
172
  * )
154
173
  * );
155
174
  * ```
@@ -161,6 +180,7 @@ declare function createFederation<TContextData>(options?: {
161
180
  * @param onFinally A cleanup function called after all tests complete.
162
181
  * It receives both message queue instances and the abort
163
182
  * controller used for the listeners.
183
+ * @param options Optional configuration for the test suite.
164
184
  * @returns A promise that resolves when all tests pass.
165
185
  */
166
186
  declare function testMessageQueue<MQ extends MessageQueue>(getMessageQueue: () => MQ | Promise<MQ>, onFinally: ({
@@ -171,8 +191,8 @@ declare function testMessageQueue<MQ extends MessageQueue>(getMessageQueue: () =
171
191
  mq1: MQ;
172
192
  mq2: MQ;
173
193
  controller: AbortController;
174
- }) => Promise<void> | void): Promise<void>;
194
+ }) => Promise<void> | void, options?: TestMessageQueueOptions): Promise<void>;
175
195
  declare function waitFor(predicate: () => boolean, timeoutMs: number): Promise<void>;
176
196
  declare const getRandomKey: (prefix: string) => string;
177
197
  //#endregion
178
- export { createContext, createFederation, createInboxContext, createRequestContext, getRandomKey, testMessageQueue, waitFor };
198
+ export { TestMessageQueueOptions, createContext, createFederation, createInboxContext, createRequestContext, getRandomKey, testMessageQueue, waitFor };
package/dist/mod.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { CryptographicKey, Multikey, lookupObject, traverseCollection } from "@fedify/vocab";
5
5
  import { RouterError } from "@fedify/fedify/federation";
6
6
  import { delay } from "es-toolkit";
7
- import { deepStrictEqual, ok } from "node:assert/strict";
7
+ import { deepStrictEqual, ok, strictEqual } from "node:assert/strict";
8
8
 
9
9
  //#region src/docloader.ts
10
10
  const mockDocumentLoader = async (url) => ({
@@ -21,7 +21,7 @@ const noopTracerProvider$1 = { getTracer: () => ({
21
21
  }) };
22
22
  function createContext(values) {
23
23
  const { federation, url = new URL("http://example.com/"), canonicalOrigin, data, documentLoader, contextLoader, tracerProvider, clone, getNodeInfoUri, getActorUri, getObjectUri, getCollectionUri, getOutboxUri, getInboxUri, getFollowingUri, getFollowersUri, getLikedUri, getFeaturedUri, getFeaturedTagsUri, parseUri, getActorKeyPairs, getDocumentLoader, lookupObject: lookupObject$1, traverseCollection: traverseCollection$1, lookupNodeInfo, lookupWebFinger, sendActivity, routeActivity } = values;
24
- function throwRouteError() {
24
+ function throwRouterError() {
25
25
  throw new RouterError("Not implemented");
26
26
  }
27
27
  return {
@@ -38,17 +38,17 @@ function createContext(values) {
38
38
  ...values,
39
39
  data: data$1
40
40
  })),
41
- getNodeInfoUri: getNodeInfoUri ?? throwRouteError,
42
- getActorUri: getActorUri ?? throwRouteError,
43
- getObjectUri: getObjectUri ?? throwRouteError,
44
- getCollectionUri: getCollectionUri ?? throwRouteError,
45
- getOutboxUri: getOutboxUri ?? throwRouteError,
46
- getInboxUri: getInboxUri ?? throwRouteError,
47
- getFollowingUri: getFollowingUri ?? throwRouteError,
48
- getFollowersUri: getFollowersUri ?? throwRouteError,
49
- getLikedUri: getLikedUri ?? throwRouteError,
50
- getFeaturedUri: getFeaturedUri ?? throwRouteError,
51
- getFeaturedTagsUri: getFeaturedTagsUri ?? throwRouteError,
41
+ getNodeInfoUri: getNodeInfoUri ?? throwRouterError,
42
+ getActorUri: getActorUri ?? throwRouterError,
43
+ getObjectUri: getObjectUri ?? throwRouterError,
44
+ getCollectionUri: getCollectionUri ?? throwRouterError,
45
+ getOutboxUri: getOutboxUri ?? throwRouterError,
46
+ getInboxUri: getInboxUri ?? throwRouterError,
47
+ getFollowingUri: getFollowingUri ?? throwRouterError,
48
+ getFollowersUri: getFollowersUri ?? throwRouterError,
49
+ getLikedUri: getLikedUri ?? throwRouterError,
50
+ getFeaturedUri: getFeaturedUri ?? throwRouterError,
51
+ getFeaturedTagsUri: getFeaturedTagsUri ?? throwRouterError,
52
52
  parseUri: parseUri ?? ((_uri) => {
53
53
  throw new Error("Not implemented");
54
54
  }),
@@ -751,6 +751,8 @@ var MockContext = class MockContext {
751
751
  * - `enqueueMany()`: Bulk message enqueueing
752
752
  * - `enqueueMany()` with delay: Delayed bulk message enqueueing
753
753
  * - Multiple listeners: Ensures messages are processed by only one listener
754
+ * - Ordering key support (optional): Ensures messages with the same ordering
755
+ * key are processed in order
754
756
  *
755
757
  * @example
756
758
  * ```typescript ignore
@@ -766,6 +768,7 @@ var MockContext = class MockContext {
766
768
  * await mq1.close();
767
769
  * await mq2.close();
768
770
  * },
771
+ * { testOrderingKey: true }, // Enable ordering key tests
769
772
  * )
770
773
  * );
771
774
  * ```
@@ -777,9 +780,10 @@ var MockContext = class MockContext {
777
780
  * @param onFinally A cleanup function called after all tests complete.
778
781
  * It receives both message queue instances and the abort
779
782
  * controller used for the listeners.
783
+ * @param options Optional configuration for the test suite.
780
784
  * @returns A promise that resolves when all tests pass.
781
785
  */
782
- async function testMessageQueue(getMessageQueue, onFinally) {
786
+ async function testMessageQueue(getMessageQueue, onFinally, options = {}) {
783
787
  const mq1 = await getMessageQueue();
784
788
  const mq2 = await getMessageQueue();
785
789
  const controller = new AbortController();
@@ -823,9 +827,81 @@ async function testMessageQueue(getMessageQueue, onFinally) {
823
827
  await waitFor(() => messages.length >= bulkCount, 3e4);
824
828
  const expectedMessages = new Set(Array.from({ length: bulkCount }, (_, i) => `message-${i}`));
825
829
  deepStrictEqual(new Set(messages), expectedMessages);
826
- controller.abort();
827
- await listening1;
828
- await listening2;
830
+ if (options.testOrderingKey) {
831
+ while (messages.length > 0) messages.pop();
832
+ const orderTracker = {
833
+ keyA: [],
834
+ keyB: [],
835
+ noKey: []
836
+ };
837
+ controller.abort();
838
+ await listening1;
839
+ await listening2;
840
+ const orderController = new AbortController();
841
+ const orderMessages = [];
842
+ const orderListening1 = mq1.listen((message) => {
843
+ orderMessages.push(message);
844
+ const trackKey = message.key ?? "noKey";
845
+ if (trackKey in orderTracker) orderTracker[trackKey].push(message.value);
846
+ }, { signal: orderController.signal });
847
+ const orderListening2 = mq2.listen((message) => {
848
+ orderMessages.push(message);
849
+ const trackKey = message.key ?? "noKey";
850
+ if (trackKey in orderTracker) orderTracker[trackKey].push(message.value);
851
+ }, { signal: orderController.signal });
852
+ await mq1.enqueue({
853
+ key: "keyA",
854
+ value: 1
855
+ }, { orderingKey: "keyA" });
856
+ await mq1.enqueue({
857
+ key: "keyB",
858
+ value: 1
859
+ }, { orderingKey: "keyB" });
860
+ await mq1.enqueue({
861
+ key: "keyA",
862
+ value: 2
863
+ }, { orderingKey: "keyA" });
864
+ await mq1.enqueue({
865
+ key: "keyB",
866
+ value: 2
867
+ }, { orderingKey: "keyB" });
868
+ await mq1.enqueue({
869
+ key: "keyA",
870
+ value: 3
871
+ }, { orderingKey: "keyA" });
872
+ await mq1.enqueue({
873
+ key: "keyB",
874
+ value: 3
875
+ }, { orderingKey: "keyB" });
876
+ await mq1.enqueue({
877
+ key: null,
878
+ value: 1
879
+ });
880
+ await mq1.enqueue({
881
+ key: null,
882
+ value: 2
883
+ });
884
+ await waitFor(() => orderMessages.length >= 8, 3e4);
885
+ deepStrictEqual(orderTracker.keyA, [
886
+ 1,
887
+ 2,
888
+ 3
889
+ ], "Messages with orderingKey 'keyA' should be processed in order");
890
+ deepStrictEqual(orderTracker.keyB, [
891
+ 1,
892
+ 2,
893
+ 3
894
+ ], "Messages with orderingKey 'keyB' should be processed in order");
895
+ strictEqual(orderTracker.noKey.length, 2, "Messages without ordering key should all be received");
896
+ ok(orderTracker.noKey.includes(1) && orderTracker.noKey.includes(2), "Messages without ordering key should contain values 1 and 2");
897
+ orderController.abort();
898
+ await orderListening1;
899
+ await orderListening2;
900
+ } else {
901
+ controller.abort();
902
+ await listening1;
903
+ await listening2;
904
+ }
829
905
  } finally {
830
906
  await onFinally({
831
907
  mq1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/testing",
3
- "version": "2.0.0-dev.237+7f2bb1de",
3
+ "version": "2.0.0-dev.279+ce1bdc22",
4
4
  "description": "Testing utilities for Fedify applications",
5
5
  "keywords": [
6
6
  "fedify",
@@ -50,7 +50,7 @@
50
50
  "package.json"
51
51
  ],
52
52
  "peerDependencies": {
53
- "@fedify/fedify": "^2.0.0-dev.237+7f2bb1de"
53
+ "@fedify/fedify": "^2.0.0-dev.279+ce1bdc22"
54
54
  },
55
55
  "dependencies": {
56
56
  "es-toolkit": "1.43.0"
@@ -64,11 +64,14 @@
64
64
  "@fedify/fixture": "^2.0.0"
65
65
  },
66
66
  "scripts": {
67
- "build": "tsdown",
68
- "prepublish": "tsdown",
69
- "test": "tsdown && node --experimental-transform-types --test",
70
- "test:bun": "tsdown && bun test --timeout 15000",
67
+ "build:self": "tsdown",
68
+ "build": "pnpm --filter @fedify/testing... run build:self",
69
+ "prepublish": "pnpm build",
70
+ "pretest": "pnpm build",
71
+ "test": "node --experimental-transform-types --test",
72
+ "pretest:bun": "pnpm build",
73
+ "test:bun": "bun test --timeout 15000",
71
74
  "test:deno": "deno task test",
72
- "test-all": "tsdown && node --experimental-transform-types --test && bun test --timeout 15000 && deno task test"
75
+ "test-all": "pnpm build && node --experimental-transform-types --test && bun test --timeout 15000 && deno task test"
73
76
  }
74
77
  }