feat(watch mode): Add watch mode support with CLI options and enhanced documentation
This commit is contained in:
		| @@ -101,6 +101,77 @@ export class TsTest { | ||||
|     tapCombinator.evaluate(); | ||||
|   } | ||||
|    | ||||
|   public async runWatch(ignorePatterns: string[] = []) { | ||||
|     const smartchokInstance = new plugins.smartchok.Smartchok([this.testDir.cwd]); | ||||
|      | ||||
|     console.clear(); | ||||
|     this.logger.watchModeStart(); | ||||
|      | ||||
|     // Initial run | ||||
|     await this.run(); | ||||
|      | ||||
|     // Set up file watcher | ||||
|     const fileChanges = new Map<string, NodeJS.Timeout>(); | ||||
|     const debounceTime = 300; // 300ms debounce | ||||
|      | ||||
|     const runTestsAfterChange = async () => { | ||||
|       console.clear(); | ||||
|       const changedFiles = Array.from(fileChanges.keys()); | ||||
|       fileChanges.clear(); | ||||
|        | ||||
|       this.logger.watchModeRerun(changedFiles); | ||||
|       await this.run(); | ||||
|       this.logger.watchModeWaiting(); | ||||
|     }; | ||||
|      | ||||
|     // Start watching before subscribing to events | ||||
|     await smartchokInstance.start(); | ||||
|      | ||||
|     // Subscribe to file change events | ||||
|     const changeObservable = await smartchokInstance.getObservableFor('change'); | ||||
|     const addObservable = await smartchokInstance.getObservableFor('add'); | ||||
|     const unlinkObservable = await smartchokInstance.getObservableFor('unlink'); | ||||
|      | ||||
|     const handleFileChange = (changedPath: string) => { | ||||
|       // Skip if path matches ignore patterns | ||||
|       if (ignorePatterns.some(pattern => changedPath.includes(pattern))) { | ||||
|         return; | ||||
|       } | ||||
|        | ||||
|       // Clear existing timeout for this file if any | ||||
|       if (fileChanges.has(changedPath)) { | ||||
|         clearTimeout(fileChanges.get(changedPath)); | ||||
|       } | ||||
|        | ||||
|       // Set new timeout for this file | ||||
|       const timeout = setTimeout(() => { | ||||
|         fileChanges.delete(changedPath); | ||||
|         if (fileChanges.size === 0) { | ||||
|           runTestsAfterChange(); | ||||
|         } | ||||
|       }, debounceTime); | ||||
|        | ||||
|       fileChanges.set(changedPath, timeout); | ||||
|     }; | ||||
|      | ||||
|     // Subscribe to all relevant events | ||||
|     changeObservable.subscribe(([path]) => handleFileChange(path)); | ||||
|     addObservable.subscribe(([path]) => handleFileChange(path)); | ||||
|     unlinkObservable.subscribe(([path]) => handleFileChange(path)); | ||||
|      | ||||
|     this.logger.watchModeWaiting(); | ||||
|      | ||||
|     // Handle Ctrl+C to exit gracefully | ||||
|     process.on('SIGINT', async () => { | ||||
|       this.logger.watchModeStop(); | ||||
|       await smartchokInstance.stop(); | ||||
|       process.exit(0); | ||||
|     }); | ||||
|      | ||||
|     // Keep the process running | ||||
|     await new Promise(() => {}); // This promise never resolves | ||||
|   } | ||||
|    | ||||
|   private async runSingleTestOrSkip(fileNameArg: string, fileIndex: number, totalFiles: number, tapCombinator: TapCombinator) { | ||||
|     // Check if this file should be skipped based on range | ||||
|     if (this.startFromFile !== null && fileIndex < this.startFromFile) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user