Set up comprehensive frontend testing infrastructure
- 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>
This commit is contained in:
		
							
								
								
									
										330
									
								
								frontend/node_modules/jake/lib/jake.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								frontend/node_modules/jake/lib/jake.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,330 @@ | ||||
| /* | ||||
|  * 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. | ||||
|  * | ||||
| */ | ||||
|  | ||||
| if (!global.jake) { | ||||
|  | ||||
|   let EventEmitter = require('events').EventEmitter; | ||||
|   // And so it begins | ||||
|   global.jake = new EventEmitter(); | ||||
|  | ||||
|   let fs = require('fs'); | ||||
|   let chalk = require('chalk'); | ||||
|   let taskNs = require('./task'); | ||||
|   let Task = taskNs.Task; | ||||
|   let FileTask = taskNs.FileTask; | ||||
|   let DirectoryTask = taskNs.DirectoryTask; | ||||
|   let Rule = require('./rule').Rule; | ||||
|   let Namespace = require('./namespace').Namespace; | ||||
|   let RootNamespace = require('./namespace').RootNamespace; | ||||
|   let api = require('./api'); | ||||
|   let utils = require('./utils'); | ||||
|   let Program = require('./program').Program; | ||||
|   let loader = require('./loader')(); | ||||
|   let pkg = JSON.parse(fs.readFileSync(__dirname + '/../package.json').toString()); | ||||
|  | ||||
|   const MAX_RULE_RECURSION_LEVEL = 16; | ||||
|  | ||||
|   // Globalize jake and top-level API methods (e.g., `task`, `desc`) | ||||
|   Object.assign(global, api); | ||||
|  | ||||
|   // Copy utils onto base jake | ||||
|   jake.logger = utils.logger; | ||||
|   jake.exec = utils.exec; | ||||
|  | ||||
|   // File utils should be aliased directly on base jake as well | ||||
|   Object.assign(jake, utils.file); | ||||
|  | ||||
|   // Also add top-level API methods to exported object for those who don't want to | ||||
|   // use the globals (`file` here will overwrite the 'file' utils namespace) | ||||
|   Object.assign(jake, api); | ||||
|  | ||||
|   Object.assign(jake, new (function () { | ||||
|  | ||||
|     this._invocationChain = []; | ||||
|     this._taskTimeout = 30000; | ||||
|  | ||||
|     // Public properties | ||||
|     // ================= | ||||
|     this.version = pkg.version; | ||||
|     // Used when Jake exits with a specific error-code | ||||
|     this.errorCode = null; | ||||
|     // Loads Jakefiles/jakelibdirs | ||||
|     this.loader = loader; | ||||
|     // The root of all ... namespaces | ||||
|     this.rootNamespace = new RootNamespace(); | ||||
|     // Non-namespaced tasks are placed into the default | ||||
|     this.defaultNamespace = this.rootNamespace; | ||||
|     // Start in the default | ||||
|     this.currentNamespace = this.defaultNamespace; | ||||
|     // Saves the description created by a 'desc' call that prefaces a | ||||
|     // 'task' call that defines a task. | ||||
|     this.currentTaskDescription = null; | ||||
|     this.program = new Program(); | ||||
|     this.FileList = require('filelist').FileList; | ||||
|     this.PackageTask = require('./package_task').PackageTask; | ||||
|     this.PublishTask = require('./publish_task').PublishTask; | ||||
|     this.TestTask = require('./test_task').TestTask; | ||||
|     this.Task = Task; | ||||
|     this.FileTask = FileTask; | ||||
|     this.DirectoryTask = DirectoryTask; | ||||
|     this.Namespace = Namespace; | ||||
|     this.Rule = Rule; | ||||
|  | ||||
|     this.parseAllTasks = function () { | ||||
|       let _parseNs = function (ns) { | ||||
|         let nsTasks = ns.tasks; | ||||
|         let nsNamespaces = ns.childNamespaces; | ||||
|         for (let q in nsTasks) { | ||||
|           let nsTask = nsTasks[q]; | ||||
|           jake.Task[nsTask.fullName] = nsTask; | ||||
|         } | ||||
|         for (let p in nsNamespaces) { | ||||
|           let nsNamespace = nsNamespaces[p]; | ||||
|           _parseNs(nsNamespace); | ||||
|         } | ||||
|       }; | ||||
|       _parseNs(jake.defaultNamespace); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Displays the list of descriptions available for tasks defined in | ||||
|      * a Jakefile | ||||
|      */ | ||||
|     this.showAllTaskDescriptions = function (f) { | ||||
|       let p; | ||||
|       let maxTaskNameLength = 0; | ||||
|       let task; | ||||
|       let padding; | ||||
|       let name; | ||||
|       let descr; | ||||
|       let filter = typeof f == 'string' ? f : null; | ||||
|       let taskParams; | ||||
|       let len; | ||||
|  | ||||
|       for (p in jake.Task) { | ||||
|         if (!Object.prototype.hasOwnProperty.call(jake.Task, p)) { | ||||
|           continue; | ||||
|         } | ||||
|         if (filter && p.indexOf(filter) == -1) { | ||||
|           continue; | ||||
|         } | ||||
|         task = jake.Task[p]; | ||||
|         taskParams = task.params; | ||||
|  | ||||
|         // Record the length of the longest task name -- used for | ||||
|         // pretty alignment of the task descriptions | ||||
|         if (task.description) { | ||||
|           len = p.length + taskParams.length; | ||||
|           maxTaskNameLength = len > maxTaskNameLength ? | ||||
|             len : maxTaskNameLength; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       // Print out each entry with descriptions neatly aligned | ||||
|       for (p in jake.Task) { | ||||
|         if (!Object.prototype.hasOwnProperty.call(jake.Task, p)) { | ||||
|           continue; | ||||
|         } | ||||
|         if (filter && p.indexOf(filter) == -1) { | ||||
|           continue; | ||||
|         } | ||||
|         task = jake.Task[p]; | ||||
|  | ||||
|         taskParams = ""; | ||||
|         if (task.params != "") { | ||||
|           taskParams = "[" + task.params + "]"; | ||||
|         } | ||||
|  | ||||
|         //name = '\033[32m' + p + '\033[39m '; | ||||
|         name = chalk.green(p); | ||||
|  | ||||
|         descr = task.description; | ||||
|         if (descr) { | ||||
|           descr = chalk.gray('# ' + descr); | ||||
|  | ||||
|           // Create padding-string with calculated length | ||||
|           padding = (new Array(maxTaskNameLength - p.length - taskParams.length + 4)).join(' '); | ||||
|  | ||||
|           console.log('jake ' + name + taskParams + padding + descr); | ||||
|         } | ||||
|       } | ||||
|     }; | ||||
|  | ||||
|     this.createTask = function () { | ||||
|       let args = Array.prototype.slice.call(arguments); | ||||
|       let arg; | ||||
|       let obj; | ||||
|       let task; | ||||
|       let type; | ||||
|       let name; | ||||
|       let action; | ||||
|       let opts = {}; | ||||
|       let prereqs = []; | ||||
|  | ||||
|       type = args.shift(); | ||||
|  | ||||
|       // name, [deps], [action] | ||||
|       // Name (string) + deps (array) format | ||||
|       if (typeof args[0] == 'string') { | ||||
|         name = args.shift(); | ||||
|         if (Array.isArray(args[0])) { | ||||
|           prereqs = args.shift(); | ||||
|         } | ||||
|       } | ||||
|       // name:deps, [action] | ||||
|       // Legacy object-literal syntax, e.g.: {'name': ['depA', 'depB']} | ||||
|       else { | ||||
|         obj = args.shift(); | ||||
|         for (let p in obj) { | ||||
|           prereqs = prereqs.concat(obj[p]); | ||||
|           name = p; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       // Optional opts/callback or callback/opts | ||||
|       while ((arg = args.shift())) { | ||||
|         if (typeof arg == 'function') { | ||||
|           action = arg; | ||||
|         } | ||||
|         else { | ||||
|           opts = Object.assign(Object.create(null), arg); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       task = jake.currentNamespace.resolveTask(name); | ||||
|       if (task && !action) { | ||||
|         // Task already exists and no action, just update prereqs, and return it. | ||||
|         task.prereqs = task.prereqs.concat(prereqs); | ||||
|         return task; | ||||
|       } | ||||
|  | ||||
|       switch (type) { | ||||
|       case 'directory': | ||||
|         action = function action() { | ||||
|           jake.mkdirP(name); | ||||
|         }; | ||||
|         task = new DirectoryTask(name, prereqs, action, opts); | ||||
|         break; | ||||
|       case 'file': | ||||
|         task = new FileTask(name, prereqs, action, opts); | ||||
|         break; | ||||
|       default: | ||||
|         task = new Task(name, prereqs, action, opts); | ||||
|       } | ||||
|  | ||||
|       jake.currentNamespace.addTask(task); | ||||
|  | ||||
|       if (jake.currentTaskDescription) { | ||||
|         task.description = jake.currentTaskDescription; | ||||
|         jake.currentTaskDescription = null; | ||||
|       } | ||||
|  | ||||
|       // FIXME: Should only need to add a new entry for the current | ||||
|       // task-definition, not reparse the entire structure | ||||
|       jake.parseAllTasks(); | ||||
|  | ||||
|       return task; | ||||
|     }; | ||||
|  | ||||
|     this.attemptRule = function (name, ns, level) { | ||||
|       let prereqRule; | ||||
|       let prereq; | ||||
|       if (level > MAX_RULE_RECURSION_LEVEL) { | ||||
|         return null; | ||||
|       } | ||||
|       // Check Rule | ||||
|       prereqRule = ns.matchRule(name); | ||||
|       if (prereqRule) { | ||||
|         prereq = prereqRule.createTask(name, level); | ||||
|       } | ||||
|       return prereq || null; | ||||
|     }; | ||||
|  | ||||
|     this.createPlaceholderFileTask = function (name, namespace) { | ||||
|       let parsed = name.split(':'); | ||||
|       let filePath = parsed.pop(); // Strip any namespace | ||||
|       let task; | ||||
|  | ||||
|       task = namespace.resolveTask(name); | ||||
|  | ||||
|       // If there's not already an existing dummy FileTask for it, | ||||
|       // create one | ||||
|       if (!task) { | ||||
|         // Create a dummy FileTask only if file actually exists | ||||
|         if (fs.existsSync(filePath)) { | ||||
|           task = new jake.FileTask(filePath); | ||||
|           task.dummy = true; | ||||
|           let ns; | ||||
|           if (parsed.length) { | ||||
|             ns = namespace.resolveNamespace(parsed.join(':')); | ||||
|           } | ||||
|           else { | ||||
|             ns = namespace; | ||||
|           } | ||||
|           if (!namespace) { | ||||
|             throw new Error('Invalid namespace, cannot add FileTask'); | ||||
|           } | ||||
|           ns.addTask(task); | ||||
|           // Put this dummy Task in the global Tasks list so | ||||
|           // modTime will be eval'd correctly | ||||
|           jake.Task[`${ns.path}:${filePath}`] = task; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       return task || null; | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     this.run = function () { | ||||
|       let args = Array.prototype.slice.call(arguments); | ||||
|       let program = this.program; | ||||
|       let loader = this.loader; | ||||
|       let preempt; | ||||
|       let opts; | ||||
|  | ||||
|       program.parseArgs(args); | ||||
|       program.init(); | ||||
|  | ||||
|       preempt = program.firstPreemptiveOption(); | ||||
|       if (preempt) { | ||||
|         preempt(); | ||||
|       } | ||||
|       else { | ||||
|         opts = program.opts; | ||||
|         // jakefile flag set but no jakefile yet | ||||
|         if (opts.autocomplete && opts.jakefile === true) { | ||||
|           process.stdout.write('no-complete'); | ||||
|           return; | ||||
|         } | ||||
|         // Load Jakefile and jakelibdir files | ||||
|         let jakefileLoaded = loader.loadFile(opts.jakefile); | ||||
|         let jakelibdirLoaded = loader.loadDirectory(opts.jakelibdir); | ||||
|  | ||||
|         if(!jakefileLoaded && !jakelibdirLoaded && !opts.autocomplete) { | ||||
|           fail('No Jakefile. Specify a valid path with -f/--jakefile, ' + | ||||
|               'or place one in the current directory.'); | ||||
|         } | ||||
|  | ||||
|         program.run(); | ||||
|       } | ||||
|     }; | ||||
|  | ||||
|   })()); | ||||
| } | ||||
|  | ||||
| module.exports = jake; | ||||
		Reference in New Issue
	
	Block a user
	 anthonyrawlins
					anthonyrawlins