@ethlete/query 6.0.0-next.55 → 6.0.0-next.56
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @ethlete/query
|
|
2
2
|
|
|
3
|
+
## 6.0.0-next.56
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- A web socket client with an `authProvider` now reconnects on user switches and logouts, rejoins rooms after login and drops stale emits; the bearer auth provider gains `sessionId()`.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Add the internal `ɵresetQueryDevtoolsForTesting()`, which undoes `provideQueryDevtools()` so a spec that shares a worker with another sees the devtools disabled again.
|
|
12
|
+
- Fix a query form's `activeFilterCount` staying stale when a function `defaultValue` re-resolves to the value already committed.
|
|
13
|
+
- Fix `keepUnusedFor: Infinity` evicting at once, hanging `executeUntilSettled`, leftover optimistic updates, `gql` printing `false`, GET variable order splitting the cache, and legacy `request()` bugs.
|
|
14
|
+
|
|
3
15
|
## 6.0.0-next.55
|
|
4
16
|
|
|
5
17
|
### Major Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ethlete-query-testing.mjs","sources":["../../../../libs/query/testing/query-test-utils.ts","../../../../libs/query/testing/auth-test-utils.ts","../../../../libs/query/testing/multi-tab-test-utils.ts","../../../../libs/query/testing/persistence-test-utils.ts","../../../../libs/query/testing/query-test-setup.ts","../../../../libs/query/testing/web-socket-test-utils.ts","../../../../libs/query/testing/token-test-utils.ts","../../../../libs/query/testing/ethlete-query-testing.ts"],"sourcesContent":["import { HttpTestingController } from '@angular/common/http/testing';\nimport { TestBed } from '@angular/core/testing';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport const expectAndFlush = <T = unknown>(\n httpTesting: HttpTestingController,\n url: string,\n response: T,\n statusOpts?: { status: number; statusText: string },\n): void => {\n const req = httpTesting.expectOne(url);\n if (statusOpts) {\n req.flush(response as any, statusOpts);\n } else {\n req.flush(response as any);\n }\n};\n\nexport const expectFlushAndWait = <T = unknown>(\n httpTesting: HttpTestingController,\n url: string,\n response: T,\n statusOpts?: { status: number; statusText: string },\n): void => {\n expectAndFlush(httpTesting, url, response, statusOpts);\n TestBed.tick();\n};\n","import { DestroyRef } from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\nimport {\n AnyQueryBuilder,\n AuthQueryBuilder,\n BearerAuthProvider,\n BearerAuthProviderFeatureContext,\n createBearerAuthProvider,\n FeatureRegistry,\n TokenRefreshQueryBuilder,\n TokenRefreshQueryConfig,\n withAuthenticationQuery,\n withRefreshQuery,\n} from '@ethlete/query';\nimport { QueryTestSetup } from './query-test-setup';\nimport { expectFlushAndWait } from './query-test-utils';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyFeatureBuilder = (context: BearerAuthProviderFeatureContext<any, readonly AnyQueryBuilder[]>) => {\n type: string;\n instance: unknown;\n};\n\ntype AuthTestArgs = { body: Record<string, unknown>; response: { accessToken: string; refreshToken: string } };\n\n/** The query builders of the provider {@link setupAuthTest} builds: a `login` and a `refresh` query. */\nexport type AuthTestQueryBuilders<\n TLoginArgs extends AuthTestArgs = AuthTestArgs,\n TRefreshArgs extends AuthTestArgs = AuthTestArgs,\n> = [AuthQueryBuilder<'login', TLoginArgs>, TokenRefreshQueryBuilder<'refresh', TRefreshArgs>];\n\n/** A feature for the provider {@link setupAuthTest} builds, typed against its `login`/`refresh` queries. */\nexport type AuthTestFeatureBuilder = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n context: BearerAuthProviderFeatureContext<any, AuthTestQueryBuilders>,\n) => unknown;\n\nexport type AuthTestSetupConfig<\n TLoginArgs extends AuthTestArgs = AuthTestArgs,\n TRefreshArgs extends AuthTestArgs = AuthTestArgs,\n TFeatures extends readonly AuthTestFeatureBuilder[] = [],\n TBearerData = unknown,\n> = {\n /** The query test setup instance */\n querySetup: QueryTestSetup;\n /** Login endpoint path. Default: '/auth/login' */\n loginPath?: string;\n /** Refresh endpoint path. Default: '/auth/refresh' */\n refreshPath?: string;\n /** Whether to refresh and retry a secure request that answers 401. Default: true, as in production */\n autoRetryOn401?: boolean;\n /** Function to extract tokens from login response */\n extractLoginTokens?: (response: TLoginArgs['response']) => { accessToken: string; refreshToken: string };\n /** Function to extract tokens from refresh response */\n extractRefreshTokens?: (response: TRefreshArgs['response']) => { accessToken: string; refreshToken: string };\n /** Builds the refresh request from the refresh token. See TokenRefreshQueryConfig for details */\n buildRefreshArgs?: TokenRefreshQueryConfig<TRefreshArgs>['buildArgs'];\n /** Feature builders for additional auth functionality */\n features?: TFeatures;\n /** Custom bearer decrypt function for testing */\n bearerDecryptFn?: (token: string) => TBearerData;\n /** Refresh strategy configuration. See TokenRefreshQueryConfig for details */\n refreshStrategy?: TokenRefreshQueryConfig<TRefreshArgs>['refreshStrategy'];\n /** Minimum refresh interval in milliseconds */\n minRefreshInterval?: number;\n /** Whether to refresh if token is already expired */\n refreshIfExpired?: boolean;\n /** Property name for expiration in JWT */\n expiresInPropertyName?: string;\n /** What to do when the refresh query fails for good. Defaults to the provider's own policy */\n onRefreshFailure?: TokenRefreshQueryConfig<TRefreshArgs>['onRefreshFailure'];\n};\n\nexport type AuthTestSetup<\n TLoginArgs extends AuthTestArgs = AuthTestArgs,\n TRefreshArgs extends AuthTestArgs = AuthTestArgs,\n TFeatures extends readonly AuthTestFeatureBuilder[] = [],\n TBearerData = unknown,\n> = {\n /** The bearer auth provider instance */\n auth: Omit<BearerAuthProvider<AuthTestQueryBuilders<TLoginArgs, TRefreshArgs>, [], TBearerData>, 'features'> & {\n features: FeatureRegistry<TFeatures, AuthTestQueryBuilders<TLoginArgs, TRefreshArgs>>;\n };\n /** Helper to login a user and flush the HTTP request */\n login: (credentials: TLoginArgs['body'], response: TLoginArgs['response']) => void;\n /** Helper to trigger a refresh and flush the HTTP request. Sends `buildRefreshArgs(token)` when configured, else `{ body: { token } }` */\n refresh: (token: string, response: TRefreshArgs['response']) => void;\n /** Helper to make a secure request that requires authentication */\n makeSecureRequest: (route: string) => void;\n};\n\nexport const setupAuthTest = <\n TLoginArgs extends AuthTestArgs = AuthTestArgs,\n TRefreshArgs extends AuthTestArgs = AuthTestArgs,\n TFeatures extends readonly AuthTestFeatureBuilder[] = readonly AuthTestFeatureBuilder[],\n TBearerData = unknown,\n>(\n config: AuthTestSetupConfig<TLoginArgs, TRefreshArgs, TFeatures, TBearerData>,\n): AuthTestSetup<TLoginArgs, TRefreshArgs, TFeatures, TBearerData> => {\n const {\n querySetup,\n loginPath = '/auth/login',\n refreshPath = '/auth/refresh',\n autoRetryOn401 = true,\n extractLoginTokens = (response) => ({\n accessToken: response.accessToken,\n refreshToken: response.refreshToken,\n }),\n extractRefreshTokens = (response) => ({\n accessToken: response.accessToken,\n refreshToken: response.refreshToken,\n }),\n buildRefreshArgs,\n features,\n bearerDecryptFn,\n refreshStrategy,\n minRefreshInterval,\n refreshIfExpired,\n expiresInPropertyName,\n onRefreshFailure,\n } = config;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const login = querySetup.createPost<TLoginArgs>(loginPath as any, {} as any) as any;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const refresh = querySetup.createPost<TRefreshArgs>(refreshPath as any, {} as any) as any;\n\n const { inject: injectAuth } = createBearerAuthProvider({\n name: 'test-auth',\n queryClientRef: querySetup.queryClientRef,\n queries: [\n withAuthenticationQuery('login', {\n queryCreator: login,\n extractTokens: extractLoginTokens,\n }),\n withRefreshQuery('refresh', {\n queryCreator: refresh,\n extractTokens: extractRefreshTokens,\n buildArgs: buildRefreshArgs,\n autoRetryOn401,\n refreshStrategy,\n minRefreshInterval,\n refreshIfExpired,\n expiresInPropertyName,\n onRefreshFailure,\n }),\n ] as AuthTestQueryBuilders<TLoginArgs, TRefreshArgs>,\n features: (features ?? []) as unknown as readonly ((\n context: BearerAuthProviderFeatureContext<TBearerData, AuthTestQueryBuilders<TLoginArgs, TRefreshArgs>>,\n ) => unknown)[],\n bearerDecryptFn,\n });\n\n const auth = TestBed.runInInjectionContext(() => {\n const provider = injectAuth();\n if (!provider) {\n throw new Error('Failed to create auth provider in test setup');\n }\n return provider;\n });\n\n const loginHelper = (credentials: TLoginArgs['body'], response: TLoginArgs['response']) => {\n TestBed.runInInjectionContext(() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n auth.queries.login.execute({ body: credentials } as any);\n });\n const fullUrl = `${querySetup.baseUrl}${loginPath}`;\n expectFlushAndWait(querySetup.httpTesting, fullUrl, response);\n };\n\n const refreshHelper = (token: string, response: TRefreshArgs['response']) => {\n TestBed.runInInjectionContext(() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n auth.queries.refresh.execute((buildRefreshArgs?.(token) ?? { body: { token } }) as any);\n });\n const fullUrl = `${querySetup.baseUrl}${refreshPath}`;\n expectFlushAndWait(querySetup.httpTesting, fullUrl, response);\n };\n\n const makeSecureRequest = (route: string) => {\n TestBed.runInInjectionContext(() => {\n querySetup.queryClient.repository.request({\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n route: route as any,\n method: 'GET',\n isSecure: true,\n consumerDestroyRef: TestBed.inject(DestroyRef),\n });\n });\n };\n\n return {\n auth: auth as unknown as AuthTestSetup<TLoginArgs, TRefreshArgs, TFeatures, TBearerData>['auth'],\n login: loginHelper,\n refresh: refreshHelper,\n makeSecureRequest,\n };\n};\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Test doubles for the two browser APIs the query client's multi-tab sync is built on:\n * `BroadcastChannel` and the Web Locks API (`navigator.locks`).\n *\n * Both fakes are process-wide and shared between every consumer created while they are installed,\n * which is exactly what makes \"two tabs\" testable: create two query clients in one test and they\n * talk to each other over the fake bus and contend for the same fake locks, going through the real\n * production code path on both sides.\n *\n * Neither jsdom nor happy-dom can stand in here - jsdom ships a `BroadcastChannel` that never\n * delivers to other instances, and no `navigator.locks` at all.\n */\n\n/** Something posted on the fake bus, as seen by a receiver. */\nexport type FakeBroadcastMessage = {\n /** The channel name it was posted on. */\n channel: string;\n\n /** The structured-cloned payload. */\n data: unknown;\n};\n\nexport type FakeBroadcastChannelHandle = {\n /** Every message posted on the bus, in order, across all channel names. */\n posted: FakeBroadcastMessage[];\n\n /** Uninstalls the fake and restores whatever `BroadcastChannel` was there before. */\n restore: () => void;\n};\n\n// Captured at import, before a spec can call `vi.useFakeTimers()`: delivery must not wait on a faked clock.\nconst nodeSetImmediate = (globalThis as { setImmediate?: (callback: () => void) => unknown }).setImmediate;\nconst scheduleTask: (callback: () => void) => void = nodeSetImmediate\n ? nodeSetImmediate.bind(globalThis)\n : setTimeout.bind(globalThis);\n\ntype FakeChannelInstance = {\n name: string;\n closed: boolean;\n onmessage: ((event: MessageEvent<unknown>) => void) | null;\n};\n\n/**\n * Replaces `globalThis.BroadcastChannel` with an in-memory bus.\n *\n * Messages are structured-cloned at post time (so a non-cloneable payload throws exactly like the\n * real API does), delivered as a task (never synchronously, and after every pending microtask), and\n * never delivered back to the channel that posted them - all three matching browser behavior. Delivery\n * does not depend on fake timers; `await flushMultiTabSync()` in a spec flushes it.\n */\nexport const installFakeBroadcastChannel = (): FakeBroadcastChannelHandle => {\n const original = (globalThis as any).BroadcastChannel;\n const instances = new Set<FakeChannelInstance>();\n const posted: FakeBroadcastMessage[] = [];\n\n class FakeBroadcastChannel implements FakeChannelInstance {\n closed = false;\n onmessage: ((event: MessageEvent<unknown>) => void) | null = null;\n\n constructor(public name: string) {\n instances.add(this);\n }\n\n postMessage(data: unknown) {\n if (this.closed) throw new DOMException('Channel is closed', 'InvalidStateError');\n\n const clone = structuredClone(data);\n\n posted.push({ channel: this.name, data: clone });\n\n for (const instance of instances) {\n if (instance === this || instance.closed || instance.name !== this.name) continue;\n\n scheduleTask(() => {\n if (instance.closed) return;\n\n instance.onmessage?.({ data: structuredClone(clone) } as MessageEvent<unknown>);\n });\n }\n }\n\n close() {\n this.closed = true;\n instances.delete(this);\n }\n\n addEventListener() {\n throw new Error('The fake BroadcastChannel only supports `onmessage`.');\n }\n }\n\n (globalThis as any).BroadcastChannel = FakeBroadcastChannel;\n\n return {\n posted,\n restore: () => {\n for (const instance of [...instances]) {\n instance.closed = true;\n }\n\n instances.clear();\n (globalThis as any).BroadcastChannel = original;\n },\n };\n};\n\nexport type FakeWebLocksHandle = {\n /** The names currently held, in no particular order. */\n heldNames: () => string[];\n\n /** The names with at least one request queued behind the holder. */\n pendingNames: () => string[];\n\n /** Uninstalls the fake and restores whatever `navigator.locks` was there before. */\n restore: () => void;\n};\n\ntype FakeLockWaiter = {\n callback: (lock: Lock | null) => unknown;\n resolve: (value: unknown) => void;\n reject: (reason: unknown) => void;\n granted: boolean;\n releaseSignal: () => void;\n};\n\n/**\n * Installs an in-memory `navigator.locks` implementing exclusive locks: one holder per name, the\n * rest queued FIFO, granted on a microtask (never synchronously), released when the callback's\n * promise settles. `signal` is honored for queued requests and - as in the real API - ignored once a\n * request has been granted.\n *\n * `ifAvailable` is a try-lock: a request that cannot be granted straight away runs its callback with\n * `null` instead of queueing, exactly as the real API does. `steal` releases the current holder -\n * rejecting its request with an `AbortError` - and is granted ahead of everything queued.\n *\n * `mode: 'shared'` is not implemented; nothing in the library uses it.\n */\nexport const installFakeWebLocks = (): FakeWebLocksHandle => {\n const originalDescriptor = Object.getOwnPropertyDescriptor(navigator, 'locks');\n const holders = new Map<string, FakeLockWaiter>();\n const queues = new Map<string, FakeLockWaiter[]>();\n\n const abortError = () => new DOMException('The lock request was aborted', 'AbortError');\n\n const pump = (name: string) => {\n if (holders.has(name)) return;\n\n const waiter = queues.get(name)?.shift();\n\n if (!waiter) return;\n\n waiter.granted = true;\n holders.set(name, waiter);\n\n const settle = (settleWaiter: () => void) => {\n // Only if this waiter is still the holder: a stolen lock already has a new one, and the callback\n // of the tab it was taken from settles afterwards.\n if (holders.get(name) === waiter) holders.delete(name);\n\n waiter.releaseSignal();\n settleWaiter();\n pump(name);\n };\n\n // `pump` itself only ever runs from a microtask, so calling the callback right here keeps the\n // grant exactly one microtask away from the `request()` call - which is what makes a single\n // `flushMultiTabSync()` per hop enough in specs.\n try {\n Promise.resolve(waiter.callback({ name, mode: 'exclusive' } as Lock)).then(\n (value) => settle(() => waiter.resolve(value)),\n (error) => settle(() => waiter.reject(error)),\n );\n } catch (error) {\n settle(() => waiter.reject(error));\n }\n };\n\n const request = (name: string, optionsOrCallback: unknown, maybeCallback?: unknown) => {\n const options = (typeof optionsOrCallback === 'function' ? {} : (optionsOrCallback ?? {})) as LockOptions;\n const callback = (typeof optionsOrCallback === 'function' ? optionsOrCallback : maybeCallback) as (\n lock: Lock | null,\n ) => unknown;\n\n return new Promise((resolve, reject) => {\n if (options.signal?.aborted) {\n reject(abortError());\n\n return;\n }\n\n const waiter: FakeLockWaiter = { callback, resolve, reject, granted: false, releaseSignal: () => undefined };\n const signal = options.signal;\n\n if (signal) {\n const onAbort = () => {\n waiter.releaseSignal();\n\n if (waiter.granted) return;\n\n const queue = queues.get(name);\n\n if (queue)\n queues.set(\n name,\n queue.filter((entry) => entry !== waiter),\n );\n\n reject(abortError());\n };\n\n signal.addEventListener('abort', onAbort);\n waiter.releaseSignal = () => {\n waiter.releaseSignal = () => undefined;\n signal.removeEventListener('abort', onAbort);\n };\n }\n\n if (options.steal) {\n queueMicrotask(() => {\n const holder = holders.get(name);\n\n if (holder) {\n holders.delete(name);\n holder.reject(abortError());\n }\n\n queues.set(name, [waiter, ...(queues.get(name) ?? [])]);\n pump(name);\n });\n\n return;\n }\n\n // Availability is decided a microtask out, not here: that is when the real API decides it too, so\n // two try-locks requested in the same tick still resolve to one winner and one `null`.\n if (options.ifAvailable) {\n queueMicrotask(() => {\n if (holders.has(name) || (queues.get(name)?.length ?? 0) > 0) {\n waiter.releaseSignal();\n Promise.resolve(callback(null)).then(resolve, reject);\n\n return;\n }\n\n queues.set(name, [waiter]);\n pump(name);\n });\n\n return;\n }\n\n queues.set(name, [...(queues.get(name) ?? []), waiter]);\n queueMicrotask(() => pump(name));\n });\n };\n\n // Both lists are reported, because a queued request is how a tab that is *not* the holder still\n // shows up - which is what the auth leader election counts its tabs by.\n const query = () =>\n Promise.resolve({\n held: [...holders.keys()].map((name) => ({ name, mode: 'exclusive' as const })),\n pending: [...queues.entries()].flatMap(([name, waiters]) =>\n waiters.map(() => ({ name, mode: 'exclusive' as const })),\n ),\n });\n\n Object.defineProperty(navigator, 'locks', {\n value: {\n request,\n query,\n },\n configurable: true,\n writable: true,\n });\n\n return {\n heldNames: () => [...holders.keys()],\n pendingNames: () => [...queues.entries()].filter(([, queue]) => queue.length > 0).map(([name]) => name),\n restore: () => {\n for (const waiter of [...holders.values(), ...[...queues.values()].flat()]) waiter.releaseSignal();\n\n holders.clear();\n queues.clear();\n\n if (originalDescriptor) {\n Object.defineProperty(navigator, 'locks', originalDescriptor);\n } else {\n delete (navigator as any).locks;\n }\n },\n };\n};\n\n/**\n * Waits for the fakes' pending work - message delivery (a task) and lock grants (a microtask) - even\n * under fake timers. Awaiting it once is enough for a single hop; a grant that has to wait for another\n * tab's release, or a reply to a delivered message, needs one await per hop.\n */\nexport const flushMultiTabSync = () => new Promise<void>((resolve) => scheduleTask(resolve));\n","import type { PersistedQueryEntry, PersistedQueryEntryMeta, QueryPersistenceAdapter } from '@ethlete/query';\n\n/**\n * An in-memory stand-in for the query client's persisted response store.\n *\n * jsdom has no IndexedDB at all, so this is how persistence is tested - and because the storage\n * adapter is a documented seam rather than a mock of one, a spec running against this exercises the\n * real engine, repository and request code on both the write and the read side.\n *\n * Everything resolves on a microtask, never synchronously, matching the real thing: `await\n * Promise.resolve()` (or `flushMicrotasks`) is what lets a hydration land in a spec.\n */\nexport type FakeQueryPersistenceStoreHandle = {\n /** Pass this as `persistence: { adapter }`. Two clients sharing one handle share one store. */\n adapter: QueryPersistenceAdapter;\n\n /** Pre-populates the store, as if a previous session had written these entries. */\n seed: (entries: PersistedQueryEntry[]) => void;\n\n /** Every entry currently held, in insertion order. */\n entries: () => PersistedQueryEntry[];\n\n /** The entry held under `key`, or `undefined`. */\n entry: (key: string) => PersistedQueryEntry | undefined;\n\n /** How often each adapter method has been called. */\n calls: () => Record<'loadIndex' | 'read' | 'write' | 'remove' | 'clear', number>;\n\n /** Makes the next `count` writes reject - a full disk, by default. */\n failNextWrites: (count: number, error?: unknown) => void;\n\n /** Makes the next `count` removals reject. */\n failNextRemoves: (count: number, error?: unknown) => void;\n\n /** Makes the next `loadIndex` reject. */\n failNextLoadIndex: (error?: unknown) => void;\n\n /**\n * Holds every subsequent `read` pending until {@link flushReads} is called, for testing the window\n * between a cold mount and its hydration (a slow disk, or a mount that happened before startup\n * finished). Each held read returns what the store held when it started, as `loadIndex` does.\n */\n deferReads: () => void;\n\n /** Settles the reads held by {@link deferReads} and stops deferring. */\n flushReads: () => Promise<void>;\n\n /**\n * Holds every subsequent `loadIndex` pending until {@link flushLoadIndex} is called, for testing\n * what happens to the store while a client's startup is still reading its index (a real disk takes\n * milliseconds). The snapshot each held load returns is the one it would have read when it started.\n */\n deferLoadIndex: () => void;\n\n /** Settles the index loads held by {@link deferLoadIndex} and stops deferring. */\n flushLoadIndex: () => Promise<void>;\n};\n\nconst quotaError = () => new DOMException('The quota has been exceeded.', 'QuotaExceededError');\n\nexport const createFakeQueryPersistenceStore = (): FakeQueryPersistenceStoreHandle => {\n const store = new Map<string, PersistedQueryEntry>();\n const calls = { loadIndex: 0, read: 0, write: 0, remove: 0, clear: 0 };\n const deferredReads: Array<() => void> = [];\n const deferredLoadIndexes: Array<() => void> = [];\n\n let failingWrites = 0;\n let writeError: unknown = null;\n let failingRemoves = 0;\n let removeError: unknown = null;\n let loadIndexError: unknown = null;\n let isDeferringReads = false;\n let isDeferringLoadIndex = false;\n\n // Cloning on the way in and on the way out is not pedantry: a real store hands back a copy, so a\n // spec (or the engine) mutating a hydrated body must not be able to change what is \"on disk\".\n const clone = <T>(value: T): T => structuredClone(value);\n\n const loadIndex = async () => {\n calls.loadIndex++;\n\n if (loadIndexError !== null) {\n const error = loadIndexError;\n loadIndexError = null;\n\n throw error;\n }\n\n // Taken before the gate, not after: a real store answers with what it held when the read started,\n // so anything that empties it while a deferred load is held must not change what that load returns.\n const snapshot = Array.from(store.values()).map(\n ({ body: _body, ...meta }) => clone(meta) satisfies PersistedQueryEntryMeta,\n );\n\n if (isDeferringLoadIndex) {\n await new Promise<void>((resolve) => deferredLoadIndexes.push(resolve));\n }\n\n return snapshot;\n };\n\n const read = async (key: string) => {\n calls.read++;\n\n const entry = store.get(key);\n const snapshot = entry ? { body: clone(entry.body), version: entry.version } : null;\n\n if (isDeferringReads) {\n await new Promise<void>((resolve) => deferredReads.push(resolve));\n }\n\n return snapshot;\n };\n\n const write = async (entries: PersistedQueryEntry[]) => {\n calls.write++;\n\n if (failingWrites > 0) {\n failingWrites--;\n\n throw writeError ?? quotaError();\n }\n\n for (const entry of entries) {\n store.set(entry.key, clone(entry));\n }\n };\n\n const remove = async (keys: string[]) => {\n calls.remove++;\n\n if (failingRemoves > 0) {\n failingRemoves--;\n\n throw removeError ?? new Error('The removal failed.');\n }\n\n for (const key of keys) {\n store.delete(key);\n }\n };\n\n const clear = async () => {\n calls.clear++;\n store.clear();\n };\n\n return {\n adapter: { loadIndex, read, write, remove, clear, isSupported: true },\n seed: (entries) => {\n for (const entry of entries) {\n store.set(entry.key, clone(entry));\n }\n },\n entries: () => Array.from(store.values()).map(clone),\n entry: (key) => {\n const entry = store.get(key);\n\n return entry ? clone(entry) : undefined;\n },\n calls: () => ({ ...calls }),\n failNextWrites: (count, error) => {\n failingWrites = count;\n writeError = error ?? null;\n },\n failNextRemoves: (count, error) => {\n failingRemoves = count;\n removeError = error ?? null;\n },\n failNextLoadIndex: (error) => {\n loadIndexError = error ?? quotaError();\n },\n deferReads: () => {\n isDeferringReads = true;\n },\n flushReads: async () => {\n isDeferringReads = false;\n\n const pending = deferredReads.splice(0, deferredReads.length);\n\n for (const resolve of pending) {\n resolve();\n }\n\n await Promise.resolve();\n },\n deferLoadIndex: () => {\n isDeferringLoadIndex = true;\n },\n flushLoadIndex: async () => {\n isDeferringLoadIndex = false;\n\n const pending = deferredLoadIndexes.splice(0, deferredLoadIndexes.length);\n\n for (const resolve of pending) {\n resolve();\n }\n\n await Promise.resolve();\n },\n };\n};\n","import { HttpClient, HttpErrorResponse, provideHttpClient } from '@angular/common/http';\nimport { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';\nimport { DestroyRef, EnvironmentProviders, ErrorHandler, Injector } from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\nimport { provideRouter } from '@angular/router';\nimport {\n AnyCreateQueryClientResult,\n createDeleteQuery,\n createGetQuery,\n createPatchQuery,\n createPostQuery,\n createPutQuery,\n createQueryClient,\n isQueryErrorResponse,\n QueryClientRef,\n} from '@ethlete/query';\n\nexport type QueryTestSetup = {\n queryClient: NonNullable<ReturnType<AnyCreateQueryClientResult['inject']>>;\n queryClientRef: QueryClientRef;\n httpClient: HttpClient;\n httpTesting: HttpTestingController;\n injector: Injector;\n baseUrl: string;\n createGet: ReturnType<typeof createGetQuery>;\n createPost: ReturnType<typeof createPostQuery>;\n createPut: ReturnType<typeof createPutQuery>;\n createPatch: ReturnType<typeof createPatchQuery>;\n createDelete: ReturnType<typeof createDeleteQuery>;\n\n /**\n * Puts back the `console.error` that was installed before the first {@link setupQueryTest} call. Runs\n * on its own when the `TestBed` module is reset; idempotent, and safe to call from any setup.\n */\n restoreConsole: () => void;\n};\n\nexport type QueryTestSetupConfig = {\n baseUrl?: string;\n name?: string;\n /**\n * `true` swallows the `ErrorHandler` reports of failed requests and rethrows every other error, `'all'`\n * swallows everything, `false` keeps Angular's own handler.\n * @default true\n */\n mockErrorHandler?: boolean | 'all';\n};\n\nlet originalError: typeof console.error | null = null;\n\nconst filteredError = (...args: unknown[]) => {\n const message = args[0];\n\n if (message && typeof message === 'object' && 'name' in message && message.name === 'HttpErrorResponse') {\n return;\n }\n\n if (typeof message === 'string' && message.includes('Failed to decrypt bearer token')) {\n return;\n }\n\n if (typeof message === 'string' && message.includes('Failed to extract tokens from')) {\n return;\n }\n\n originalError?.(...args);\n};\n\n// Capture only what is not already the wrapper, so repeated calls reinstall the one filter instead\n// of nesting a new closure over the previous one and stranding the pristine handlers.\nconst installConsoleFilters = () => {\n if (console.error !== filteredError) originalError = console.error;\n\n console.error = filteredError;\n};\n\nconst restoreConsole = () => {\n if (originalError && console.error === filteredError) console.error = originalError;\n\n originalError = null;\n};\n\nconst isFailedRequestError = (error: unknown) => error instanceof HttpErrorResponse || isQueryErrorResponse(error);\n\nconst requestErrorHandler: Pick<ErrorHandler, 'handleError'> = {\n handleError: (error: unknown) => {\n if (isFailedRequestError(error)) return;\n\n throw error;\n },\n};\n\nexport const setupQueryTest = (config?: QueryTestSetupConfig): QueryTestSetup => {\n const baseUrl = config?.baseUrl ?? 'https://api.test.com';\n const name = config?.name ?? 'test';\n const mockErrorHandler = config?.mockErrorHandler ?? true;\n\n installConsoleFilters();\n\n const providers: (EnvironmentProviders | object)[] = [\n provideHttpClient(),\n provideHttpClientTesting(),\n provideRouter([]),\n ];\n\n if (mockErrorHandler) {\n providers.push({\n provide: ErrorHandler,\n useValue: mockErrorHandler === 'all' ? { handleError: () => undefined } : requestErrorHandler,\n });\n }\n\n TestBed.configureTestingModule({ providers });\n\n const queryClientRef = createQueryClient({ baseUrl, name });\n\n return TestBed.runInInjectionContext(() => {\n const { inject } = queryClientRef;\n const queryClient = inject();\n\n TestBed.inject(DestroyRef).onDestroy(restoreConsole);\n\n if (!queryClient) {\n throw new Error('Failed to create query client in test setup');\n }\n\n return {\n queryClient,\n queryClientRef,\n httpClient: TestBed.inject(HttpClient),\n httpTesting: TestBed.inject(HttpTestingController),\n injector: TestBed.inject(Injector),\n baseUrl,\n createGet: createGetQuery(queryClientRef),\n createPost: createPostQuery(queryClientRef),\n createPut: createPutQuery(queryClientRef),\n createPatch: createPatchQuery(queryClientRef),\n createDelete: createDeleteQuery(queryClientRef),\n restoreConsole,\n };\n });\n};\n","import type {\n SocketMessageView,\n WebSocketClientIo,\n WebSocketClientIoOptions,\n WebSocketClientSocket,\n} from '@ethlete/query';\n\n/** A scripted stand-in for `socket.io-client`'s `io`, driven from a spec. */\nexport type WebSocketTestDouble = {\n /** Pass this as `createWebSocketClient({ io })`. */\n io: WebSocketClientIo;\n\n /** The url and options the client called the factory with, or `null` until it did. */\n connection: () => { url: string; transports: string[] | undefined } | null;\n\n /** The `withCredentials` the client asked the factory for, or `null` until it called it. */\n withCredentials: () => boolean | null;\n\n /** The auth payload of every handshake, oldest first - `null` for one made without `auth`. */\n handshakes: () => (object | null)[];\n\n /** Every message the client emitted, newest last - room joins and leaves included, buffered ones too. */\n sent: () => { event: string; data: unknown }[];\n\n /** Every message that reached the server, newest last. An emit buffered while offline lands here on the next connect. */\n delivered: () => { event: string; data: unknown }[];\n\n /**\n * Whether the client asked the socket to connect, and whether it has since disconnected it. `active` is\n * socket.io's own flag - `false` after a server disconnect or a rejected handshake, until the next\n * `connect()`; `connectCalls` counts every `connect()`.\n */\n state: () => { connectRequested: boolean; disconnected: boolean; active: boolean; connectCalls: number };\n\n /**\n * Complete the handshake: flush every buffered emit, then turn the client's `isConnected` true. Pass\n * `recovered: true` for a connection-state-recovered reconnect, in which the server kept the rooms.\n */\n serverConnect: (options?: { recovered?: boolean }) => void;\n\n /**\n * Drop the connection, so `isConnected` turns false. The default reason, `'transport close'`, is one\n * socket.io recovers from itself; `'io server disconnect'` is the server kicking the socket, after which\n * socket.io only reconnects when `connect()` is called again.\n */\n serverDisconnect: (options?: { reason?: 'transport close' | 'io server disconnect' }) => void;\n\n /**\n * Reject the handshake the way a server middleware does: the `auth` payload is recorded in\n * {@link handshakes}, `connect_error` fires and the socket stops reconnecting on its own.\n */\n serverRejectHandshake: (message?: string) => void;\n\n /**\n * Let the ping expire: the socket still reports itself connected, but buffers every emit like socket.io\n * does until it notices and closes. Follow it with {@link serverDisconnect}.\n */\n serverPingExpire: () => void;\n\n /** Deliver a message the way the server would. */\n serverSend: (message: SocketMessageView) => void;\n\n /** Deliver a raw frame, for the malformed-payload path. */\n serverSendRaw: (frame: string) => void;\n};\n\n/**\n * A socket io test double, for specs around `createWebSocketClient` - which takes its `io` factory as\n * an option precisely so a spec (or an app that never opens a socket) needs no `socket.io-client`.\n *\n * Nothing here connects on its own: the client's own `connect()` only flips\n * {@link WebSocketTestDouble.state}, and it is {@link WebSocketTestDouble.serverConnect} that fires\n * the `connect` listener. That split is what makes \"joined a room while disconnected, and it was\n * re-joined after a reconnect\" testable.\n */\nexport const createWebSocketTestDouble = (): WebSocketTestDouble => {\n const sent: { event: string; data: unknown }[] = [];\n const delivered: { event: string; data: unknown }[] = [];\n const buffered: { event: string; data: unknown }[] = [];\n const listeners = {\n connect: [] as (() => void)[],\n disconnect: [] as ((reason: string) => void)[],\n connect_error: [] as ((error: Error) => void)[],\n };\n const anyListeners: ((eventName: string, ...args: unknown[]) => void)[] = [];\n const outgoingListeners: ((eventName: string, ...args: unknown[]) => void)[] = [];\n\n let connection: { url: string; transports: string[] | undefined } | null = null;\n let withCredentials: boolean | null = null;\n let auth: WebSocketClientIoOptions['auth'];\n const handshakes: (object | null)[] = [];\n let connectRequested = false;\n let disconnected = false;\n let connected = false;\n let active = false;\n let connectCalls = 0;\n let pingExpired = false;\n let recovered = false;\n\n const deliver = (message: { event: string; data: unknown }) => {\n for (const listener of outgoingListeners) listener(message.event, message.data);\n delivered.push(message);\n };\n\n const recordHandshake = () => {\n if (auth) auth((data) => handshakes.push(data));\n else handshakes.push(null);\n };\n\n const disconnect = (reason: string) => {\n connected = false;\n pingExpired = false;\n for (const listener of listeners.disconnect) listener(reason);\n };\n\n const socket: WebSocketClientSocket = {\n connect: () => {\n connectRequested = true;\n active = true;\n connectCalls++;\n },\n disconnect: () => {\n disconnected = true;\n active = false;\n if (connected) disconnect('io client disconnect');\n },\n emit: (event, data) => {\n sent.push({ event, data });\n\n if (connected && !pingExpired) deliver({ event, data });\n else buffered.push({ event, data });\n },\n on: (event: 'connect' | 'disconnect' | 'connect_error', listener: (arg: never) => void) =>\n void (listeners[event] as ((arg: never) => void)[]).push(listener),\n onAny: (listener) => void anyListeners.push(listener),\n onAnyOutgoing: (listener) => void outgoingListeners.push(listener),\n get recovered() {\n return recovered;\n },\n get active() {\n return active;\n },\n };\n\n return {\n io: (url, options) => {\n connection = { url, transports: options.transports };\n withCredentials = options.withCredentials;\n auth = options.auth;\n return socket;\n },\n connection: () => connection,\n withCredentials: () => withCredentials,\n handshakes: () => [...handshakes],\n sent: () => [...sent],\n delivered: () => [...delivered],\n state: () => ({ connectRequested, disconnected, active, connectCalls }),\n serverConnect: (options) => {\n recordHandshake();\n\n active = true;\n recovered = options?.recovered ?? false;\n connected = true;\n pingExpired = false;\n\n for (const message of buffered.splice(0)) deliver(message);\n\n for (const listener of listeners.connect) listener();\n },\n serverDisconnect: (options) => {\n const reason = options?.reason ?? 'transport close';\n\n if (reason === 'io server disconnect') active = false;\n\n disconnect(reason);\n },\n serverRejectHandshake: (message) => {\n recordHandshake();\n\n active = false;\n\n for (const listener of listeners.connect_error) listener(new Error(message ?? 'unauthorized'));\n },\n serverPingExpire: () => void (pingExpired = true),\n serverSend: (message) => {\n const frame = JSON.stringify(message);\n for (const listener of anyListeners) listener('message', frame);\n },\n serverSendRaw: (frame) => {\n for (const listener of anyListeners) listener('message', frame);\n },\n };\n};\n","const toBase64Url = (json: string) => {\n const encoded = btoa(\n encodeURIComponent(json).replace(/%([0-9A-F]{2})/g, (_, hex: string) => String.fromCharCode(parseInt(hex, 16))),\n );\n\n return encoded.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n};\n\nexport type MintTestTokenOptions = {\n /** @default 900000 (15 minutes) */\n expiresInMs?: number;\n\n /** Extra payload claims, e.g. the user id or roles `bearerData()` and the auth guards read. */\n claims?: Record<string, unknown>;\n};\n\nlet mintCount = 0;\n\n/**\n * Mints an unsigned JWT the bearer auth provider can decode, with `iat`, `exp` and a unique `jti`.\n * Hand it to `setTokens()` to put the app's own provider into a session.\n *\n * @example\n * ```ts\n * TestBed.runInInjectionContext(() => authProviderRef.inject().setTokens(mintTestToken({ claims: { sub: '1' } }), 'refresh'));\n * ```\n */\nexport const mintTestToken = (options: MintTestTokenOptions = {}) => {\n const { expiresInMs = 15 * 60 * 1000, claims = {} } = options;\n const iat = Math.floor(Date.now() / 1000);\n const exp = Math.floor((Date.now() + expiresInMs) / 1000);\n\n const header = toBase64Url(JSON.stringify({ alg: 'none', typ: 'JWT' }));\n const payload = toBase64Url(JSON.stringify({ iat, exp, jti: ++mintCount, ...claims }));\n\n return `${header}.${payload}.`;\n};\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ethlete-query-testing.mjs","sources":["../../../../libs/query/testing/query-test-utils.ts","../../../../libs/query/testing/auth-test-utils.ts","../../../../libs/query/testing/multi-tab-test-utils.ts","../../../../libs/query/testing/persistence-test-utils.ts","../../../../libs/query/testing/query-test-setup.ts","../../../../libs/query/testing/web-socket-test-utils.ts","../../../../libs/query/testing/token-test-utils.ts","../../../../libs/query/testing/ethlete-query-testing.ts"],"sourcesContent":["import { HttpTestingController } from '@angular/common/http/testing';\nimport { TestBed } from '@angular/core/testing';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport const expectAndFlush = <T = unknown>(\n httpTesting: HttpTestingController,\n url: string,\n response: T,\n statusOpts?: { status: number; statusText: string },\n): void => {\n const req = httpTesting.expectOne(url);\n if (statusOpts) {\n req.flush(response as any, statusOpts);\n } else {\n req.flush(response as any);\n }\n};\n\nexport const expectFlushAndWait = <T = unknown>(\n httpTesting: HttpTestingController,\n url: string,\n response: T,\n statusOpts?: { status: number; statusText: string },\n): void => {\n expectAndFlush(httpTesting, url, response, statusOpts);\n TestBed.tick();\n};\n","import { DestroyRef } from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\nimport {\n AnyQueryBuilder,\n AuthQueryBuilder,\n BearerAuthProvider,\n BearerAuthProviderFeatureContext,\n createBearerAuthProvider,\n FeatureRegistry,\n TokenRefreshQueryBuilder,\n TokenRefreshQueryConfig,\n withAuthenticationQuery,\n withRefreshQuery,\n} from '@ethlete/query';\nimport { QueryTestSetup } from './query-test-setup';\nimport { expectFlushAndWait } from './query-test-utils';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyFeatureBuilder = (context: BearerAuthProviderFeatureContext<any, readonly AnyQueryBuilder[]>) => {\n type: string;\n instance: unknown;\n};\n\ntype AuthTestArgs = { body: Record<string, unknown>; response: { accessToken: string; refreshToken: string } };\n\n/** The query builders of the provider {@link setupAuthTest} builds: a `login` and a `refresh` query. */\nexport type AuthTestQueryBuilders<\n TLoginArgs extends AuthTestArgs = AuthTestArgs,\n TRefreshArgs extends AuthTestArgs = AuthTestArgs,\n> = [AuthQueryBuilder<'login', TLoginArgs>, TokenRefreshQueryBuilder<'refresh', TRefreshArgs>];\n\n/** A feature for the provider {@link setupAuthTest} builds, typed against its `login`/`refresh` queries. */\nexport type AuthTestFeatureBuilder = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n context: BearerAuthProviderFeatureContext<any, AuthTestQueryBuilders>,\n) => unknown;\n\nexport type AuthTestSetupConfig<\n TLoginArgs extends AuthTestArgs = AuthTestArgs,\n TRefreshArgs extends AuthTestArgs = AuthTestArgs,\n TFeatures extends readonly AuthTestFeatureBuilder[] = [],\n TBearerData = unknown,\n> = {\n /** The query test setup instance */\n querySetup: QueryTestSetup;\n /** Login endpoint path. Default: '/auth/login' */\n loginPath?: string;\n /** Refresh endpoint path. Default: '/auth/refresh' */\n refreshPath?: string;\n /** Whether to refresh and retry a secure request that answers 401. Default: true, as in production */\n autoRetryOn401?: boolean;\n /** Function to extract tokens from login response */\n extractLoginTokens?: (response: TLoginArgs['response']) => { accessToken: string; refreshToken: string };\n /** Function to extract tokens from refresh response */\n extractRefreshTokens?: (response: TRefreshArgs['response']) => { accessToken: string; refreshToken: string };\n /** Builds the refresh request from the refresh token. See TokenRefreshQueryConfig for details */\n buildRefreshArgs?: TokenRefreshQueryConfig<TRefreshArgs>['buildArgs'];\n /** Feature builders for additional auth functionality */\n features?: TFeatures;\n /** Custom bearer decrypt function for testing */\n bearerDecryptFn?: (token: string) => TBearerData;\n /** Refresh strategy configuration. See TokenRefreshQueryConfig for details */\n refreshStrategy?: TokenRefreshQueryConfig<TRefreshArgs>['refreshStrategy'];\n /** Minimum refresh interval in milliseconds */\n minRefreshInterval?: number;\n /** Whether to refresh if token is already expired */\n refreshIfExpired?: boolean;\n /** Property name for expiration in JWT */\n expiresInPropertyName?: string;\n /** What to do when the refresh query fails for good. Defaults to the provider's own policy */\n onRefreshFailure?: TokenRefreshQueryConfig<TRefreshArgs>['onRefreshFailure'];\n};\n\nexport type AuthTestSetup<\n TLoginArgs extends AuthTestArgs = AuthTestArgs,\n TRefreshArgs extends AuthTestArgs = AuthTestArgs,\n TFeatures extends readonly AuthTestFeatureBuilder[] = [],\n TBearerData = unknown,\n> = {\n /** The bearer auth provider instance */\n auth: Omit<BearerAuthProvider<AuthTestQueryBuilders<TLoginArgs, TRefreshArgs>, [], TBearerData>, 'features'> & {\n features: FeatureRegistry<TFeatures, AuthTestQueryBuilders<TLoginArgs, TRefreshArgs>>;\n };\n /** Helper to login a user and flush the HTTP request */\n login: (credentials: TLoginArgs['body'], response: TLoginArgs['response']) => void;\n /** Helper to trigger a refresh and flush the HTTP request. Sends `buildRefreshArgs(token)` when configured, else `{ body: { token } }` */\n refresh: (token: string, response: TRefreshArgs['response']) => void;\n /** Helper to make a secure request that requires authentication */\n makeSecureRequest: (route: string) => void;\n};\n\nexport const setupAuthTest = <\n TLoginArgs extends AuthTestArgs = AuthTestArgs,\n TRefreshArgs extends AuthTestArgs = AuthTestArgs,\n TFeatures extends readonly AuthTestFeatureBuilder[] = readonly AuthTestFeatureBuilder[],\n TBearerData = unknown,\n>(\n config: AuthTestSetupConfig<TLoginArgs, TRefreshArgs, TFeatures, TBearerData>,\n): AuthTestSetup<TLoginArgs, TRefreshArgs, TFeatures, TBearerData> => {\n const {\n querySetup,\n loginPath = '/auth/login',\n refreshPath = '/auth/refresh',\n autoRetryOn401 = true,\n extractLoginTokens = (response) => ({\n accessToken: response.accessToken,\n refreshToken: response.refreshToken,\n }),\n extractRefreshTokens = (response) => ({\n accessToken: response.accessToken,\n refreshToken: response.refreshToken,\n }),\n buildRefreshArgs,\n features,\n bearerDecryptFn,\n refreshStrategy,\n minRefreshInterval,\n refreshIfExpired,\n expiresInPropertyName,\n onRefreshFailure,\n } = config;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const login = querySetup.createPost<TLoginArgs>(loginPath as any, {} as any) as any;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const refresh = querySetup.createPost<TRefreshArgs>(refreshPath as any, {} as any) as any;\n\n const { inject: injectAuth } = createBearerAuthProvider({\n name: 'test-auth',\n queryClientRef: querySetup.queryClientRef,\n queries: [\n withAuthenticationQuery('login', {\n queryCreator: login,\n extractTokens: extractLoginTokens,\n }),\n withRefreshQuery('refresh', {\n queryCreator: refresh,\n extractTokens: extractRefreshTokens,\n buildArgs: buildRefreshArgs,\n autoRetryOn401,\n refreshStrategy,\n minRefreshInterval,\n refreshIfExpired,\n expiresInPropertyName,\n onRefreshFailure,\n }),\n ] as AuthTestQueryBuilders<TLoginArgs, TRefreshArgs>,\n features: (features ?? []) as unknown as readonly ((\n context: BearerAuthProviderFeatureContext<TBearerData, AuthTestQueryBuilders<TLoginArgs, TRefreshArgs>>,\n ) => unknown)[],\n bearerDecryptFn,\n });\n\n const auth = TestBed.runInInjectionContext(() => {\n const provider = injectAuth();\n if (!provider) {\n throw new Error('Failed to create auth provider in test setup');\n }\n return provider;\n });\n\n const loginHelper = (credentials: TLoginArgs['body'], response: TLoginArgs['response']) => {\n TestBed.runInInjectionContext(() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n auth.queries.login.execute({ body: credentials } as any);\n });\n const fullUrl = `${querySetup.baseUrl}${loginPath}`;\n expectFlushAndWait(querySetup.httpTesting, fullUrl, response);\n };\n\n const refreshHelper = (token: string, response: TRefreshArgs['response']) => {\n TestBed.runInInjectionContext(() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n auth.queries.refresh.execute((buildRefreshArgs?.(token) ?? { body: { token } }) as any);\n });\n const fullUrl = `${querySetup.baseUrl}${refreshPath}`;\n expectFlushAndWait(querySetup.httpTesting, fullUrl, response);\n };\n\n const makeSecureRequest = (route: string) => {\n TestBed.runInInjectionContext(() => {\n querySetup.queryClient.repository.request({\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n route: route as any,\n method: 'GET',\n isSecure: true,\n consumerDestroyRef: TestBed.inject(DestroyRef),\n });\n });\n };\n\n return {\n auth: auth as unknown as AuthTestSetup<TLoginArgs, TRefreshArgs, TFeatures, TBearerData>['auth'],\n login: loginHelper,\n refresh: refreshHelper,\n makeSecureRequest,\n };\n};\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Test doubles for the two browser APIs the query client's multi-tab sync is built on:\n * `BroadcastChannel` and the Web Locks API (`navigator.locks`).\n *\n * Both fakes are process-wide and shared between every consumer created while they are installed,\n * which is exactly what makes \"two tabs\" testable: create two query clients in one test and they\n * talk to each other over the fake bus and contend for the same fake locks, going through the real\n * production code path on both sides.\n *\n * Neither jsdom nor happy-dom can stand in here - jsdom ships a `BroadcastChannel` that never\n * delivers to other instances, and no `navigator.locks` at all.\n */\n\n/** Something posted on the fake bus, as seen by a receiver. */\nexport type FakeBroadcastMessage = {\n /** The channel name it was posted on. */\n channel: string;\n\n /** The structured-cloned payload. */\n data: unknown;\n};\n\nexport type FakeBroadcastChannelHandle = {\n /** Every message posted on the bus, in order, across all channel names. */\n posted: FakeBroadcastMessage[];\n\n /** Uninstalls the fake and restores whatever `BroadcastChannel` was there before. */\n restore: () => void;\n};\n\n// Captured at import, before a spec can call `vi.useFakeTimers()`: delivery must not wait on a faked clock.\nconst nodeSetImmediate = (globalThis as { setImmediate?: (callback: () => void) => unknown }).setImmediate;\nconst scheduleTask: (callback: () => void) => void = nodeSetImmediate\n ? nodeSetImmediate.bind(globalThis)\n : setTimeout.bind(globalThis);\n\ntype FakeChannelInstance = {\n name: string;\n closed: boolean;\n onmessage: ((event: MessageEvent<unknown>) => void) | null;\n};\n\n/**\n * Replaces `globalThis.BroadcastChannel` with an in-memory bus.\n *\n * Messages are structured-cloned at post time (so a non-cloneable payload throws exactly like the\n * real API does), delivered as a task (never synchronously, and after every pending microtask), and\n * never delivered back to the channel that posted them - all three matching browser behavior. Delivery\n * does not depend on fake timers; `await flushMultiTabSync()` in a spec flushes it.\n */\nexport const installFakeBroadcastChannel = (): FakeBroadcastChannelHandle => {\n const original = (globalThis as any).BroadcastChannel;\n const instances = new Set<FakeChannelInstance>();\n const posted: FakeBroadcastMessage[] = [];\n\n class FakeBroadcastChannel implements FakeChannelInstance {\n closed = false;\n onmessage: ((event: MessageEvent<unknown>) => void) | null = null;\n\n constructor(public name: string) {\n instances.add(this);\n }\n\n postMessage(data: unknown) {\n if (this.closed) throw new DOMException('Channel is closed', 'InvalidStateError');\n\n const clone = structuredClone(data);\n\n posted.push({ channel: this.name, data: clone });\n\n for (const instance of instances) {\n if (instance === this || instance.closed || instance.name !== this.name) continue;\n\n scheduleTask(() => {\n if (instance.closed) return;\n\n instance.onmessage?.({ data: structuredClone(clone) } as MessageEvent<unknown>);\n });\n }\n }\n\n close() {\n this.closed = true;\n instances.delete(this);\n }\n\n addEventListener() {\n throw new Error('The fake BroadcastChannel only supports `onmessage`.');\n }\n }\n\n (globalThis as any).BroadcastChannel = FakeBroadcastChannel;\n\n return {\n posted,\n restore: () => {\n for (const instance of [...instances]) {\n instance.closed = true;\n }\n\n instances.clear();\n (globalThis as any).BroadcastChannel = original;\n },\n };\n};\n\nexport type FakeWebLocksHandle = {\n /** The names currently held, in no particular order. */\n heldNames: () => string[];\n\n /** The names with at least one request queued behind the holder. */\n pendingNames: () => string[];\n\n /** Uninstalls the fake and restores whatever `navigator.locks` was there before. */\n restore: () => void;\n};\n\ntype FakeLockWaiter = {\n callback: (lock: Lock | null) => unknown;\n resolve: (value: unknown) => void;\n reject: (reason: unknown) => void;\n granted: boolean;\n releaseSignal: () => void;\n};\n\n/**\n * Installs an in-memory `navigator.locks` implementing exclusive locks: one holder per name, the\n * rest queued FIFO, granted on a microtask (never synchronously), released when the callback's\n * promise settles. `signal` is honored for queued requests and - as in the real API - ignored once a\n * request has been granted.\n *\n * `ifAvailable` is a try-lock: a request that cannot be granted straight away runs its callback with\n * `null` instead of queueing, exactly as the real API does. `steal` releases the current holder -\n * rejecting its request with an `AbortError` - and is granted ahead of everything queued.\n *\n * `mode: 'shared'` is not implemented; nothing in the library uses it.\n */\nexport const installFakeWebLocks = (): FakeWebLocksHandle => {\n const originalDescriptor = Object.getOwnPropertyDescriptor(navigator, 'locks');\n const holders = new Map<string, FakeLockWaiter>();\n const queues = new Map<string, FakeLockWaiter[]>();\n\n const abortError = () => new DOMException('The lock request was aborted', 'AbortError');\n\n const pump = (name: string) => {\n if (holders.has(name)) return;\n\n const waiter = queues.get(name)?.shift();\n\n if (!waiter) return;\n\n waiter.granted = true;\n holders.set(name, waiter);\n\n const settle = (settleWaiter: () => void) => {\n // Only if this waiter is still the holder: a stolen lock already has a new one, and the callback\n // of the tab it was taken from settles afterwards.\n if (holders.get(name) === waiter) holders.delete(name);\n\n waiter.releaseSignal();\n settleWaiter();\n pump(name);\n };\n\n // `pump` itself only ever runs from a microtask, so calling the callback right here keeps the\n // grant exactly one microtask away from the `request()` call - which is what makes a single\n // `flushMultiTabSync()` per hop enough in specs.\n try {\n Promise.resolve(waiter.callback({ name, mode: 'exclusive' } as Lock)).then(\n (value) => settle(() => waiter.resolve(value)),\n (error) => settle(() => waiter.reject(error)),\n );\n } catch (error) {\n settle(() => waiter.reject(error));\n }\n };\n\n const request = (name: string, optionsOrCallback: unknown, maybeCallback?: unknown) => {\n const options = (typeof optionsOrCallback === 'function' ? {} : (optionsOrCallback ?? {})) as LockOptions;\n const callback = (typeof optionsOrCallback === 'function' ? optionsOrCallback : maybeCallback) as (\n lock: Lock | null,\n ) => unknown;\n\n return new Promise((resolve, reject) => {\n if (options.signal?.aborted) {\n reject(abortError());\n\n return;\n }\n\n const waiter: FakeLockWaiter = { callback, resolve, reject, granted: false, releaseSignal: () => undefined };\n const signal = options.signal;\n\n if (signal) {\n const onAbort = () => {\n waiter.releaseSignal();\n\n if (waiter.granted) return;\n\n const queue = queues.get(name);\n\n if (queue)\n queues.set(\n name,\n queue.filter((entry) => entry !== waiter),\n );\n\n reject(abortError());\n };\n\n signal.addEventListener('abort', onAbort);\n waiter.releaseSignal = () => {\n waiter.releaseSignal = () => undefined;\n signal.removeEventListener('abort', onAbort);\n };\n }\n\n if (options.steal) {\n queueMicrotask(() => {\n const holder = holders.get(name);\n\n if (holder) {\n holders.delete(name);\n holder.reject(abortError());\n }\n\n queues.set(name, [waiter, ...(queues.get(name) ?? [])]);\n pump(name);\n });\n\n return;\n }\n\n // Availability is decided a microtask out, not here: that is when the real API decides it too, so\n // two try-locks requested in the same tick still resolve to one winner and one `null`.\n if (options.ifAvailable) {\n queueMicrotask(() => {\n if (holders.has(name) || (queues.get(name)?.length ?? 0) > 0) {\n waiter.releaseSignal();\n Promise.resolve(callback(null)).then(resolve, reject);\n\n return;\n }\n\n queues.set(name, [waiter]);\n pump(name);\n });\n\n return;\n }\n\n queues.set(name, [...(queues.get(name) ?? []), waiter]);\n queueMicrotask(() => pump(name));\n });\n };\n\n // Both lists are reported, because a queued request is how a tab that is *not* the holder still\n // shows up - which is what the auth leader election counts its tabs by.\n const query = () =>\n Promise.resolve({\n held: [...holders.keys()].map((name) => ({ name, mode: 'exclusive' as const })),\n pending: [...queues.entries()].flatMap(([name, waiters]) =>\n waiters.map(() => ({ name, mode: 'exclusive' as const })),\n ),\n });\n\n Object.defineProperty(navigator, 'locks', {\n value: {\n request,\n query,\n },\n configurable: true,\n writable: true,\n });\n\n return {\n heldNames: () => [...holders.keys()],\n pendingNames: () => [...queues.entries()].filter(([, queue]) => queue.length > 0).map(([name]) => name),\n restore: () => {\n for (const waiter of [...holders.values(), ...[...queues.values()].flat()]) waiter.releaseSignal();\n\n holders.clear();\n queues.clear();\n\n if (originalDescriptor) {\n Object.defineProperty(navigator, 'locks', originalDescriptor);\n } else {\n delete (navigator as any).locks;\n }\n },\n };\n};\n\n/**\n * Waits for the fakes' pending work - message delivery (a task) and lock grants (a microtask) - even\n * under fake timers. Awaiting it once is enough for a single hop; a grant that has to wait for another\n * tab's release, or a reply to a delivered message, needs one await per hop.\n */\nexport const flushMultiTabSync = () => new Promise<void>((resolve) => scheduleTask(resolve));\n","import type { PersistedQueryEntry, PersistedQueryEntryMeta, QueryPersistenceAdapter } from '@ethlete/query';\n\n/**\n * An in-memory stand-in for the query client's persisted response store.\n *\n * jsdom has no IndexedDB at all, so this is how persistence is tested - and because the storage\n * adapter is a documented seam rather than a mock of one, a spec running against this exercises the\n * real engine, repository and request code on both the write and the read side.\n *\n * Everything resolves on a microtask, never synchronously, matching the real thing: `await\n * Promise.resolve()` (or `flushMicrotasks`) is what lets a hydration land in a spec.\n */\nexport type FakeQueryPersistenceStoreHandle = {\n /** Pass this as `persistence: { adapter }`. Two clients sharing one handle share one store. */\n adapter: QueryPersistenceAdapter;\n\n /** Pre-populates the store, as if a previous session had written these entries. */\n seed: (entries: PersistedQueryEntry[]) => void;\n\n /** Every entry currently held, in insertion order. */\n entries: () => PersistedQueryEntry[];\n\n /** The entry held under `key`, or `undefined`. */\n entry: (key: string) => PersistedQueryEntry | undefined;\n\n /** How often each adapter method has been called. */\n calls: () => Record<'loadIndex' | 'read' | 'write' | 'remove' | 'clear', number>;\n\n /** Makes the next `count` writes reject - a full disk, by default. */\n failNextWrites: (count: number, error?: unknown) => void;\n\n /** Makes the next `count` removals reject. */\n failNextRemoves: (count: number, error?: unknown) => void;\n\n /** Makes the next `loadIndex` reject. */\n failNextLoadIndex: (error?: unknown) => void;\n\n /**\n * Holds every subsequent `read` pending until {@link flushReads} is called, for testing the window\n * between a cold mount and its hydration (a slow disk, or a mount that happened before startup\n * finished). Each held read returns what the store held when it started, as `loadIndex` does.\n */\n deferReads: () => void;\n\n /** Settles the reads held by {@link deferReads} and stops deferring. */\n flushReads: () => Promise<void>;\n\n /**\n * Holds every subsequent `loadIndex` pending until {@link flushLoadIndex} is called, for testing\n * what happens to the store while a client's startup is still reading its index (a real disk takes\n * milliseconds). The snapshot each held load returns is the one it would have read when it started.\n */\n deferLoadIndex: () => void;\n\n /** Settles the index loads held by {@link deferLoadIndex} and stops deferring. */\n flushLoadIndex: () => Promise<void>;\n};\n\nconst quotaError = () => new DOMException('The quota has been exceeded.', 'QuotaExceededError');\n\nexport const createFakeQueryPersistenceStore = (): FakeQueryPersistenceStoreHandle => {\n const store = new Map<string, PersistedQueryEntry>();\n const calls = { loadIndex: 0, read: 0, write: 0, remove: 0, clear: 0 };\n const deferredReads: Array<() => void> = [];\n const deferredLoadIndexes: Array<() => void> = [];\n\n let failingWrites = 0;\n let writeError: unknown = null;\n let failingRemoves = 0;\n let removeError: unknown = null;\n let loadIndexError: unknown = null;\n let isDeferringReads = false;\n let isDeferringLoadIndex = false;\n\n // Cloning on the way in and on the way out is not pedantry: a real store hands back a copy, so a\n // spec (or the engine) mutating a hydrated body must not be able to change what is \"on disk\".\n const clone = <T>(value: T): T => structuredClone(value);\n\n const loadIndex = async () => {\n calls.loadIndex++;\n\n if (loadIndexError !== null) {\n const error = loadIndexError;\n loadIndexError = null;\n\n throw error;\n }\n\n // Taken before the gate, not after: a real store answers with what it held when the read started,\n // so anything that empties it while a deferred load is held must not change what that load returns.\n const snapshot = Array.from(store.values()).map(\n ({ body: _body, ...meta }) => clone(meta) satisfies PersistedQueryEntryMeta,\n );\n\n if (isDeferringLoadIndex) {\n await new Promise<void>((resolve) => deferredLoadIndexes.push(resolve));\n }\n\n return snapshot;\n };\n\n const read = async (key: string) => {\n calls.read++;\n\n const entry = store.get(key);\n const snapshot = entry ? { body: clone(entry.body), version: entry.version } : null;\n\n if (isDeferringReads) {\n await new Promise<void>((resolve) => deferredReads.push(resolve));\n }\n\n return snapshot;\n };\n\n const write = async (entries: PersistedQueryEntry[]) => {\n calls.write++;\n\n if (failingWrites > 0) {\n failingWrites--;\n\n throw writeError ?? quotaError();\n }\n\n for (const entry of entries) {\n store.set(entry.key, clone(entry));\n }\n };\n\n const remove = async (keys: string[]) => {\n calls.remove++;\n\n if (failingRemoves > 0) {\n failingRemoves--;\n\n throw removeError ?? new Error('The removal failed.');\n }\n\n for (const key of keys) {\n store.delete(key);\n }\n };\n\n const clear = async () => {\n calls.clear++;\n store.clear();\n };\n\n return {\n adapter: { loadIndex, read, write, remove, clear, isSupported: true },\n seed: (entries) => {\n for (const entry of entries) {\n store.set(entry.key, clone(entry));\n }\n },\n entries: () => Array.from(store.values()).map(clone),\n entry: (key) => {\n const entry = store.get(key);\n\n return entry ? clone(entry) : undefined;\n },\n calls: () => ({ ...calls }),\n failNextWrites: (count, error) => {\n failingWrites = count;\n writeError = error ?? null;\n },\n failNextRemoves: (count, error) => {\n failingRemoves = count;\n removeError = error ?? null;\n },\n failNextLoadIndex: (error) => {\n loadIndexError = error ?? quotaError();\n },\n deferReads: () => {\n isDeferringReads = true;\n },\n flushReads: async () => {\n isDeferringReads = false;\n\n const pending = deferredReads.splice(0, deferredReads.length);\n\n for (const resolve of pending) {\n resolve();\n }\n\n await Promise.resolve();\n },\n deferLoadIndex: () => {\n isDeferringLoadIndex = true;\n },\n flushLoadIndex: async () => {\n isDeferringLoadIndex = false;\n\n const pending = deferredLoadIndexes.splice(0, deferredLoadIndexes.length);\n\n for (const resolve of pending) {\n resolve();\n }\n\n await Promise.resolve();\n },\n };\n};\n","import { HttpClient, HttpErrorResponse, provideHttpClient } from '@angular/common/http';\nimport { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';\nimport { DestroyRef, EnvironmentProviders, ErrorHandler, Injector } from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\nimport { provideRouter } from '@angular/router';\nimport {\n AnyCreateQueryClientResult,\n createDeleteQuery,\n createGetQuery,\n createPatchQuery,\n createPostQuery,\n createPutQuery,\n createQueryClient,\n isQueryErrorResponse,\n QueryClientRef,\n} from '@ethlete/query';\n\nexport type QueryTestSetup = {\n queryClient: NonNullable<ReturnType<AnyCreateQueryClientResult['inject']>>;\n queryClientRef: QueryClientRef;\n httpClient: HttpClient;\n httpTesting: HttpTestingController;\n injector: Injector;\n baseUrl: string;\n createGet: ReturnType<typeof createGetQuery>;\n createPost: ReturnType<typeof createPostQuery>;\n createPut: ReturnType<typeof createPutQuery>;\n createPatch: ReturnType<typeof createPatchQuery>;\n createDelete: ReturnType<typeof createDeleteQuery>;\n\n /**\n * Puts back the `console.error` that was installed before the first {@link setupQueryTest} call. Runs\n * on its own when the `TestBed` module is reset; idempotent, and safe to call from any setup.\n */\n restoreConsole: () => void;\n};\n\nexport type QueryTestSetupConfig = {\n baseUrl?: string;\n name?: string;\n /**\n * `true` swallows the `ErrorHandler` reports of failed requests and rethrows every other error, `'all'`\n * swallows everything, `false` keeps Angular's own handler.\n * @default true\n */\n mockErrorHandler?: boolean | 'all';\n};\n\nlet originalError: typeof console.error | null = null;\n\nconst filteredError = (...args: unknown[]) => {\n const message = args[0];\n\n if (message && typeof message === 'object' && 'name' in message && message.name === 'HttpErrorResponse') {\n return;\n }\n\n if (typeof message === 'string' && message.includes('Failed to decrypt bearer token')) {\n return;\n }\n\n if (typeof message === 'string' && message.includes('Failed to extract tokens from')) {\n return;\n }\n\n originalError?.(...args);\n};\n\n// Capture only what is not already the wrapper, so repeated calls reinstall the one filter instead\n// of nesting a new closure over the previous one and stranding the pristine handlers.\nconst installConsoleFilters = () => {\n if (console.error !== filteredError) originalError = console.error;\n\n console.error = filteredError;\n};\n\nconst restoreConsole = () => {\n if (originalError && console.error === filteredError) console.error = originalError;\n\n originalError = null;\n};\n\nconst isFailedRequestError = (error: unknown) => error instanceof HttpErrorResponse || isQueryErrorResponse(error);\n\nconst requestErrorHandler: Pick<ErrorHandler, 'handleError'> = {\n handleError: (error: unknown) => {\n if (isFailedRequestError(error)) return;\n\n throw error;\n },\n};\n\nexport const setupQueryTest = (config?: QueryTestSetupConfig): QueryTestSetup => {\n const baseUrl = config?.baseUrl ?? 'https://api.test.com';\n const name = config?.name ?? 'test';\n const mockErrorHandler = config?.mockErrorHandler ?? true;\n\n installConsoleFilters();\n\n const providers: (EnvironmentProviders | object)[] = [\n provideHttpClient(),\n provideHttpClientTesting(),\n provideRouter([]),\n ];\n\n if (mockErrorHandler) {\n providers.push({\n provide: ErrorHandler,\n useValue: mockErrorHandler === 'all' ? { handleError: () => undefined } : requestErrorHandler,\n });\n }\n\n TestBed.configureTestingModule({ providers });\n\n const queryClientRef = createQueryClient({ baseUrl, name });\n\n return TestBed.runInInjectionContext(() => {\n const { inject } = queryClientRef;\n const queryClient = inject();\n\n TestBed.inject(DestroyRef).onDestroy(restoreConsole);\n\n if (!queryClient) {\n throw new Error('Failed to create query client in test setup');\n }\n\n return {\n queryClient,\n queryClientRef,\n httpClient: TestBed.inject(HttpClient),\n httpTesting: TestBed.inject(HttpTestingController),\n injector: TestBed.inject(Injector),\n baseUrl,\n createGet: createGetQuery(queryClientRef),\n createPost: createPostQuery(queryClientRef),\n createPut: createPutQuery(queryClientRef),\n createPatch: createPatchQuery(queryClientRef),\n createDelete: createDeleteQuery(queryClientRef),\n restoreConsole,\n };\n });\n};\n","import type {\n SocketMessageView,\n WebSocketClientIo,\n WebSocketClientIoOptions,\n WebSocketClientSocket,\n} from '@ethlete/query';\n\n/** A scripted stand-in for `socket.io-client`'s `io`, driven from a spec. */\nexport type WebSocketTestDouble = {\n /** Pass this as `createWebSocketClient({ io })`. */\n io: WebSocketClientIo;\n\n /** The url and options the client called the factory with, or `null` until it did. */\n connection: () => { url: string; transports: string[] | undefined } | null;\n\n /** The `withCredentials` the client asked the factory for, or `null` until it called it. */\n withCredentials: () => boolean | null;\n\n /** The auth payload of every handshake, oldest first - `null` for one made without `auth`. */\n handshakes: () => (object | null)[];\n\n /** Every message the client emitted, newest last - room joins and leaves included, buffered ones too. */\n sent: () => { event: string; data: unknown }[];\n\n /** Every message that reached the server, newest last. An emit buffered while offline lands here on the next connect. */\n delivered: () => { event: string; data: unknown }[];\n\n /**\n * Whether the client asked the socket to connect, and whether it has since disconnected it. `active` is\n * socket.io's own flag - `false` after a server disconnect or a rejected handshake, until the next\n * `connect()`; `connectCalls` counts every `connect()`.\n */\n state: () => { connectRequested: boolean; disconnected: boolean; active: boolean; connectCalls: number };\n\n /**\n * Complete the handshake: flush every buffered emit, then turn the client's `isConnected` true. Pass\n * `recovered: true` for a connection-state-recovered reconnect, in which the server kept the rooms.\n */\n serverConnect: (options?: { recovered?: boolean }) => void;\n\n /**\n * Drop the connection, so `isConnected` turns false. The default reason, `'transport close'`, is one\n * socket.io recovers from itself; `'io server disconnect'` is the server kicking the socket, after which\n * socket.io only reconnects when `connect()` is called again.\n */\n serverDisconnect: (options?: { reason?: 'transport close' | 'io server disconnect' }) => void;\n\n /**\n * Reject the handshake the way a server middleware does: the `auth` payload is recorded in\n * {@link handshakes}, `connect_error` fires and the socket stops reconnecting on its own.\n */\n serverRejectHandshake: (message?: string) => void;\n\n /**\n * Let the ping expire: the socket still reports itself connected, but buffers every emit like socket.io\n * does until it notices and closes. Follow it with {@link serverDisconnect}.\n */\n serverPingExpire: () => void;\n\n /** Deliver a message the way the server would. */\n serverSend: (message: SocketMessageView) => void;\n\n /** Deliver a raw frame, for the malformed-payload path. */\n serverSendRaw: (frame: string) => void;\n};\n\n/**\n * A socket io test double, for specs around `createWebSocketClient` - which takes its `io` factory as\n * an option precisely so a spec (or an app that never opens a socket) needs no `socket.io-client`.\n *\n * Nothing here connects on its own: the client's own `connect()` only flips\n * {@link WebSocketTestDouble.state}, and it is {@link WebSocketTestDouble.serverConnect} that fires\n * the `connect` listener. That split is what makes \"joined a room while disconnected, and it was\n * re-joined after a reconnect\" testable.\n */\nexport const createWebSocketTestDouble = (): WebSocketTestDouble => {\n const sent: { event: string; data: unknown }[] = [];\n const delivered: { event: string; data: unknown }[] = [];\n const buffered: { event: string; data: unknown }[] = [];\n const listeners = {\n connect: [] as (() => void)[],\n disconnect: [] as ((reason: string) => void)[],\n connect_error: [] as ((error: Error) => void)[],\n };\n const anyListeners: ((eventName: string, ...args: unknown[]) => void)[] = [];\n const outgoingListeners: ((eventName: string, ...args: unknown[]) => void)[] = [];\n\n let connection: { url: string; transports: string[] | undefined } | null = null;\n let withCredentials: boolean | null = null;\n let auth: WebSocketClientIoOptions['auth'];\n const handshakes: (object | null)[] = [];\n let connectRequested = false;\n let disconnected = false;\n let connected = false;\n let active = false;\n let connectCalls = 0;\n let pingExpired = false;\n let recovered = false;\n\n const deliver = (message: { event: string; data: unknown }) => {\n for (const listener of outgoingListeners) listener(message.event, message.data);\n delivered.push(message);\n };\n\n const recordHandshake = () => {\n if (auth) auth((data) => handshakes.push(data));\n else handshakes.push(null);\n };\n\n const disconnect = (reason: string) => {\n connected = false;\n pingExpired = false;\n for (const listener of listeners.disconnect) listener(reason);\n };\n\n const socket: WebSocketClientSocket = {\n connect: () => {\n connectRequested = true;\n active = true;\n connectCalls++;\n },\n disconnect: () => {\n disconnected = true;\n active = false;\n if (connected) disconnect('io client disconnect');\n },\n emit: (event, data) => {\n sent.push({ event, data });\n\n if (connected && !pingExpired) deliver({ event, data });\n else buffered.push({ event, data });\n },\n on: (event: 'connect' | 'disconnect' | 'connect_error', listener: (arg: never) => void) =>\n void (listeners[event] as ((arg: never) => void)[]).push(listener),\n onAny: (listener) => void anyListeners.push(listener),\n onAnyOutgoing: (listener) => void outgoingListeners.push(listener),\n get recovered() {\n return recovered;\n },\n get active() {\n return active;\n },\n get sendBuffer() {\n return buffered;\n },\n };\n\n return {\n io: (url, options) => {\n connection = { url, transports: options.transports };\n withCredentials = options.withCredentials;\n auth = options.auth;\n return socket;\n },\n connection: () => connection,\n withCredentials: () => withCredentials,\n handshakes: () => [...handshakes],\n sent: () => [...sent],\n delivered: () => [...delivered],\n state: () => ({ connectRequested, disconnected, active, connectCalls }),\n serverConnect: (options) => {\n recordHandshake();\n\n active = true;\n recovered = options?.recovered ?? false;\n connected = true;\n pingExpired = false;\n\n for (const message of buffered.splice(0)) deliver(message);\n\n for (const listener of listeners.connect) listener();\n },\n serverDisconnect: (options) => {\n const reason = options?.reason ?? 'transport close';\n\n if (reason === 'io server disconnect') active = false;\n\n disconnect(reason);\n },\n serverRejectHandshake: (message) => {\n recordHandshake();\n\n active = false;\n\n for (const listener of listeners.connect_error) listener(new Error(message ?? 'unauthorized'));\n },\n serverPingExpire: () => void (pingExpired = true),\n serverSend: (message) => {\n const frame = JSON.stringify(message);\n for (const listener of anyListeners) listener('message', frame);\n },\n serverSendRaw: (frame) => {\n for (const listener of anyListeners) listener('message', frame);\n },\n };\n};\n","const toBase64Url = (json: string) => {\n const encoded = btoa(\n encodeURIComponent(json).replace(/%([0-9A-F]{2})/g, (_, hex: string) => String.fromCharCode(parseInt(hex, 16))),\n );\n\n return encoded.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n};\n\nexport type MintTestTokenOptions = {\n /** @default 900000 (15 minutes) */\n expiresInMs?: number;\n\n /** Extra payload claims, e.g. the user id or roles `bearerData()` and the auth guards read. */\n claims?: Record<string, unknown>;\n};\n\nlet mintCount = 0;\n\n/**\n * Mints an unsigned JWT the bearer auth provider can decode, with `iat`, `exp` and a unique `jti`.\n * Hand it to `setTokens()` to put the app's own provider into a session.\n *\n * @example\n * ```ts\n * TestBed.runInInjectionContext(() => authProviderRef.inject().setTokens(mintTestToken({ claims: { sub: '1' } }), 'refresh'));\n * ```\n */\nexport const mintTestToken = (options: MintTestTokenOptions = {}) => {\n const { expiresInMs = 15 * 60 * 1000, claims = {} } = options;\n const iat = Math.floor(Date.now() / 1000);\n const exp = Math.floor((Date.now() + expiresInMs) / 1000);\n\n const header = toBase64Url(JSON.stringify({ alg: 'none', typ: 'JWT' }));\n const payload = toBase64Url(JSON.stringify({ iat, exp, jti: ++mintCount, ...claims }));\n\n return `${header}.${payload}.`;\n};\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|