Skip to main content
Glama
windows.test.ts11.4 kB
/** * Tests for Windows Credential Manager Provider * * Tests are designed to run on any platform using mocks. * The actual Windows implementation is tested via integration on Windows CI. * * @package WP_Navigator_MCP * @since 2.7.0 */ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import * as childProcess from 'child_process'; import { WindowsCredentialProvider } from './windows.js'; // Mock child_process for cross-platform testing vi.mock('child_process', async () => { const actual = await vi.importActual<typeof import('child_process')>('child_process'); return { ...actual, execFileSync: vi.fn(), }; }); const mockExecFileSync = vi.mocked(childProcess.execFileSync); // ============================================================================= // Test Setup // ============================================================================= describe('WindowsCredentialProvider', () => { let provider: WindowsCredentialProvider; let originalPlatform: PropertyDescriptor | undefined; beforeEach(() => { provider = new WindowsCredentialProvider(); vi.clearAllMocks(); // Save original platform descriptor originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform'); }); afterEach(() => { // Restore original platform if (originalPlatform) { Object.defineProperty(process, 'platform', originalPlatform); } }); // Helper to mock Windows platform function mockWindows(): void { Object.defineProperty(process, 'platform', { value: 'win32', writable: true, enumerable: true, configurable: true, }); } // Helper to mock non-Windows platform function mockDarwin(): void { Object.defineProperty(process, 'platform', { value: 'darwin', writable: true, enumerable: true, configurable: true, }); } // ============================================================================= // Provider Properties // ============================================================================= describe('name', () => { it('should return "Windows Credential Manager"', () => { expect(provider.name).toBe('Windows Credential Manager'); }); }); describe('available', () => { it('should return false on non-Windows platforms', () => { mockDarwin(); provider = new WindowsCredentialProvider(); expect(provider.available).toBe(false); }); it('should return true on Windows when cmdkey exists', () => { mockWindows(); mockExecFileSync.mockReturnValueOnce(Buffer.from('cmdkey help')); provider = new WindowsCredentialProvider(); expect(provider.available).toBe(true); }); it('should return false on Windows when cmdkey is not available', () => { mockWindows(); mockExecFileSync.mockImplementationOnce(() => { throw new Error('cmdkey not found'); }); provider = new WindowsCredentialProvider(); expect(provider.available).toBe(false); }); }); // ============================================================================= // Store // ============================================================================= describe('store', () => { beforeEach(() => { mockWindows(); }); it('should store credential using cmdkey', async () => { // First call deletes existing (may fail) mockExecFileSync.mockImplementationOnce(() => { throw new Error('not found'); }); // Second call stores new credential mockExecFileSync.mockReturnValueOnce(Buffer.from('')); await provider.store({ service: 'wpnav', account: 'example.com', password: 'test-password', }); // Should have tried delete first, then store expect(mockExecFileSync).toHaveBeenCalledTimes(2); expect(mockExecFileSync).toHaveBeenLastCalledWith( 'cmdkey.exe', ['/generic:wpnav-example.com', '/user:wpnav', '/pass:test-password'], expect.objectContaining({ timeout: 10000 }) ); }); it('should delete existing credential before storing new one', async () => { mockExecFileSync.mockReturnValue(Buffer.from('')); await provider.store({ service: 'wpnav', account: 'site.com', password: 'new-pass', }); // First call should be delete expect(mockExecFileSync).toHaveBeenNthCalledWith( 1, 'cmdkey.exe', ['/delete:wpnav-site.com'], expect.any(Object) ); }); it('should throw on invalid account', async () => { await expect( provider.store({ service: 'wpnav', account: '', password: 'test', }) ).rejects.toThrow('Invalid account'); }); it('should throw on invalid password', async () => { await expect( provider.store({ service: 'wpnav', account: 'example.com', password: '', }) ).rejects.toThrow('Invalid password: cannot be empty'); }); it('should throw on cmdkey failure', async () => { // Delete succeeds mockExecFileSync.mockReturnValueOnce(Buffer.from('')); // Store fails mockExecFileSync.mockImplementationOnce(() => { throw new Error('Access denied'); }); await expect( provider.store({ service: 'wpnav', account: 'example.com', password: 'test', }) ).rejects.toThrow('Failed to store credential in Windows Credential Manager'); }); }); // ============================================================================= // Retrieve // ============================================================================= describe('retrieve', () => { beforeEach(() => { mockWindows(); }); it('should retrieve password via PowerShell', async () => { mockExecFileSync.mockReturnValueOnce('my-secret-password\n'); const password = await provider.retrieve('example.com'); expect(password).toBe('my-secret-password'); expect(mockExecFileSync).toHaveBeenCalledWith( 'powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', expect.stringContaining('WpnavCredManager')], expect.objectContaining({ timeout: 15000 }) ); }); it('should return null when credential not found', async () => { mockExecFileSync.mockReturnValueOnce(''); const password = await provider.retrieve('nonexistent.com'); expect(password).toBeNull(); }); it('should return null on PowerShell error', async () => { mockExecFileSync.mockImplementationOnce(() => { throw new Error('PowerShell error'); }); const password = await provider.retrieve('example.com'); expect(password).toBeNull(); }); it('should throw on invalid account', async () => { await expect(provider.retrieve('')).rejects.toThrow('Invalid account'); }); it('should use correct target format', async () => { mockExecFileSync.mockReturnValueOnce('pass'); await provider.retrieve('blog.example.org'); expect(mockExecFileSync).toHaveBeenCalled(); const call = mockExecFileSync.mock.calls[0]; expect(call).toBeDefined(); const scriptArg = call?.[1]?.[3] as string | undefined; expect(scriptArg).toContain("GetPassword('wpnav-blog.example.org')"); }); }); // ============================================================================= // Delete // ============================================================================= describe('delete', () => { beforeEach(() => { mockWindows(); }); it('should delete credential using cmdkey', async () => { mockExecFileSync.mockReturnValueOnce(Buffer.from('')); const result = await provider.delete('example.com'); expect(result).toBe(true); expect(mockExecFileSync).toHaveBeenCalledWith( 'cmdkey.exe', ['/delete:wpnav-example.com'], expect.objectContaining({ timeout: 10000 }) ); }); it('should return false when credential not found', async () => { mockExecFileSync.mockImplementationOnce(() => { throw new Error('not found'); }); const result = await provider.delete('nonexistent.com'); expect(result).toBe(false); }); it('should throw on invalid account', async () => { await expect(provider.delete('')).rejects.toThrow('Invalid account'); }); }); // ============================================================================= // List // ============================================================================= describe('list', () => { beforeEach(() => { mockWindows(); }); it('should parse cmdkey /list output', async () => { const cmdkeyOutput = ` Currently stored credentials: Target: LegacyGeneric:target=wpnav-example.com Type: Generic User: wpnav Target: LegacyGeneric:target=wpnav-another-site.org Type: Generic User: wpnav Target: SomeOtherCredential Type: Generic User: other `; mockExecFileSync.mockReturnValueOnce(cmdkeyOutput); const accounts = await provider.list(); expect(accounts).toEqual(['another-site.org', 'example.com']); }); it('should handle direct target format', async () => { const cmdkeyOutput = ` Currently stored credentials: Target: wpnav-simple.com Type: Generic User: wpnav `; mockExecFileSync.mockReturnValueOnce(cmdkeyOutput); const accounts = await provider.list(); expect(accounts).toEqual(['simple.com']); }); it('should filter out non-wpnav credentials', async () => { const cmdkeyOutput = ` Currently stored credentials: Target: other-credential Type: Generic User: other Target: wpnav-my-site.com Type: Generic User: wpnav `; mockExecFileSync.mockReturnValueOnce(cmdkeyOutput); const accounts = await provider.list(); expect(accounts).toEqual(['my-site.com']); }); it('should filter out accounts that are too short', async () => { const cmdkeyOutput = ` Target: wpnav-ab Type: Generic `; mockExecFileSync.mockReturnValueOnce(cmdkeyOutput); const accounts = await provider.list(); expect(accounts).toEqual([]); }); it('should return empty array on cmdkey error', async () => { mockExecFileSync.mockImplementationOnce(() => { throw new Error('cmdkey error'); }); const accounts = await provider.list(); expect(accounts).toEqual([]); }); it('should deduplicate accounts', async () => { const cmdkeyOutput = ` Target: wpnav-duplicate.com Target: wpnav-duplicate.com `; mockExecFileSync.mockReturnValueOnce(cmdkeyOutput); const accounts = await provider.list(); expect(accounts).toEqual(['duplicate.com']); }); it('should sort accounts alphabetically', async () => { const cmdkeyOutput = ` Target: wpnav-zebra.com Target: wpnav-alpha.com Target: wpnav-middle.com `; mockExecFileSync.mockReturnValueOnce(cmdkeyOutput); const accounts = await provider.list(); expect(accounts).toEqual(['alpha.com', 'middle.com', 'zebra.com']); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/littlebearapps/wp-navigator-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server