@zudojs/testing 1.1.1 → 1.1.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.
package/README.md CHANGED
@@ -76,6 +76,11 @@ assertResponseBody(response, { id: "u_1", roles: new Set(["admin"]) });
76
76
  `assertSerializesCorrectly`.
77
77
  - `createStub()` answers `then` with `undefined`, so awaiting a stub — or
78
78
  returning one from an async factory — resolves rather than hanging.
79
+ - `createStub()` hands back the same no-op for a given property every time,
80
+ so `stub.handler === stub.handler` and a register/unregister pair written
81
+ against a stub actually unregisters.
82
+ - `InMemoryTestStorage.set(key, value, 0)` means "already expired", not "no
83
+ expiry"; only an omitted TTL never expires.
79
84
  - `cleanup.dispose()` rejects with an `AggregateError` when any cleanup fails,
80
85
  after running them all.
81
86
  - `mockResolvedValue` and `mockRejectedValue` return promises; `results` stays
@@ -44,6 +44,10 @@ const NON_CALLABLE_KEYS = new Set([
44
44
  * ```
45
45
  */
46
46
  export function createStub(overrides = {}) {
47
+ // One no-op per property key, kept for the life of the stub. Handing out a
48
+ // fresh closure per access would make `stub.handler !== stub.handler`, so a
49
+ // register/unregister pair written against a stub could never match.
50
+ const noops = new Map();
47
51
  return new Proxy({}, {
48
52
  get(_target, prop, _receiver) {
49
53
  // `hasOwn`, not `in`: `in` walks the prototype chain, so `toString`,
@@ -55,7 +59,12 @@ export function createStub(overrides = {}) {
55
59
  return undefined;
56
60
  if (typeof prop === "symbol")
57
61
  return undefined;
58
- return (..._args) => undefined;
62
+ const existing = noops.get(prop);
63
+ if (existing)
64
+ return existing;
65
+ const noop = (..._args) => undefined;
66
+ noops.set(prop, noop);
67
+ return noop;
59
68
  },
60
69
  has(_target, prop) {
61
70
  return !NON_CALLABLE_KEYS.has(prop);
@@ -22,7 +22,13 @@ export declare class InMemoryTestStorage {
22
22
  * test needs to distinguish.
23
23
  */
24
24
  get<T = unknown>(key: string): T | null;
25
- /** Set a value with optional TTL in milliseconds. */
25
+ /**
26
+ * Set a value with optional TTL in milliseconds.
27
+ *
28
+ * Only an omitted (or `undefined`) TTL means "never expires". A TTL of `0`
29
+ * is a real deadline of now, so the entry is already expired on the next
30
+ * read — a cache test writing `0` to mean "already stale" gets that.
31
+ */
26
32
  set(key: string, value: unknown, ttlMs?: number): void;
27
33
  /** Delete a value by key. Returns true if deleted. */
28
34
  delete(key: string): boolean;
@@ -36,9 +36,15 @@ export class InMemoryTestStorage {
36
36
  return null;
37
37
  return (entry.value ?? null);
38
38
  }
39
- /** Set a value with optional TTL in milliseconds. */
39
+ /**
40
+ * Set a value with optional TTL in milliseconds.
41
+ *
42
+ * Only an omitted (or `undefined`) TTL means "never expires". A TTL of `0`
43
+ * is a real deadline of now, so the entry is already expired on the next
44
+ * read — a cache test writing `0` to mean "already stale" gets that.
45
+ */
40
46
  set(key, value, ttlMs) {
41
- const expiresAt = ttlMs ? new Date(Date.now() + ttlMs) : null;
47
+ const expiresAt = ttlMs === undefined ? null : new Date(Date.now() + ttlMs);
42
48
  this.store.set(key, { value, expiresAt });
43
49
  }
44
50
  /** Delete a value by key. Returns true if deleted. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/testing",
3
- "version": "1.1.1",
3
+ "version": "1.1.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,20 +19,20 @@
19
19
  "!dist/.tsbuildinfo"
20
20
  ],
21
21
  "dependencies": {
22
- "@zudojs/config": "1.1.0",
23
- "@zudojs/constants": "1.1.0",
24
- "@zudojs/container": "1.1.1",
25
- "@zudojs/errors": "1.1.0",
26
- "@zudojs/events": "1.1.0",
27
- "@zudojs/http": "1.2.0",
28
- "@zudojs/logger": "1.2.0",
29
- "@zudojs/messaging": "1.0.2",
30
- "@zudojs/middleware": "1.0.2",
31
- "@zudojs/queue": "1.2.0",
32
- "@zudojs/security": "1.1.0",
33
- "@zudojs/serialization": "1.1.0",
34
- "@zudojs/storage": "1.1.1",
35
- "@zudojs/types": "1.1.0"
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"
36
36
  },
37
37
  "devDependencies": {
38
38
  "typescript": "7.0.2",