Files
Recordly/electron/saveBeforeClose.test.ts

72 lines
2.3 KiB
TypeScript

import { afterEach, expect, it, vi } from "vitest";
import { createSaveBeforeCloseController } from "./saveBeforeClose";
afterEach(() => vi.useRealTimers());
function fixture(discard = false) {
let reply!: (saved: boolean) => void;
const unsubscribe = vi.fn();
const options = {
requestSave: vi.fn(),
subscribe: vi.fn((done: (saved: boolean) => void) => {
reply = done;
return unsubscribe;
}),
offerDiscard: vi.fn().mockResolvedValue(discard),
close: vi.fn(),
cancel: vi.fn(),
timeoutMs: 100,
};
return {
options,
unsubscribe,
reply: (saved: boolean) => reply(saved),
controller: createSaveBeforeCloseController(options),
};
}
it("closes once after saving and removes the listener", () => {
const f = fixture();
f.controller.start();
f.controller.start();
f.reply(true);
f.reply(true);
expect(f.options.requestSave).toHaveBeenCalledTimes(1);
expect(f.options.close).toHaveBeenCalledTimes(1);
expect(f.unsubscribe).toHaveBeenCalledTimes(1);
expect(f.options.offerDiscard).not.toHaveBeenCalled();
});
it.each([true, false])("offers discard/cancel after failed save (discard=%s)", async (discard) => {
const f = fixture(discard);
f.controller.start();
f.reply(false);
await vi.waitFor(() =>
expect(discard ? f.options.close : f.options.cancel).toHaveBeenCalledTimes(1),
);
expect(f.unsubscribe).toHaveBeenCalledTimes(1);
if (!discard) {
f.controller.start();
expect(f.options.requestSave).toHaveBeenCalledTimes(2);
}
});
it("recovers a hung renderer on timeout and ignores late replies", async () => {
vi.useFakeTimers();
const f = fixture();
f.controller.start();
await vi.advanceTimersByTimeAsync(100);
f.reply(true);
expect(f.options.offerDiscard).toHaveBeenCalledTimes(1);
expect(f.options.cancel).toHaveBeenCalledTimes(1);
expect(f.options.close).not.toHaveBeenCalled();
f.controller.start();
expect(f.options.requestSave).toHaveBeenCalledTimes(2);
});
it("removes a pending timeout/listener when the window is destroyed", async () => {
vi.useFakeTimers();
const f = fixture();
f.controller.start();
f.controller.dispose();
await vi.advanceTimersByTimeAsync(100);
f.reply(true);
expect(f.unsubscribe).toHaveBeenCalledTimes(1);
expect(f.options.close).not.toHaveBeenCalled();
expect(f.options.offerDiscard).not.toHaveBeenCalled();
});