/ index.test.ts
index.test.ts
  1  import { describe, it, expect, vi, beforeEach } from "bun:test";
  2  import orgStyleguideReminder, { isOrgFile } from "./index";
  3  import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
  4  
  5  describe("orgStyleguideReminder filter", () => {
  6    it("should return true for .org files", () => {
  7      expect(isOrgFile("test.org")).toBe(true);
  8    });
  9  
 10    it("should return true for .org_archive files", () => {
 11      expect(isOrgFile("test.org_archive")).toBe(true);
 12    });
 13  
 14    it("should return true for .org.gpg files", () => {
 15      expect(isOrgFile("test.org.gpg")).toBe(true);
 16    });
 17  
 18    it("should return false for non-org files", () => {
 19      expect(isOrgFile("test.txt")).toBe(false);
 20      expect(isOrgFile("test.ts")).toBe(false);
 21      expect(isOrgFile(undefined)).toBe(false);
 22    });
 23  });
 24  
 25  describe("orgStyleguideReminder logic", () => {
 26    let mockPi: any;
 27    let mockCtx: any;
 28    let handlers: Record<string, Array<(event: any, ctx: any) => any>>;
 29  
 30    beforeEach(() => {
 31      handlers = {};
 32      mockPi = {
 33        on: (event: string, handler: (event: any, ctx: any) => any) => {
 34          if (!handlers[event]) handlers[event] = [];
 35          handlers[event].push(handler);
 36        },
 37        sendUserMessage: vi.fn(),
 38      };
 39      mockCtx = {
 40        hasUI: true,
 41        ui: {
 42          notify: vi.fn(),
 43        },
 44      };
 45    });
 46  
 47    function triggerEvent(event: string, eventData: any) {
 48      const eventHandlers = handlers[event];
 49      if (eventHandlers) {
 50        eventHandlers.forEach((h) => h(eventData, mockCtx));
 51      }
 52    }
 53  
 54    it("should notify and steer on first org file edit", () => {
 55      orgStyleguideReminder(mockPi);
 56      
 57      triggerEvent("tool_call", {
 58        toolName: "edit",
 59        input: { path: "test.org" },
 60      });
 61  
 62      expect(mockPi.sendUserMessage).toHaveBeenCalledTimes(1);
 63      expect(mockCtx.ui.notify).toHaveBeenCalledTimes(1);
 64    });
 65  
 66    it("should not notify on second org file edit in same session", () => {
 67      orgStyleguideReminder(mockPi);
 68      
 69      triggerEvent("tool_call", {
 70        toolName: "edit",
 71        input: { path: "test.org" },
 72      });
 73      triggerEvent("tool_call", {
 74        toolName: "edit",
 75        input: { path: "another.org" },
 76      });
 77  
 78      expect(mockPi.sendUserMessage).toHaveBeenCalledTimes(1);
 79      expect(mockCtx.ui.notify).toHaveBeenCalledTimes(1);
 80    });
 81  
 82    it("should notify again after session_start", () => {
 83      orgStyleguideReminder(mockPi);
 84      
 85      triggerEvent("tool_call", {
 86        toolName: "edit",
 87        input: { path: "test.org" },
 88      });
 89      triggerEvent("session_start", {});
 90      triggerEvent("tool_call", {
 91        toolName: "edit",
 92        input: { path: "test.org" },
 93      });
 94  
 95      expect(mockPi.sendUserMessage).toHaveBeenCalledTimes(2);
 96      expect(mockCtx.ui.notify).toHaveBeenCalledTimes(2);
 97    });
 98  
 99    it("should not notify for non-org tools", () => {
100      orgStyleguideReminder(mockPi);
101      
102      triggerEvent("tool_call", {
103        toolName: "bash",
104        input: { command: "ls" },
105      });
106  
107      expect(mockPi.sendUserMessage).not.toHaveBeenCalled();
108      expect(mockCtx.ui.notify).not.toHaveBeenCalled();
109    });
110  
111    it("should not notify for non-org files", () => {
112      orgStyleguideReminder(mockPi);
113      
114      triggerEvent("tool_call", {
115        toolName: "edit",
116        input: { path: "test.txt" },
117      });
118  
119      expect(mockPi.sendUserMessage).not.toHaveBeenCalled();
120      expect(mockCtx.ui.notify).not.toHaveBeenCalled();
121    });
122  });