From 772a791d9af06a1c38fd8329617cc528beed6cd0 Mon Sep 17 00:00:00 2001 From: Amit Haridas Date: Thu, 23 Jul 2026 00:38:51 +0530 Subject: [PATCH] fix(git): git-status IPC returns a flat array, not wrapped object GitOperations.getStatus returns { files: [...] } but the renderer's ipc.file.gitStatus type declares Array<...> and calls result.data.map(). The mismatch made GitStatusPanel.tsx throw 'n.map is not a function' on mount, which blanked the entire React tree. Unwrap result.files in the IPC handler so it returns the array the renderer expects. Add tests covering the success, empty, and non-git branches so this regression cannot recur. Refs: blank-screen-on-md-open --- src/main/files/git.js | 3 +- tests/unit/main/files/git-handler.test.js | 72 +++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 tests/unit/main/files/git-handler.test.js diff --git a/src/main/files/git.js b/src/main/files/git.js index b2611dc..585adf9 100644 --- a/src/main/files/git.js +++ b/src/main/files/git.js @@ -8,7 +8,8 @@ function register(currentFileRef) { const dir = rootPath || (currentFileRef.current ? require('path').dirname(currentFileRef.current) : process.cwd()); - return GitOperations.getStatus(dir); + const result = GitOperations.getStatus(dir); + return Array.isArray(result?.files) ? result.files : []; }); ipcMain.handle('git-stage', async (_event, { rootPath, files }) => { diff --git a/tests/unit/main/files/git-handler.test.js b/tests/unit/main/files/git-handler.test.js new file mode 100644 index 0000000..bfb00e6 --- /dev/null +++ b/tests/unit/main/files/git-handler.test.js @@ -0,0 +1,72 @@ +/** + * Regression: src/main/files/git.js must return a flat array from the + * 'git-status' handler so that the renderer's `result.data.map(...)` works. + * Previously the handler returned `{ files: [...] }` and the renderer blew + * up with `n.map is not a function`, blanking the entire UI. + */ +const EventEmitter = require('events'); + +class FakeIpcMain extends EventEmitter { + constructor() { + super(); + this.handlers = new Map(); + } + handle(channel, handler) { + this.handlers.set(channel, handler); + } +} + +describe('files/git IPC handler', () => { + let ipc; + let register; + let currentFileRef; + + beforeEach(() => { + jest.resetModules(); + ipc = new FakeIpcMain(); + currentFileRef = { current: null }; + jest.doMock('electron', () => ({ ipcMain: ipc })); + jest.doMock('../../../../src/main/GitOperations', () => ({ + getStatus: () => ({ files: [{ filePath: 'a.md', status: 'modified' }] }), + })); + ({ register } = require('../../../../src/main/files/git')); + }); + + test('git-status returns a flat array, not a wrapped object', async () => { + register(currentFileRef); + const handler = ipc.handlers.get('git-status'); + const result = await handler({}, '/repo'); + expect(Array.isArray(result)).toBe(true); + expect(result).toEqual([{ filePath: 'a.md', status: 'modified' }]); + }); + + test('git-status falls back to [] when GitOperations returns no files', async () => { + jest.resetModules(); + ipc = new FakeIpcMain(); + jest.doMock('electron', () => ({ ipcMain: ipc })); + jest.doMock('../../../../src/main/GitOperations', () => ({ + getStatus: () => ({ files: undefined }), + })); + ({ register } = require('../../../../src/main/files/git')); + register(currentFileRef); + const handler = ipc.handlers.get('git-status'); + const result = await handler({}, '/repo'); + expect(Array.isArray(result)).toBe(true); + expect(result).toEqual([]); + }); + + test('git-status returns [] for non-git directories (error path)', async () => { + jest.resetModules(); + ipc = new FakeIpcMain(); + jest.doMock('electron', () => ({ ipcMain: ipc })); + jest.doMock('../../../../src/main/GitOperations', () => ({ + getStatus: () => ({ files: [], error: 'Not a git repository' }), + })); + ({ register } = require('../../../../src/main/files/git')); + register(currentFileRef); + const handler = ipc.handlers.get('git-status'); + const result = await handler({}, '/repo'); + expect(Array.isArray(result)).toBe(true); + expect(result).toEqual([]); + }); +});