diff --git a/test/core/completions/installers/bash-installer.test.ts b/test/core/completions/installers/bash-installer.test.ts index 948a3622..726b90d0 100644 --- a/test/core/completions/installers/bash-installer.test.ts +++ b/test/core/completions/installers/bash-installer.test.ts @@ -139,12 +139,11 @@ describe('BashInstaller', () => { }); it('should handle installation errors gracefully', async () => { - // Create installer with non-existent/invalid home directory - // Use a path that will fail on both Unix and Windows - const invalidPath = process.platform === 'win32' - ? 'Z:\\nonexistent\\invalid\\path' // Non-existent drive letter on Windows - : '/root/invalid/nonexistent/path'; // Permission-denied path on Unix - const invalidInstaller = new BashInstaller(invalidPath); + // Create a temporary file and use its path as homeDir + // This guarantees ENOTDIR when trying to create subdirectories (cross-platform) + const blockingFile = path.join(testHomeDir, 'blocking-file'); + await fs.writeFile(blockingFile, 'blocking content'); + const invalidInstaller = new BashInstaller(blockingFile); const result = await invalidInstaller.install(testScript); @@ -377,12 +376,11 @@ describe('BashInstaller', () => { }); it('should handle write permission errors gracefully', async () => { - // Create installer with path that can't be written - // Use a path that will fail on both Unix and Windows - const invalidPath = process.platform === 'win32' - ? 'Z:\\nonexistent\\invalid\\path' // Non-existent drive letter on Windows - : '/root/invalid/path'; // Permission-denied path on Unix - const invalidInstaller = new BashInstaller(invalidPath); + // Create a temporary file and use its path as homeDir + // This guarantees ENOTDIR when trying to write .bashrc (cross-platform) + const blockingFile = path.join(testHomeDir, 'blocking-file'); + await fs.writeFile(blockingFile, 'blocking content'); + const invalidInstaller = new BashInstaller(blockingFile); const result = await invalidInstaller.configureBashrc(completionsDir); diff --git a/test/core/completions/installers/fish-installer.test.ts b/test/core/completions/installers/fish-installer.test.ts index db54f8b0..3993edfd 100644 --- a/test/core/completions/installers/fish-installer.test.ts +++ b/test/core/completions/installers/fish-installer.test.ts @@ -286,7 +286,9 @@ complete -c openspec -a 'init' expect(result.message).toBe('Completion script uninstalled successfully'); }); - it('should return failure on permission error', async () => { + // Skip on Windows: fs.chmod() on directories doesn't restrict write access on Windows + // Windows uses ACLs which Node.js chmod doesn't control + it.skipIf(process.platform === 'win32')('should return failure on permission error', async () => { await installer.install(mockCompletionScript); const targetPath = path.join(testHomeDir, '.config', 'fish', 'completions', 'openspec.fish'); const parentDir = path.dirname(targetPath); diff --git a/test/core/completions/installers/powershell-installer.test.ts b/test/core/completions/installers/powershell-installer.test.ts index 780f6310..27960179 100644 --- a/test/core/completions/installers/powershell-installer.test.ts +++ b/test/core/completions/installers/powershell-installer.test.ts @@ -171,7 +171,9 @@ describe('PowerShellInstaller', () => { expect(content).toContain('Write-Host "Hello"'); }); - it('should skip configuration when script line already exists', async () => { + // Skip on Windows: Windows has dual profile paths (PowerShell Core + Windows PowerShell 5.1), + // so even if one profile is already configured, the second one will be configured and return true + it.skipIf(process.platform === 'win32')('should skip configuration when script line already exists', async () => { delete process.env.OPENSPEC_NO_AUTO_CONFIG; const profilePath = installer.getProfilePath(); await fs.mkdir(path.dirname(profilePath), { recursive: true });