 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>
		
			
				
	
	
		
			407 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			407 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  * Jake JavaScript build tool
 | |
|  * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *         http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  *
 | |
| */
 | |
| 
 | |
| let path = require('path');
 | |
| let fs = require('fs');
 | |
| let exec = require('child_process').exec;
 | |
| let FileList = require('filelist').FileList;
 | |
| 
 | |
| /**
 | |
|   @name jake
 | |
|   @namespace jake
 | |
| */
 | |
| /**
 | |
|   @name jake.PackageTask
 | |
|   @constructor
 | |
|   @description Instantiating a PackageTask creates a number of Jake
 | |
|   Tasks that make packaging and distributing your software easy.
 | |
| 
 | |
|   @param {String} name The name of the project
 | |
|   @param {String} version The current project version (will be
 | |
|   appended to the project-name in the package-archive
 | |
|   @param {Function} definition Defines the contents of the package,
 | |
|   and format of the package-archive. Will be executed on the instantiated
 | |
|   PackageTask (i.e., 'this', will be the PackageTask instance),
 | |
|   to set the various instance-propertiess.
 | |
| 
 | |
|   @example
 | |
|   let t = new jake.PackageTask('rous', 'v' + version, function () {
 | |
|     let files = [
 | |
|       'Capfile'
 | |
|     , 'Jakefile'
 | |
|     , 'README.md'
 | |
|     , 'package.json'
 | |
|     , 'app/*'
 | |
|     , 'bin/*'
 | |
|     , 'config/*'
 | |
|     , 'lib/*'
 | |
|     , 'node_modules/*'
 | |
|     ];
 | |
|     this.packageFiles.include(files);
 | |
|     this.packageFiles.exclude('node_modules/foobar');
 | |
|     this.needTarGz = true;
 | |
|   });
 | |
| 
 | |
|  */
 | |
| let PackageTask = function () {
 | |
|   let args = Array.prototype.slice.call(arguments);
 | |
|   let name = args.shift();
 | |
|   let version = args.shift();
 | |
|   let definition = args.pop();
 | |
|   let prereqs = args.pop() || []; // Optional
 | |
| 
 | |
|   prereqs = [].concat(prereqs); // Accept string or list
 | |
| 
 | |
|   /**
 | |
|     @name jake.PackageTask#name
 | |
|     @public
 | |
|     @type {String}
 | |
|     @description The name of the project
 | |
|    */
 | |
|   this.name = name;
 | |
|   /**
 | |
|     @name jake.PackageTask#version
 | |
|     @public
 | |
|     @type {String}
 | |
|     @description The project version-string
 | |
|    */
 | |
|   this.version = version;
 | |
|   /**
 | |
|     @name jake.PackageTask#prereqs
 | |
|     @public
 | |
|     @type {Array}
 | |
|     @description Tasks to run before packaging
 | |
|    */
 | |
|   this.prereqs = prereqs;
 | |
|   /**
 | |
|     @name jake.PackageTask#packageDir
 | |
|     @public
 | |
|     @type {String='pkg'}
 | |
|     @description The directory-name to use for packaging the software
 | |
|    */
 | |
|   this.packageDir = 'pkg';
 | |
|   /**
 | |
|     @name jake.PackageTask#packageFiles
 | |
|     @public
 | |
|     @type {jake.FileList}
 | |
|     @description The list of files and directories to include in the
 | |
|     package-archive
 | |
|    */
 | |
|   this.packageFiles = new FileList();
 | |
|   /**
 | |
|     @name jake.PackageTask#needTar
 | |
|     @public
 | |
|     @type {Boolean=false}
 | |
|     @description If set to true, uses the `tar` utility to create
 | |
|     a gzip .tgz archive of the package
 | |
|    */
 | |
|   this.needTar = false;
 | |
|   /**
 | |
|     @name jake.PackageTask#needTarGz
 | |
|     @public
 | |
|     @type {Boolean=false}
 | |
|     @description If set to true, uses the `tar` utility to create
 | |
|     a gzip .tar.gz archive of the package
 | |
|    */
 | |
|   this.needTarGz = false;
 | |
|   /**
 | |
|     @name jake.PackageTask#needTarBz2
 | |
|     @public
 | |
|     @type {Boolean=false}
 | |
|     @description If set to true, uses the `tar` utility to create
 | |
|     a bzip2 .bz2 archive of the package
 | |
|    */
 | |
|   this.needTarBz2 = false;
 | |
|   /**
 | |
|     @name jake.PackageTask#needJar
 | |
|     @public
 | |
|     @type {Boolean=false}
 | |
|     @description If set to true, uses the `jar` utility to create
 | |
|     a .jar archive of the package
 | |
|    */
 | |
|   this.needJar = false;
 | |
|   /**
 | |
|     @name jake.PackageTask#needZip
 | |
|     @public
 | |
|     @type {Boolean=false}
 | |
|     @description If set to true, uses the `zip` utility to create
 | |
|     a .zip archive of the package
 | |
|    */
 | |
|   this.needZip = false;
 | |
|   /**
 | |
|     @name jake.PackageTask#manifestFile
 | |
|     @public
 | |
|     @type {String=null}
 | |
|     @description Can be set to point the `jar` utility at a manifest
 | |
|     file to use in a .jar archive. If unset, one will be automatically
 | |
|     created by the `jar` utility. This path should be relative to the
 | |
|     root of the package directory (this.packageDir above, likely 'pkg')
 | |
|    */
 | |
|   this.manifestFile = null;
 | |
|   /**
 | |
|     @name jake.PackageTask#tarCommand
 | |
|     @public
 | |
|     @type {String='tar'}
 | |
|     @description The shell-command to use for creating tar archives.
 | |
|    */
 | |
|   this.tarCommand = 'tar';
 | |
|   /**
 | |
|     @name jake.PackageTask#jarCommand
 | |
|     @public
 | |
|     @type {String='jar'}
 | |
|     @description The shell-command to use for creating jar archives.
 | |
|    */
 | |
|   this.jarCommand = 'jar';
 | |
|   /**
 | |
|     @name jake.PackageTask#zipCommand
 | |
|     @public
 | |
|     @type {String='zip'}
 | |
|     @description The shell-command to use for creating zip archives.
 | |
|    */
 | |
|   this.zipCommand = 'zip';
 | |
|   /**
 | |
|     @name jake.PackageTask#archiveNoBaseDir
 | |
|     @public
 | |
|     @type {Boolean=false}
 | |
|     @description Simple option for performing the archive on the
 | |
|     contents of the directory instead of the directory itself
 | |
|    */
 | |
|   this.archiveNoBaseDir = false;
 | |
|   /**
 | |
|     @name jake.PackageTask#archiveChangeDir
 | |
|     @public
 | |
|     @type {String=null}
 | |
|     @description Equivalent to the '-C' command for the `tar` and `jar`
 | |
|     commands. ("Change to this directory before adding files.")
 | |
|    */
 | |
|   this.archiveChangeDir = null;
 | |
|   /**
 | |
|     @name jake.PackageTask#archiveContentDir
 | |
|     @public
 | |
|     @type {String=null}
 | |
|     @description Specifies the files and directories to include in the
 | |
|     package-archive. If unset, this will default to the main package
 | |
|     directory -- i.e., name + version.
 | |
|    */
 | |
|   this.archiveContentDir = null;
 | |
| 
 | |
|   if (typeof definition == 'function') {
 | |
|     definition.call(this);
 | |
|   }
 | |
|   this.define();
 | |
| };
 | |
| 
 | |
| PackageTask.prototype = new (function () {
 | |
| 
 | |
|   let _compressOpts = {
 | |
|     Tar: {
 | |
|       ext: '.tgz',
 | |
|       flags: 'czf',
 | |
|       cmd: 'tar'
 | |
|     },
 | |
|     TarGz: {
 | |
|       ext: '.tar.gz',
 | |
|       flags: 'czf',
 | |
|       cmd: 'tar'
 | |
|     },
 | |
|     TarBz2: {
 | |
|       ext: '.tar.bz2',
 | |
|       flags: 'cjf',
 | |
|       cmd: 'tar'
 | |
|     },
 | |
|     Jar: {
 | |
|       ext: '.jar',
 | |
|       flags: 'cf',
 | |
|       cmd: 'jar'
 | |
|     },
 | |
|     Zip: {
 | |
|       ext: '.zip',
 | |
|       flags: 'qr',
 | |
|       cmd: 'zip'
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   this.define = function () {
 | |
|     let self = this;
 | |
|     let packageDirPath = this.packageDirPath();
 | |
|     let compressTaskArr = [];
 | |
| 
 | |
|     desc('Build the package for distribution');
 | |
|     task('package', self.prereqs.concat(['clobberPackage', 'buildPackage']));
 | |
|     // Backward-compat alias
 | |
|     task('repackage', ['package']);
 | |
| 
 | |
|     task('clobberPackage', function () {
 | |
|       jake.rmRf(self.packageDir, {silent: true});
 | |
|     });
 | |
| 
 | |
|     desc('Remove the package');
 | |
|     task('clobber', ['clobberPackage']);
 | |
| 
 | |
|     let doCommand = function (p) {
 | |
|       let filename = path.resolve(self.packageDir + '/' + self.packageName() +
 | |
|                                   _compressOpts[p].ext);
 | |
|       if (process.platform == 'win32') {
 | |
|         // Windows full path may have drive letter, which is going to cause
 | |
|         // namespace problems, so strip it.
 | |
|         if (filename.length > 2 && filename[1] == ':') {
 | |
|           filename = filename.substr(2);
 | |
|         }
 | |
|       }
 | |
|       compressTaskArr.push(filename);
 | |
| 
 | |
|       file(filename, [packageDirPath], function () {
 | |
|         let cmd;
 | |
|         let opts = _compressOpts[p];
 | |
|         // Directory to move to when doing the compression-task
 | |
|         // Changes in the case of zip for emulating -C option
 | |
|         let chdir = self.packageDir;
 | |
|         // Save the current dir so it's possible to pop back up
 | |
|         // after compressing
 | |
|         let currDir = process.cwd();
 | |
|         let archiveChangeDir;
 | |
|         let archiveContentDir;
 | |
| 
 | |
|         if (self.archiveNoBaseDir) {
 | |
|           archiveChangeDir = self.packageName();
 | |
|           archiveContentDir = '.';
 | |
|         }
 | |
|         else {
 | |
|           archiveChangeDir = self.archiveChangeDir;
 | |
|           archiveContentDir = self.archiveContentDir;
 | |
|         }
 | |
| 
 | |
|         cmd = self[opts.cmd + 'Command'];
 | |
|         cmd += ' -' + opts.flags;
 | |
|         if (opts.cmd == 'jar' && self.manifestFile) {
 | |
|           cmd += 'm';
 | |
|         }
 | |
| 
 | |
|         // The name of the archive to create -- use full path
 | |
|         // so compression can be performed from a different dir
 | |
|         // if needed
 | |
|         cmd += ' ' + filename;
 | |
| 
 | |
|         if (opts.cmd == 'jar' && self.manifestFile) {
 | |
|           cmd += ' ' + self.manifestFile;
 | |
|         }
 | |
| 
 | |
|         // Where to perform the compression -- -C option isn't
 | |
|         // supported in zip, so actually do process.chdir for this
 | |
|         if (archiveChangeDir) {
 | |
|           if (opts.cmd == 'zip') {
 | |
|             chdir = path.join(chdir, archiveChangeDir);
 | |
|           }
 | |
|           else {
 | |
|             cmd += ' -C ' + archiveChangeDir;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         // Where to get the archive content
 | |
|         if (archiveContentDir) {
 | |
|           cmd += ' ' + archiveContentDir;
 | |
|         }
 | |
|         else {
 | |
|           cmd += ' ' + self.packageName();
 | |
|         }
 | |
| 
 | |
|         // Move into the desired dir (usually packageDir) to compress
 | |
|         // Return back up to the current dir after the exec
 | |
|         process.chdir(chdir);
 | |
| 
 | |
|         exec(cmd, function (err, stdout, stderr) {
 | |
|           if (err) { throw err; }
 | |
| 
 | |
|           // Return back up to the starting directory (see above,
 | |
|           // before exec)
 | |
|           process.chdir(currDir);
 | |
| 
 | |
|           complete();
 | |
|         });
 | |
|       }, {async: true});
 | |
|     };
 | |
| 
 | |
|     for (let p in _compressOpts) {
 | |
|       if (this['need' + p]) {
 | |
|         doCommand(p);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     task('buildPackage', compressTaskArr, function () {});
 | |
| 
 | |
|     directory(this.packageDir);
 | |
| 
 | |
|     file(packageDirPath, this.packageFiles, function () {
 | |
|       jake.mkdirP(packageDirPath);
 | |
|       let fileList = [];
 | |
|       self.packageFiles.forEach(function (name) {
 | |
|         let f = path.join(self.packageDirPath(), name);
 | |
|         let fDir = path.dirname(f);
 | |
|         jake.mkdirP(fDir, {silent: true});
 | |
| 
 | |
|         // Add both files and directories
 | |
|         fileList.push({
 | |
|           from: name,
 | |
|           to: f
 | |
|         });
 | |
|       });
 | |
|       let _copyFile = function () {
 | |
|         let file = fileList.pop();
 | |
|         let stat;
 | |
|         if (file) {
 | |
|           stat = fs.statSync(file.from);
 | |
|           // Target is a directory, just create it
 | |
|           if (stat.isDirectory()) {
 | |
|             jake.mkdirP(file.to, {silent: true});
 | |
|             _copyFile();
 | |
|           }
 | |
|           // Otherwise copy the file
 | |
|           else {
 | |
|             jake.cpR(file.from, file.to, {silent: true});
 | |
|             _copyFile();
 | |
|           }
 | |
|         }
 | |
|         else {
 | |
|           complete();
 | |
|         }
 | |
|       };
 | |
|       _copyFile();
 | |
|     }, {async: true});
 | |
| 
 | |
| 
 | |
|   };
 | |
| 
 | |
|   this.packageName = function () {
 | |
|     if (this.version) {
 | |
|       return this.name + '-' + this.version;
 | |
|     }
 | |
|     else {
 | |
|       return this.name;
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   this.packageDirPath = function () {
 | |
|     return this.packageDir + '/' + this.packageName();
 | |
|   };
 | |
| 
 | |
| })();
 | |
| 
 | |
| jake.PackageTask = PackageTask;
 | |
| exports.PackageTask = PackageTask;
 | |
| 
 |