1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-21 10:43:35 +00:00
Files
browser/libs/common/src/vault/utils/skeleton-loading.operator.spec.ts
Nick Krantz b00987180d [PM-26688][PM-27710] Delay skeletons from showing + search (#17394)
* add custom operator for loading skeleton delays

* add `isCipherSearching$` observable to search service

* prevent vault skeleton from showing immediately

* add skeleton for search + delay to sends

* update fade-in-out component selector

* add fade-in-out component for generic use

* address memory leak by using defer to encapsulate `skeletonShownAt`

* add missing provider
2025-11-20 08:26:47 -06:00

110 lines
2.9 KiB
TypeScript

import { BehaviorSubject } from "rxjs";
import { skeletonLoadingDelay } from "./skeleton-loading.operator";
describe("skeletonLoadingDelay", () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
});
it("returns false immediately when starting with false", () => {
const source$ = new BehaviorSubject<boolean>(false);
const results: boolean[] = [];
source$.pipe(skeletonLoadingDelay()).subscribe((value) => results.push(value));
expect(results).toEqual([false]);
});
it("waits 1 second before returning true when starting with true", () => {
const source$ = new BehaviorSubject<boolean>(true);
const results: boolean[] = [];
source$.pipe(skeletonLoadingDelay()).subscribe((value) => results.push(value));
expect(results).toEqual([]);
jest.advanceTimersByTime(999);
expect(results).toEqual([]);
jest.advanceTimersByTime(1);
expect(results).toEqual([true]);
});
it("cancels if source becomes false before show delay completes", () => {
const source$ = new BehaviorSubject<boolean>(true);
const results: boolean[] = [];
source$.pipe(skeletonLoadingDelay()).subscribe((value) => results.push(value));
jest.advanceTimersByTime(500);
source$.next(false);
expect(results).toEqual([false]);
jest.advanceTimersByTime(1000);
expect(results).toEqual([false]);
});
it("delays hiding if minimum display time has not elapsed", () => {
const source$ = new BehaviorSubject<boolean>(true);
const results: boolean[] = [];
source$.pipe(skeletonLoadingDelay()).subscribe((value) => results.push(value));
jest.advanceTimersByTime(1000);
expect(results).toEqual([true]);
source$.next(false);
expect(results).toEqual([true]);
jest.advanceTimersByTime(1000);
expect(results).toEqual([true, false]);
});
it("handles rapid true->false->true transitions", () => {
const source$ = new BehaviorSubject<boolean>(true);
const results: boolean[] = [];
source$.pipe(skeletonLoadingDelay()).subscribe((value) => results.push(value));
jest.advanceTimersByTime(500);
expect(results).toEqual([]);
source$.next(false);
expect(results).toEqual([false]);
source$.next(true);
jest.advanceTimersByTime(999);
expect(results).toEqual([false]);
jest.advanceTimersByTime(1);
expect(results).toEqual([false, true]);
});
it("allows for custom timings", () => {
const source$ = new BehaviorSubject<boolean>(true);
const results: boolean[] = [];
source$.pipe(skeletonLoadingDelay(1000, 2000)).subscribe((value) => results.push(value));
jest.advanceTimersByTime(1000);
expect(results).toEqual([true]);
source$.next(false);
jest.advanceTimersByTime(1999);
expect(results).toEqual([true]);
jest.advanceTimersByTime(1);
expect(results).toEqual([true, false]);
});
});