|
20 | 20 | * internal state and events during integration tests. Do not use this class
|
21 | 21 | * except for testing purposes.
|
22 | 22 | *
|
23 |
| - * There are two ways to retrieve an instance of this class: |
| 23 | + * There are two ways to retrieve the global singleton instance of this class: |
24 | 24 | * 1. The `instance` property, which returns null if the global singleton
|
25 |
| - * instance has not been created. |
| 25 | + * instance has not been created. Use this property if the caller should |
| 26 | + * "do nothing" if there are no testing hooks registered, such as when |
| 27 | + * delivering an event to notify registered callbacks. |
26 | 28 | * 2. The `getOrCreateInstance()` method, which creates the global singleton
|
27 |
| - * instance if it has not been created. |
28 |
| - * |
29 |
| - * Use the former method if the caller should "do nothing" there are no testing |
30 |
| - * hooks registered. Use the latter if the instance is needed to, for example, |
31 |
| - * register a testing hook. |
| 29 | + * instance if it has not been created. Use this method if the instance is |
| 30 | + * needed to, for example, register a callback. |
32 | 31 | *
|
33 | 32 | * @internal
|
34 | 33 | */
|
35 | 34 | export class TestingHooks {
|
36 |
| - private readonly onExistenceFilterMismatchCallbacks: Array< |
| 35 | + private readonly onExistenceFilterMismatchCallbacks: Map< |
| 36 | + Symbol, |
37 | 37 | (arg: unknown) => void
|
38 | 38 | > = [];
|
39 | 39 |
|
@@ -61,30 +61,30 @@ export class TestingHooks {
|
61 | 61 | /**
|
62 | 62 | * Registers a callback to be notified when an existence filter mismatch
|
63 | 63 | * occurs in the Watch listen stream.
|
64 |
| - * @param callback the callback to invoke upon existence filter mismatch. |
| 64 | + * |
| 65 | + * The relative order in which callbacks are notified is unspecified; do not |
| 66 | + * rely on any particular ordering. |
| 67 | + * |
| 68 | + * @param callback the callback to invoke upon existence filter mismatch. The |
| 69 | + * type of the argument to this callback is intentionally declared as |
| 70 | + * `unknown`, rather than something more specific, to discourage its use |
| 71 | + * unless you really, really know what you are doing. If you know what you are |
| 72 | + * doing then you know the type and how to interpret it. |
| 73 | + * |
65 | 74 | * @return a function that, when called, unregisters the given callback; only
|
66 | 75 | * the first invocation of the returned function does anything; all subsequent
|
67 | 76 | * invocations do nothing.
|
68 | 77 | */
|
69 | 78 | onExistenceFilterMismatch(callback: (arg: unknown) => void): () => void {
|
70 |
| - this.onExistenceFilterMismatchCallbacks.push(callback); |
71 |
| - |
72 |
| - let removed = false; |
73 |
| - return () => { |
74 |
| - if (!removed) { |
75 |
| - const index = this.onExistenceFilterMismatchCallbacks.indexOf(callback); |
76 |
| - this.onExistenceFilterMismatchCallbacks.splice(index, 1); |
77 |
| - removed = true; |
78 |
| - } |
79 |
| - }; |
| 79 | + const key = Symbol(); |
| 80 | + this.onExistenceFilterMismatchCallbacks.set(key, callback); |
| 81 | + return () => this.onExistenceFilterMismatchCallbacks.delete(key); |
80 | 82 | }
|
81 | 83 |
|
82 | 84 | /**
|
83 | 85 | * Invokes all currently-registered `onExistenceFilterMismatch` callbacks.
|
84 |
| - * @param arg the argument to specify to the callbacks; the type of this |
85 |
| - * argument is intentionally declared as `unknown` to discourage casual use; |
86 |
| - * the specific use of this callback in tests knows the structure of the |
87 |
| - * given argument and will use it accordingly. |
| 86 | + * @param arg the argument to specify to the callbacks; see the documentation |
| 87 | + * for `onExistenceFilterMismatch()` for details. |
88 | 88 | */
|
89 | 89 | notifyOnExistenceFilterMismatch(arg: unknown): void {
|
90 | 90 | this.onExistenceFilterMismatchCallbacks.forEach(callback => callback(arg));
|
|
0 commit comments