test(integration): make desktop notifier platform mock hermetic

This commit is contained in:
itrytoohard 2026-06-08 02:54:08 +05:30
parent 62297ed174
commit 02a80b6c7f
1 changed files with 26 additions and 2 deletions

View File

@ -4,7 +4,7 @@
* Mocks ONLY the I/O boundary: node:child_process and node:os.
* Everything else runs for real: config parsing, escaping chains, formatting.
*/
import { describe, it, expect, vi, beforeEach, type Mock } from "vitest";
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
import type { NotifyAction } from "@aoagents/ao-core";
import { makeEvent } from "./helpers/event-factory.js";
@ -24,11 +24,17 @@ vi.mock("node:os", () => ({
platform: vi.fn(() => "darwin"),
}));
import { execFile } from "node:child_process";
import { execFile, execFileSync } from "node:child_process";
import { platform } from "node:os";
const mockExecFile = execFile as unknown as Mock;
const mockExecFileSync = execFileSync as unknown as Mock;
const mockPlatform = platform as unknown as Mock;
const originalProcessPlatform = Object.getOwnPropertyDescriptor(process, "platform");
function setProcessPlatform(value: NodeJS.Platform): void {
Object.defineProperty(process, "platform", { value, configurable: true });
}
// Import the full plugin module — config parsing, escaping, formatting all run for real
import desktopPlugin from "@aoagents/ao-plugin-notifier-desktop";
@ -37,6 +43,12 @@ describe("notifier-desktop integration", () => {
beforeEach(() => {
vi.clearAllMocks();
mockPlatform.mockReturnValue("darwin");
setProcessPlatform("darwin");
mockExecFileSync.mockImplementation(() => {
const error = new Error("not found") as NodeJS.ErrnoException;
error.code = "ENOENT";
throw error;
});
mockExecFile.mockImplementation((..._args: unknown[]) => {
// execFile is called as (cmd, args, cb) on darwin/linux and as
// (cmd, args, opts, cb) on win32 — pick whichever trailing arg is the
@ -48,6 +60,12 @@ describe("notifier-desktop integration", () => {
});
});
afterEach(() => {
if (originalProcessPlatform) {
Object.defineProperty(process, "platform", originalProcessPlatform);
}
});
describe("config -> behavior flow", () => {
it("sound=false config + urgent event -> no sound clause in osascript", async () => {
const notifier = desktopPlugin.create({ sound: false });
@ -124,6 +142,7 @@ describe("notifier-desktop integration", () => {
it("linux -> notify-send with title and message as separate args", async () => {
mockPlatform.mockReturnValue("linux");
setProcessPlatform("linux");
const notifier = desktopPlugin.create();
await notifier.notify(makeEvent({ sessionId: "backend-1", message: "Test msg" }));
@ -135,6 +154,7 @@ describe("notifier-desktop integration", () => {
it("linux + urgent -> --urgency=critical before title", async () => {
mockPlatform.mockReturnValue("linux");
setProcessPlatform("linux");
const notifier = desktopPlugin.create();
await notifier.notify(makeEvent({ priority: "urgent" }));
@ -144,6 +164,7 @@ describe("notifier-desktop integration", () => {
it("linux + info -> no --urgency flag", async () => {
mockPlatform.mockReturnValue("linux");
setProcessPlatform("linux");
const notifier = desktopPlugin.create();
await notifier.notify(makeEvent({ priority: "info" }));
@ -153,6 +174,7 @@ describe("notifier-desktop integration", () => {
it("win32 -> powershell.exe with EncodedCommand toast XML", async () => {
mockPlatform.mockReturnValue("win32");
setProcessPlatform("win32");
const notifier = desktopPlugin.create();
await notifier.notify(makeEvent({ message: "ci test" }));
@ -172,6 +194,7 @@ describe("notifier-desktop integration", () => {
it("unsupported platform -> no execFile, warns", async () => {
mockPlatform.mockReturnValue("freebsd");
setProcessPlatform("freebsd");
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
const notifier = desktopPlugin.create();
await notifier.notify(makeEvent());
@ -222,6 +245,7 @@ describe("notifier-desktop integration", () => {
it("rejects when execFile fails on linux", async () => {
mockPlatform.mockReturnValue("linux");
setProcessPlatform("linux");
mockExecFile.mockImplementation(
(_cmd: string, _args: string[], cb: (err: Error | null) => void) => {
cb(new Error("notify-send: not found"));