feat(cli): Add new timeout and file range options with enhanced logfile diff logging
This commit is contained in:
		| @@ -18,6 +18,7 @@ export class TsTest { | ||||
|   public filterTags: string[]; | ||||
|   public startFromFile: number | null; | ||||
|   public stopAtFile: number | null; | ||||
|   public timeoutSeconds: number | null; | ||||
|  | ||||
|   public smartshellInstance = new plugins.smartshell.Smartshell({ | ||||
|     executor: 'bash', | ||||
| @@ -28,13 +29,14 @@ export class TsTest { | ||||
|  | ||||
|   public tsbundleInstance = new plugins.tsbundle.TsBundle(); | ||||
|  | ||||
|   constructor(cwdArg: string, testPathArg: string, executionModeArg: TestExecutionMode, logOptions: LogOptions = {}, tags: string[] = [], startFromFile: number | null = null, stopAtFile: number | null = null) { | ||||
|   constructor(cwdArg: string, testPathArg: string, executionModeArg: TestExecutionMode, logOptions: LogOptions = {}, tags: string[] = [], startFromFile: number | null = null, stopAtFile: number | null = null, timeoutSeconds: number | null = null) { | ||||
|     this.executionMode = executionModeArg; | ||||
|     this.testDir = new TestDirectory(cwdArg, testPathArg, executionModeArg); | ||||
|     this.logger = new TsTestLogger(logOptions); | ||||
|     this.filterTags = tags; | ||||
|     this.startFromFile = startFromFile; | ||||
|     this.stopAtFile = stopAtFile; | ||||
|     this.timeoutSeconds = timeoutSeconds; | ||||
|   } | ||||
|  | ||||
|   async run() { | ||||
| @@ -147,7 +149,30 @@ export class TsTest { | ||||
|     const execResultStreaming = await this.smartshellInstance.execStreamingSilent( | ||||
|       `tsrun ${fileNameArg}${tsrunOptions}` | ||||
|     ); | ||||
|     await tapParser.handleTapProcess(execResultStreaming.childProcess); | ||||
|      | ||||
|     // Handle timeout if specified | ||||
|     if (this.timeoutSeconds !== null) { | ||||
|       const timeoutMs = this.timeoutSeconds * 1000; | ||||
|       const timeoutPromise = new Promise<void>((_resolve, reject) => { | ||||
|         setTimeout(() => { | ||||
|           execResultStreaming.childProcess.kill('SIGTERM'); | ||||
|           reject(new Error(`Test file timed out after ${this.timeoutSeconds} seconds`)); | ||||
|         }, timeoutMs); | ||||
|       }); | ||||
|        | ||||
|       try { | ||||
|         await Promise.race([ | ||||
|           tapParser.handleTapProcess(execResultStreaming.childProcess), | ||||
|           timeoutPromise | ||||
|         ]); | ||||
|       } catch (error) { | ||||
|         // Handle timeout error | ||||
|         tapParser.handleTimeout(this.timeoutSeconds); | ||||
|       } | ||||
|     } else { | ||||
|       await tapParser.handleTapProcess(execResultStreaming.childProcess); | ||||
|     } | ||||
|      | ||||
|     return tapParser; | ||||
|   } | ||||
|  | ||||
| @@ -205,9 +230,10 @@ export class TsTest { | ||||
|       }); | ||||
|     }); | ||||
|  | ||||
|     // lets do the browser bit | ||||
|     // lets do the browser bit with timeout handling | ||||
|     await this.smartbrowserInstance.start(); | ||||
|     await this.smartbrowserInstance.evaluateOnPage( | ||||
|      | ||||
|     const evaluatePromise = this.smartbrowserInstance.evaluateOnPage( | ||||
|       `http://localhost:3007/test?bundleName=${bundleFileName}`, | ||||
|       async () => { | ||||
|         // lets enable real time comms | ||||
| @@ -264,6 +290,29 @@ export class TsTest { | ||||
|         return logStore.join('\n'); | ||||
|       } | ||||
|     ); | ||||
|      | ||||
|     // Handle timeout if specified | ||||
|     if (this.timeoutSeconds !== null) { | ||||
|       const timeoutMs = this.timeoutSeconds * 1000; | ||||
|       const timeoutPromise = new Promise<void>((_resolve, reject) => { | ||||
|         setTimeout(() => { | ||||
|           reject(new Error(`Test file timed out after ${this.timeoutSeconds} seconds`)); | ||||
|         }, timeoutMs); | ||||
|       }); | ||||
|        | ||||
|       try { | ||||
|         await Promise.race([ | ||||
|           evaluatePromise, | ||||
|           timeoutPromise | ||||
|         ]); | ||||
|       } catch (error) { | ||||
|         // Handle timeout error | ||||
|         tapParser.handleTimeout(this.timeoutSeconds); | ||||
|       } | ||||
|     } else { | ||||
|       await evaluatePromise; | ||||
|     } | ||||
|      | ||||
|     await this.smartbrowserInstance.stop(); | ||||
|     await server.stop(); | ||||
|     wss.close(); | ||||
| @@ -280,28 +329,38 @@ export class TsTest { | ||||
|   private async movePreviousLogFiles() { | ||||
|     const logDir = plugins.path.join('.nogit', 'testlogs'); | ||||
|     const previousDir = plugins.path.join('.nogit', 'testlogs', 'previous'); | ||||
|     const errDir = plugins.path.join('.nogit', 'testlogs', '00err'); | ||||
|     const diffDir = plugins.path.join('.nogit', 'testlogs', '00diff'); | ||||
|      | ||||
|     try { | ||||
|       // Get all files in log directory | ||||
|       // Delete 00err and 00diff directories if they exist | ||||
|       if (await plugins.smartfile.fs.isDirectory(errDir)) { | ||||
|         await plugins.smartfile.fs.remove(errDir); | ||||
|       } | ||||
|       if (await plugins.smartfile.fs.isDirectory(diffDir)) { | ||||
|         await plugins.smartfile.fs.remove(diffDir); | ||||
|       } | ||||
|        | ||||
|       // Get all .log files in log directory (not in subdirectories) | ||||
|       const files = await plugins.smartfile.fs.listFileTree(logDir, '*.log'); | ||||
|       if (files.length === 0) { | ||||
|       const logFiles = files.filter(file => !file.includes('/')); | ||||
|        | ||||
|       if (logFiles.length === 0) { | ||||
|         return; | ||||
|       } | ||||
|        | ||||
|       // Ensure previous directory exists | ||||
|       await plugins.smartfile.fs.ensureDir(previousDir); | ||||
|        | ||||
|       // Move each file to previous directory | ||||
|       for (const file of files) { | ||||
|       // Move each log file to previous directory | ||||
|       for (const file of logFiles) { | ||||
|         const filename = plugins.path.basename(file); | ||||
|         const sourcePath = plugins.path.join(logDir, filename); | ||||
|         const destPath = plugins.path.join(previousDir, filename); | ||||
|          | ||||
|         try { | ||||
|           // Read file content and write to new location | ||||
|           const content = await plugins.smartfile.fs.toStringSync(sourcePath); | ||||
|           await plugins.smartfile.fs.toFs(content, destPath); | ||||
|           // Remove original file | ||||
|           // Copy file to new location and remove original | ||||
|           await plugins.smartfile.fs.copy(sourcePath, destPath); | ||||
|           await plugins.smartfile.fs.remove(sourcePath); | ||||
|         } catch (error) { | ||||
|           // Silently continue if a file can't be moved | ||||
|   | ||||
		Reference in New Issue
	
	Block a user