From 3d365661c90ea468767233a357083cfd538eb47d Mon Sep 17 00:00:00 2001 From: addisonbeck Date: Wed, 30 Jul 2025 16:32:37 -0400 Subject: [PATCH] move trackEmissions and awaitAsync to core-test-utils --- libs/common/spec/index.ts | 1 + libs/common/spec/utils.ts | 56 ----------------------------- libs/core-test-utils/src/index.ts | 60 +++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 56 deletions(-) diff --git a/libs/common/spec/index.ts b/libs/common/spec/index.ts index 90ee121896f..d9157ec9452 100644 --- a/libs/common/spec/index.ts +++ b/libs/common/spec/index.ts @@ -6,3 +6,4 @@ export * from "./fake-state"; export * from "./fake-account-service"; export * from "./fake-storage.service"; export * from "./observable-tracker"; +export { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils"; diff --git a/libs/common/spec/utils.ts b/libs/common/spec/utils.ts index 65b709a201c..1b2b7e1bc74 100644 --- a/libs/common/spec/utils.ts +++ b/libs/common/spec/utils.ts @@ -1,7 +1,6 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { mock, MockProxy } from "jest-mock-extended"; -import { Observable } from "rxjs"; import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; @@ -77,58 +76,3 @@ export const mockFromSdk = (stub: any) => { return `${stub}_fromSdk`; }; - -/** - * Tracks the emissions of the given observable. - * - * Call this function before you expect any emissions and then use code that will cause the observable to emit values, - * then assert after all expected emissions have occurred. - * @param observable - * @returns An array that will be populated with all emissions of the observable. - */ -export function trackEmissions(observable: Observable): T[] { - const emissions: T[] = []; - observable.subscribe((value) => { - switch (value) { - case undefined: - case null: - emissions.push(value); - return; - default: - // process by type - break; - } - - switch (typeof value) { - case "string": - case "number": - case "boolean": - emissions.push(value); - break; - case "symbol": - // Cheating types to make symbols work at all - emissions.push(value.toString() as T); - break; - default: { - emissions.push(clone(value)); - } - } - }); - return emissions; -} - -function clone(value: any): any { - if (global.structuredClone != undefined) { - return structuredClone(value); - } else { - return JSON.parse(JSON.stringify(value)); - } -} - -export async function awaitAsync(ms = 1) { - if (ms < 1) { - await Promise.resolve(); - } else { - await new Promise((resolve) => setTimeout(resolve, ms)); - } -} diff --git a/libs/core-test-utils/src/index.ts b/libs/core-test-utils/src/index.ts index e69de29bb2d..abb60213c55 100644 --- a/libs/core-test-utils/src/index.ts +++ b/libs/core-test-utils/src/index.ts @@ -0,0 +1,60 @@ +import { Observable } from "rxjs"; + +/** + * Tracks all emissions of a given observable and returns them as an array. + * + * Typically used for testing: Call before actions that trigger observable emissions, + * then assert that expected values have been emitted. + * @param observable The observable to track. + * @returns An array of all emitted values. + */ +export function trackEmissions(observable: Observable): T[] { + const emissions: T[] = []; + observable.subscribe((value) => { + switch (value) { + case undefined: + case null: + emissions.push(value); + return; + default: + break; + } + switch (typeof value) { + case "string": + case "number": + case "boolean": + emissions.push(value); + break; + case "symbol": + // Symbols are converted to strings for storage + emissions.push(value.toString() as T); + break; + default: + emissions.push(clone(value)); + } + }); + return emissions; +} + +function clone(value: any): any { + if (global.structuredClone !== undefined) { + return structuredClone(value); + } else { + return JSON.parse(JSON.stringify(value)); + } +} + +/** + * Waits asynchronously for a given number of milliseconds. + * + * If ms < 1, yields to the event loop immediately. + * Useful in tests to await the next tick or introduce artificial delays. + * @param ms Milliseconds to wait (default: 1) + */ +export async function awaitAsync(ms = 1) { + if (ms < 1) { + await Promise.resolve(); + } else { + await new Promise((resolve) => setTimeout(resolve, ms)); + } +}