From fc3934097bb8f79a2e9d7a9239bca9d37a1efe06 Mon Sep 17 00:00:00 2001 From: Matthew Breedlove Date: Fri, 27 Feb 2026 13:08:57 -0500 Subject: [PATCH] chore: Fix for test failures when testing with vitest, remove 'test' script from package.json, prefer running tests using 'bun test' --- package.json | 1 - .../__tests__/CurrentWorkingDir.test.ts | 31 ++++++-- src/widgets/__tests__/FreeMemory.test.ts | 77 +++++++++++++------ src/widgets/__tests__/SessionName.test.ts | 15 +++- 4 files changed, 87 insertions(+), 37 deletions(-) diff --git a/package.json b/package.json index edd7f0a..29e2cc0 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "example": "cat scripts/payload.example.json | bun start", "prepublishOnly": "bun run build", "lint": "bun tsc --noEmit; eslint . --config eslint.config.js --max-warnings=999999 --fix", - "test": "bun vitest", "docs": "typedoc", "docs:clean": "rm -rf docs" }, diff --git a/src/widgets/__tests__/CurrentWorkingDir.test.ts b/src/widgets/__tests__/CurrentWorkingDir.test.ts index a75c802..d3b1711 100644 --- a/src/widgets/__tests__/CurrentWorkingDir.test.ts +++ b/src/widgets/__tests__/CurrentWorkingDir.test.ts @@ -1,6 +1,7 @@ import * as os from 'node:os'; import { afterEach, + beforeEach, describe, expect, it, @@ -12,12 +13,24 @@ import type { Settings } from '../../types/Settings'; import type { WidgetItem } from '../../types/Widget'; import { CurrentWorkingDirWidget } from '../CurrentWorkingDir'; +vi.mock('node:os', () => ({ homedir: vi.fn() })); + +const mockHomedir = os.homedir as unknown as { + mockReset: () => void; + mockReturnValue: (value: string) => void; +}; + describe('CurrentWorkingDirWidget', () => { const widget = new CurrentWorkingDirWidget(); - const homeDir = os.homedir(); + const defaultHomeDir = '/Users/alice'; + + beforeEach(() => { + mockHomedir.mockReset(); + mockHomedir.mockReturnValue(defaultHomeDir); + }); afterEach(() => { - vi.restoreAllMocks(); + vi.clearAllMocks(); }); const createContext = (cwd?: string, isPreview = false): RenderContext => ({ @@ -57,10 +70,11 @@ describe('CurrentWorkingDirWidget', () => { describe('abbreviateHome', () => { it('should replace home directory with ~ when enabled', () => { + mockHomedir.mockReturnValue(defaultHomeDir); const item = createItem({ abbreviateHome: 'true' }, true); const result = widget.render( item, - createContext(`${homeDir}/Documents/Projects`), + createContext(`${defaultHomeDir}/Documents/Projects`), defaultSettings ); expect(result).toBe('~/Documents/Projects'); @@ -70,10 +84,10 @@ describe('CurrentWorkingDirWidget', () => { const item = createItem(undefined, true); const result = widget.render( item, - createContext(`${homeDir}/Documents/Projects`), + createContext(`${defaultHomeDir}/Documents/Projects`), defaultSettings ); - expect(result).toBe(`${homeDir}/Documents/Projects`); + expect(result).toBe(`${defaultHomeDir}/Documents/Projects`); }); it('should not modify paths outside home directory', () => { @@ -87,7 +101,7 @@ describe('CurrentWorkingDirWidget', () => { }); it('should not abbreviate non-home sibling paths with shared prefix', () => { - vi.spyOn(os, 'homedir').mockReturnValue('/Users/al'); + mockHomedir.mockReturnValue('/Users/al'); const item = createItem({ abbreviateHome: 'true' }, true); const result = widget.render( @@ -100,10 +114,11 @@ describe('CurrentWorkingDirWidget', () => { }); it('should combine with segments option', () => { + mockHomedir.mockReturnValue(defaultHomeDir); const item = createItem({ abbreviateHome: 'true', segments: '2' }, true); const result = widget.render( item, - createContext(`${homeDir}/Documents/Projects/my-project`), + createContext(`${defaultHomeDir}/Documents/Projects/my-project`), defaultSettings ); expect(result).toBe('~/.../Projects/my-project'); @@ -140,7 +155,7 @@ describe('CurrentWorkingDirWidget', () => { }); it('should preserve windows path separators when combining home abbreviation and segments', () => { - vi.spyOn(os, 'homedir').mockReturnValue('C:\\Users\\alice'); + mockHomedir.mockReturnValue('C:\\Users\\alice'); const item = createItem({ abbreviateHome: 'true', segments: '2' }, true); const result = widget.render( diff --git a/src/widgets/__tests__/FreeMemory.test.ts b/src/widgets/__tests__/FreeMemory.test.ts index 21b5ae8..12a1588 100644 --- a/src/widgets/__tests__/FreeMemory.test.ts +++ b/src/widgets/__tests__/FreeMemory.test.ts @@ -1,4 +1,4 @@ -import * as childProcess from 'child_process'; +import { execSync } from 'child_process'; import os from 'os'; import { afterEach, @@ -16,18 +16,47 @@ import type { import { DEFAULT_SETTINGS } from '../../types/Settings'; import { FreeMemoryWidget } from '../FreeMemory'; +vi.mock('child_process', () => ({ execSync: vi.fn() })); +vi.mock('os', () => { + const mockOs = { + totalmem: vi.fn(), + freemem: vi.fn(), + platform: vi.fn() + }; + + return { + default: mockOs, + ...mockOs + }; +}); + +const mockTotalmem = os.totalmem as unknown as { + mockReturnValue: (value: number) => void; + mockReset: () => void; +}; +const mockFreemem = os.freemem as unknown as { + mockReturnValue: (value: number) => void; + mockReset: () => void; +}; +const mockPlatform = os.platform as unknown as { + mockReturnValue: (value: NodeJS.Platform) => void; + mockReset: () => void; +}; +const mockExecSync = execSync as unknown as { + mockReturnValue: (value: string) => void; + mockImplementation: (impl: () => never) => void; + mockReset: () => void; +}; + describe('FreeMemoryWidget', () => { const widget = new FreeMemoryWidget(); - let totalmemSpy = vi.spyOn(os, 'totalmem'); - let freememSpy = vi.spyOn(os, 'freemem'); - let platformSpy = vi.spyOn(os, 'platform'); - let execSyncSpy = vi.spyOn(childProcess, 'execSync'); beforeEach(() => { - totalmemSpy = vi.spyOn(os, 'totalmem'); - freememSpy = vi.spyOn(os, 'freemem'); - platformSpy = vi.spyOn(os, 'platform'); - execSyncSpy = vi.spyOn(childProcess, 'execSync'); + vi.clearAllMocks(); + mockTotalmem.mockReset(); + mockFreemem.mockReset(); + mockPlatform.mockReset(); + mockExecSync.mockReset(); }); afterEach(() => { @@ -79,14 +108,14 @@ describe('FreeMemoryWidget', () => { describe('render on macOS (vm_stat)', () => { beforeEach(() => { - platformSpy.mockReturnValue('darwin'); - totalmemSpy.mockReturnValue(16 * 1024 ** 3); // 16GB total + mockPlatform.mockReturnValue('darwin'); + mockTotalmem.mockReturnValue(16 * 1024 ** 3); // 16GB total }); it('should calculate used memory from vm_stat (active + wired)', () => { // Page size 16384, active 500000 pages, wired 100000 pages // Used = (500000 + 100000) * 16384 = 9,830,400,000 bytes ≈ 9.2G - execSyncSpy.mockReturnValue(`Mach Virtual Memory Statistics: (page size of 16384 bytes) + mockExecSync.mockReturnValue(`Mach Virtual Memory Statistics: (page size of 16384 bytes) Pages free: 100000. Pages active: 500000. Pages inactive: 200000. @@ -105,7 +134,7 @@ Pages purgeable: 5000. }); it('should show raw value without label', () => { - execSyncSpy.mockReturnValue(`Mach Virtual Memory Statistics: (page size of 16384 bytes) + mockExecSync.mockReturnValue(`Mach Virtual Memory Statistics: (page size of 16384 bytes) Pages free: 100000. Pages active: 500000. Pages inactive: 200000. @@ -121,10 +150,10 @@ Pages wired down: 100000. }); it('should fallback to os.freemem if vm_stat fails', () => { - execSyncSpy.mockImplementation(() => { + mockExecSync.mockImplementation(() => { throw new Error('command not found'); }); - freememSpy.mockReturnValue(8 * 1024 ** 3); // 8GB free -> 8GB used + mockFreemem.mockReturnValue(8 * 1024 ** 3); // 8GB free -> 8GB used const context: RenderContext = {}; const item: WidgetItem = { id: 'mem', type: 'free-memory', rawValue: true }; @@ -135,8 +164,8 @@ Pages wired down: 100000. }); it('should fallback if vm_stat output is malformed', () => { - execSyncSpy.mockReturnValue('garbage output'); - freememSpy.mockReturnValue(4 * 1024 ** 3); // 4GB free -> 12GB used + mockExecSync.mockReturnValue('garbage output'); + mockFreemem.mockReturnValue(4 * 1024 ** 3); // 4GB free -> 12GB used const context: RenderContext = {}; const item: WidgetItem = { id: 'mem', type: 'free-memory', rawValue: true }; @@ -149,12 +178,12 @@ Pages wired down: 100000. describe('render on non-macOS (os.freemem fallback)', () => { beforeEach(() => { - platformSpy.mockReturnValue('linux'); + mockPlatform.mockReturnValue('linux'); }); it('should use total - free calculation on Linux', () => { - freememSpy.mockReturnValue(8 * 1024 ** 3); // 8GB free - totalmemSpy.mockReturnValue(16 * 1024 ** 3); // 16GB total -> 8GB used + mockFreemem.mockReturnValue(8 * 1024 ** 3); // 8GB free + mockTotalmem.mockReturnValue(16 * 1024 ** 3); // 16GB total -> 8GB used const context: RenderContext = {}; const item: WidgetItem = { id: 'mem', type: 'free-memory' }; @@ -165,8 +194,8 @@ Pages wired down: 100000. }); it('should handle fractional gigabytes', () => { - freememSpy.mockReturnValue(4.5 * 1024 ** 3); // 4.5GB free - totalmemSpy.mockReturnValue(32 * 1024 ** 3); // 32GB total -> 27.5GB used + mockFreemem.mockReturnValue(4.5 * 1024 ** 3); // 4.5GB free + mockTotalmem.mockReturnValue(32 * 1024 ** 3); // 32GB total -> 27.5GB used const context: RenderContext = {}; const item: WidgetItem = { id: 'mem', type: 'free-memory', rawValue: true }; @@ -177,8 +206,8 @@ Pages wired down: 100000. }); it('should handle megabyte values', () => { - freememSpy.mockReturnValue(512 * 1024 ** 2); // 512MB free - totalmemSpy.mockReturnValue(1024 * 1024 ** 2); // 1GB total -> 512MB used + mockFreemem.mockReturnValue(512 * 1024 ** 2); // 512MB free + mockTotalmem.mockReturnValue(1024 * 1024 ** 2); // 1GB total -> 512MB used const context: RenderContext = {}; const item: WidgetItem = { id: 'mem', type: 'free-memory', rawValue: true }; diff --git a/src/widgets/__tests__/SessionName.test.ts b/src/widgets/__tests__/SessionName.test.ts index 3ccaad7..b26e3a2 100644 --- a/src/widgets/__tests__/SessionName.test.ts +++ b/src/widgets/__tests__/SessionName.test.ts @@ -1,4 +1,4 @@ -import * as fs from 'fs'; +import { readFileSync } from 'fs'; import { afterEach, beforeEach, @@ -15,6 +15,13 @@ import type { import { DEFAULT_SETTINGS } from '../../types/Settings'; import { SessionNameWidget } from '../SessionName'; +vi.mock('fs', () => ({ readFileSync: vi.fn() })); + +const mockReadFileSync = readFileSync as unknown as { + mockImplementation: (impl: () => string) => void; + mockReset: () => void; +}; + function render(transcriptPath: string | undefined, fileContent: string | null, rawValue = false, isPreview = false) { const widget = new SessionNameWidget(); const context: RenderContext = { @@ -27,11 +34,10 @@ function render(transcriptPath: string | undefined, fileContent: string | null, rawValue }; - const readFileSyncSpy = vi.spyOn(fs, 'readFileSync'); if (fileContent !== null) { - readFileSyncSpy.mockImplementation(() => fileContent as never); + mockReadFileSync.mockImplementation(() => fileContent); } else { - readFileSyncSpy.mockImplementation(() => { + mockReadFileSync.mockImplementation(() => { throw new Error('File not found'); }); } @@ -42,6 +48,7 @@ function render(transcriptPath: string | undefined, fileContent: string | null, describe('SessionNameWidget', () => { beforeEach(() => { vi.clearAllMocks(); + mockReadFileSync.mockReset(); }); afterEach(() => {