 aacb45156b
			
		
	
	aacb45156b
	
	
	
		
			
			- Install Jest for unit testing with React Testing Library - Install Playwright for end-to-end testing - Configure Jest with proper TypeScript support and module mapping - Create test setup files and utilities for both unit and e2e tests Components: * Jest configuration with coverage thresholds * Playwright configuration with browser automation * Unit tests for LoginForm, AuthContext, and useSocketIO hook * E2E tests for authentication, dashboard, and agents workflows * GitHub Actions workflow for automated testing * Mock data and API utilities for consistent testing * Test documentation with best practices Testing features: - Unit tests with 70% coverage threshold - E2E tests with API mocking and user journey testing - CI/CD integration for automated test runs - Cross-browser testing support with Playwright - Authentication system testing end-to-end 🚀 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			190 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| /*
 | |
|  Copyright 2012-2015, Yahoo Inc.
 | |
|  Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 | |
|  */
 | |
| const path = require('path');
 | |
| const fs = require('fs');
 | |
| const mkdirp = require('make-dir');
 | |
| const supportsColor = require('supports-color');
 | |
| 
 | |
| /**
 | |
|  * Base class for writing content
 | |
|  * @class ContentWriter
 | |
|  * @constructor
 | |
|  */
 | |
| class ContentWriter {
 | |
|     /**
 | |
|      * returns the colorized version of a string. Typically,
 | |
|      * content writers that write to files will return the
 | |
|      * same string and ones writing to a tty will wrap it in
 | |
|      * appropriate escape sequences.
 | |
|      * @param {String} str the string to colorize
 | |
|      * @param {String} clazz one of `high`, `medium` or `low`
 | |
|      * @returns {String} the colorized form of the string
 | |
|      */
 | |
|     colorize(str /*, clazz*/) {
 | |
|         return str;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * writes a string appended with a newline to the destination
 | |
|      * @param {String} str the string to write
 | |
|      */
 | |
|     println(str) {
 | |
|         this.write(`${str}\n`);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * closes this content writer. Should be called after all writes are complete.
 | |
|      */
 | |
|     close() {}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * a content writer that writes to a file
 | |
|  * @param {Number} fd - the file descriptor
 | |
|  * @extends ContentWriter
 | |
|  * @constructor
 | |
|  */
 | |
| class FileContentWriter extends ContentWriter {
 | |
|     constructor(fd) {
 | |
|         super();
 | |
| 
 | |
|         this.fd = fd;
 | |
|     }
 | |
| 
 | |
|     write(str) {
 | |
|         fs.writeSync(this.fd, str);
 | |
|     }
 | |
| 
 | |
|     close() {
 | |
|         fs.closeSync(this.fd);
 | |
|     }
 | |
| }
 | |
| 
 | |
| // allow stdout to be captured for tests.
 | |
| let capture = false;
 | |
| let output = '';
 | |
| 
 | |
| /**
 | |
|  * a content writer that writes to the console
 | |
|  * @extends ContentWriter
 | |
|  * @constructor
 | |
|  */
 | |
| class ConsoleWriter extends ContentWriter {
 | |
|     write(str) {
 | |
|         if (capture) {
 | |
|             output += str;
 | |
|         } else {
 | |
|             process.stdout.write(str);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     colorize(str, clazz) {
 | |
|         const colors = {
 | |
|             low: '31;1',
 | |
|             medium: '33;1',
 | |
|             high: '32;1'
 | |
|         };
 | |
| 
 | |
|         /* istanbul ignore next: different modes for CI and local */
 | |
|         if (supportsColor.stdout && colors[clazz]) {
 | |
|             return `\u001b[${colors[clazz]}m${str}\u001b[0m`;
 | |
|         }
 | |
|         return str;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * utility for writing files under a specific directory
 | |
|  * @class FileWriter
 | |
|  * @param {String} baseDir the base directory under which files should be written
 | |
|  * @constructor
 | |
|  */
 | |
| class FileWriter {
 | |
|     constructor(baseDir) {
 | |
|         if (!baseDir) {
 | |
|             throw new Error('baseDir must be specified');
 | |
|         }
 | |
|         this.baseDir = baseDir;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * static helpers for capturing stdout report output;
 | |
|      * super useful for tests!
 | |
|      */
 | |
|     static startCapture() {
 | |
|         capture = true;
 | |
|     }
 | |
| 
 | |
|     static stopCapture() {
 | |
|         capture = false;
 | |
|     }
 | |
| 
 | |
|     static getOutput() {
 | |
|         return output;
 | |
|     }
 | |
| 
 | |
|     static resetOutput() {
 | |
|         output = '';
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * returns a FileWriter that is rooted at the supplied subdirectory
 | |
|      * @param {String} subdir the subdirectory under which to root the
 | |
|      *  returned FileWriter
 | |
|      * @returns {FileWriter}
 | |
|      */
 | |
|     writerForDir(subdir) {
 | |
|         if (path.isAbsolute(subdir)) {
 | |
|             throw new Error(
 | |
|                 `Cannot create subdir writer for absolute path: ${subdir}`
 | |
|             );
 | |
|         }
 | |
|         return new FileWriter(`${this.baseDir}/${subdir}`);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * copies a file from a source directory to a destination name
 | |
|      * @param {String} source path to source file
 | |
|      * @param {String} dest relative path to destination file
 | |
|      * @param {String} [header=undefined] optional text to prepend to destination
 | |
|      *  (e.g., an "this file is autogenerated" comment, copyright notice, etc.)
 | |
|      */
 | |
|     copyFile(source, dest, header) {
 | |
|         if (path.isAbsolute(dest)) {
 | |
|             throw new Error(`Cannot write to absolute path: ${dest}`);
 | |
|         }
 | |
|         dest = path.resolve(this.baseDir, dest);
 | |
|         mkdirp.sync(path.dirname(dest));
 | |
|         let contents;
 | |
|         if (header) {
 | |
|             contents = header + fs.readFileSync(source, 'utf8');
 | |
|         } else {
 | |
|             contents = fs.readFileSync(source);
 | |
|         }
 | |
|         fs.writeFileSync(dest, contents);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * returns a content writer for writing content to the supplied file.
 | |
|      * @param {String|null} file the relative path to the file or the special
 | |
|      *  values `"-"` or `null` for writing to the console
 | |
|      * @returns {ContentWriter}
 | |
|      */
 | |
|     writeFile(file) {
 | |
|         if (file === null || file === '-') {
 | |
|             return new ConsoleWriter();
 | |
|         }
 | |
|         if (path.isAbsolute(file)) {
 | |
|             throw new Error(`Cannot write to absolute path: ${file}`);
 | |
|         }
 | |
|         file = path.resolve(this.baseDir, file);
 | |
|         mkdirp.sync(path.dirname(file));
 | |
|         return new FileContentWriter(fs.openSync(file, 'w'));
 | |
|     }
 | |
| }
 | |
| 
 | |
| module.exports = FileWriter;
 |