From 2b3e2f61884ddb40335843f63adaf6548f815fd1 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 26 Nov 2025 19:13:07 +0100 Subject: [PATCH] test: Enable quality gate and touch a file --- codecov.yaml | 3 +- src/state/ObservableScope.test.ts | 51 ++++++++++++++++++++++++++++++- src/state/ObservableScope.ts | 5 +++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/codecov.yaml b/codecov.yaml index e1289344..f08dc9b2 100644 --- a/codecov.yaml +++ b/codecov.yaml @@ -13,7 +13,6 @@ coverage: informational: true patch: default: - # Encourage (but don't enforce) 80% coverage on all lines that a PR + # Enforce 80% coverage on all lines that a PR # touches target: 80% - informational: true diff --git a/src/state/ObservableScope.test.ts b/src/state/ObservableScope.test.ts index 99f2b424..8513b54b 100644 --- a/src/state/ObservableScope.test.ts +++ b/src/state/ObservableScope.test.ts @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ -import { describe, expect, it } from "vitest"; +import { describe, expect, it, vi } from "vitest"; import { BehaviorSubject, combineLatest, Subject } from "rxjs"; import { logger } from "matrix-js-sdk/lib/logger"; @@ -102,3 +102,52 @@ describe("Epoch", () => { s$.complete(); }); }); + +describe("Reconcile", () => { + it("should wait for cleanup to complete before processing next Value", async () => { + vi.useFakeTimers(); + + const scope = new ObservableScope(); + const cleanUp1 = Promise.withResolvers(); + const cleanUp2 = vi.fn(); + + const behavior$ = new BehaviorSubject(1); + let lastProcessed = 0; + + scope.reconcile( + behavior$, + async (value: number): Promise<(() => Promise) | void> => { + lastProcessed = value; + if (value === 1) { + return Promise.resolve(async (): Promise => cleanUp1.promise); + } else if (value === 2) { + return Promise.resolve(async (): Promise => { + cleanUp2(); + return Promise.resolve(undefined); + }); + } + return Promise.resolve(); + }, + ); + + // behavior$.next(1); + await vi.advanceTimersByTimeAsync(200); + behavior$.next(2); + await vi.advanceTimersByTimeAsync(300); + + await vi.runAllTimersAsync(); + + // Should not have processed 2 yet because cleanup of 1 is pending + expect(lastProcessed).toBe(1); + cleanUp1.resolve(); + // await flushPromises(); + + await vi.runAllTimersAsync(); + // Now 2 should be processed + expect(lastProcessed).toBe(2); + + scope.end(); + await vi.runAllTimersAsync(); + expect(cleanUp2).toHaveBeenCalled(); + }); +}); diff --git a/src/state/ObservableScope.ts b/src/state/ObservableScope.ts index 27f501c7..87a95ba5 100644 --- a/src/state/ObservableScope.ts +++ b/src/state/ObservableScope.ts @@ -117,6 +117,10 @@ export class ObservableScope { * values may be skipped. * * Basically, this is like React's useEffect but async and for Behaviors. + * + * @arg value$ - The Behavior to track. + * @arg callback - Called whenever the value must be handled. May return a clean-up function + * */ public reconcile( value$: Behavior, @@ -221,6 +225,7 @@ export class Epoch { this.value = value; this.epoch = epoch ?? 0; } + /** * Maps the value inside the epoch to a new value while keeping the epoch number. * # usage