1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-01-20 21:01:29 +01:00

Add matchers for Observable emissions

This commit is contained in:
Matt Gibson 2023-09-28 14:47:02 -04:00 committed by Justin Baur
parent 0425b03ba1
commit 3d2cfa952f
No known key found for this signature in database
GPG Key ID: 46438BBD28B69008
4 changed files with 126 additions and 1 deletions

View File

@ -1 +1,2 @@
export * from "./to-equal-buffer";
export * from "./to-emit";

View File

@ -0,0 +1,54 @@
import { Subject } from "rxjs";
describe("toEmit", () => {
let subject: Subject<boolean>;
beforeEach(() => {
subject = new Subject<boolean>();
});
afterEach(() => {
subject.complete();
});
it("should pass if the observable emits", () => {
subject.next(true);
expect(subject).toEmit();
});
it("should fail if the observable does not emit", () => {
expect(subject).not.toEmit(1);
});
it("should fail if the observable emits after the timeout", () => {
setTimeout(() => subject.next(true), 100);
expect(subject).not.toEmit(1);
});
});
describe("toEmitValue", () => {
let subject: Subject<boolean>;
beforeEach(() => {
subject = new Subject<boolean>();
});
it("should pass if the observable emits the expected value", () => {
subject.next(true);
expect(subject).toEmitValue(true);
});
it("should fail if the observable does not emit the expected value", () => {
subject.next(true);
expect(subject).not.toEmitValue(false);
});
it("should fail if the observable does not emit anything", () => {
expect(subject).not.toEmitValue(true);
});
it("should fail if the observable emits the expected value after the timeout", () => {
setTimeout(() => subject.next(true), 100);
expect(subject).not.toEmitValue(true);
});
});

View File

@ -0,0 +1,62 @@
import { Observable, Subscription } from "rxjs";
/** Asserts that an observable emitted any value */
export const toEmit: jest.CustomMatcher = async function toEmit<T>(
received: Observable<T>,
timeoutMs = 100
) {
return new Promise((resolve) => {
let subscription: Subscription = undefined;
const timeout = setTimeout(() => {
subscription?.unsubscribe();
resolve({
pass: false,
message: () => "expected observable to emit",
});
}, timeoutMs);
subscription = received.subscribe(() => {
clearTimeout(timeout);
resolve({
pass: true,
message: () => "expected observable not to emit",
});
});
});
};
/** Asserts that the first value emitted from an observable is equal to the expected value.
* Optionally, a comparer function can be provided to compare the values. By default, a strict equality check is used.
*/
export const toEmitValue: jest.CustomMatcher = async function toEmitValue<T>(
received: Observable<T>,
expected: T,
comparer?: (a: T, b: T) => boolean,
timeoutMs = 100
) {
comparer = comparer ?? ((a, b) => a === b);
let emitted = false;
const value = await new Promise<T>((resolve) => {
let subscription: Subscription = undefined;
const timeout = setTimeout(() => {
subscription?.unsubscribe();
resolve(undefined);
}, timeoutMs);
subscription = received.subscribe((value) => {
clearTimeout(timeout);
emitted = true;
resolve(value);
});
});
return {
pass: emitted && comparer(value, expected),
message: () =>
comparer(value, expected)
? emitted
? `expected observable not to emit ${expected}`
: `expected observable to emit ${expected}, but it did not emit`
: `expected observable to emit ${expected}, but it emitted `,
};
};

View File

@ -1,6 +1,6 @@
import { webcrypto } from "crypto";
import { toEqualBuffer } from "./spec";
import { toEmit, toEmitValue, toEqualBuffer } from "./spec";
Object.defineProperty(window, "crypto", {
value: webcrypto,
@ -10,8 +10,16 @@ Object.defineProperty(window, "crypto", {
expect.extend({
toEqualBuffer: toEqualBuffer,
toEmit: toEmit,
toEmitValue: toEmitValue,
});
export interface CustomMatchers<R = unknown> {
toEqualBuffer(expected: Uint8Array | ArrayBuffer): R;
toEmit(timeoutMs?: number): R;
toEmitValue(
expected: unknown,
comparer?: (a: unknown, b: unknown) => boolean,
timeoutMs?: number
): R;
}