diff --git a/src/settings/rageshake.flush.test.ts b/src/settings/rageshake.flush.test.ts new file mode 100644 index 000000000..2bbe120cc --- /dev/null +++ b/src/settings/rageshake.flush.test.ts @@ -0,0 +1,52 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { afterEach, expect, it, vi } from "vitest"; + +import { init as initRageshake } from "./rageshake"; + +afterEach(() => { + vi.useRealTimers(); + vi.unstubAllGlobals(); +}); + +it("flushes logs to IndexedDB periodically without an explicit flush", async () => { + vi.useFakeTimers(); + const add = vi.fn(); + const txn = { + oncomplete: undefined as (() => void) | undefined, + onerror: undefined, + objectStore: (name: string) => + name === "logs" + ? { + add: (entry: unknown): void => { + add(entry); + queueMicrotask(() => txn.oncomplete?.()); + }, + } + : { put: vi.fn() }, + }; + const open = (): unknown => { + const req = { + result: { transaction: () => txn }, + onsuccess: undefined as (() => void) | undefined, + }; + queueMicrotask(() => req.onsuccess?.()); + return req; + }; + vi.stubGlobal("indexedDB", { open }); + + await initRageshake(); + global.mx_rage_logger.log(1, "test", "hello from the buffer"); + expect(add).not.toHaveBeenCalled(); + + await vi.advanceTimersByTimeAsync(2000); + expect(add).toHaveBeenCalledOnce(); + expect(add.mock.calls[0][0]).toMatchObject({ + lines: expect.stringContaining("hello from the buffer"), + }); +}); diff --git a/src/settings/rageshake.ts b/src/settings/rageshake.ts index b9ecbff50..8fe759a8c 100644 --- a/src/settings/rageshake.ts +++ b/src/settings/rageshake.ts @@ -204,10 +204,13 @@ class IndexedDBLogStore { // Throttled function to flush logs. We use throttle rather // than debounce as we want logs to be written regularly, otherwise // if there's a constant stream of logging, we'd never write anything. - private throttledFlush = throttle(() => this.flush, MAX_FLUSH_INTERVAL_MS, { - leading: false, - trailing: true, - }); + private throttledFlush = throttle( + () => { + this.flush().catch((e) => logger.error("Failed to flush logs", e)); + }, + MAX_FLUSH_INTERVAL_MS, + { leading: false, trailing: true }, + ); /** * Flush logs to disk.