import { assert, describe, it } from "@effect/vitest";import * as Effect from "effect/Effect";import { beforeEach, vi } from "vite-plus/test"; const { onMock, removeListenerMock, themeState } = vi.hoisted(() => ({ onMock: vi.fn(), removeListenerMock: vi.fn(), themeState: { shouldUseDarkColors: true, themeSource: "system", setSourceError: null as unknown, },})); vi.mock("electron", () => ({ nativeTheme: { get shouldUseDarkColors() { return themeState.shouldUseDarkColors; }, set themeSource(value: string) { if (themeState.setSourceError !== null) { throw themeState.setSourceError; } themeState.themeSource = value; }, on: onMock, removeListener: removeListenerMock, },})); import * as ElectronTheme from "./ElectronTheme.ts"; describe("ElectronTheme", () => { beforeEach(() => { onMock.mockClear(); removeListenerMock.mockClear(); themeState.shouldUseDarkColors = true; themeState.themeSource = "system"; themeState.setSourceError = null; }); it.effect("scopes native theme update listeners", () => Effect.gen(function* () { const listener = vi.fn(); yield* Effect.scoped( Effect.gen(function* () { const electronTheme = yield* ElectronTheme.ElectronTheme; yield* electronTheme.onUpdated(listener); }), ); assert.deepEqual(onMock.mock.calls, [["updated", listener]]); assert.deepEqual(removeListenerMock.mock.calls, [["updated", listener]]); }).pipe(Effect.provide(ElectronTheme.layer)), ); it.effect("preserves the requested source and cause when setting the theme fails", () => Effect.gen(function* () { const cause = new Error("theme source failed"); themeState.setSourceError = cause; const electronTheme = yield* ElectronTheme.ElectronTheme; const error = yield* Effect.flip(electronTheme.setSource("dark")); assert.instanceOf(error, ElectronTheme.ElectronThemeSetSourceError); assert.strictEqual(error.source, "dark"); assert.strictEqual(error.cause, cause); assert.include(error.message, "dark"); assert.notInclude(error.message, cause.message); }).pipe(Effect.provide(ElectronTheme.layer)), );});
import { assert, describe, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import { beforeEach, vi } from "vite-plus/test";
const { onMock, removeListenerMock, themeState } = vi.hoisted(() => ({
onMock: vi.fn(),
removeListenerMock: vi.fn(),
themeState: {
shouldUseDarkColors: true,
themeSource: "system",
setSourceError: null as unknown,
},
}));
vi.mock("electron", () => ({
nativeTheme: {
get shouldUseDarkColors() {
return themeState.shouldUseDarkColors;
},
set themeSource(value: string) {
if (themeState.setSourceError !== null) {
throw themeState.setSourceError;
}
themeState.themeSource = value;
},
on: onMock,
removeListener: removeListenerMock,
},
}));
import * as ElectronTheme from "./ElectronTheme.ts";
describe("ElectronTheme", () => {
beforeEach(() => {
onMock.mockClear();
removeListenerMock.mockClear();
themeState.shouldUseDarkColors = true;
themeState.themeSource = "system";
themeState.setSourceError = null;
});
it.effect("scopes native theme update listeners", () =>
Effect.gen(function* () {
const listener = vi.fn();
yield* Effect.scoped(
Effect.gen(function* () {
const electronTheme = yield* ElectronTheme.ElectronTheme;
yield* electronTheme.onUpdated(listener);
}),
);
assert.deepEqual(onMock.mock.calls, [["updated", listener]]);
assert.deepEqual(removeListenerMock.mock.calls, [["updated", listener]]);
}).pipe(Effect.provide(ElectronTheme.layer)),
);
it.effect("preserves the requested source and cause when setting the theme fails", () =>
Effect.gen(function* () {
const cause = new Error("theme source failed");
themeState.setSourceError = cause;
const electronTheme = yield* ElectronTheme.ElectronTheme;
const error = yield* Effect.flip(electronTheme.setSource("dark"));
assert.instanceOf(error, ElectronTheme.ElectronThemeSetSourceError);
assert.strictEqual(error.source, "dark");
assert.strictEqual(error.cause, cause);
assert.include(error.message, "dark");
assert.notInclude(error.message, cause.message);
}).pipe(Effect.provide(ElectronTheme.layer)),
);
});