207 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import * as plugins from './tstest.plugins.js';
 | |
| import * as paths from './tstest.paths.js';
 | |
| import * as logPrefixes from './tstest.logprefixes.js';
 | |
| 
 | |
| import { coloredString as cs } from '@push.rocks/consolecolor';
 | |
| 
 | |
| import { TestDirectory } from './tstest.classes.testdirectory.js';
 | |
| import { TapCombinator } from './tstest.classes.tap.combinator.js';
 | |
| import { TapParser } from './tstest.classes.tap.parser.js';
 | |
| 
 | |
| export class TsTest {
 | |
|   public testDir: TestDirectory;
 | |
| 
 | |
|   public smartshellInstance = new plugins.smartshell.Smartshell({
 | |
|     executor: 'bash',
 | |
|     pathDirectories: [paths.binDirectory],
 | |
|     sourceFilePaths: [],
 | |
|   });
 | |
|   public smartbrowserInstance = new plugins.smartbrowser.SmartBrowser();
 | |
| 
 | |
|   public tsbundleInstance = new plugins.tsbundle.TsBundle();
 | |
| 
 | |
|   constructor(cwdArg: string, relativePathToTestDirectory: string) {
 | |
|     this.testDir = new TestDirectory(cwdArg, relativePathToTestDirectory);
 | |
|   }
 | |
| 
 | |
|   async run() {
 | |
|     const fileNamesToRun: string[] = await this.testDir.getTestFilePathArray();
 | |
|     console.log(cs(plugins.figures.hamburger.repeat(80), 'cyan'));
 | |
|     console.log('');
 | |
|     console.log(`${logPrefixes.TsTestPrefix} FOUND ${fileNamesToRun.length} TESTFILE(S):`);
 | |
|     for (const fileName of fileNamesToRun) {
 | |
|       console.log(`${logPrefixes.TsTestPrefix} ${cs(fileName, 'orange')}`);
 | |
|     }
 | |
|     console.log('-'.repeat(48));
 | |
|     console.log(''); // force new line
 | |
| 
 | |
|     const tapCombinator = new TapCombinator(); // lets create the TapCombinator
 | |
|     for (const fileNameArg of fileNamesToRun) {
 | |
|       switch (true) {
 | |
|         case process.env.CI && fileNameArg.includes('.nonci.'):
 | |
|           console.log('!!!!!!!!!!!');
 | |
|           console.log(
 | |
|             `not running testfile ${fileNameArg}, since we are CI and file name includes '.nonci.' tag`
 | |
|           );
 | |
|           console.log('!!!!!!!!!!!');
 | |
|           break;
 | |
|         case fileNameArg.endsWith('.browser.ts') || fileNameArg.endsWith('.browser.nonci.ts'):
 | |
|           const tapParserBrowser = await this.runInChrome(fileNameArg);
 | |
|           tapCombinator.addTapParser(tapParserBrowser);
 | |
|           break;
 | |
|         case fileNameArg.endsWith('.both.ts') || fileNameArg.endsWith('.both.nonci.ts'):
 | |
|           console.log('>>>>>>> TEST PART 1: chrome');
 | |
|           const tapParserBothBrowser = await this.runInChrome(fileNameArg);
 | |
|           tapCombinator.addTapParser(tapParserBothBrowser);
 | |
|           console.log(cs(`|`.repeat(16), 'cyan'));
 | |
|           console.log(''); // force new line
 | |
|           console.log('>>>>>>> TEST PART 2: node');
 | |
|           const tapParserBothNode = await this.runInNode(fileNameArg);
 | |
|           tapCombinator.addTapParser(tapParserBothNode);
 | |
|           break;
 | |
|         default:
 | |
|           const tapParserNode = await this.runInNode(fileNameArg);
 | |
|           tapCombinator.addTapParser(tapParserNode);
 | |
|           break;
 | |
|       }
 | |
| 
 | |
|       console.log(cs(`^`.repeat(16), 'cyan'));
 | |
|       console.log(''); // force new line
 | |
|     }
 | |
|     tapCombinator.evaluate();
 | |
|   }
 | |
| 
 | |
|   public async runInNode(fileNameArg: string): Promise<TapParser> {
 | |
|     console.log(`${cs('=> ', 'blue')} Running ${cs(fileNameArg, 'orange')} in node.js runtime.`);
 | |
|     console.log(`${cs(`= `.repeat(32), 'cyan')}`);
 | |
|     const tapParser = new TapParser(fileNameArg + ':node');
 | |
| 
 | |
|     // tsrun options
 | |
|     let tsrunOptions = '';
 | |
|     if (process.argv.includes('--web')) {
 | |
|       tsrunOptions += ' --web';
 | |
|     }
 | |
| 
 | |
|     const execResultStreaming = await this.smartshellInstance.execStreamingSilent(
 | |
|       `tsrun ${fileNameArg}${tsrunOptions}`
 | |
|     );
 | |
|     await tapParser.handleTapProcess(execResultStreaming.childProcess);
 | |
|     return tapParser;
 | |
|   }
 | |
| 
 | |
|   public async runInChrome(fileNameArg: string): Promise<TapParser> {
 | |
|     console.log(`${cs('=> ', 'blue')} Running ${cs(fileNameArg, 'orange')} in chromium runtime.`);
 | |
|     console.log(`${cs(`= `.repeat(32), 'cyan')}`);
 | |
| 
 | |
|     // lets get all our paths sorted
 | |
|     const tsbundleCacheDirPath = plugins.path.join(paths.cwd, './.nogit/tstest_cache');
 | |
|     const bundleFileName = fileNameArg.replace('/', '__') + '.js';
 | |
|     const bundleFilePath = plugins.path.join(tsbundleCacheDirPath, bundleFileName);
 | |
| 
 | |
|     // lets bundle the test
 | |
|     await plugins.smartfile.fs.ensureEmptyDir(tsbundleCacheDirPath);
 | |
|     await this.tsbundleInstance.build(process.cwd(), fileNameArg, bundleFilePath, {
 | |
|       bundler: 'esbuild',
 | |
|     });
 | |
| 
 | |
|     // lets create a server
 | |
|     const server = new plugins.typedserver.servertools.Server({
 | |
|       cors: true,
 | |
|       port: 3007,
 | |
|     });
 | |
|     server.addRoute(
 | |
|       '/test',
 | |
|       new plugins.typedserver.servertools.Handler('GET', async (req, res) => {
 | |
|         res.type('.html');
 | |
|         res.write(`
 | |
|         <html>
 | |
|           <head>
 | |
|             <script>
 | |
|               globalThis.testdom = true;
 | |
|             </script>
 | |
|           </head>
 | |
|           <body></body>
 | |
|         </html>
 | |
|       `);
 | |
|         res.end();
 | |
|       })
 | |
|     );
 | |
|     server.addRoute('*', new plugins.typedserver.servertools.HandlerStatic(tsbundleCacheDirPath));
 | |
|     await server.start();
 | |
| 
 | |
|     // lets handle realtime comms
 | |
|     const tapParser = new TapParser(fileNameArg + ':chrome');
 | |
|     const wss = new plugins.ws.WebSocketServer({ port: 8080 });
 | |
|     wss.on('connection', (ws) => {
 | |
|       ws.on('message', (message) => {
 | |
|         tapParser.handleTapLog(message.toString());
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     // lets do the browser bit
 | |
|     await this.smartbrowserInstance.start();
 | |
|     const evaluation = await this.smartbrowserInstance.evaluateOnPage(
 | |
|       `http://localhost:3007/test?bundleName=${bundleFileName}`,
 | |
|       async () => {
 | |
|         // lets enable real time comms
 | |
|         const ws = new WebSocket('ws://localhost:8080');
 | |
|         await new Promise((resolve) => (ws.onopen = resolve));
 | |
| 
 | |
|         // Ensure this function is declared with 'async'
 | |
|         const logStore = [];
 | |
|         const originalLog = console.log;
 | |
|         const originalError = console.error;
 | |
| 
 | |
|         // Override console methods to capture the logs
 | |
|         console.log = (...args) => {
 | |
|           logStore.push(args.join(' '));
 | |
|           ws.send(args.join(' '));
 | |
|           originalLog(...args);
 | |
|         };
 | |
|         console.error = (...args) => {
 | |
|           logStore.push(args.join(' '));
 | |
|           ws.send(args.join(' '));
 | |
|           originalError(...args);
 | |
|         };
 | |
| 
 | |
|         const bundleName = new URLSearchParams(window.location.search).get('bundleName');
 | |
|         originalLog(`::TSTEST IN CHROMIUM:: Relevant Script name is: ${bundleName}`);
 | |
| 
 | |
|         try {
 | |
|           // Dynamically import the test module
 | |
|           const testModule = await import(`/${bundleName}`);
 | |
|           if (testModule && testModule.default && testModule.default instanceof Promise) {
 | |
|             // Execute the exported test function
 | |
|             await testModule.default;
 | |
|           } else if (testModule && testModule.default && testModule.default.then === 'function') {
 | |
|             console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
 | |
|             console.log('Test module default export is just promiselike: Something might be messing with your Promise implementation.');
 | |
|             console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
 | |
|             await testModule.default;
 | |
|           } else {
 | |
|             console.error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
 | |
|             console.error('Test module does not export a default promise.');
 | |
|             console.error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
 | |
| 
 | |
|           }
 | |
|         } catch (err) {
 | |
|           console.error(err);
 | |
|         }
 | |
| 
 | |
|         return logStore.join('\n');
 | |
|       }
 | |
|     );
 | |
|     await this.smartbrowserInstance.stop();
 | |
|     await server.stop();
 | |
|     wss.close();
 | |
|     console.log(
 | |
|       `${cs('=> ', 'blue')} Stopped ${cs(fileNameArg, 'orange')} chromium instance and server.`
 | |
|     );
 | |
|     // lets create the tap parser
 | |
|     await tapParser.evaluateFinalResult();
 | |
|     return tapParser;
 | |
|   }
 | |
| 
 | |
|   public async runInDeno() {}
 | |
| }
 |