mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-05 09:33:07 +00:00
fix: resolve three critical bugs from GitHub issue tracker
Fix #684: Prevent Windows reserved filename creation - Add sanitizeFilename() utility to detect and prefix Windows reserved names (NUL, CON, PRN, AUX, COM1-9, LPT1-9) - Apply sanitization to save-image route to prevent "nul" file creation - Add 23 comprehensive tests for filename sanitization edge cases Fix #576: Detect actual dev server port from output - Parse stdout/stderr for real server URLs (Vite, Next.js, generic formats) - Update server URL when detected instead of using allocated PORT - Emit dev-server:url-detected event for frontend updates - Add 6 tests for URL detection patterns Fix #193: Commit only feature-specific changes - Change from 'git add -A' to branch-aware file staging - Use git diff to find files changed on feature branch only - Prevent committing unrelated changes from other features - Maintain backward compatibility with main branch workflow All fixes include comprehensive tests and maintain backward compatibility. Test results: 1,968 tests passed (547 package + 1,421 server tests)
This commit is contained in:
@@ -380,6 +380,148 @@ describe('dev-server-service.ts', () => {
|
||||
expect(service.listDevServers().result.servers).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('URL detection from output', () => {
|
||||
it('should detect Vite format URL', async () => {
|
||||
vi.mocked(secureFs.access).mockResolvedValue(undefined);
|
||||
|
||||
const mockProcess = createMockProcess();
|
||||
vi.mocked(spawn).mockReturnValue(mockProcess as any);
|
||||
|
||||
const { getDevServerService } = await import('@/services/dev-server-service.js');
|
||||
const service = getDevServerService();
|
||||
|
||||
// Start server
|
||||
await service.startDevServer(testDir, testDir);
|
||||
|
||||
// Simulate Vite output
|
||||
mockProcess.stdout.emit('data', Buffer.from(' VITE v5.0.0 ready in 123 ms\n'));
|
||||
mockProcess.stdout.emit('data', Buffer.from(' ➜ Local: http://localhost:5173/\n'));
|
||||
|
||||
// Give it a moment to process
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
const serverInfo = service.getServerInfo(testDir);
|
||||
expect(serverInfo?.url).toBe('http://localhost:5173/');
|
||||
expect(serverInfo?.urlDetected).toBe(true);
|
||||
});
|
||||
|
||||
it('should detect Next.js format URL', async () => {
|
||||
vi.mocked(secureFs.access).mockResolvedValue(undefined);
|
||||
|
||||
const mockProcess = createMockProcess();
|
||||
vi.mocked(spawn).mockReturnValue(mockProcess as any);
|
||||
|
||||
const { getDevServerService } = await import('@/services/dev-server-service.js');
|
||||
const service = getDevServerService();
|
||||
|
||||
await service.startDevServer(testDir, testDir);
|
||||
|
||||
// Simulate Next.js output
|
||||
mockProcess.stdout.emit(
|
||||
'data',
|
||||
Buffer.from('ready - started server on 0.0.0.0:3000, url: http://localhost:3000\n')
|
||||
);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
const serverInfo = service.getServerInfo(testDir);
|
||||
expect(serverInfo?.url).toBe('http://localhost:3000');
|
||||
expect(serverInfo?.urlDetected).toBe(true);
|
||||
});
|
||||
|
||||
it('should detect generic localhost URL', async () => {
|
||||
vi.mocked(secureFs.access).mockResolvedValue(undefined);
|
||||
|
||||
const mockProcess = createMockProcess();
|
||||
vi.mocked(spawn).mockReturnValue(mockProcess as any);
|
||||
|
||||
const { getDevServerService } = await import('@/services/dev-server-service.js');
|
||||
const service = getDevServerService();
|
||||
|
||||
await service.startDevServer(testDir, testDir);
|
||||
|
||||
// Simulate generic output with URL
|
||||
mockProcess.stdout.emit('data', Buffer.from('Server running at http://localhost:8080\n'));
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
const serverInfo = service.getServerInfo(testDir);
|
||||
expect(serverInfo?.url).toBe('http://localhost:8080');
|
||||
expect(serverInfo?.urlDetected).toBe(true);
|
||||
});
|
||||
|
||||
it('should keep initial URL if no URL detected in output', async () => {
|
||||
vi.mocked(secureFs.access).mockResolvedValue(undefined);
|
||||
|
||||
const mockProcess = createMockProcess();
|
||||
vi.mocked(spawn).mockReturnValue(mockProcess as any);
|
||||
|
||||
const { getDevServerService } = await import('@/services/dev-server-service.js');
|
||||
const service = getDevServerService();
|
||||
|
||||
const result = await service.startDevServer(testDir, testDir);
|
||||
|
||||
// Simulate output without URL
|
||||
mockProcess.stdout.emit('data', Buffer.from('Server starting...\n'));
|
||||
mockProcess.stdout.emit('data', Buffer.from('Ready!\n'));
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
const serverInfo = service.getServerInfo(testDir);
|
||||
// Should keep the initial allocated URL
|
||||
expect(serverInfo?.url).toBe(result.result?.url);
|
||||
expect(serverInfo?.urlDetected).toBe(false);
|
||||
});
|
||||
|
||||
it('should detect HTTPS URLs', async () => {
|
||||
vi.mocked(secureFs.access).mockResolvedValue(undefined);
|
||||
|
||||
const mockProcess = createMockProcess();
|
||||
vi.mocked(spawn).mockReturnValue(mockProcess as any);
|
||||
|
||||
const { getDevServerService } = await import('@/services/dev-server-service.js');
|
||||
const service = getDevServerService();
|
||||
|
||||
await service.startDevServer(testDir, testDir);
|
||||
|
||||
// Simulate HTTPS dev server
|
||||
mockProcess.stdout.emit('data', Buffer.from('Server at https://localhost:3443\n'));
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
const serverInfo = service.getServerInfo(testDir);
|
||||
expect(serverInfo?.url).toBe('https://localhost:3443');
|
||||
expect(serverInfo?.urlDetected).toBe(true);
|
||||
});
|
||||
|
||||
it('should only detect URL once (not update after first detection)', async () => {
|
||||
vi.mocked(secureFs.access).mockResolvedValue(undefined);
|
||||
|
||||
const mockProcess = createMockProcess();
|
||||
vi.mocked(spawn).mockReturnValue(mockProcess as any);
|
||||
|
||||
const { getDevServerService } = await import('@/services/dev-server-service.js');
|
||||
const service = getDevServerService();
|
||||
|
||||
await service.startDevServer(testDir, testDir);
|
||||
|
||||
// First URL
|
||||
mockProcess.stdout.emit('data', Buffer.from('Local: http://localhost:5173/\n'));
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
const firstUrl = service.getServerInfo(testDir)?.url;
|
||||
|
||||
// Try to emit another URL
|
||||
mockProcess.stdout.emit('data', Buffer.from('Network: http://192.168.1.1:5173/\n'));
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
// Should keep the first detected URL
|
||||
const serverInfo = service.getServerInfo(testDir);
|
||||
expect(serverInfo?.url).toBe(firstUrl);
|
||||
expect(serverInfo?.url).toBe('http://localhost:5173/');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Helper to create a mock child process
|
||||
|
||||
Reference in New Issue
Block a user