@zudojs/testing 1.1.2 → 1.2.2

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 (96) hide show
  1. package/README.md +138 -2
  2. package/dist/assertions/httpAssertions.core.d.ts +2 -2
  3. package/dist/httpTestClient/httpTestClient.cookieJar.d.ts +30 -0
  4. package/dist/httpTestClient/httpTestClient.cookieJar.js +107 -0
  5. package/dist/httpTestClient/httpTestClient.factory.d.ts +25 -0
  6. package/dist/httpTestClient/httpTestClient.factory.js +84 -0
  7. package/dist/httpTestClient/httpTestClient.target.d.ts +16 -0
  8. package/dist/httpTestClient/httpTestClient.target.js +80 -0
  9. package/dist/httpTestClient/httpTestClient.type.d.ts +74 -0
  10. package/dist/httpTestClient/httpTestClient.type.js +5 -0
  11. package/dist/httpTestClient/httpTestRequest/httpTestRequest.core.d.ts +10 -0
  12. package/dist/httpTestClient/httpTestRequest/httpTestRequest.core.js +97 -0
  13. package/dist/httpTestClient/httpTestRequest/httpTestRequest.encode.d.ts +26 -0
  14. package/dist/httpTestClient/httpTestRequest/httpTestRequest.encode.js +73 -0
  15. package/dist/httpTestClient/httpTestRequest/httpTestRequest.execute.d.ts +26 -0
  16. package/dist/httpTestClient/httpTestRequest/httpTestRequest.execute.js +58 -0
  17. package/dist/httpTestClient/httpTestRequest/httpTestRequest.type.d.ts +53 -0
  18. package/dist/httpTestClient/httpTestRequest/httpTestRequest.type.js +5 -0
  19. package/dist/httpTestClient/httpTestRequest/index.d.ts +13 -0
  20. package/dist/httpTestClient/httpTestRequest/index.js +10 -0
  21. package/dist/httpTestClient/httpTestResponse/httpTestResponse.core.d.ts +15 -0
  22. package/dist/httpTestClient/httpTestResponse/httpTestResponse.core.js +71 -0
  23. package/dist/httpTestClient/httpTestResponse/httpTestResponse.expect.d.ts +19 -0
  24. package/dist/httpTestClient/httpTestResponse/httpTestResponse.expect.js +74 -0
  25. package/dist/httpTestClient/httpTestResponse/httpTestResponse.match.d.ts +15 -0
  26. package/dist/httpTestClient/httpTestResponse/httpTestResponse.match.js +52 -0
  27. package/dist/httpTestClient/httpTestResponse/httpTestResponse.type.d.ts +44 -0
  28. package/dist/httpTestClient/httpTestResponse/httpTestResponse.type.js +5 -0
  29. package/dist/httpTestClient/httpTestResponse/index.d.ts +12 -0
  30. package/dist/httpTestClient/httpTestResponse/index.js +10 -0
  31. package/dist/httpTestClient/httpTestTransport/httpTestTransport.fetch.d.ts +15 -0
  32. package/dist/httpTestClient/httpTestTransport/httpTestTransport.fetch.js +65 -0
  33. package/dist/httpTestClient/httpTestTransport/httpTestTransport.node.d.ts +18 -0
  34. package/dist/httpTestClient/httpTestTransport/httpTestTransport.node.js +94 -0
  35. package/dist/httpTestClient/httpTestTransport/httpTestTransport.server.d.ts +23 -0
  36. package/dist/httpTestClient/httpTestTransport/httpTestTransport.server.js +76 -0
  37. package/dist/httpTestClient/httpTestTransport/httpTestTransport.type.d.ts +46 -0
  38. package/dist/httpTestClient/httpTestTransport/httpTestTransport.type.js +9 -0
  39. package/dist/httpTestClient/httpTestTransport/httpTestTransport.zudo.d.ts +25 -0
  40. package/dist/httpTestClient/httpTestTransport/httpTestTransport.zudo.js +71 -0
  41. package/dist/httpTestClient/httpTestTransport/index.d.ts +15 -0
  42. package/dist/httpTestClient/httpTestTransport/index.js +13 -0
  43. package/dist/httpTestClient/index.d.ts +18 -0
  44. package/dist/httpTestClient/index.js +13 -0
  45. package/dist/httpTesting/httpRequest/httpRequest.builder.d.ts +13 -0
  46. package/dist/httpTesting/httpRequest/httpRequest.builder.js +64 -0
  47. package/dist/httpTesting/httpRequest/httpRequest.factory.d.ts +17 -0
  48. package/dist/httpTesting/httpRequest/httpRequest.factory.js +25 -0
  49. package/dist/httpTesting/{httpRequest.core.d.ts → httpRequest/httpRequest.type.d.ts} +6 -21
  50. package/dist/httpTesting/httpRequest/httpRequest.type.js +5 -0
  51. package/dist/httpTesting/httpRequest/index.d.ts +10 -0
  52. package/dist/httpTesting/httpRequest/index.js +9 -0
  53. package/dist/httpTesting/{httpResponse.helpers.d.ts → httpResponse/httpResponse.helpers.d.ts} +1 -1
  54. package/dist/httpTesting/{httpResponse.type.d.ts → httpResponse/httpResponse.type.d.ts} +1 -1
  55. package/dist/httpTesting/httpResponse/index.d.ts +10 -0
  56. package/dist/httpTesting/httpResponse/index.js +9 -0
  57. package/dist/httpTesting/index.d.ts +6 -6
  58. package/dist/httpTesting/index.js +4 -4
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.js +1 -0
  61. package/dist/mocking/spy.core.d.ts +6 -1
  62. package/dist/mocking/spy.core.js +1 -3
  63. package/dist/mocking/stub.core.d.ts +3 -1
  64. package/dist/mocking/stub.core.js +15 -2
  65. package/dist/testApplication/index.d.ts +1 -1
  66. package/dist/testApplication/index.js +1 -1
  67. package/dist/testApplication/testApplication.core.d.ts +35 -5
  68. package/dist/testApplication/testApplication.core.js +18 -3
  69. package/dist/testEventBus/index.d.ts +2 -2
  70. package/dist/testEventBus/index.js +1 -1
  71. package/dist/testEventBus/testEventBus.core.d.ts +12 -45
  72. package/dist/testEventBus/testEventBus.core.js +55 -46
  73. package/dist/testEventBus/testEventBus.type.d.ts +40 -0
  74. package/dist/testEventBus/testEventBus.type.js +2 -0
  75. package/dist/testMessageBus/index.d.ts +1 -1
  76. package/dist/testMessageBus/index.js +1 -1
  77. package/dist/testMessageBus/testMessageBus.core.d.ts +20 -24
  78. package/dist/testMessageBus/testMessageBus.core.js +45 -47
  79. package/dist/testQueue/index.d.ts +2 -2
  80. package/dist/testQueue/index.js +1 -1
  81. package/dist/testQueue/testQueue.core.d.ts +19 -38
  82. package/dist/testQueue/testQueue.core.js +34 -30
  83. package/dist/testQueue/testQueue.type.d.ts +30 -0
  84. package/dist/testQueue/testQueue.type.js +2 -0
  85. package/dist/testQueue/testQueue.view.d.ts +37 -0
  86. package/dist/testQueue/testQueue.view.js +44 -0
  87. package/dist/testStorage/testStorageMemory.core.d.ts +6 -1
  88. package/dist/testStorage/testStorageMemory.core.js +13 -3
  89. package/package.json +17 -17
  90. package/dist/httpTesting/httpRequest.core.js +0 -114
  91. package/dist/httpTesting/httpStatusCode.type.d.ts +0 -10
  92. package/dist/httpTesting/httpStatusCode.type.js +0 -9
  93. /package/dist/httpTesting/{httpResponse.core.d.ts → httpResponse/httpResponse.core.d.ts} +0 -0
  94. /package/dist/httpTesting/{httpResponse.core.js → httpResponse/httpResponse.core.js} +0 -0
  95. /package/dist/httpTesting/{httpResponse.helpers.js → httpResponse/httpResponse.helpers.js} +0 -0
  96. /package/dist/httpTesting/{httpResponse.type.js → httpResponse/httpResponse.type.js} +0 -0
@@ -0,0 +1,40 @@
1
+ import type { Event, EventBus, EventInput, EventPublishResult, PublishOptions } from "@zudojs/events";
2
+ /**
3
+ * A recorded event publication.
4
+ */
5
+ export interface RecordedEvent<TPayload = unknown> {
6
+ readonly event: Event<TPayload>;
7
+ readonly result: EventPublishResult<Event<TPayload>>;
8
+ readonly timestamp: Date;
9
+ }
10
+ /**
11
+ * A test event bus: an `EventBus` (so it can be handed to any code that
12
+ * takes one) that records every publication.
13
+ *
14
+ * `publish`, `publishEvent` and `emit` all record, whether called on the
15
+ * test bus or on `bus` (the same instance).
16
+ */
17
+ export interface TestEventBus extends EventBus {
18
+ /** This bus. Kept for code written against the earlier wrapper. */
19
+ readonly bus: EventBus;
20
+ /**
21
+ * All recorded publications, oldest first.
22
+ */
23
+ readonly published: readonly RecordedEvent[];
24
+ /**
25
+ * Publishes an event and records the result. Accepts a full `Event`,
26
+ * like `EventBus.publish`, or an `EventInput` (`{ type, payload }`),
27
+ * like `publishEvent`.
28
+ */
29
+ publish<TEvent extends Event>(event: TEvent, options?: PublishOptions): Promise<EventPublishResult<TEvent>>;
30
+ publish<TPayload>(input: EventInput<TPayload>, options?: PublishOptions): Promise<EventPublishResult<Event<TPayload>>>;
31
+ /**
32
+ * Find published events by type.
33
+ */
34
+ findByType(type: string): readonly RecordedEvent[];
35
+ /**
36
+ * Clear recorded publications.
37
+ */
38
+ clear(): void;
39
+ }
40
+ //# sourceMappingURL=testEventBus.type.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=testEventBus.type.js.map
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Test message bus helpers.
3
3
  *
4
- * MessageBus with recording and assertion support.
4
+ * A real MessageBus that records every dispatch.
5
5
  */
6
6
  export { createTestMessageBus } from "./testMessageBus.core.js";
7
7
  export type { RecordedMessage, TestMessageBus } from "./testMessageBus.core.js";
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Test message bus helpers.
3
3
  *
4
- * MessageBus with recording and assertion support.
4
+ * A real MessageBus that records every dispatch.
5
5
  */
6
6
  export { createTestMessageBus } from "./testMessageBus.core.js";
7
7
  //# sourceMappingURL=index.js.map
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * Test message bus helpers.
3
3
  *
4
- * Wraps the real MessageBus with recording and assertion support.
4
+ * A real in-memory MessageBus that records every dispatch, whichever
5
+ * method it came through.
5
6
  */
6
- import type { Message, MessageInput, MessageBus, MessageBusOptions, DispatchResult, DispatchOptions } from "@zudojs/messaging";
7
+ import type { Message, MessageBus, MessageBusOptions, DispatchResult } from "@zudojs/messaging";
7
8
  /**
8
9
  * A recorded message dispatch.
9
10
  */
@@ -13,48 +14,43 @@ export interface RecordedMessage<TPayload = unknown> {
13
14
  readonly timestamp: Date;
14
15
  }
15
16
  /**
16
- * A test message bus with recording capabilities.
17
+ * A test message bus: a `MessageBus` (so it can be handed to any code
18
+ * that takes one) that records every dispatch.
19
+ *
20
+ * `send` and `dispatch` both record, whether called on the test bus or on
21
+ * `bus` (the same instance).
17
22
  */
18
- export interface TestMessageBus {
23
+ export interface TestMessageBus extends MessageBus {
24
+ /** This bus. Kept for code written against the earlier wrapper. */
19
25
  readonly bus: MessageBus;
20
26
  /**
21
- * All recorded dispatches.
27
+ * All recorded dispatches, oldest first.
22
28
  */
23
29
  readonly dispatched: readonly RecordedMessage[];
24
- /**
25
- * Send a message and record the result.
26
- */
27
- send: <TPayload>(input: MessageInput<TPayload>, options?: DispatchOptions) => Promise<DispatchResult>;
28
30
  /**
29
31
  * Find dispatched messages by type.
30
32
  */
31
- findByType: (type: string) => readonly RecordedMessage[];
33
+ findByType(type: string): readonly RecordedMessage[];
32
34
  /**
33
35
  * Clear recorded dispatches.
34
36
  */
35
- clear: () => void;
36
- /**
37
- * Dispose the message bus.
38
- */
39
- dispose: () => void;
37
+ clear(): void;
40
38
  }
41
39
  /**
42
- * Creates a test message bus with recording.
40
+ * Creates a test message bus that records every dispatch.
43
41
  *
44
42
  * @param options - MessageBus options.
45
- * @returns A TestMessageBus instance.
43
+ * @returns A TestMessageBus, which is itself a `MessageBus`.
46
44
  *
47
45
  * @example
48
46
  * ```ts
49
- * const testBus = createTestMessageBus();
50
- *
51
- * testBus.bus.on("user.created", handler);
52
- * await testBus.send({ type: "user.created", payload: { id: "123" } });
47
+ * const messages = createTestMessageBus();
48
+ * messages.on("user.created", handler);
53
49
  *
54
- * expect(testBus.dispatched).toHaveLength(1);
55
- * expect(testBus.findByType("user.created")).toHaveLength(1);
50
+ * await notifier.run(messages); // takes a MessageBus, calls send(...)
56
51
  *
57
- * testBus.dispose();
52
+ * expect(messages.findByType("user.created")).toHaveLength(1);
53
+ * messages.dispose();
58
54
  * ```
59
55
  */
60
56
  export declare function createTestMessageBus(options?: MessageBusOptions): TestMessageBus;
@@ -1,64 +1,62 @@
1
1
  /**
2
2
  * Test message bus helpers.
3
3
  *
4
- * Wraps the real MessageBus with recording and assertion support.
4
+ * A real in-memory MessageBus that records every dispatch, whichever
5
+ * method it came through.
5
6
  */
6
- import { createMessageBus } from "@zudojs/messaging";
7
- import { randomUUID } from "node:crypto";
7
+ import { InMemoryMessageBus } from "@zudojs/messaging";
8
8
  /**
9
- * Creates a test message bus with recording.
9
+ * InMemoryMessageBus subclass that records at `dispatch`, the entry point
10
+ * `send` funnels into.
11
+ */
12
+ class RecordingMessageBus extends InMemoryMessageBus {
13
+ recorded = [];
14
+ constructor(options) {
15
+ super(options);
16
+ // Bound, so destructured methods keep working as they did with the
17
+ // earlier closure-based wrapper.
18
+ this.send = this.send.bind(this);
19
+ this.dispatch = this.dispatch.bind(this);
20
+ this.findByType = this.findByType.bind(this);
21
+ this.clear = this.clear.bind(this);
22
+ this.dispose = this.dispose.bind(this);
23
+ }
24
+ get bus() {
25
+ return this;
26
+ }
27
+ get dispatched() {
28
+ return [...this.recorded];
29
+ }
30
+ async dispatch(message, options) {
31
+ const result = await super.dispatch(message, options);
32
+ this.recorded.push(Object.freeze({ message, result, timestamp: new Date() }));
33
+ return result;
34
+ }
35
+ findByType(type) {
36
+ return this.recorded.filter((entry) => entry.message.type === type);
37
+ }
38
+ clear() {
39
+ this.recorded.length = 0;
40
+ }
41
+ }
42
+ /**
43
+ * Creates a test message bus that records every dispatch.
10
44
  *
11
45
  * @param options - MessageBus options.
12
- * @returns A TestMessageBus instance.
46
+ * @returns A TestMessageBus, which is itself a `MessageBus`.
13
47
  *
14
48
  * @example
15
49
  * ```ts
16
- * const testBus = createTestMessageBus();
17
- *
18
- * testBus.bus.on("user.created", handler);
19
- * await testBus.send({ type: "user.created", payload: { id: "123" } });
50
+ * const messages = createTestMessageBus();
51
+ * messages.on("user.created", handler);
20
52
  *
21
- * expect(testBus.dispatched).toHaveLength(1);
22
- * expect(testBus.findByType("user.created")).toHaveLength(1);
53
+ * await notifier.run(messages); // takes a MessageBus, calls send(...)
23
54
  *
24
- * testBus.dispose();
55
+ * expect(messages.findByType("user.created")).toHaveLength(1);
56
+ * messages.dispose();
25
57
  * ```
26
58
  */
27
59
  export function createTestMessageBus(options = {}) {
28
- const bus = createMessageBus(options);
29
- const dispatched = [];
30
- const send = async (input, dispatchOptions) => {
31
- const message = {
32
- id: `msg_${randomUUID()}`,
33
- type: input.type,
34
- payload: input.payload,
35
- timestamp: new Date(),
36
- ...(input.metadata ? { metadata: input.metadata } : {}),
37
- };
38
- const result = await bus.send(message, dispatchOptions);
39
- dispatched.push({
40
- message,
41
- result,
42
- timestamp: new Date(),
43
- });
44
- return result;
45
- };
46
- const findByType = (type) => dispatched.filter((d) => d.message.type === type);
47
- const clear = () => {
48
- dispatched.length = 0;
49
- };
50
- const dispose = () => {
51
- bus.dispose();
52
- };
53
- return {
54
- bus,
55
- get dispatched() {
56
- return [...dispatched];
57
- },
58
- send,
59
- findByType,
60
- clear,
61
- dispose,
62
- };
60
+ return new RecordingMessageBus(options);
63
61
  }
64
62
  //# sourceMappingURL=testMessageBus.core.js.map
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Test queue helpers.
3
3
  *
4
- * InMemoryQueue with recording and assertion support.
4
+ * A `Queue` backed by a real InMemoryQueue that records every job added.
5
5
  */
6
6
  export { createTestQueue } from "./testQueue.core.js";
7
- export type { RecordedJob, TestQueue } from "./testQueue.core.js";
7
+ export type { RecordedJob, TestQueue } from "./testQueue.type.js";
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Test queue helpers.
3
3
  *
4
- * InMemoryQueue with recording and assertion support.
4
+ * A `Queue` backed by a real InMemoryQueue that records every job added.
5
5
  */
6
6
  export { createTestQueue } from "./testQueue.core.js";
7
7
  //# sourceMappingURL=index.js.map
@@ -1,46 +1,27 @@
1
1
  /**
2
2
  * Test queue helpers.
3
3
  *
4
- * Wraps the real InMemoryQueue with recording and assertion support.
4
+ * A real InMemoryQueue that records every job added to it.
5
5
  */
6
- import { InMemoryQueue } from "@zudojs/queue";
7
- import type { Job, QueueName, QueueOptions, QueueStats, JobOptions } from "@zudojs/queue";
6
+ import type { QueueName, QueueOptions } from "@zudojs/queue";
7
+ import type { TestQueue } from "./testQueue.type.js";
8
+ export type { RecordedJob, TestQueue } from "./testQueue.type.js";
8
9
  /**
9
- * A recorded job addition.
10
- */
11
- export interface RecordedJob<TData = unknown> {
12
- readonly job: Job<TData>;
13
- readonly timestamp: Date;
14
- }
15
- /**
16
- * A test queue with recording capabilities.
10
+ * Creates a test queue that records every job added to it.
11
+ *
12
+ * @param name - Queue name.
13
+ * @param options - Queue options.
14
+ * @returns A TestQueue, which is itself a `Queue`.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const reminders = createTestQueue<{ taskId: number }>(createQueueName("reminders"));
19
+ *
20
+ * await scheduler.remind(reminders, 7); // takes a Queue, calls add(...)
21
+ *
22
+ * expect(reminders.findByName("remind")).toHaveLength(1);
23
+ * await reminders.close();
24
+ * ```
17
25
  */
18
- export interface TestQueue<TData = unknown> {
19
- readonly queue: InMemoryQueue<TData>;
20
- /**
21
- * All recorded jobs.
22
- */
23
- readonly jobs: readonly RecordedJob<TData>[];
24
- /**
25
- * Add a job and record it.
26
- */
27
- add: (name: string, data: TData, options?: JobOptions) => Promise<Job<TData>>;
28
- /**
29
- * Find jobs by name.
30
- */
31
- findByName: (name: string) => readonly RecordedJob<TData>[];
32
- /**
33
- * Get all job states.
34
- */
35
- getStats: () => Promise<QueueStats>;
36
- /**
37
- * Clear recorded jobs.
38
- */
39
- clear: () => void;
40
- /**
41
- * Close the queue.
42
- */
43
- close: () => Promise<void>;
44
- }
45
26
  export declare function createTestQueue<TData = unknown>(name: QueueName, options?: QueueOptions): TestQueue<TData>;
46
27
  //# sourceMappingURL=testQueue.core.d.ts.map
@@ -1,38 +1,42 @@
1
1
  /**
2
2
  * Test queue helpers.
3
3
  *
4
- * Wraps the real InMemoryQueue with recording and assertion support.
4
+ * A real InMemoryQueue that records every job added to it.
5
+ */
6
+ import { InMemoryQueue } from "@zudojs/queue";
7
+ import { RecordingQueueView } from "./testQueue.view.js";
8
+ /**
9
+ * Creates a test queue that records every job added to it.
10
+ *
11
+ * @param name - Queue name.
12
+ * @param options - Queue options.
13
+ * @returns A TestQueue, which is itself a `Queue`.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const reminders = createTestQueue<{ taskId: number }>(createQueueName("reminders"));
18
+ *
19
+ * await scheduler.remind(reminders, 7); // takes a Queue, calls add(...)
20
+ *
21
+ * expect(reminders.findByName("remind")).toHaveLength(1);
22
+ * await reminders.close();
23
+ * ```
5
24
  */
6
- import { createInMemoryQueue, InMemoryQueue } from "@zudojs/queue";
7
25
  export function createTestQueue(name, options) {
8
- const queue = createInMemoryQueue(name, options);
9
- const recordedJobs = [];
10
- const add = async (jobName, data, jobOptions) => {
11
- const job = await queue.add(jobName, data, jobOptions);
12
- recordedJobs.push({
13
- job,
14
- timestamp: new Date(),
15
- });
16
- return job;
17
- };
18
- const findByName = (name) => recordedJobs.filter((r) => r.job.name === name);
19
- const getStats = async () => queue.getStats();
20
- const clear = () => {
21
- recordedJobs.length = 0;
22
- };
23
- const close = async () => {
24
- await queue.close();
25
- };
26
- return {
27
- queue,
28
- get jobs() {
29
- return [...recordedJobs];
26
+ const queue = new InMemoryQueue(name, options);
27
+ const recorded = [];
28
+ // Recorded on the queue instance itself, so `testQueue.queue.add(...)`,
29
+ // and code that was handed `queue`, record too.
30
+ const add = queue.add.bind(queue);
31
+ Object.defineProperty(queue, "add", {
32
+ configurable: true,
33
+ writable: true,
34
+ value: async (jobName, data, jobOptions) => {
35
+ const job = await add(jobName, data, jobOptions);
36
+ recorded.push(Object.freeze({ job, timestamp: new Date() }));
37
+ return job;
30
38
  },
31
- add,
32
- findByName,
33
- getStats,
34
- clear,
35
- close,
36
- };
39
+ });
40
+ return new RecordingQueueView(queue, recorded);
37
41
  }
38
42
  //# sourceMappingURL=testQueue.core.js.map
@@ -0,0 +1,30 @@
1
+ import type { InMemoryQueue, Job, Queue } from "@zudojs/queue";
2
+ /**
3
+ * A recorded job addition.
4
+ */
5
+ export interface RecordedJob<TData = unknown> {
6
+ readonly job: Job<TData>;
7
+ readonly timestamp: Date;
8
+ }
9
+ /**
10
+ * A test queue: a `Queue` (so it can be handed to any code that takes
11
+ * one) backed by a real `InMemoryQueue`, recording every job added to it,
12
+ * whether `add` is called on the test queue or on the underlying `queue`.
13
+ */
14
+ export interface TestQueue<TData = unknown> extends Queue<TData> {
15
+ /** The underlying `InMemoryQueue`; `add` on it records too. */
16
+ readonly queue: InMemoryQueue<TData>;
17
+ /**
18
+ * All recorded jobs, oldest first.
19
+ */
20
+ readonly jobs: readonly RecordedJob<TData>[];
21
+ /**
22
+ * Find jobs by name.
23
+ */
24
+ findByName(name: string): readonly RecordedJob<TData>[];
25
+ /**
26
+ * Clear recorded jobs.
27
+ */
28
+ clear(): void;
29
+ }
30
+ //# sourceMappingURL=testQueue.type.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=testQueue.type.js.map
@@ -0,0 +1,37 @@
1
+ import type { DeadLetterJob, InMemoryQueue, Job, JobId, JobOptions, Processor, Queue, QueueEventEmitter, QueueName, QueueStats } from "@zudojs/queue";
2
+ import type { RecordedJob, TestQueue } from "./testQueue.type.js";
3
+ type RunJobOptions<TData> = Parameters<Queue<TData>["runJob"]>[1];
4
+ /**
5
+ * The `TestQueue` handed to tests: every `Queue` member delegates to the
6
+ * underlying `InMemoryQueue` (whose `add` records), plus the recording
7
+ * accessors. Members are arrow functions, so they survive destructuring.
8
+ */
9
+ export declare class RecordingQueueView<TData> implements TestQueue<TData> {
10
+ readonly queue: InMemoryQueue<TData>;
11
+ private readonly recorded;
12
+ constructor(queue: InMemoryQueue<TData>, recorded: RecordedJob<TData>[]);
13
+ get name(): QueueName;
14
+ get events(): QueueEventEmitter;
15
+ get jobs(): readonly RecordedJob<TData>[];
16
+ readonly findByName: (name: string) => readonly RecordedJob<TData>[];
17
+ readonly clear: () => void;
18
+ readonly add: (name: string, data: TData, options?: JobOptions) => Promise<Job<TData>>;
19
+ readonly process: (name: string, processor: Processor<TData>) => void;
20
+ readonly getJob: (jobId: JobId) => Promise<Job<TData> | null>;
21
+ readonly getNextJob: () => Promise<Job<TData> | null>;
22
+ readonly claimNextJob: () => Promise<Job<TData> | null>;
23
+ readonly releaseJob: (jobId: JobId) => Promise<boolean>;
24
+ readonly runJob: (job: Job<TData>, options?: RunJobOptions<TData>) => Promise<void>;
25
+ readonly getProcessor: (name: string) => Processor<TData> | undefined;
26
+ readonly getStats: () => Promise<QueueStats>;
27
+ readonly pause: () => Promise<void>;
28
+ readonly resume: () => Promise<void>;
29
+ readonly isPaused: () => boolean;
30
+ readonly isDisposed: () => boolean;
31
+ readonly getDeadLetterJobs: () => Promise<readonly DeadLetterJob<TData>[]>;
32
+ readonly close: () => Promise<void>;
33
+ readonly onJobReady: (listener: () => void) => (() => void);
34
+ readonly setAutoProcess: (enabled: boolean) => void;
35
+ }
36
+ export {};
37
+ //# sourceMappingURL=testQueue.view.d.ts.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The `TestQueue` handed to tests: every `Queue` member delegates to the
3
+ * underlying `InMemoryQueue` (whose `add` records), plus the recording
4
+ * accessors. Members are arrow functions, so they survive destructuring.
5
+ */
6
+ export class RecordingQueueView {
7
+ queue;
8
+ recorded;
9
+ constructor(queue, recorded) {
10
+ this.queue = queue;
11
+ this.recorded = recorded;
12
+ }
13
+ get name() {
14
+ return this.queue.name;
15
+ }
16
+ get events() {
17
+ return this.queue.events;
18
+ }
19
+ get jobs() {
20
+ return [...this.recorded];
21
+ }
22
+ findByName = (name) => this.recorded.filter((entry) => entry.job.name === name);
23
+ clear = () => {
24
+ this.recorded.length = 0;
25
+ };
26
+ add = (name, data, options) => this.queue.add(name, data, options);
27
+ process = (name, processor) => this.queue.process(name, processor);
28
+ getJob = (jobId) => this.queue.getJob(jobId);
29
+ getNextJob = () => this.queue.getNextJob();
30
+ claimNextJob = () => this.queue.claimNextJob();
31
+ releaseJob = (jobId) => this.queue.releaseJob(jobId);
32
+ runJob = (job, options) => this.queue.runJob(job, options);
33
+ getProcessor = (name) => this.queue.getProcessor(name);
34
+ getStats = () => this.queue.getStats();
35
+ pause = () => this.queue.pause();
36
+ resume = () => this.queue.resume();
37
+ isPaused = () => this.queue.isPaused();
38
+ isDisposed = () => this.queue.isDisposed();
39
+ getDeadLetterJobs = () => this.queue.getDeadLetterJobs();
40
+ close = () => this.queue.close();
41
+ onJobReady = (listener) => this.queue.onJobReady(listener);
42
+ setAutoProcess = (enabled) => this.queue.setAutoProcess(enabled);
43
+ }
44
+ //# sourceMappingURL=testQueue.view.js.map
@@ -28,9 +28,14 @@ export declare class InMemoryTestStorage {
28
28
  * Only an omitted (or `undefined`) TTL means "never expires". A TTL of `0`
29
29
  * is a real deadline of now, so the entry is already expired on the next
30
30
  * read — a cache test writing `0` to mean "already stale" gets that.
31
+ * `Infinity` never expires, a negative TTL is already expired, and `NaN`
32
+ * throws (it used to produce an invalid deadline that never expired).
31
33
  */
32
34
  set(key: string, value: unknown, ttlMs?: number): void;
33
- /** Delete a value by key. Returns true if deleted. */
35
+ /**
36
+ * Delete a value by key. Returns true if a live value was deleted; an
37
+ * expired entry counts as absent, matching `has()`.
38
+ */
34
39
  delete(key: string): boolean;
35
40
  /** Check if a key exists and is not expired, whatever its value. */
36
41
  has(key: string): boolean;
@@ -42,14 +42,24 @@ export class InMemoryTestStorage {
42
42
  * Only an omitted (or `undefined`) TTL means "never expires". A TTL of `0`
43
43
  * is a real deadline of now, so the entry is already expired on the next
44
44
  * read — a cache test writing `0` to mean "already stale" gets that.
45
+ * `Infinity` never expires, a negative TTL is already expired, and `NaN`
46
+ * throws (it used to produce an invalid deadline that never expired).
45
47
  */
46
48
  set(key, value, ttlMs) {
47
- const expiresAt = ttlMs === undefined ? null : new Date(Date.now() + ttlMs);
49
+ if (ttlMs !== undefined && Number.isNaN(ttlMs)) {
50
+ throw new RangeError(`TTL for "${key}" is NaN; pass a number of milliseconds or omit it.`);
51
+ }
52
+ const expiresAt = ttlMs === undefined || ttlMs === Infinity
53
+ ? null
54
+ : new Date(Math.max(0, Date.now() + ttlMs));
48
55
  this.store.set(key, { value, expiresAt });
49
56
  }
50
- /** Delete a value by key. Returns true if deleted. */
57
+ /**
58
+ * Delete a value by key. Returns true if a live value was deleted; an
59
+ * expired entry counts as absent, matching `has()`.
60
+ */
51
61
  delete(key) {
52
- return this.store.delete(key);
62
+ return this.live(key) !== undefined && this.store.delete(key);
53
63
  }
54
64
  /** Check if a key exists and is not expired, whatever its value. */
55
65
  has(key) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/testing",
3
- "version": "1.1.2",
3
+ "version": "1.2.2",
4
4
  "description": "Test helpers, fixtures, mocks, and utilities for testing Zudojs applications.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -19,24 +19,24 @@
19
19
  "!dist/.tsbuildinfo"
20
20
  ],
21
21
  "dependencies": {
22
- "@zudojs/config": "1.2.0",
23
- "@zudojs/constants": "1.1.1",
24
- "@zudojs/container": "1.1.2",
25
- "@zudojs/errors": "1.2.0",
26
- "@zudojs/events": "1.2.0",
27
- "@zudojs/http": "1.3.0",
28
- "@zudojs/logger": "1.3.0",
29
- "@zudojs/messaging": "1.1.0",
30
- "@zudojs/middleware": "1.0.3",
31
- "@zudojs/queue": "1.3.0",
32
- "@zudojs/security": "1.2.0",
33
- "@zudojs/serialization": "1.1.1",
34
- "@zudojs/storage": "1.1.2",
35
- "@zudojs/types": "1.1.1"
22
+ "@zudojs/config": "1.3.1",
23
+ "@zudojs/constants": "1.1.2",
24
+ "@zudojs/container": "1.2.1",
25
+ "@zudojs/errors": "1.3.0",
26
+ "@zudojs/events": "1.3.1",
27
+ "@zudojs/http": "1.4.2",
28
+ "@zudojs/logger": "1.4.1",
29
+ "@zudojs/messaging": "1.2.1",
30
+ "@zudojs/middleware": "1.1.0",
31
+ "@zudojs/queue": "1.4.1",
32
+ "@zudojs/security": "1.3.1",
33
+ "@zudojs/serialization": "1.2.1",
34
+ "@zudojs/storage": "1.2.1",
35
+ "@zudojs/types": "1.2.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "typescript": "7.0.2",
39
- "vitest": "^4.1.11"
39
+ "vitest": "^5.0.1"
40
40
  },
41
41
  "engines": {
42
42
  "node": ">=24.0.0"
@@ -56,7 +56,7 @@
56
56
  "fixtures",
57
57
  "vitest"
58
58
  ],
59
- "homepage": "https://github.com/oyinlola-tech/zudo#readme",
59
+ "homepage": "https://zudojs.oyinlola.site/docs/packages-testing",
60
60
  "bugs": {
61
61
  "url": "https://github.com/oyinlola-tech/zudo/issues"
62
62
  },